#include <SketchSolver_Constraint.h>
+#include <Events_Error.h>
#include <Events_Loop.h>
#include <GeomDataAPI_Dir.h>
#include <GeomDataAPI_Point.h>
#include <GeomDataAPI_Point2D.h>
#include <ModelAPI_AttributeDouble.h>
#include <ModelAPI_AttributeRefList.h>
-#include <Model_Events.h>
+#include <ModelAPI_Events.h>
#include <SketchPlugin_Constraint.h>
+#include <SketchPlugin_ConstraintLength.h>
+#include <SketchPlugin_ConstraintCoincidence.h>
#include <SketchPlugin_Arc.h>
#include <SketchPlugin_Circle.h>
/// Tolerance for value of parameters
const double tolerance = 1.e-10;
+const std::string ERROR_SOLVE_CONSTRAINTS = "Conflicting constraints";
+
/// This value is used to give unique index to the groups
static Slvs_hGroup myGroupIndexer = 0;
theConstraint->data()->attribute(CONSTRAINT_ATTRIBUTES[i])
);
if (!aCAttrRef) continue;
- if (!aCAttrRef->isFeature() &&
+ if (!aCAttrRef->isObject() &&
myEntityAttrMap.find(aCAttrRef->attr()) != myEntityAttrMap.end())
return true;
- if (aCAttrRef->isFeature() &&
- myEntityFeatMap.find(aCAttrRef->feature()) != myEntityFeatMap.end())
+ if (aCAttrRef->isObject() &&
+ myEntityFeatMap.find(boost::dynamic_pointer_cast<ModelAPI_Feature>(aCAttrRef->object()))
+ != myEntityFeatMap.end())
return true;
}
// Create constraint parameters
double aDistance = 0.0; // scalar value of the constraint
- boost::shared_ptr<ModelAPI_AttributeDouble> aDistAttr =
+ AttributeDoublePtr aDistAttr =
boost::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theConstraint->data()->attribute(CONSTRAINT_ATTR_VALUE));
if (aDistAttr)
{
aDistance = aDistAttr->value();
+ // SketchPlugin circle defined by its radius, but SolveSpace uses constraint for diameter
+ if (aConstrType == SLVS_C_DIAMETER)
+ aDistance *= 2.0;
if (aConstrMapIter != myConstraintMap.end() && fabs(aConstrIter->valA - aDistance) > tolerance)
{
myNeedToSolve = true;
aConstrIter->valA = aDistance;
}
- // SketchPlugin circle defined by its radius, but SolveSpace uses constraint for diameter
- if (aConstrType == SLVS_C_DIAMETER)
- aDistance *= 2.0;
}
Slvs_hEntity aConstrEnt[CONSTRAINT_ATTR_SIZE]; // parameters of the constraint
if (!aConstrAttr) continue;
// For the length constraint the start and end points of the line should be added to the entities list instead of line
- if (aConstrType == SLVS_C_PT_PT_DISTANCE && theConstraint->getKind().compare("SketchConstraintLength") == 0)
+ if (aConstrType == SLVS_C_PT_PT_DISTANCE && theConstraint->getKind().compare(SKETCH_CONSTRAINT_LENGTH_KIND) == 0)
{
- boost::shared_ptr<ModelAPI_Data> aData = aConstrAttr->feature()->data();
+ boost::shared_ptr<ModelAPI_Data> aData = aConstrAttr->object()->data();
aConstrEnt[indAttr] = changeEntity(aData->attribute(LINE_ATTR_START));
aConstrEnt[indAttr+1] = changeEntity(aData->attribute(LINE_ATTR_END));
+ // measured object is added into the map of objects to avoid problems with interaction betwee constraint and group
+ myEntityFeatMap[boost::dynamic_pointer_cast<ModelAPI_Feature>(aConstrAttr->object())] = 0;
break; // there should be no other entities
}
- else if (aConstrAttr->isFeature())
- aConstrEnt[indAttr] = changeEntity(aConstrAttr->feature());
+ else if (aConstrAttr->isObject())
+ aConstrEnt[indAttr] = changeEntity(boost::dynamic_pointer_cast<ModelAPI_Feature>(aConstrAttr->object()));
else
aConstrEnt[indAttr] = changeEntity(aConstrAttr->attr());
}
{
// Several points may be coincident, it is not necessary to store all constraints between them.
// Try to find sequence of coincident points which connects the points of new constraint
- if (aConstrType == SLVS_C_POINTS_COINCIDENT &&
- !addCoincidentPoints(aConstrEnt[0], aConstrEnt[1]))
+ if (aConstrType == SLVS_C_POINTS_COINCIDENT)
{
- myExtraCoincidence.insert(theConstraint); // the constraint is stored for further purposes
- return false;
+ if (aConstrEnt[0] == aConstrEnt[1]) // no need to add self coincidence
+ {
+ return false;
+ }
+ if (!addCoincidentPoints(aConstrEnt[0], aConstrEnt[1]))
+ {
+ myExtraCoincidence.insert(theConstraint); // the constraint is stored for further purposes
+ return false;
+ }
}
// Create SolveSpace constraint structure
}
// Scalar value (used for the distance entities)
- boost::shared_ptr<ModelAPI_AttributeDouble> aScalar =
+ AttributeDoublePtr aScalar =
boost::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theEntity);
if (aScalar)
{
// Purpose: create/update the element defined by the feature affected by any constraint
// ============================================================================
Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity(
- boost::shared_ptr<ModelAPI_Feature> theEntity)
+ FeaturePtr theEntity)
{
// If the entity is already in the group, try to find it
- std::map<boost::shared_ptr<ModelAPI_Feature>, Slvs_hEntity>::const_iterator
+ std::map<FeaturePtr, Slvs_hEntity>::const_iterator
aEntIter = myEntityFeatMap.find(theEntity);
// defines that the entity already exists
const bool isEntExists = (myEntityFeatMap.find(theEntity) != myEntityFeatMap.end());
// SketchPlugin features
- boost::shared_ptr<SketchPlugin_Feature> aFeature;
+ boost::shared_ptr<SketchPlugin_Feature> aFeature =
boost::dynamic_pointer_cast<SketchPlugin_Feature>(theEntity);
if (aFeature)
{ // Verify the feature by its kind
const std::string& aFeatureKind = aFeature->getKind();
// Line
- if (aFeatureKind.compare("SketchLine") == 0)
+ if (aFeatureKind.compare(SKETCH_LINE_KIND) == 0)
{
Slvs_hEntity aStart = changeEntity(aFeature->data()->attribute(LINE_ATTR_START));
Slvs_hEntity aEnd = changeEntity(aFeature->data()->attribute(LINE_ATTR_END));
return aLineEntity.h;
}
// Circle
- else if (aFeatureKind.compare("SketchCircle") == 0)
+ else if (aFeatureKind.compare(SKETCH_CIRCLE_KIND) == 0)
{
Slvs_hEntity aCenter = changeEntity(aFeature->data()->attribute(CIRCLE_ATTR_CENTER));
Slvs_hEntity aRadius = changeEntity(aFeature->data()->attribute(CIRCLE_ATTR_RADIUS));
return aCircleEntity.h;
}
// Arc
- else if (aFeatureKind.compare("SketchArc") == 0)
+ else if (aFeatureKind.compare(SKETCH_ARC_KIND) == 0)
{
Slvs_hEntity aCenter = changeEntity(aFeature->data()->attribute(ARC_ATTR_CENTER));
Slvs_hEntity aStart = changeEntity(aFeature->data()->attribute(ARC_ATTR_START));
return anArcEntity.h;
}
// Point (it has low probability to be an attribute of constraint, so it is checked at the end)
- else if (aFeatureKind.compare("SketchPoint") == 0)
+ else if (aFeatureKind.compare(SKETCH_POINT_KIND) == 0)
{
Slvs_hEntity aPoint = changeEntity(aFeature->data()->attribute(POINT_ATTR_COORD));
bool SketchSolver_ConstraintGroup::addWorkplane(
boost::shared_ptr<SketchPlugin_Feature> theSketch)
{
- if (myWorkplane.h || theSketch->getKind().compare("Sketch") != 0)
+ if (myWorkplane.h || theSketch->getKind().compare(SKETCH_KIND) != 0)
return false; // the workplane already exists or the function parameter is not Sketch
mySketch = theSketch;
std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
anEntIter = myEntityAttrMap.begin();
for ( ; anEntIter != myEntityAttrMap.end(); anEntIter++)
- updateAttribute(anEntIter->first, anEntIter->second);
+ if (updateAttribute(anEntIter->first, anEntIter->second))
+ updateRelatedConstraints(anEntIter->first);
}
- /// \todo Implement error handling
+ else if (!myConstraints.empty())
+ Events_Error::send(ERROR_SOLVE_CONSTRAINTS, this);
removeTemporaryConstraints();
myNeedToSolve = false;
{
if (!aConstrIter->first->data()->isValid())
{
- if (aConstrIter->first->getKind().compare("SketchConstraintCoincidence") == 0)
+ if (aConstrIter->first->getKind().compare(SKETCH_CONSTRAINT_COINCIDENCE_KIND) == 0)
isCCRemoved = true;
std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::reverse_iterator
aCopyIter = aConstrIter++;
// Class: SketchSolver_ConstraintGroup
// Purpose: update features of sketch after resolving constraints
// ============================================================================
-void SketchSolver_ConstraintGroup::updateAttribute(
+bool SketchSolver_ConstraintGroup::updateAttribute(
boost::shared_ptr<ModelAPI_Attribute> theAttribute,
const Slvs_hEntity& theEntityID)
{
boost::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
if (aPoint)
{
- aPoint->setValue(myParams[aFirstParamPos].val,
- myParams[aFirstParamPos+1].val,
- myParams[aFirstParamPos+2].val);
- return ;
+ if (fabs(aPoint->x() - myParams[aFirstParamPos].val) > tolerance ||
+ fabs(aPoint->y() - myParams[aFirstParamPos+1].val) > tolerance ||
+ fabs(aPoint->z() - myParams[aFirstParamPos+2].val) > tolerance)
+ {
+ aPoint->setValue(myParams[aFirstParamPos].val,
+ myParams[aFirstParamPos+1].val,
+ myParams[aFirstParamPos+2].val);
+ return true;
+ }
+ return false;
}
// Point in 2D
boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
if (aPoint2D)
{
- aPoint2D->setValue(myParams[aFirstParamPos].val,
- myParams[aFirstParamPos+1].val);
- return ;
+ if (fabs(aPoint2D->x() - myParams[aFirstParamPos].val) > tolerance ||
+ fabs(aPoint2D->y() - myParams[aFirstParamPos+1].val) > tolerance)
+ {
+ aPoint2D->setValue(myParams[aFirstParamPos].val,
+ myParams[aFirstParamPos+1].val);
+ return true;
+ }
+ return false;
}
// Scalar value
- boost::shared_ptr<ModelAPI_AttributeDouble> aScalar =
+ AttributeDoublePtr aScalar =
boost::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
if (aScalar)
{
- aScalar->setValue(myParams[aFirstParamPos].val);
- return ;
+ if (fabs(aScalar->value() - myParams[aFirstParamPos].val) > tolerance)
+ {
+ aScalar->setValue(myParams[aFirstParamPos].val);
+ return true;
+ }
+ return false;
}
/// \todo Support other types of entities
+ return false;
}
// ============================================================================
// Restore flag of changes
myNeedToSolve = myNeedToSolve || aNeedToSolveCopy;
+
+ if (myNeedToSolve)
+ updateRelatedConstraints(theEntity);
}
}
}
else anEntAttrIter++;
}
- std::map<boost::shared_ptr<ModelAPI_Feature>, Slvs_hEntity>::iterator
+ std::map<FeaturePtr, Slvs_hEntity>::iterator
anEntFeatIter = myEntityFeatMap.begin();
while (anEntFeatIter != myEntityFeatMap.end())
{
if (anEntToRemove.find(anEntFeatIter->second) != anEntToRemove.end())
{
- std::map<boost::shared_ptr<ModelAPI_Feature>, Slvs_hEntity>::iterator
+ std::map<FeaturePtr, Slvs_hEntity>::iterator
aRemovedIter = anEntFeatIter;
anEntFeatIter++;
myEntityFeatMap.erase(aRemovedIter);
}
+// ============================================================================
+// Function: updateRelatedConstraints
+// Class: SketchSolver_ConstraintGroup
+// Purpose: emit the signal to update constraints
+// ============================================================================
+void SketchSolver_ConstraintGroup::updateRelatedConstraints(
+ boost::shared_ptr<ModelAPI_Attribute> theEntity) const
+{
+ std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::const_iterator
+ aConstrIter = myConstraintMap.begin();
+ for ( ; aConstrIter != myConstraintMap.end(); aConstrIter++)
+ {
+ std::list< boost::shared_ptr<ModelAPI_Attribute> > anAttributes =
+ aConstrIter->first->data()->attributes(std::string());
+
+ std::list< boost::shared_ptr<ModelAPI_Attribute> >::iterator
+ anAttrIter = anAttributes.begin();
+ for ( ; anAttrIter != anAttributes.end(); anAttrIter++)
+ {
+ bool isUpd = (*anAttrIter == theEntity);
+ boost::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr =
+ boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
+ if (aRefAttr && !aRefAttr->isObject() && aRefAttr->attr() == theEntity)
+ isUpd = true;
+
+ if (isUpd)
+ {
+ static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
+ ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
+ break;
+ }
+ }
+ }
+}
+
+void SketchSolver_ConstraintGroup::updateRelatedConstraints(
+ boost::shared_ptr<ModelAPI_Feature> theFeature) const
+{
+ std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::const_iterator
+ aConstrIter = myConstraintMap.begin();
+ for ( ; aConstrIter != myConstraintMap.end(); aConstrIter++)
+ {
+ std::list< boost::shared_ptr<ModelAPI_Attribute> > anAttributes =
+ aConstrIter->first->data()->attributes(std::string());
+
+ std::list< boost::shared_ptr<ModelAPI_Attribute> >::iterator
+ anAttrIter = anAttributes.begin();
+ for ( ; anAttrIter != anAttributes.end(); anAttrIter++)
+ {
+ boost::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr =
+ boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
+ if (aRefAttr && aRefAttr->isObject() && aRefAttr->object() == theFeature)
+ {
+ static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
+ ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
+ break;
+ }
+ }
+ }
+}
+
// ========================================================
int aVecSize = theEntities.size();
while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
aResIndex--;
- while (aResIndex < aVecSize && theEntities[aResIndex].h < theEntityID)
+ while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
aResIndex++;
if (aResIndex == -1)
aResIndex = aVecSize;