}
};
+typedef std::shared_ptr<SketchPlugin_Constraint> ConstraintPtr;
+
#endif
SET(PROJECT_HEADERS
SketchSolver.h
+ SketchSolver_Error.h
SketchSolver_Solver.h
SketchSolver_Constraint.h
- SketchSolver_ConstraintGroup.h
+ SketchSolver_ConstraintCoincidence.h
+ SketchSolver_ConstraintRigid.h
+ SketchSolver_Builder.h
+ SketchSolver_Group.h
SketchSolver_ConstraintManager.h
+ SketchSolver_Storage.h
+ SketchSolver_FeatureStorage.h
)
SET(PROJECT_SOURCES
SketchSolver_Solver.cpp
SketchSolver_Constraint.cpp
- SketchSolver_ConstraintGroup.cpp
+ SketchSolver_ConstraintCoincidence.cpp
+ SketchSolver_ConstraintRigid.cpp
+ SketchSolver_Builder.cpp
+ SketchSolver_Group.cpp
SketchSolver_ConstraintManager.cpp
+ SketchSolver_Storage.cpp
+ SketchSolver_FeatureStorage.cpp
)
SET(PROJECT_LIBRARIES
#endif
#endif
+/// Tolerance for value of parameters
+const double tolerance = 1.e-10;
+
#endif
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_Builder.cpp
+// Created: 25 Mar 2015
+// Author: Artem ZHIDKOV
+
+#include "SketchSolver_Builder.h"
+#include <SketchSolver_ConstraintCoincidence.h>
+#include <SketchSolver_ConstraintRigid.h>
+
+#include <GeomAPI_Edge.h>
+#include <GeomDataAPI_Dir.h>
+#include <GeomDataAPI_Point.h>
+#include <GeomDataAPI_Point2D.h>
+#include <ModelAPI_Attribute.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeRefAttr.h>
+#include <ModelAPI_AttributeRefList.h>
+#include <ModelAPI_ResultConstruction.h>
+
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
+#include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintDistance.h>
+#include <SketchPlugin_ConstraintEqual.h>
+#include <SketchPlugin_ConstraintFillet.h>
+#include <SketchPlugin_ConstraintHorizontal.h>
+#include <SketchPlugin_ConstraintLength.h>
+#include <SketchPlugin_ConstraintMirror.h>
+#include <SketchPlugin_ConstraintParallel.h>
+#include <SketchPlugin_ConstraintPerpendicular.h>
+#include <SketchPlugin_ConstraintRadius.h>
+#include <SketchPlugin_ConstraintRigid.h>
+#include <SketchPlugin_ConstraintTangent.h>
+#include <SketchPlugin_ConstraintVertical.h>
+
+
+// Initialization of constraint builder self pointer
+SketchSolver_Builder* SketchSolver_Builder::mySelf = 0;
+
+SketchSolver_Builder* SketchSolver_Builder::getInstance()
+{
+ if (!mySelf)
+ mySelf = new SketchSolver_Builder();
+ return mySelf;
+}
+
+SolverConstraintPtr SketchSolver_Builder::createConstraint(ConstraintPtr theConstraint)
+{
+ SolverConstraintPtr aResult;
+ DataPtr aData = theConstraint->data();
+ if (!aData || !aData->isValid())
+ return aResult;
+
+ if (theConstraint->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
+ return SolverConstraintPtr(new SketchSolver_ConstraintCoincidence(theConstraint));
+ } else if (theConstraint->getKind() == SketchPlugin_ConstraintDistance::ID()) {
+ return SolverConstraintPtr(new SketchSolver_ConstraintDistance(theConstraint));
+ } else if (theConstraint->getKind() == SketchPlugin_ConstraintEqual::ID()) {
+//// return SolverConstraintPtr(new SketchSolver_ConstraintEqual(theConstraint));
+ } else if (theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID()) {
+//// return SolverConstraintPtr(new SketchSolver_ConstraintFillet(theConstraint));
+ } else if (theConstraint->getKind() == SketchPlugin_ConstraintHorizontal::ID()) {
+ return SolverConstraintPtr(new SketchSolver_ConstraintHorizontal(theConstraint));
+ } else if (theConstraint->getKind() == SketchPlugin_ConstraintLength::ID()) {
+//// return SolverConstraintPtr(new SketchSolver_ConstraintLength(theConstraint));
+ } else if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) {
+//// return SolverConstraintPtr(new SketchSolver_ConstraintMirror(theConstraint));
+ } else if (theConstraint->getKind() == SketchPlugin_ConstraintParallel::ID()) {
+ return SolverConstraintPtr(new SketchSolver_ConstraintParallel(theConstraint));
+ } else if (theConstraint->getKind() == SketchPlugin_ConstraintPerpendicular::ID()) {
+ return SolverConstraintPtr(new SketchSolver_ConstraintPerpendicular(theConstraint));
+ } else if (theConstraint->getKind() == SketchPlugin_ConstraintRadius::ID()) {
+//// return SolverConstraintPtr(new SketchSolver_ConstraintRadius(theConstraint));
+ } else if (theConstraint->getKind() == SketchPlugin_ConstraintTangent::ID()) {
+//// return SolverConstraintPtr(new SketchSolver_ConstraintTangent(theConstraint));
+ } else if (theConstraint->getKind() == SketchPlugin_ConstraintVertical::ID()) {
+ return SolverConstraintPtr(new SketchSolver_ConstraintVertical(theConstraint));
+ } else if (theConstraint->getKind() == SketchPlugin_ConstraintRigid::ID()) {
+ return SolverConstraintPtr(new SketchSolver_ConstraintRigid(theConstraint));
+ }
+ return aResult;
+}
+
+SolverConstraintPtr SketchSolver_Builder::createRigidConstraint(FeaturePtr theFixedFeature)
+{
+ DataPtr aData = theFixedFeature->data();
+ if (!aData || !aData->isValid())
+ return SolverConstraintPtr();
+ return SolverConstraintPtr(new SketchSolver_ConstraintRigid(theFixedFeature));
+}
+
+
+
+bool SketchSolver_Builder::createWorkplane(
+ CompositeFeaturePtr theSketch,
+ std::vector<Slvs_Entity>& theEntities,
+ std::vector<Slvs_Param>& theParameters)
+{
+ DataPtr aSketchData = theSketch->data();
+ if (!aSketchData || !aSketchData->isValid())
+ return false; // the sketch is incorrect
+
+ // Get parameters of workplane
+ std::shared_ptr<ModelAPI_Attribute> aDirX = aSketchData->attribute(
+ SketchPlugin_Sketch::DIRX_ID());
+ std::shared_ptr<ModelAPI_Attribute> aNorm = aSketchData->attribute(
+ SketchPlugin_Sketch::NORM_ID());
+ std::shared_ptr<ModelAPI_Attribute> anOrigin = aSketchData->attribute(
+ SketchPlugin_Sketch::ORIGIN_ID());
+ // Create SolveSpace entity corresponding to the sketch origin
+ if (!createEntity(anOrigin, theEntities, theParameters))
+ return false;
+ Slvs_hEntity anOriginID = theEntities.back().h;
+ // Create SolveSpace entity corresponding the the sketch normal
+ if (!createNormal(aNorm, aDirX, theEntities, theParameters))
+ return false;
+ Slvs_hEntity aNormalID = theEntities.back().h;
+
+ // Create workplane
+ Slvs_hEntity aWorkplaneID = theEntities.back().h + 1;
+ Slvs_Entity aWorkplane = Slvs_MakeWorkplane(aWorkplaneID, SLVS_G_UNKNOWN, anOriginID, aNormalID);
+ theEntities.push_back(aWorkplane);
+ return true;
+}
+
+bool SketchSolver_Builder::createEntity(
+ AttributePtr theAttribute,
+ std::vector<Slvs_Entity>& theEntities,
+ std::vector<Slvs_Param>& theParameters)
+{
+ Slvs_hEntity anEntID = theEntities.empty() ? 0 : theEntities.back().h;
+ Slvs_hParam aParamID = theParameters.empty() ? 0 : theParameters.back().h;
+
+ // Point in 3D
+ std::shared_ptr<GeomDataAPI_Point> aPoint =
+ std::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
+ if (aPoint) {
+ theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint->x()));
+ theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint->y()));
+ theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint->z()));
+ theEntities.push_back(Slvs_MakePoint3d(++anEntID, SLVS_G_UNKNOWN,
+ aParamID-2, aParamID-1, aParamID));
+ return true;
+ }
+ // Point in 2D
+ std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
+ if (aPoint2D) {
+ theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint2D->x()));
+ theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint2D->y()));
+ theEntities.push_back(Slvs_MakePoint2d(++anEntID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN,
+ aParamID-1, aParamID));
+ return true;
+ }
+ // Scalar value (used for the distance entities)
+ AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
+ if (aScalar) {
+ theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aScalar->value()));
+ theEntities.push_back(Slvs_MakeDistance(++anEntID, SLVS_G_UNKNOWN,
+ SLVS_E_UNKNOWN, aParamID));
+ return true;
+ }
+ // unknown attribute type
+ return false;
+}
+
+bool SketchSolver_Builder::createEntity(
+ FeaturePtr theFeature,
+ std::vector<Slvs_Entity>& theEntities,
+ std::vector<Slvs_Param>& theParameters)
+{
+ if (!theFeature->data()->isValid())
+ return false;
+
+ // SketchPlugin features
+ std::shared_ptr<SketchPlugin_Feature> aFeature = std::dynamic_pointer_cast<
+ SketchPlugin_Feature>(theFeature);
+ if (!aFeature)
+ return false;
+
+ // Verify the feature by its kind
+ const std::string& aFeatureKind = aFeature->getKind();
+ DataPtr aData = aFeature->data();
+ // Line
+ if (aFeatureKind == SketchPlugin_Line::ID()) {
+ AttributePtr aStart = aData->attribute(SketchPlugin_Line::START_ID());
+ AttributePtr aEnd = aData->attribute(SketchPlugin_Line::END_ID());
+ if (!aStart->isInitialized() || !aEnd->isInitialized())
+ return false;
+ if (!createEntity(aStart, theEntities, theParameters) ||
+ !createEntity(aEnd, theEntities, theParameters))
+ return false;
+ Slvs_hEntity aLineID = theEntities.back().h + 1;
+ theEntities.push_back(Slvs_MakeLineSegment(aLineID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN,
+ aLineID-2, aLineID-1));
+ }
+ // Circle
+ else if (aFeatureKind == SketchPlugin_Circle::ID()) {
+ AttributePtr aCenter = aData->attribute(SketchPlugin_Circle::CENTER_ID());
+ AttributePtr aRadius = aData->attribute(SketchPlugin_Circle::RADIUS_ID());
+ if (!aCenter->isInitialized() || !aRadius->isInitialized())
+ return false;
+ if (!createEntity(aCenter, theEntities, theParameters) ||
+ !createEntity(aRadius, theEntities, theParameters))
+ return false;
+ Slvs_hEntity aCircID = theEntities.back().h;
+ theEntities.push_back(Slvs_MakeCircle(aCircID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN, aCircID-2,
+ SLVS_E_UNKNOWN, aCircID-1));
+ }
+ // Arc
+ else if (aFeatureKind == SketchPlugin_Arc::ID()) {
+ AttributePtr aCenter = aData->attribute(SketchPlugin_Arc::CENTER_ID());
+ AttributePtr aStart = aData->attribute(SketchPlugin_Arc::START_ID());
+ AttributePtr aEnd = aData->attribute(SketchPlugin_Arc::END_ID());
+ if (!aCenter->isInitialized() || !aStart->isInitialized() || !aEnd->isInitialized())
+ return false;
+ if (!createEntity(aCenter, theEntities, theParameters) ||
+ !createEntity(aStart, theEntities, theParameters) ||
+ !createEntity(aEnd, theEntities, theParameters))
+ return false;
+ Slvs_hEntity anArcID = theEntities.back().h;
+ theEntities.push_back(Slvs_MakeArcOfCircle(anArcID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN,
+ SLVS_E_UNKNOWN, anArcID-3, anArcID-2, anArcID-1));
+ }
+ // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
+ else if (aFeatureKind == SketchPlugin_Point::ID()) {
+ AttributePtr aPoint = aData->attribute(SketchPlugin_Point::COORD_ID());
+ if (!aPoint->isInitialized() ||
+ !createEntity(aPoint, theEntities, theParameters))
+ return false;
+ // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier.
+ // No need to add another entity.
+ }
+ return true;
+}
+
+bool SketchSolver_Builder::createNormal(
+ AttributePtr theNormal,
+ AttributePtr theDirX,
+ std::vector<Slvs_Entity>& theEntities,
+ std::vector<Slvs_Param>& theParameters)
+{
+ std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theNormal);
+ std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
+ if (!aDirX || (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance))
+ return false;
+ // calculate Y direction
+ std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aDirX->dir())));
+
+ // quaternion parameters of normal vector
+ double qw, qx, qy, qz;
+ Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), aDirY->x(), aDirY->y(), aDirY->z(), &qw,
+ &qx, &qy, &qz);
+ double aNormCoord[4] = { qw, qx, qy, qz };
+
+ // Create parameters of the normal
+ Slvs_hParam aCurParam = theParameters.back().h;
+ for (int i = 0; i < 4; i++)
+ theParameters.push_back(Slvs_MakeParam(++aCurParam, SLVS_G_UNKNOWN, aNormCoord[i]));
+
+ // Create a normal
+ Slvs_hEntity aCurEntity = theEntities.back().h + 1;
+ Slvs_Entity aNormal = Slvs_MakeNormal3d(aCurEntity, SLVS_G_UNKNOWN,
+ aCurParam-3, aCurParam-2, aCurParam-1, aCurParam);
+ theEntities.push_back(aNormal);
+ return true;
+}
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_Builder.h
+// Created: 25 Mar 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SketchSolver_Builder_H_
+#define SketchSolver_Builder_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+
+#include <SketchPlugin_Constraint.h>
+
+#include <ModelAPI_CompositeFeature.h>
+
+/** \class SketchSolver_Builder
+ * \ingroup Plugins
+ * \brief Create bridges between SketchPlugin constraints and SolveSpace constraints
+ */
+class SketchSolver_Builder
+{
+private:
+ /// Default constructor
+ SketchSolver_Builder() {}
+
+public:
+ /// \brief Returns single instance of builder
+ static SketchSolver_Builder* getInstance();
+
+ /// \brief Creates a solver's constraint using given SketchPlugin constraint
+ /// or returns empty pointer if not all attributes are correct
+ SolverConstraintPtr createConstraint(ConstraintPtr theConstraint);
+
+ /// \brief Creates temporary constraint to fix the placement of the feature
+ SolverConstraintPtr createRigidConstraint(FeaturePtr theFixedFeature);
+
+ /// \brief Converts sketch parameters to the list of SolveSpace entities.
+ /// Identifiers of entities and parameters are local. They should be changed while adding into storage.
+ /// The sketch entity goes last.
+ /// \param[in] theSketch the element to be converted
+ /// \param[out] theEntities created list of entities
+ /// \param[out] theParameters created list of parameters of the entities
+ /// \return \c true if workplane created
+ bool createWorkplane(CompositeFeaturePtr theSketch,
+ std::vector<Slvs_Entity>& theEntities,
+ std::vector<Slvs_Param>& theParameters);
+
+ /// \brief Converts attribute to the list of entities.
+ /// Identifiers are local (see createWorkplane).
+ /// The main entity goes last.
+ bool createEntity(AttributePtr theAttribute,
+ std::vector<Slvs_Entity>& theEntities,
+ std::vector<Slvs_Param>& theParameters);
+ /// \brief Converts feature to the list of entities.
+ /// Identifiers are local (see createWorkplane).
+ /// The main entity goes last.
+ bool createEntity(FeaturePtr theFeature,
+ std::vector<Slvs_Entity>& theEntities,
+ std::vector<Slvs_Param>& theParameters);
+
+ /// \brief Converts normal and OX direction to the list of entities representing a normal in SolveSpace.
+ /// Identifiers are local (see createWorkplane).
+ /// The main entity goes last.
+ bool createNormal(AttributePtr theNormal,
+ AttributePtr theDirX,
+ std::vector<Slvs_Entity>& theEntities,
+ std::vector<Slvs_Param>& theParameters);
+
+private:
+ static SketchSolver_Builder* mySelf;
+};
+
+#endif
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File: SketchSolver_Constraint.cpp
-// Created: 27 May 2014
-// Author: Artem ZHIDKOV
-
-#include "SketchSolver_Constraint.h"
-#include <SketchSolver_Solver.h>
+#include <SketchSolver_Constraint.h>
+#include <SketchSolver_Group.h>
+#include <SketchSolver_Error.h>
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
#include <SketchPlugin_Line.h>
#include <SketchPlugin_Point.h>
-#include <SketchPlugin_Circle.h>
-#include <SketchPlugin_Arc.h>
-#include <SketchPlugin_ConstraintCoincidence.h>
-#include <SketchPlugin_ConstraintDistance.h>
-#include <SketchPlugin_ConstraintEqual.h>
-#include <SketchPlugin_ConstraintFillet.h>
-#include <SketchPlugin_ConstraintHorizontal.h>
-#include <SketchPlugin_ConstraintLength.h>
-#include <SketchPlugin_ConstraintMirror.h>
-#include <SketchPlugin_ConstraintParallel.h>
-#include <SketchPlugin_ConstraintPerpendicular.h>
-#include <SketchPlugin_ConstraintRadius.h>
-#include <SketchPlugin_ConstraintRigid.h>
-#include <SketchPlugin_ConstraintTangent.h>
-#include <SketchPlugin_ConstraintVertical.h>
-
-#include <ModelAPI_AttributeRefAttr.h>
-#include <ModelAPI_AttributeRefList.h>
-#include <ModelAPI_Data.h>
-#include <ModelAPI_Document.h>
-#include <ModelAPI_Object.h>
-#include <ModelAPI_ResultConstruction.h>
#include <GeomDataAPI_Point.h>
#include <GeomDataAPI_Point2D.h>
-#include <GeomAPI_Edge.h>
-#include <GeomAPI_Shape.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_ResultConstruction.h>
+
-/// Possible types of attributes (used to determine constraint type)
-enum AttrType
+SketchSolver_Constraint::SketchSolver_Constraint(
+ ConstraintPtr theConstraint)
+ : myBaseConstraint(theConstraint),
+ myGroup(0)
{
- UNKNOWN, // Something wrong during type determination
- POINT2D,
- POINT3D,
- LINE,
- CIRCLE,
- ARC
-};
-
-/// Calculate type of the attribute
-static AttrType typeOfAttribute(std::shared_ptr<ModelAPI_Attribute> theAttribute);
-
-SketchSolver_Constraint::SketchSolver_Constraint()
- : myConstraint(std::shared_ptr<SketchPlugin_Constraint>()),
- myType(SLVS_C_UNKNOWN),
- myAttributesList()
+}
+
+SketchSolver_Constraint::~SketchSolver_Constraint()
{
+ std::map<AttributePtr, Slvs_hParam>::const_iterator anIt1 = myValueMap.begin();
+ for (; anIt1 != myValueMap.end(); anIt1++)
+ myStorage->removeParameter(anIt1->second);
+ myValueMap.clear();
+
+ std::map<AttributePtr, Slvs_hEntity>::const_iterator anIt2 = myAttributeMap.begin();
+ for (; anIt2 != myAttributeMap.end(); anIt2++)
+ myStorage->removeEntity(anIt2->second);
+ myAttributeMap.clear();
+
+ std::map<FeaturePtr, Slvs_hEntity>::const_iterator anIt3 = myFeatureMap.begin();
+ for (; anIt3 != myFeatureMap.end(); anIt3++)
+ myStorage->removeEntity(anIt3->second);
+ myFeatureMap.clear();
+
+ std::vector<Slvs_hConstraint>::const_iterator anIt4 = mySlvsConstraints.begin();
+ for (; anIt4 != mySlvsConstraints.end(); anIt4++)
+ myStorage->removeConstraint(*anIt4);
+ mySlvsConstraints.clear();
}
-SketchSolver_Constraint::SketchSolver_Constraint(
- std::shared_ptr<SketchPlugin_Constraint> theConstraint)
- : myConstraint(theConstraint),
- myAttributesList()
+void SketchSolver_Constraint::setStorage(StoragePtr theStorage)
{
- myType = getType(myConstraint);
+ myStorage = theStorage;
+ process();
}
-const int& SketchSolver_Constraint::getType(
- std::shared_ptr<SketchPlugin_Constraint> theConstraint)
+void SketchSolver_Constraint::setGroup(SketchSolver_Group* theGroup)
{
- myType = SLVS_C_UNKNOWN;
- if (!theConstraint)
- return getType();
-
- DataPtr aConstrData = theConstraint->data();
- if (!aConstrData || !aConstrData->isValid())
- return getType();
-
- // Assign empty names of attributes
- myAttributesList.clear();
- for (int i = 0; i < CONSTRAINT_ATTR_SIZE; i++)
- myAttributesList.push_back(std::string());
-
- const std::string& aConstraintKind = theConstraint->getKind();
- // Constraint for coincidence of two points
- if (aConstraintKind.compare(SketchPlugin_ConstraintCoincidence::ID()) == 0) {
- int anAttrPos = 0;
- // Verify the constraint has only two attributes and they are points
- int aPt2d = 0; // bit-mapped field, each bit indicates whether the attribute is 2D point
- int aPt3d = 0; // bit-mapped field, the same information for 3D points
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
- std::shared_ptr<ModelAPI_Attribute> anAttr =
- aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
- if (!anAttr)
- continue;
- switch (typeOfAttribute(anAttr)) {
- case POINT2D: // the attribute is a 2D point
- aPt2d |= (1 << indAttr);
- myAttributesList[anAttrPos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
- break;
- case POINT3D: // the attribute is a 3D point
- aPt3d |= (1 << indAttr);
- myAttributesList[anAttrPos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
- break;
- default:
- // Attribute neither 2D nor 3D point is not supported by this type of constraint
- return getType();
- }
- }
- // The constrained points should be in first and second positions,
- // so the expected value of aPt2d or aPt3d is 3
- if (aPt2d + aPt3d == 3)
- myType = SLVS_C_POINTS_COINCIDENT;
- // Constraint parameters are wrong
- return getType();
+ myGroup = theGroup;
+ process();
+}
+
+
+void SketchSolver_Constraint::process()
+{
+ cleanErrorMsg();
+ if (!myBaseConstraint || !myStorage || myGroup == 0) {
+ /// TODO: Put error message here
+ return;
}
+ if (!mySlvsConstraints.empty()) // some data is changed, update constraint
+ update(myBaseConstraint);
- // Constraint for distance between point and another entity
- if (aConstraintKind.compare(SketchPlugin_ConstraintDistance::ID()) == 0) {
- int aNbPoints = 0;
- int aNbEntities = 0;
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
- std::shared_ptr<ModelAPI_Attribute> anAttr =
- aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
- switch (typeOfAttribute(anAttr)) {
- case POINT2D:
- case POINT3D:
- myAttributesList[aNbPoints++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
- break;
- case LINE:
- // entities are placed starting from SketchPlugin_Constraint::ENTITY_C() attribute
- myAttributesList[2 + aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
- myType = SLVS_C_PT_LINE_DISTANCE;
- break;
- }
- }
- // Verify the correctness of constraint arguments
- if (aNbPoints == 2 && aNbEntities == 0)
- myType = SLVS_C_PT_PT_DISTANCE;
- else if (aNbPoints != 1 || aNbEntities != 1)
- myType = SLVS_C_UNKNOWN;
- return getType();
+ int aConstrType = getType();
+ double aValue = 0.0;
+ std::vector<Slvs_hEntity> anAttributes;
+ getAttributes(aValue, anAttributes);
+ if (!myErrorMsg.empty())
+ return;
+
+ Slvs_hGroup aGroupID = myGroup->getId();
+ Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId();
+ Slvs_Constraint aConstraint;
+ if (mySlvsConstraints.empty())
+ aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, aGroupID, aConstrType, aWorkplaneID,
+ aValue, anAttributes[0], anAttributes[1], anAttributes[2], anAttributes[3]);
+ else {
+ aConstraint = myStorage->getConstraint(mySlvsConstraints[0]);
+ aConstraint.valA = aValue;
+ static const int aNbAttrs = 6;
+ Slvs_hEntity* aConstrAttrs[aNbAttrs] = {
+ &aConstraint.ptA, &aConstraint.ptB,
+ &aConstraint.entityA, &aConstraint.entityB,
+ &aConstraint.entityC, &aConstraint.entityD};
+ std::vector<Slvs_hEntity>::const_iterator anIter = anAttributes.begin();
+ for (int i = 0; i < aNbAttrs && anIter != anAttributes.end(); i++, anIter++)
+ *(aConstrAttrs[i]) = *anIter;
}
- // Constraint for the given length of a line
- if (aConstraintKind.compare(SketchPlugin_ConstraintLength::ID()) == 0) {
- int aNbLines = 0;
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
- std::shared_ptr<ModelAPI_Attribute> anAttr =
- aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
- if (typeOfAttribute(anAttr) == LINE)
- myAttributesList[aNbLines++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
- }
- if (aNbLines == 1)
- myType = SLVS_C_PT_PT_DISTANCE;
- return getType();
+ Slvs_hConstraint anID = myStorage->addConstraint(aConstraint);
+ if (mySlvsConstraints.empty())
+ mySlvsConstraints.push_back(anID);
+ else
+ mySlvsConstraints[0] = anID;
+}
+
+void SketchSolver_Constraint::update(ConstraintPtr theConstraint)
+{
+ cleanErrorMsg();
+ if (theConstraint && theConstraint != myBaseConstraint) {
+ if (theConstraint->getKind() != myBaseConstraint->getKind())
+ return;
+ remove(myBaseConstraint);
+ myBaseConstraint = theConstraint;
+ process();
}
- // Constraint for two parallel/perpendicular lines
- bool isParallel = (aConstraintKind.compare(SketchPlugin_ConstraintParallel::ID()) == 0);
- bool isPerpendicular = (aConstraintKind.compare(SketchPlugin_ConstraintPerpendicular::ID()) == 0);
- if (isParallel || isPerpendicular) {
- int aNbEntities = 2; // lines in SolveSpace constraints should start from SketchPlugin_Constraint::ENTITY_C() attribute
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
- std::shared_ptr<ModelAPI_Attribute> anAttr =
- aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
- if (typeOfAttribute(anAttr) == LINE)
- myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+ int aType;
+ std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIter = myFeatureMap.begin();
+ for (; aFeatIter != myFeatureMap.end(); aFeatIter++)
+ aFeatIter->second = changeEntity(aFeatIter->first, aType);
+ std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIter = myAttributeMap.begin();
+ for (; anAttrIter != myAttributeMap.end(); anAttrIter++)
+ anAttrIter->second = changeEntity(anAttrIter->first, aType);
+}
+
+bool SketchSolver_Constraint::remove(ConstraintPtr theConstraint)
+{
+ cleanErrorMsg();
+ if (theConstraint && theConstraint != myBaseConstraint)
+ return false;
+ bool isFullyRemoved = myStorage->removeConstraint(mySlvsConstraints.front());
+ if (isFullyRemoved) {
+ myFeatureMap.clear();
+ myAttributeMap.clear();
+ myValueMap.clear();
+ } else
+ cleanRemovedEntities();
+ return true;
+}
+
+void SketchSolver_Constraint::cleanRemovedEntities()
+{
+ std::set<Slvs_hParam> aRemovedParams;
+ std::set<Slvs_hEntity> aRemovedEntities;
+ std::set<Slvs_hConstraint> aRemovedConstraints;
+ myStorage->getRemoved(aRemovedParams, aRemovedEntities, aRemovedConstraints);
+ std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = myFeatureMap.begin();
+ while (aFeatIt != myFeatureMap.end()) {
+ if (aRemovedEntities.find(aFeatIt->second) == aRemovedEntities.end()) {
+ aFeatIt++;
+ continue;
+ }
+ std::map<FeaturePtr, Slvs_hEntity>::iterator aTmpIter = aFeatIt++;
+ myFeatureMap.erase(aTmpIter);
+ }
+ std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIt = myAttributeMap.begin();
+ while (anAttrIt != myAttributeMap.end()) {
+ if (aRemovedEntities.find(anAttrIt->second) == aRemovedEntities.end()) {
+ anAttrIt++;
+ continue;
}
- if (aNbEntities == 4)
- myType = isParallel ? SLVS_C_PARALLEL : SLVS_C_PERPENDICULAR;
- return getType();
+ std::map<AttributePtr, Slvs_hEntity>::iterator aTmpIter = anAttrIt++;
+ myAttributeMap.erase(aTmpIter);
}
+ std::map<AttributePtr, Slvs_hParam>::iterator aValIt = myValueMap.begin();
+ while (aValIt != myValueMap.end()) {
+ if (aRemovedParams.find(aValIt->second) == aRemovedParams.end()) {
+ aValIt++;
+ continue;
+ }
+ std::map<AttributePtr, Slvs_hParam>::iterator aTmpIter = aValIt++;
+ myValueMap.erase(aTmpIter);
+ }
+}
+
+void SketchSolver_Constraint::getAttributes(
+ double& theValue,
+ std::vector<Slvs_hEntity>& theAttributes)
+{
+ static const int anInitNbOfAttr = 4;
+ theAttributes.assign(anInitNbOfAttr, SLVS_E_UNKNOWN);
+
+ DataPtr aData = myBaseConstraint->data();
- // Constraint for radius of a circle or an arc of circle
- if (aConstraintKind.compare(SketchPlugin_ConstraintRadius::ID()) == 0) {
- int aNbEntities = 2; // lines in SolveSpace constraints should started from SketchPlugin_Constraint::ENTITY_C() attribute
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
- std::shared_ptr<ModelAPI_Attribute> anAttr =
- aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
- AttrType aType = typeOfAttribute(anAttr);
- if (aType == CIRCLE || aType == ARC)
- myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+ AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+ aData->attribute(SketchPlugin_Constraint::VALUE()));
+ theValue = aValueAttr ? aValueAttr->value() : 0.0;
+
+ int aPtInd = 0; // index of first point in the list of attributes
+ int aEntInd = 2; // index of first antity in the list of attributes
+ std::list<AttributePtr> aConstrAttrs = aData->attributes(ModelAPI_AttributeRefAttr::typeId());
+ std::list<AttributePtr>::iterator anIter = aConstrAttrs.begin();
+ for (; anIter != aConstrAttrs.end(); anIter++) {
+ AttributeRefAttrPtr aRefAttr =
+ std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+ if (!aRefAttr || !aRefAttr->isInitialized()) {
+ myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+ return;
+ }
+
+ int aType = SLVS_E_UNKNOWN; // type of created entity
+ Slvs_hEntity anEntity = myGroup->getAttributeId(aRefAttr);
+ if (anEntity == SLVS_E_UNKNOWN)
+ anEntity = changeEntity(aRefAttr, aType);
+ else {
+ Slvs_Entity anEnt = myStorage->getEntity(anEntity);
+ aType = anEnt.type;
+ }
+
+ if (aType == SLVS_E_UNKNOWN)
+ continue;
+ else if (aType == SLVS_E_POINT_IN_2D || aType == SLVS_E_POINT_IN_3D)
+ theAttributes[aPtInd++] = anEntity; // the point is created
+ else { // another entity (not a point) is created
+ if (aEntInd < anInitNbOfAttr)
+ theAttributes[aEntInd] = anEntity;
+ else
+ theAttributes.push_back(anEntity);
+ aEntInd++;
}
- if (aNbEntities == 3)
- myType = SLVS_C_DIAMETER;
- return getType();
}
+}
- // Constraint for fixed entity
- if (aConstraintKind.compare(SketchPlugin_ConstraintRigid::ID()) == 0) {
- // Verify that only one entity is filled
- int aNbAttrs = 0;
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
- std::shared_ptr<ModelAPI_Attribute> anAttr =
- aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
- AttrType aType = typeOfAttribute(anAttr);
- if (aType != UNKNOWN)
- myAttributesList[aNbAttrs++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+Slvs_hEntity SketchSolver_Constraint::changeEntity(AttributeRefAttrPtr theAttribute, int& theType)
+{
+ // Convert the object of the attribute to the feature
+ FeaturePtr aFeature;
+ if (theAttribute->isObject() && theAttribute->object()) {
+ ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+ theAttribute->object());
+ if (!aRC) {
+ myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+ return SLVS_E_UNKNOWN;
}
- if (aNbAttrs == 1)
- myType = SLVS_C_WHERE_DRAGGED;
- return getType();
+ std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
+ aFeature = aDoc->feature(aRC);
+
+ return changeEntity(aFeature, theType);
}
- // Constraint for horizontal/vertical line
- bool isHorizontal = (aConstraintKind.compare(SketchPlugin_ConstraintHorizontal::ID()) == 0);
- bool isVertical = (aConstraintKind.compare(SketchPlugin_ConstraintVertical::ID()) == 0);
- if (isHorizontal || isVertical) {
- int aNbEntities = 2; // lines in SolveSpace constraints should start from SketchPlugin_Constraint::ENTITY_C() attribute
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
- std::shared_ptr<ModelAPI_Attribute> anAttr =
- aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
- if (typeOfAttribute(anAttr) == LINE)
- myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+ return changeEntity(theAttribute->attr(), theType);
+}
+
+Slvs_hEntity SketchSolver_Constraint::changeEntity(AttributePtr theEntity, int& theType)
+{
+ Slvs_hEntity aResult = SLVS_E_UNKNOWN;
+ if (!theEntity->isInitialized())
+ return SLVS_E_UNKNOWN;
+
+ // If the entity is already in the group, try to find it
+ std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator anEntIter =
+ myAttributeMap.find(theEntity);
+ Slvs_Entity aCurrentEntity;
+ aCurrentEntity.h = SLVS_E_UNKNOWN;
+ if (anEntIter != myAttributeMap.end())
+ aCurrentEntity = myStorage->getEntity(anEntIter->second);
+ else {
+ aResult = myGroup->getAttributeId(theEntity);
+ if (aResult != SLVS_E_UNKNOWN) {
+ Slvs_Entity anEnt = myStorage->getEntity(aResult);
+ theType = anEnt.type;
+ return aResult;
}
- if (aNbEntities == 3)
- myType = isHorizontal ? SLVS_C_HORIZONTAL : SLVS_C_VERTICAL;
- return getType();
}
- if (aConstraintKind.compare(SketchPlugin_ConstraintEqual::ID()) == 0) {
- static const int aConstrType[3] = {
- SLVS_C_EQUAL_RADIUS,
- SLVS_C_EQUAL_LINE_ARC_LEN,
- SLVS_C_EQUAL_LENGTH_LINES
- };
- int aNbLines = 0;
- int aNbEntities = 2; // lines and circles in SolveSpace constraints should start from SketchPlugin_Constraint::ENTITY_C() attribute
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
- std::shared_ptr<ModelAPI_Attribute> anAttr =
- aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
- AttrType aType = typeOfAttribute(anAttr);
- if (aType == LINE) {
- myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
- aNbLines++;
+ Slvs_hGroup aGroupID = myGroup->getId();
+ // Point in 3D
+ std::shared_ptr<GeomDataAPI_Point> aPoint =
+ std::dynamic_pointer_cast<GeomDataAPI_Point>(theEntity);
+ if (aPoint) {
+ double aXYZ[3] = {aPoint->x(), aPoint->y(), aPoint->z()};
+ Slvs_hParam aParams[3];
+ for (int i = 0; i < 3; i++) {
+ Slvs_Param aPar = aCurrentEntity.h != SLVS_E_UNKNOWN ?
+ myStorage->getParameter(aCurrentEntity.param[i]) :
+ Slvs_MakeParam(SLVS_E_UNKNOWN, aGroupID, 0.0);
+ aPar.val = aXYZ[i];
+ aParams[i] = myStorage->addParameter(aPar);
+ }
+
+ if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
+ aCurrentEntity = Slvs_MakePoint3d(SLVS_E_UNKNOWN, aGroupID, aParams[0], aParams[1], aParams[2]);
+ else { // update entity data
+ for (int i = 0; i < 3; i++)
+ aCurrentEntity.param[i] = aParams[i];
+ }
+ aResult = myStorage->addEntity(aCurrentEntity);
+ } else {
+ // All entities except 3D points are created on workplane. So, if there is no workplane yet, then error
+ Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId();
+ if (aWorkplaneID == SLVS_E_UNKNOWN)
+ return SLVS_E_UNKNOWN;
+
+ // Point in 2D
+ std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
+ if (aPoint2D) {
+ double aXY[2] = {aPoint2D->x(), aPoint2D->y()};
+ Slvs_hParam aParams[2];
+ for (int i = 0; i < 2; i++) {
+ Slvs_Param aPar = aCurrentEntity.h != SLVS_E_UNKNOWN ?
+ myStorage->getParameter(aCurrentEntity.param[i]) :
+ Slvs_MakeParam(SLVS_E_UNKNOWN, aGroupID, 0.0);
+ aPar.val = aXY[i];
+ aParams[i] = myStorage->addParameter(aPar);
+ }
+
+ if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
+ aCurrentEntity = Slvs_MakePoint2d(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aParams[0], aParams[1]);
+ else { // update entity data
+ for (int i = 0; i < 2; i++)
+ aCurrentEntity.param[i] = aParams[i];
+ }
+ aResult = myStorage->addEntity(aCurrentEntity);
+ } else {
+ // Scalar value (used for the distance entities)
+ AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theEntity);
+ if (aScalar) {
+ Slvs_Param aParam = aCurrentEntity.h != SLVS_E_UNKNOWN ?
+ myStorage->getParameter(aCurrentEntity.param[0]) :
+ Slvs_MakeParam(SLVS_E_UNKNOWN, aGroupID, 0.0);
+ aParam.val = aScalar->value();
+ Slvs_hParam aValue = myStorage->addParameter(aParam);
+
+ if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
+ aCurrentEntity = Slvs_MakeDistance(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aValue);
+ else
+ aCurrentEntity.param[0] = aValue;
+ aResult = myStorage->addEntity(aCurrentEntity);
}
- else if (aType == CIRCLE || aType == ARC)
- myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
}
- if (aNbEntities == 4)
- myType = aConstrType[aNbLines];
- return getType();
}
- if (aConstraintKind.compare(SketchPlugin_ConstraintTangent::ID()) == 0) {
- static const int anArcPosDefault = 2;
- static const int aLinePosDefault = 3;
- int anArcPos = anArcPosDefault; // arc in tangency constraint should be placed before line
- int aLinePos = aLinePosDefault;
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
- std::shared_ptr<ModelAPI_Attribute> anAttr =
- aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
- AttrType aType = typeOfAttribute(anAttr);
- if (aType == LINE && aLinePos < CONSTRAINT_ATTR_SIZE)
- myAttributesList[aLinePos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
- else if (aType == ARC)
- myAttributesList[anArcPos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+ myAttributeMap[theEntity] = aResult;
+ theType = aCurrentEntity.type;
+ return aResult;
+}
+
+Slvs_hEntity SketchSolver_Constraint::changeEntity(FeaturePtr theEntity, int& theType)
+{
+ Slvs_hEntity aResult = SLVS_E_UNKNOWN;
+ if (!theEntity->data()->isValid())
+ return SLVS_E_UNKNOWN;
+ // If the entity is already in the group, try to find it
+ std::map<FeaturePtr, Slvs_hEntity>::const_iterator anEntIter = myFeatureMap.find(theEntity);
+ Slvs_Entity aCurrentEntity;
+ aCurrentEntity.h = SLVS_E_UNKNOWN;
+ if (anEntIter != myFeatureMap.end())
+ aCurrentEntity = myStorage->getEntity(anEntIter->second);
+ else {
+ aResult = myGroup->getFeatureId(theEntity);
+ if (aResult != SLVS_E_UNKNOWN) {
+ Slvs_Entity anEnt = myStorage->getEntity(aResult);
+ theType = anEnt.type;
+ return aResult;
}
- if (anArcPos - anArcPosDefault + aLinePos - aLinePosDefault == 2)
- myType = aLinePos > 3 ? SLVS_C_ARC_LINE_TANGENT : SLVS_C_CURVE_CURVE_TANGENT;
- return getType();
}
- if (aConstraintKind.compare(SketchPlugin_ConstraintMirror::ID()) == 0) {
- int aNbAttrs = 0;
- bool hasMirrorLine = false;
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
- AttributeRefListPtr anAttrRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
- aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr)));
- if (anAttrRefList) {
- aNbAttrs++;
- myAttributesList[aNbAttrs] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
- }
+ Slvs_hGroup aGroupID = myGroup->getId();
+ Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId();
+ // SketchPlugin features
+ std::shared_ptr<SketchPlugin_Feature> aFeature = std::dynamic_pointer_cast<
+ SketchPlugin_Feature>(theEntity);
+ if (aFeature) { // Verify the feature by its kind
+ const std::string& aFeatureKind = aFeature->getKind();
+ AttributePtr anAttribute;
+ int anAttrType;
+
+ // Line
+ if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) {
+ anAttribute = aFeature->data()->attribute(SketchPlugin_Line::START_ID());
+ if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+ Slvs_hEntity aStart = changeEntity(anAttribute, anAttrType);
+
+ anAttribute = aFeature->data()->attribute(SketchPlugin_Line::END_ID());
+ if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+ Slvs_hEntity aEnd = changeEntity(anAttribute, anAttrType);
+
+ if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
+ aCurrentEntity = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aStart, aEnd);
else {
- std::shared_ptr<ModelAPI_Attribute> anAttr =
- aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
- if (typeOfAttribute(anAttr) == LINE) {
- hasMirrorLine = !hasMirrorLine;
- myAttributesList[0] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
- }
+ aCurrentEntity.point[0] = aStart;
+ aCurrentEntity.point[1] = aEnd;
}
+ aResult = myStorage->addEntity(aCurrentEntity);
}
- if (aNbAttrs == 2 && hasMirrorLine)
- myType = SLVS_C_SYMMETRIC_LINE;
- return getType();
- }
+ // Circle
+ else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) {
+ anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::CENTER_ID());
+ if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+ Slvs_hEntity aCenter = changeEntity(anAttribute, anAttrType);
- if (aConstraintKind.compare(SketchPlugin_ConstraintFillet::ID()) == 0) {
- int aNbAttrs = 0;
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
- AttributeRefListPtr anAttrRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
- aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr)));
- if (anAttrRefList)
- myAttributesList[aNbAttrs++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
- else {
- std::shared_ptr<ModelAPI_Attribute> anAttr =
- aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
- AttrType aType = typeOfAttribute(anAttr);
- if (aType == LINE || aType == ARC)
- myAttributesList[aNbAttrs++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+ anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID());
+ if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+ Slvs_hEntity aRadius = changeEntity(anAttribute, anAttrType);
+
+ if (aCurrentEntity.h == SLVS_E_UNKNOWN) { // New entity
+ Slvs_Entity aWorkplane = myStorage->getEntity(aWorkplaneID);
+ aCurrentEntity = Slvs_MakeCircle(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID,
+ aCenter, aWorkplane.normal, aRadius);
+ } else {
+ aCurrentEntity.point[0] = aCenter;
+ aCurrentEntity.distance = aRadius;
}
+ aResult = myStorage->addEntity(aCurrentEntity);
}
- if (aNbAttrs == 3)
- myType = SLVS_C_FILLET;
- return getType();
- }
+ // Arc
+ else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) {
+ anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID());
+ if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+ Slvs_hEntity aCenter = changeEntity(anAttribute, anAttrType);
- /// \todo Implement other kind of constraints
+ anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::START_ID());
+ if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+ Slvs_hEntity aStart = changeEntity(anAttribute, anAttrType);
+
+ anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::END_ID());
+ if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+ Slvs_hEntity aEnd = changeEntity(anAttribute, anAttrType);
+
+ if (aCurrentEntity.h == SLVS_E_UNKNOWN) { // New entity
+ Slvs_Entity aWorkplane = myStorage->getEntity(aWorkplaneID);
+ aCurrentEntity = Slvs_MakeArcOfCircle(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID,
+ aWorkplane.normal, aCenter, aStart, aEnd);
+ } else {
+ aCurrentEntity.point[0] = aCenter;
+ aCurrentEntity.point[1] = aStart;
+ aCurrentEntity.point[2] = aEnd;
+ }
+ aResult = myStorage->addEntity(aCurrentEntity);
+ }
+ // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
+ else if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0) {
+ anAttribute = aFeature->data()->attribute(SketchPlugin_Point::COORD_ID());
+ if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+ // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier
+ aResult = changeEntity(anAttribute, anAttrType);
+ aCurrentEntity.type = SLVS_E_POINT_IN_3D;
+ }
+ }
- return getType();
+ myFeatureMap[theEntity] = aResult;
+ theType = aCurrentEntity.type;
+ return aResult;
}
-// ================= Auxiliary functions ==============================
-AttrType typeOfAttribute(std::shared_ptr<ModelAPI_Attribute> theAttribute)
+std::list<ConstraintPtr> SketchSolver_Constraint::constraints() const
{
- std::shared_ptr<ModelAPI_AttributeRefAttr> anAttrRef = std::dynamic_pointer_cast<
- ModelAPI_AttributeRefAttr>(theAttribute);
- if (!anAttrRef)
- return UNKNOWN;
+ std::list<ConstraintPtr> aConstraints;
+ aConstraints.push_back(myBaseConstraint);
+ return aConstraints;
+}
- if (anAttrRef->isObject()) {
- ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
- anAttrRef->object());
- if (!aRC || !aRC->shape())
- return UNKNOWN;
-
- if (aRC->shape()->isVertex())
- return POINT3D;
- else if (aRC->shape()->isEdge()) {
- std::shared_ptr<GeomAPI_Edge> anEdge = std::dynamic_pointer_cast<GeomAPI_Edge>(
- aRC->shape());
- if (anEdge->isLine())
- return LINE;
- else if (anEdge->isCircle())
- return CIRCLE;
- else if (anEdge->isArc())
- return ARC;
+void SketchSolver_Constraint::refresh()
+{
+ cleanErrorMsg();
+ std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIter = myAttributeMap.begin();
+ for (; anAttrIter != myAttributeMap.end(); anAttrIter++) {
+ std::shared_ptr<GeomDataAPI_Point> aPoint =
+ std::dynamic_pointer_cast<GeomDataAPI_Point>(anAttrIter->first);
+ if (aPoint) {
+ Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second);
+ double aXYZ[3];
+ for (int i = 0; i < 3; i++) {
+ Slvs_Param aPar = myStorage->getParameter(anEntity.param[i]);
+ aXYZ[i] = aPar.val;
+ }
+ aPoint->setValue(aXYZ[0], aXYZ[1], aXYZ[2]);
+ } else {
+ // Point in 2D
+ std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrIter->first);
+ if (aPoint2D) {
+ Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second);
+ double aXYZ[2];
+ for (int i = 0; i < 2; i++) {
+ Slvs_Param aPar = myStorage->getParameter(anEntity.param[i]);
+ aXYZ[i] = aPar.val;
+ }
+ aPoint2D->setValue(aXYZ[0], aXYZ[1]);
+ } else {
+ // Scalar value (used for the distance entities)
+ AttributeDoublePtr aScalar =
+ std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttrIter->first);
+ if (aScalar) {
+ Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second);
+ Slvs_Param aPar = myStorage->getParameter(anEntity.param[0]);
+ aScalar->setValue(aPar.val);
+ }
+ }
}
- } else {
- if (anAttrRef->attr().get() != NULL) {
- const std::string aType = anAttrRef->attr()->attributeType();
- if (aType == GeomDataAPI_Point2D::typeId())
- return POINT2D;
- if (aType == GeomDataAPI_Point2D::typeId())
- return POINT2D;
+ }
+
+ std::map<AttributePtr, Slvs_hParam>::iterator aValIter = myValueMap.begin();
+ for (; aValIter != myValueMap.end(); aValIter++) {
+ AttributeDoublePtr aScalar =
+ std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttrIter->first);
+ if (aScalar) {
+ Slvs_Param aPar = myStorage->getParameter(anAttrIter->second);
+ aScalar->setValue(aPar.val);
}
}
+}
+
+Slvs_hEntity SketchSolver_Constraint::getId(FeaturePtr theFeature) const
+{
+ std::map<FeaturePtr, Slvs_hEntity>::const_iterator aFIter = myFeatureMap.find(theFeature);
+ if (aFIter == myFeatureMap.end())
+ return SLVS_E_UNKNOWN;
+ return aFIter->second;
+}
- return UNKNOWN;
+Slvs_hEntity SketchSolver_Constraint::getId(AttributePtr theAttribute) const
+{
+ std::map<AttributePtr, Slvs_hEntity>::const_iterator anAttrIter = myAttributeMap.find(theAttribute);
+ if (anAttrIter == myAttributeMap.end())
+ return SLVS_E_UNKNOWN;
+ return anAttrIter->second;
}
#define SketchSolver_Constraint_H_
#include "SketchSolver.h"
+#include <SketchSolver_Storage.h>
#include <SketchPlugin_Constraint.h>
+#include <ModelAPI_AttributeRefAttr.h>
+
#include <string>
#include <vector>
+class SketchSolver_Group;
+
/** \class SketchSolver_Constraint
* \ingroup Plugins
- * \brief Obtain information about SketchPlugin's constraint
+ * \brief Stores mapping between SketchPlugin and SolveSpace constraints data
*/
class SketchSolver_Constraint
{
-public:
+protected:
/// Default constructor
- SketchSolver_Constraint();
- /// Creates constraint to manage the given constraint from plugin
- SketchSolver_Constraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
-
- /** \brief Compute constraint type according to SolveSpace identifiers
- * and verify that constraint parameters are correct
- * \param[in] theConstraint constraint which type should be determined
- * \return identifier of constraint type or SLVS_C_UNKNOWN if the type is wrong
- */
- const int& getType(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
- /// \brief Returns the type of myConstraint member
- inline const int& getType() const
- {
- return myType;
- }
-
- /// \brief Returns list of attributes names in the correct order required by SolveSpace
- inline const std::vector<std::string>& getAttributes() const
- {
- return myAttributesList;
- }
-
- private:
- std::shared_ptr<SketchPlugin_Constraint> myConstraint;
- int myType;
- std::vector<std::string> myAttributesList;
+ SketchSolver_Constraint() {}
+ SketchSolver_Constraint(ConstraintPtr theConstraint);
+
+public:
+ virtual ~SketchSolver_Constraint();
+
+ /// \brief Initializes the storage of SolveSpace constraints
+ void setStorage(StoragePtr theStorage);
+ /// \brief Initializes group ID for this constraint
+ void setGroup(SketchSolver_Group* theGroup);
+
+ /// \brief Update constraint
+ virtual void update(ConstraintPtr theConstraint = ConstraintPtr());
+
+ /// \brief Tries to remove constraint
+ /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
+ virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
+
+ /// \brief Update SketchPlugin attributes using the data obtained from SolveSpace entities
+ void refresh();
+
+ /// \brief Returns the type of constraint
+ virtual int getType() const = 0;
+
+ /// \brief Checks the constraint is used by current object
+ virtual bool hasConstraint(ConstraintPtr theConstraint) const
+ { return theConstraint == myBaseConstraint; }
+
+ /// \brief Return list of SketchPlugin constraints attached to this object
+ virtual std::list<ConstraintPtr> constraints() const;
+
+ /// \brief Return identifier of SolveSpace entity relating to the feature
+ Slvs_hEntity getId(FeaturePtr theFeature) const;
+ /// \brief Return identifier of SolveSpace entity relating to the attribute
+ Slvs_hEntity getId(AttributePtr theAttribute) const;
+
+ /// \brief Shows error message
+ const std::string& error() const
+ { return myErrorMsg; }
+
+protected:
+ /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+ virtual void process();
+
+ /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
+ /// \param[out] theValue numerical characteristic of constraint (e.g. distance)
+ /// \param[out] theAttributes list of attributes to be filled
+ virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes);
+
+ /// \brief Create or change SlveSpace entity according to the given attribute
+ /// \param[in] theAttribute reference to the entity to be changed
+ /// \param[out] theType type of created entity
+ /// \return identifier of created/updated entity
+ Slvs_hEntity changeEntity(AttributeRefAttrPtr theAttribute, int& theType);
+ /// \brief Create or change SlveSpace entity according to the given attribute
+ Slvs_hEntity changeEntity(AttributePtr theAttribute, int& theType);
+ /// \brief Create or change SlveSpace entity according to the given feature
+ Slvs_hEntity changeEntity(FeaturePtr theFeature, int& theType);
+
+ /// \brief Removes the links to unused entities
+ void cleanRemovedEntities();
+
+ /// \brief Removes last error
+ void cleanErrorMsg()
+ { myErrorMsg.clear(); }
+
+protected:
+ SketchSolver_Group* myGroup; ///< the group which contains current constraint
+ ConstraintPtr myBaseConstraint; ///< SketchPlugin constraint
+ std::vector<Slvs_hConstraint> mySlvsConstraints; ///< list of indices of SolveSpace constraints, together which equivalent to SketchPlugin constraint
+ std::map<FeaturePtr, Slvs_hEntity> myFeatureMap; ///< map feature to the entity it represents
+ std::map<AttributePtr, Slvs_hEntity> myAttributeMap; ///< map attribute to the corresponding entity
+ std::map<AttributePtr, Slvs_hParam> myValueMap; ///< list of attributes, which represents single value (e.g. distance) used in constraint
+ StoragePtr myStorage; ///< storage, which contains all information about entities and constraints in current group
+
+ std::string myErrorMsg; ///< error message
+};
+
+typedef std::shared_ptr<SketchSolver_Constraint> SolverConstraintPtr;
+
+
+
+/** \class SketchSolver_ConstraintDistance
+ * \ingroup Plugins
+ * \brief Convert distance constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintDistance : public SketchSolver_Constraint
+{
+public:
+ SketchSolver_ConstraintDistance(ConstraintPtr theConstraint) :
+ SketchSolver_Constraint(theConstraint)
+ {}
+
+ virtual int getType() const
+ { return SLVS_C_PT_PT_DISTANCE; }
+};
+
+
+/** \class SketchSolver_ConstraintParallel
+ * \ingroup Plugins
+ * \brief Convert Parallel constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintParallel : public SketchSolver_Constraint
+{
+public:
+ SketchSolver_ConstraintParallel(ConstraintPtr theConstraint) :
+ SketchSolver_Constraint(theConstraint)
+ {}
+
+ virtual int getType() const
+ { return SLVS_C_PARALLEL; }
+};
+
+
+/** \class SketchSolver_ConstraintPerpendicular
+ * \ingroup Plugins
+ * \brief Convert Perpendicular constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintPerpendicular : public SketchSolver_Constraint
+{
+public:
+ SketchSolver_ConstraintPerpendicular(ConstraintPtr theConstraint) :
+ SketchSolver_Constraint(theConstraint)
+ {}
+
+ virtual int getType() const
+ { return SLVS_C_PERPENDICULAR; }
+};
+
+
+/** \class SketchSolver_ConstraintHorizontal
+ * \ingroup Plugins
+ * \brief Convert Horizontal constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintHorizontal : public SketchSolver_Constraint
+{
+public:
+ SketchSolver_ConstraintHorizontal(ConstraintPtr theConstraint) :
+ SketchSolver_Constraint(theConstraint)
+ {}
+
+ virtual int getType() const
+ { return SLVS_C_HORIZONTAL; }
+};
+
+
+/** \class SketchSolver_ConstraintVertical
+ * \ingroup Plugins
+ * \brief Convert Vertical constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintVertical : public SketchSolver_Constraint
+{
+public:
+ SketchSolver_ConstraintVertical(ConstraintPtr theConstraint) :
+ SketchSolver_Constraint(theConstraint)
+ {}
+
+ virtual int getType() const
+ { return SLVS_C_VERTICAL; }
};
#endif
--- /dev/null
+#include <SketchSolver_ConstraintCoincidence.h>
+#include <SketchSolver_Error.h>
+#include <SketchSolver_Group.h>
+
+#include <map>
+
+bool SketchSolver_ConstraintCoincidence::hasConstraint(ConstraintPtr theConstraint) const
+{
+ if (myBaseConstraint == theConstraint)
+ return true;
+ std::map<ConstraintPtr, Slvs_hConstraint>::const_iterator anIt = myExtraCoincidence.begin();
+ for (; anIt != myExtraCoincidence.end(); anIt++)
+ if (anIt->first == theConstraint)
+ return true;
+ return false;
+}
+
+std::list<ConstraintPtr> SketchSolver_ConstraintCoincidence::constraints() const
+{
+ std::list<ConstraintPtr> aConstraints;
+ aConstraints.push_back(myBaseConstraint);
+ std::map<ConstraintPtr, Slvs_hConstraint>::const_iterator anIt = myExtraCoincidence.begin();
+ for (; anIt != myExtraCoincidence.end(); anIt++)
+ aConstraints.push_back(anIt->first);
+ return aConstraints;
+}
+
+bool SketchSolver_ConstraintCoincidence::isCoincide(
+ std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint) const
+{
+ std::map<FeaturePtr, Slvs_hEntity>::const_iterator aFeatIter = myFeatureMap.begin();
+ for (; aFeatIter != myFeatureMap.end(); aFeatIter++)
+ if (theConstraint->myFeatureMap.find(aFeatIter->first) != theConstraint->myFeatureMap.end())
+ return true;
+ std::map<AttributePtr, Slvs_hEntity>::const_iterator anAttrIter = myAttributeMap.begin();
+ for (; anAttrIter != myAttributeMap.end(); anAttrIter++)
+ if (theConstraint->myAttributeMap.find(anAttrIter->first) != theConstraint->myAttributeMap.end())
+ return true;
+ return false;
+}
+
+void SketchSolver_ConstraintCoincidence::attach(
+ std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint)
+{
+ cleanErrorMsg();
+ Slvs_Constraint aBaseCoincidence = myStorage->getConstraint(mySlvsConstraints.front());
+ // Remove constraints from theConstraint
+ std::vector<Slvs_hConstraint>::iterator aCIter = theConstraint->mySlvsConstraints.begin();
+ for (; aCIter != theConstraint->mySlvsConstraints.end(); aCIter++)
+ theConstraint->myStorage->removeConstraint(*aCIter);
+
+ if (myStorage == theConstraint->myStorage) {
+ // Clean removed items
+ std::set<Slvs_hParam> aRemParams;
+ std::set<Slvs_hEntity> aRemEnts;
+ std::set<Slvs_hConstraint> aRemConstr;
+ theConstraint->myStorage->getRemoved(aRemParams, aRemEnts, aRemConstr);
+ }
+
+ // Copy data.
+ addConstraint(theConstraint->myBaseConstraint);
+ std::map<ConstraintPtr, Slvs_hConstraint>::iterator aConstrIter =
+ theConstraint->myExtraCoincidence.begin();
+ for (; aConstrIter != theConstraint->myExtraCoincidence.end(); aConstrIter++)
+ addConstraint(aConstrIter->first);
+ // Clear the lists to not remove the entities on destruction
+ theConstraint->mySlvsConstraints.clear();
+ theConstraint->myFeatureMap.clear();
+ theConstraint->myAttributeMap.clear();
+}
+
+Slvs_hConstraint SketchSolver_ConstraintCoincidence::addConstraint(
+ Slvs_hEntity thePoint1, Slvs_hEntity thePoint2)
+{
+ Slvs_Constraint aNewConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
+ SLVS_C_POINTS_COINCIDENT, myGroup->getWorkplaneId(), 0.0, thePoint1, thePoint2,
+ SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+ Slvs_hConstraint aNewID = myStorage->addConstraint(aNewConstraint);
+ mySlvsConstraints.push_back(aNewID);
+ return aNewID;
+}
+
+void SketchSolver_ConstraintCoincidence::addConstraint(ConstraintPtr theConstraint)
+{
+ std::list<AttributePtr> anAttrList =
+ theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
+ std::list<AttributePtr>::iterator anIter = anAttrList.begin();
+ std::vector<Slvs_hEntity> anEntities;
+ for (; anIter != anAttrList.end(); anIter++) {
+ AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+ if (!aRefAttr || aRefAttr->isObject() ||
+ myAttributeMap.find(aRefAttr->attr()) != myAttributeMap.end())
+ continue;
+ int aType;
+ Slvs_hEntity anEntityID = myGroup->getAttributeId(aRefAttr->attr());
+ if (anEntityID == SLVS_E_UNKNOWN)
+ anEntityID = changeEntity(aRefAttr->attr(), aType);
+ anEntities.push_back(anEntityID);
+ }
+
+ Slvs_Constraint aBaseCoincidence = myStorage->getConstraint(mySlvsConstraints.front());
+ Slvs_hConstraint aNewConstr = SLVS_E_UNKNOWN;
+ std::vector<Slvs_hEntity>::iterator anEntIter = anEntities.begin();
+ for (; anEntIter != anEntities.end(); anEntIter++)
+ aNewConstr = addConstraint(aBaseCoincidence.ptA, *anEntIter);
+ myExtraCoincidence[theConstraint] = aNewConstr;
+}
+
+bool SketchSolver_ConstraintCoincidence::remove(ConstraintPtr theConstraint)
+{
+ cleanErrorMsg();
+ ConstraintPtr aConstraint = theConstraint ? theConstraint : myBaseConstraint;
+ int aPos = -1; // position of constraint in the list (-1 for base constraint)
+ if (aConstraint != myBaseConstraint) {
+ std::map<ConstraintPtr, Slvs_hConstraint>::const_iterator anIt = myExtraCoincidence.begin();
+ for (aPos = 0; anIt != myExtraCoincidence.end(); anIt++, aPos++)
+ if (anIt->first == aConstraint)
+ break;
+ if (aPos >= (int)myExtraCoincidence.size())
+ return false; // there is no constraint, which is specified to remove
+ }
+
+ bool isFullyRemoved = myStorage->removeConstraint(mySlvsConstraints[aPos+1]);
+ mySlvsConstraints.erase(mySlvsConstraints.begin() + (1+aPos));
+ cleanRemovedEntities();
+ if (aPos < 0 && !myExtraCoincidence.empty()) {
+ // Need to specify another base coincidence constraint
+ myBaseConstraint = myExtraCoincidence.begin()->first;
+ myExtraCoincidence.erase(myExtraCoincidence.begin());
+ std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
+ Slvs_Constraint aBase = myStorage->getConstraint(*aCIter);
+ for (++aCIter; aCIter != mySlvsConstraints.end(); aCIter++) {
+ Slvs_Constraint aConstr = myStorage->getConstraint(*aCIter);
+ aConstr.ptA = aBase.ptA;
+ myStorage->updateConstraint(aConstr);
+ }
+ }
+ return true;
+}
+
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_ConstraintCoincidence.h
+// Created: 29 Mar 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SketchSolver_ConstraintCoincidence_H_
+#define SketchSolver_ConstraintCoincidence_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+#include <SketchSolver_Storage.h>
+
+/** \class SketchSolver_ConstraintCoincidence
+ * \ingroup Plugins
+ * \brief Convert coincidence constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintCoincidence : public SketchSolver_Constraint
+{
+public:
+ SketchSolver_ConstraintCoincidence(ConstraintPtr theConstraint) :
+ SketchSolver_Constraint(theConstraint)
+ {}
+
+ virtual int getType() const
+ { return SLVS_C_POINTS_COINCIDENT; }
+
+ /// \brief Tries to remove constraint
+ /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
+ virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
+
+ /// \brief Checks the constraint is used by current object
+ virtual bool hasConstraint(ConstraintPtr theConstraint) const;
+
+ /// \brief Return list of SketchPlugin constraints attached to this object
+ virtual std::list<ConstraintPtr> constraints() const;
+
+ /// \brief Verifies the two Coincidence constraints are intersects (have shared point)
+ bool isCoincide(std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint) const;
+
+ /// \brief Append all data of coincidence constaint to the current
+ void attach(std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint);
+
+private:
+ /// \brief Creates new coincidence constraint
+ Slvs_hConstraint addConstraint(Slvs_hEntity thePoint1, Slvs_hEntity thePoint2);
+
+ /// \brief Create full SolveSpace structure according to given constraint
+ void addConstraint(ConstraintPtr theConstraint);
+
+private:
+ std::map<ConstraintPtr, Slvs_hConstraint> myExtraCoincidence; ///< multiple coincidence of points
+};
+
+#endif
+++ /dev/null
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File: SketchSolver_ConstraintGroup.cpp
-// Created: 27 May 2014
-// Author: Artem ZHIDKOV
-
-#include "SketchSolver_ConstraintGroup.h"
-
-#include <SketchSolver_Constraint.h>
-
-#include <Events_Error.h>
-#include <Events_Loop.h>
-#include <GeomAPI_XY.h>
-#include <GeomAPI_Dir2d.h>
-#include <GeomAPI_Pnt2d.h>
-#include <GeomDataAPI_Dir.h>
-#include <GeomDataAPI_Point.h>
-#include <GeomDataAPI_Point2D.h>
-#include <ModelAPI_AttributeDouble.h>
-#include <ModelAPI_AttributeRefList.h>
-#include <ModelAPI_Document.h>
-#include <ModelAPI_Events.h>
-#include <ModelAPI_ResultConstruction.h>
-
-#include <SketchPlugin_Constraint.h>
-#include <SketchPlugin_ConstraintFillet.h>
-#include <SketchPlugin_ConstraintLength.h>
-#include <SketchPlugin_ConstraintCoincidence.h>
-#include <SketchPlugin_ConstraintMirror.h>
-#include <SketchPlugin_ConstraintRigid.h>
-
-#include <SketchPlugin_Arc.h>
-#include <SketchPlugin_Circle.h>
-#include <SketchPlugin_Line.h>
-#include <SketchPlugin_Point.h>
-#include <SketchPlugin_Sketch.h>
-
-#include <math.h>
-#include <assert.h>
-
-/// Tolerance for value of parameters
-const double tolerance = 1.e-10;
-
-/**
- * Collects all sketch solver error' codes
- * as inline static functions
- */
- // TODO: Move this class into a separate file
-class SketchSolver_Error
-{
- public:
- /// The value parameter for the constraint
- inline static const std::string& CONSTRAINTS()
- {
- static const std::string MY_ERROR_VALUE("Conflicting constraints");
- return MY_ERROR_VALUE;
- }
- /// The entities need to have shared point, but they have not
- inline static const std::string& NO_COINCIDENT_POINTS()
- {
- static const std::string MY_ERROR_VALUE("Objects should have coincident point");
- return MY_ERROR_VALUE;
- }
-};
-
-/// This value is used to give unique index to the groups
-static Slvs_hGroup myGroupIndexer = 0;
-
-/** \brief Search the entity/parameter with specified ID in the list of elements
- * \param[in] theEntityID unique ID of the element
- * \param[in] theEntities list of elements
- * \return position of the found element or -1 if the element is not found
- */
-template<typename T>
-static int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities);
-
-// ========================================================
-// ========= SketchSolver_ConstraintGroup ===============
-// ========================================================
-
-SketchSolver_ConstraintGroup::SketchSolver_ConstraintGroup(
- std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane)
- : myID(++myGroupIndexer),
- myParamMaxID(0),
- myEntityMaxID(0),
- myConstrMaxID(0),
- myConstraintMap(),
- myNeedToSolve(false),
- myConstrSolver()
-{
- myParams.clear();
- myEntities.clear();
- myEntOfConstr.clear();
- myConstraints.clear();
-
- myTempConstraints.clear();
- myTempPointWhereDragged.clear();
- myTempPointWDrgdID = 0;
-
- // Initialize workplane
- myWorkplane.h = SLVS_E_UNKNOWN;
-#ifndef NDEBUG
- assert(addWorkplane(theWorkplane));
-#else
- addWorkplane(theWorkplane);
-#endif
-}
-
-SketchSolver_ConstraintGroup::~SketchSolver_ConstraintGroup()
-{
- myParams.clear();
- myEntities.clear();
- myEntOfConstr.clear();
- myConstraints.clear();
- myConstraintMap.clear();
- myTempConstraints.clear();
- myTempPointWhereDragged.clear();
-
- // If the group with maximal identifier is deleted, decrease the indexer
- if (myID == myGroupIndexer)
- myGroupIndexer--;
-}
-
-// ============================================================================
-// Function: isBaseWorkplane
-// Class: SketchSolver_ConstraintGroup
-// Purpose: verify the group is based on the given workplane
-// ============================================================================
-bool SketchSolver_ConstraintGroup::isBaseWorkplane(
- std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane) const
-{
- return theWorkplane == mySketch;
-}
-
-// ============================================================================
-// Function: isInteract
-// Class: SketchSolver_ConstraintGroup
-// Purpose: verify are there any entities in the group used by given constraint
-// ============================================================================
-bool SketchSolver_ConstraintGroup::isInteract(
- std::shared_ptr<SketchPlugin_Feature> theFeature) const
-{
- // Check the group is empty
- if (isEmpty())
- return true;
-
- // Check if the feature is already in the group
- if (myEntityFeatMap.find(theFeature) != myEntityFeatMap.end())
- return true;
- std::shared_ptr<SketchPlugin_Constraint> aConstr =
- std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
- if (aConstr && myConstraintMap.find(aConstr) != myConstraintMap.end())
- return true;
-
- // Go through the attributes and verify if some of them already in the group
- std::list<std::shared_ptr<ModelAPI_Attribute>>
- anAttrList = theFeature->data()->attributes(std::string());
- std::list<std::shared_ptr<ModelAPI_Attribute>>::const_iterator
- anAttrIter = anAttrList.begin();
- for ( ; anAttrIter != anAttrList.end(); anAttrIter++) {
- AttributeRefListPtr aCAttrRefList =
- std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anAttrIter);
- if (aCAttrRefList) {
- std::list<ObjectPtr> anObjList = aCAttrRefList->list();
- std::list<ObjectPtr>::iterator anIt = anObjList.begin();
- for ( ; anIt != anObjList.end(); anIt++) {
- FeaturePtr aFeature = std::dynamic_pointer_cast<SketchPlugin_Feature>(*anIt);
- if (aFeature && myEntityFeatMap.find(aFeature) != myEntityFeatMap.end())
- return true;
- }
- continue;
- }
- AttributeRefAttrPtr aCAttrRef =
- std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
- if (!aCAttrRef || !aCAttrRef->isObject()) {
- std::shared_ptr<ModelAPI_Attribute> anAttr =
- aCAttrRef ? aCAttrRef->attr() : *anAttrIter;
- if (myEntityAttrMap.find(anAttr) != myEntityAttrMap.end())
- return true;
- } else {
- ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
- aCAttrRef->object());
- if (!aRC)
- continue;
- std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
- FeaturePtr aFeature = aDoc->feature(aRC);
- if (myEntityFeatMap.find(aFeature) != myEntityFeatMap.end())
- return true;
- // search attributes of a feature to be parameters of constraint
- std::list<std::shared_ptr<ModelAPI_Attribute> > aFeatAttrList =
- aFeature->data()->attributes(std::string());
- std::list<std::shared_ptr<ModelAPI_Attribute> >::const_iterator aFAIter = aFeatAttrList
- .begin();
- for (; aFAIter != aFeatAttrList.end(); aFAIter++)
- if (myEntityAttrMap.find(*aFAIter) != myEntityAttrMap.end())
- return true;
- }
- }
-
- // Entities did not found
- return false;
-}
-
-// ============================================================================
-// Function: checkConstraintConsistence
-// Class: SketchSolver_ConstraintGroup
-// Purpose: verifies and changes parameters of the constraint
-// ============================================================================
-void SketchSolver_ConstraintGroup::checkConstraintConsistence(Slvs_Constraint& theConstraint)
-{
- if (theConstraint.type == SLVS_C_PT_LINE_DISTANCE) {
- // Get constraint parameters and check the sign of constraint value
-
- // point coordinates
- int aPtPos = Search(theConstraint.ptA, myEntities);
- int aPtParamPos = Search(myEntities[aPtPos].param[0], myParams);
- std::shared_ptr<GeomAPI_XY> aPoint(
- new GeomAPI_XY(myParams[aPtParamPos].val, myParams[aPtParamPos + 1].val));
-
- // line coordinates
- int aLnPos = Search(theConstraint.entityA, myEntities);
- aPtPos = Search(myEntities[aLnPos].point[0], myEntities);
- aPtParamPos = Search(myEntities[aPtPos].param[0], myParams);
- std::shared_ptr<GeomAPI_XY> aStart(
- new GeomAPI_XY(-myParams[aPtParamPos].val, -myParams[aPtParamPos + 1].val));
- aPtPos = Search(myEntities[aLnPos].point[1], myEntities);
- aPtParamPos = Search(myEntities[aPtPos].param[0], myParams);
- std::shared_ptr<GeomAPI_XY> aEnd(
- new GeomAPI_XY(myParams[aPtParamPos].val, myParams[aPtParamPos + 1].val));
-
- aEnd = aEnd->added(aStart);
- aPoint = aPoint->added(aStart);
- if (aPoint->cross(aEnd) * theConstraint.valA < 0.0)
- theConstraint.valA *= -1.0;
- }
-}
-
-// ============================================================================
-// Function: changeConstraint
-// Class: SketchSolver_ConstraintGroup
-// Purpose: create/update the constraint in the group
-// ============================================================================
-bool SketchSolver_ConstraintGroup::changeConstraint(
- std::shared_ptr<SketchPlugin_Constraint> theConstraint)
-{
- // There is no workplane yet, something wrong
- if (myWorkplane.h == SLVS_E_UNKNOWN)
- return false;
-
- if (theConstraint) {
- if (theConstraint->getKind() == SketchPlugin_ConstraintRigid::ID())
- return changeRigidConstraint(theConstraint);
- if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID())
- return changeMirrorConstraint(theConstraint);
- if (theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID())
- return changeFilletConstraint(theConstraint);
- }
-
- // Search this constraint in the current group to update it
- ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
- std::vector<Slvs_Constraint>::iterator aConstrIter;
- if (aConstrMapIter != myConstraintMap.end()) {
- int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
- aConstrIter = myConstraints.begin() + aConstrPos;
- }
-
- // Get constraint type and verify the constraint parameters are correct
- SketchSolver_Constraint aConstraint(theConstraint);
- int aConstrType = aConstraint.getType();
- if (aConstrType == SLVS_C_UNKNOWN
- || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
- return false;
- const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
-
- // Create constraint parameters
- double aDistance = 0.0; // scalar value of the constraint
- AttributeDoublePtr aDistAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
- theConstraint->data()->attribute(SketchPlugin_Constraint::VALUE()));
- if (aDistAttr) {
- aDistance = aDistAttr->value();
- // Issue #196: checking the positivity of the distance constraint
- if (aDistance < tolerance &&
- (aConstrType == SLVS_C_PT_PT_DISTANCE || aConstrType == SLVS_C_PT_LINE_DISTANCE))
- return false;
- // 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;
- }
- }
-
- size_t aNbTmpConstraints = myTempConstraints.size();
- Slvs_hEntity aConstrEnt[CONSTRAINT_ATTR_SIZE]; // parameters of the constraint
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
- aConstrEnt[indAttr] = SLVS_E_UNKNOWN;
- std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
- ModelAPI_AttributeRefAttr>(
- theConstraint->data()->attribute(aConstraintAttributes[indAttr]));
- if (!aConstrAttr)
- continue;
-
- // Convert the object of the attribute to the feature
- FeaturePtr aFeature;
- if (aConstrAttr->isObject() && aConstrAttr->object()) {
- ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
- aConstrAttr->object());
- if (!aRC)
- continue;
- std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
- aFeature = aDoc->feature(aRC);
- }
-
- // 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(SketchPlugin_ConstraintLength::ID()) == 0) {
- Slvs_hEntity aLineEnt = changeEntityFeature(aFeature);
- int aEntPos = Search(aLineEnt, myEntities);
- aConstrEnt[indAttr++] = myEntities[aEntPos].point[0];
- aConstrEnt[indAttr++] = myEntities[aEntPos].point[1];
- while (indAttr < CONSTRAINT_ATTR_SIZE)
- aConstrEnt[indAttr++] = 0;
- break; // there should be no other entities
- } else if (aConstrAttr->isObject())
- aConstrEnt[indAttr] = changeEntityFeature(aFeature);
- else
- aConstrEnt[indAttr] = changeEntity(aConstrAttr->attr());
- }
-
- if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
- // 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) {
- 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;
- }
- if (aNbTmpConstraints < myTempConstraints.size()) {
- // There was added temporary constraint. Check that there is no coincident points which already rigid.
-
- // Get list of already fixed points
- std::set<Slvs_hEntity> anAlreadyFixed;
- std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
- for (; aCIter != myConstraints.end(); aCIter++)
- if (aCIter->type == SLVS_C_WHERE_DRAGGED) {
- std::list<Slvs_hConstraint>::const_iterator aTmpIt = myTempConstraints.begin();
- for (; aTmpIt != myTempConstraints.end(); aTmpIt++)
- if (*aTmpIt == aCIter->h)
- break;
- if (aTmpIt == myTempConstraints.end())
- anAlreadyFixed.insert(aCIter->ptA);
- }
-
- std::set<Slvs_hConstraint> aTmpConstrToDelete;
- std::list<Slvs_hConstraint>::reverse_iterator aTmpIter = myTempConstraints.rbegin();
- size_t aCurSize = myTempConstraints.size();
- for (; aCurSize > aNbTmpConstraints && aTmpIter != myTempConstraints.rend();
- aTmpIter++, aCurSize--) {
- int aConstrPos = Search(*aTmpIter, myConstraints);
- std::vector<std::set<Slvs_hEntity> >::const_iterator
- aCoincIter = myCoincidentPoints.begin();
- for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++)
- if (aCoincIter->find(myConstraints[aConstrPos].ptA) != aCoincIter->end()) {
- std::set<Slvs_hEntity>::const_iterator anIt;
- for (anIt = aCoincIter->begin(); anIt != aCoincIter->end(); anIt++)
- if (anAlreadyFixed.find(*anIt) != anAlreadyFixed.end()) {
- aTmpConstrToDelete.insert(*aTmpIter);
- break;
- }
- break;
- }
- }
- if (!aTmpConstrToDelete.empty())
- removeTemporaryConstraints(aTmpConstrToDelete);
- }
- }
- // For the tangency constraints it is necessary to identify which points of entities are coincident
- int aSlvsOtherFlag = 0;
- int aSlvsOther2Flag = 0;
- if (aConstrType == SLVS_C_ARC_LINE_TANGENT || aConstrType == SLVS_C_CURVE_CURVE_TANGENT) {
- // Search entities used by constraint
- int anEnt1Pos = Search(aConstrEnt[2], myEntities);
- int anEnt2Pos = Search(aConstrEnt[3], myEntities);
- // Obtain start and end points of entities
- Slvs_hEntity aPointsToFind[4];
- aPointsToFind[0] = myEntities[anEnt1Pos].point[1];
- aPointsToFind[1]= myEntities[anEnt1Pos].point[2];
- bool hasLine = (myEntities[anEnt2Pos].type == SLVS_E_LINE_SEGMENT);
- aPointsToFind[2]= myEntities[anEnt2Pos].point[hasLine ? 0 : 1];
- aPointsToFind[3]= myEntities[anEnt2Pos].point[hasLine ? 1 : 2];
- // Search coincident points
- bool isPointFound[4];
- std::vector<std::set<Slvs_hEntity> >::const_iterator aCPIter = myCoincidentPoints.begin();
- for ( ; aCPIter != myCoincidentPoints.end(); aCPIter++) {
- for (int i = 0; i < 4; i++)
- isPointFound[i] = (aCPIter->find(aPointsToFind[i]) != aCPIter->end());
- if ((isPointFound[0] || isPointFound[1]) && (isPointFound[2] || isPointFound[3])) {
- // the arc is tangent by end point
- if (isPointFound[1]) aSlvsOtherFlag = 1;
- // the second item is an arc and it is tangent by end point too
- if (!hasLine && isPointFound[3]) aSlvsOther2Flag = 1;
- break;
- }
- }
- if (aCPIter == myCoincidentPoints.end()) {
- // There is no coincident points between tangential objects. Generate error message
- Events_Error::send(SketchSolver_Error::NO_COINCIDENT_POINTS(), this);
- return false;
- }
- }
-
- // Create SolveSpace constraint structure
- Slvs_Constraint aSlvsConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType,
- myWorkplane.h, aDistance, aConstrEnt[0],
- aConstrEnt[1], aConstrEnt[2], aConstrEnt[3]);
- if (aSlvsOtherFlag != 0) aSlvsConstr.other = aSlvsOtherFlag;
- if (aSlvsOther2Flag != 0) aSlvsConstr.other2 = aSlvsOther2Flag;
- myConstraints.push_back(aSlvsConstr);
- myConstraintMap[theConstraint] = std::vector<Slvs_hEntity>(1, aSlvsConstr.h);
- int aConstrPos = Search(aSlvsConstr.h, myConstraints);
- aConstrIter = myConstraints.begin() + aConstrPos;
- myNeedToSolve = true;
- } else { // Attributes of constraint may be changed => update constraint
- Slvs_hEntity* aCurrentAttr[] = {&aConstrIter->ptA, &aConstrIter->ptB,
- &aConstrIter->entityA, &aConstrIter->entityB,
- &aConstrIter->entityC, &aConstrIter->entityD};
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
- if (*(aCurrentAttr[indAttr]) != aConstrEnt[indAttr])
- {
- *(aCurrentAttr[indAttr]) = aConstrEnt[indAttr];
- myNeedToSolve = true;
- }
- }
- }
-
- // Update flags of entities to be used by constraints
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++)
- if (aConstrEnt[indAttr] != 0) {
- int aPos = Search(aConstrEnt[indAttr], myEntities);
- myEntOfConstr[aPos] = true;
- // Sub-entities should be used implcitly
- Slvs_hEntity* aEntPtr = myEntities[aPos].point;
- while (*aEntPtr != 0) {
- aPos = Search(*aEntPtr, myEntities);
- myEntOfConstr[aPos] = true;
- aEntPtr++;
- }
- }
-
- checkConstraintConsistence(*aConstrIter);
- return true;
-}
-
-// ============================================================================
-// Function: changeRigidConstraint
-// Class: SketchSolver_ConstraintGroup
-// Purpose: create/update the "Rigid" constraint in the group
-// ============================================================================
-bool SketchSolver_ConstraintGroup::changeRigidConstraint(
- std::shared_ptr<SketchPlugin_Constraint> theConstraint)
-{
- // Search this constraint in the current group to update it
- ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
- std::vector<Slvs_Constraint>::iterator aConstrIter;
- if (aConstrMapIter != myConstraintMap.end()) {
- int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
- aConstrIter = myConstraints.begin() + aConstrPos;
- }
-
- // Get constraint type and verify the constraint parameters are correct
- SketchSolver_Constraint aConstraint(theConstraint);
- int aConstrType = aConstraint.getType();
- if (aConstrType == SLVS_C_UNKNOWN
- || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
- return false;
- const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
-
- Slvs_hEntity aConstrEnt = SLVS_E_UNKNOWN;
- std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
- ModelAPI_AttributeRefAttr>(
- theConstraint->data()->attribute(aConstraintAttributes[0]));
- if (!aConstrAttr)
- return false;
-
- // Convert the object of the attribute to the feature
- FeaturePtr aFeature;
- if (aConstrAttr->isObject() && aConstrAttr->object()) {
- ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
- aConstrAttr->object());
- if (!aRC)
- return false;
- std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
- aFeature = aDoc->feature(aRC);
- }
-
- aConstrEnt = aConstrAttr->isObject() ? changeEntityFeature(aFeature) : changeEntity(aConstrAttr->attr());
-
- if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
- // Check the fixed entity is not a point.
- std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
- ModelAPI_AttributeRefAttr>(theConstraint->data()->attribute(aConstraintAttributes[0]));
- std::shared_ptr<GeomDataAPI_Point> aPoint =
- std::dynamic_pointer_cast<GeomDataAPI_Point>(aConstrAttr->attr());
- std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aConstrAttr->attr());
- if (aPoint || aPoint2D || aFeature->getKind() == SketchPlugin_Point::ID()) {
- // Create SolveSpace constraint structure
- Slvs_Constraint aConstraint = Slvs_MakeConstraint(
- ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
- aConstrEnt, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
- myConstraints.push_back(aConstraint);
- myConstraintMap[theConstraint] = std::vector<Slvs_hEntity>(1, aConstraint.h);
- int aConstrPos = Search(aConstraint.h, myConstraints);
- aConstrIter = myConstraints.begin() + aConstrPos;
- myNeedToSolve = true;
- } else {
- myConstraintMap[theConstraint] = std::vector<Slvs_hConstraint>();
-
- // To avoid SolveSpace problems:
- // * if the circle is rigid, we will fix its center and radius;
- // * if the arc is rigid, we will fix its start and end points and radius.
- double aRadius = 0.0;
- bool isArc = false;
- bool isCircle = false;
- if (aFeature) {
- if (aFeature->getKind() == SketchPlugin_Arc::ID()) {
- std::shared_ptr<GeomDataAPI_Point2D> aCenter =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID()));
- std::shared_ptr<GeomDataAPI_Point2D> aStart =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aFeature->data()->attribute(SketchPlugin_Arc::START_ID()));
- aRadius = aStart->pnt()->distance(aCenter->pnt());
- isArc = true;
- } else if (aFeature->getKind() == SketchPlugin_Circle::ID()) {
- aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
- aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID()))->value();
- isCircle = true;
- }
- }
-
- // Get list of already fixed points
- std::set<Slvs_hEntity> anAlreadyFixed;
- std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
- for (; aCIter != myConstraints.end(); aCIter++)
- if (aCIter->type == SLVS_C_WHERE_DRAGGED)
- anAlreadyFixed.insert(aCIter->ptA);
-
- // Create constraints to fix the parameters of the entity
- int aEntPos = Search(aConstrEnt, myEntities);
- Slvs_hEntity* aPointsPtr = myEntities[aEntPos].point;
- if (isArc) aPointsPtr++; // avoid to fix center of arc
- while (*aPointsPtr != 0) {
- // Avoid to create additional "Rigid" constraints for coincident points
- bool isCoincAlreadyFixed = false;
- if (!anAlreadyFixed.empty()) {
- if (anAlreadyFixed.find(*aPointsPtr) != anAlreadyFixed.end())
- isCoincAlreadyFixed = true;
-
- std::vector<std::set<Slvs_hEntity> >::const_iterator aCoincIter =
- myCoincidentPoints.begin();
- for (; !isCoincAlreadyFixed && aCoincIter != myCoincidentPoints.end(); aCoincIter++) {
- if (aCoincIter->find(*aPointsPtr) == aCoincIter->end())
- continue;
- std::set<Slvs_hEntity>::const_iterator anIter = anAlreadyFixed.begin();
- for (; !isCoincAlreadyFixed && anIter != anAlreadyFixed.end(); anIter++)
- if (aCoincIter->find(*anIter) != aCoincIter->end())
- isCoincAlreadyFixed = true;
- }
- }
-
- if (!isCoincAlreadyFixed) {
- Slvs_Constraint aConstraint = Slvs_MakeConstraint(
- ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
- *aPointsPtr, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
- myConstraints.push_back(aConstraint);
- myConstraintMap[theConstraint].push_back(aConstraint.h);
- }
- aPointsPtr++;
- }
-
- if (isArc || isCircle) { // add radius constraint
- Slvs_Constraint aConstraint = Slvs_MakeConstraint(
- ++myConstrMaxID, myID, SLVS_C_DIAMETER, myWorkplane.h, 2.0 * aRadius,
- SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aConstrEnt, SLVS_E_UNKNOWN);
- myConstraints.push_back(aConstraint);
- myConstraintMap[theConstraint].push_back(aConstraint.h);
- }
-
- // The object is already rigid, so there is no constraints added
- if (myConstraintMap[theConstraint].empty()) {
- myConstraintMap.erase(theConstraint);
- myNeedToSolve = false;
- }
- else
- myNeedToSolve = true;
- }
- }
- return true;
-}
-
-// ============================================================================
-// Function: changeMirrorConstraint
-// Class: SketchSolver_ConstraintGroup
-// Purpose: create/update the "Mirror" constraint in the group
-// ============================================================================
-bool SketchSolver_ConstraintGroup::changeMirrorConstraint(
- std::shared_ptr<SketchPlugin_Constraint> theConstraint)
-{
- DataPtr aConstrData = theConstraint->data();
-
- // Search this constraint in the current group to update it
- ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
- std::vector<Slvs_Constraint>::iterator aConstrIter;
- bool isExists = false;
- if (aConstrMapIter != myConstraintMap.end()) {
- int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
- aConstrIter = myConstraints.begin() + aConstrPos;
- isExists = true;
- }
-
- // Get constraint type and verify the constraint parameters are correct
- SketchSolver_Constraint aConstraint(theConstraint);
- int aConstrType = aConstraint.getType();
- if (aConstrType == SLVS_C_UNKNOWN
- || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
- return false;
- const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
-
- Slvs_hEntity aMirrorLineEnt = SLVS_E_UNKNOWN;
- AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- aConstrData->attribute(aConstraintAttributes[0]));
- if (!aConstrAttr)
- return false;
-
- // Convert the object of the attribute to the feature
- FeaturePtr aMirrorLineFeat;
- if (aConstrAttr->isObject() && aConstrAttr->object()) {
- ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
- aConstrAttr->object());
- if (!aRC)
- return false;
- std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
- aMirrorLineFeat = aDoc->feature(aRC);
- }
- aMirrorLineEnt = aConstrAttr->isObject() ?
- changeEntityFeature(aMirrorLineFeat) : changeEntity(aConstrAttr->attr());
-
- // Append symmetric constraint for each point of mirroring features
- AttributeRefListPtr aBaseRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
- aConstrData->attribute(aConstraintAttributes[1]));
- AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
- aConstrData->attribute(aConstraintAttributes[2]));
- if (!aBaseRefList || !aMirroredRefList)
- return false;
-
- std::list<ObjectPtr> aBaseList = aBaseRefList->list();
- std::list<ObjectPtr> aMirroredList = aMirroredRefList->list();
- // remove all empty items
- std::list<ObjectPtr>::iterator anIt = aBaseList.begin();
- std::list<ObjectPtr>::iterator aTmpIt;
- while (anIt != aBaseList.end()) {
- aTmpIt = anIt;
- anIt++;
- if (!(*aTmpIt))
- aBaseList.erase(aTmpIt);
- }
- anIt = aMirroredList.begin();
- while (anIt != aMirroredList.end()) {
- aTmpIt = anIt;
- anIt++;
- if (!(*aTmpIt))
- aMirroredList.erase(aTmpIt);
- }
- if (aBaseList.empty() || aBaseList.size() != aMirroredList.size())
- return false;
-
- std::vector<Slvs_hConstraint> aNewConstraints;
- // Fill the list of already mirrored points
- std::vector<Slvs_Constraint> anOldConstraints;
- std::map<Slvs_hEntity, Slvs_hEntity> aMirroredPoints;
- if (isExists) {
- std::vector<Slvs_hConstraint>::const_iterator aCIter = aConstrMapIter->second.begin();
- for (; aCIter != aConstrMapIter->second.end(); aCIter++) {
- int anInd = Search(*aCIter, myConstraints);
- if (myConstraints[anInd].type != aConstrType)
- continue;
- aMirroredPoints[myConstraints[anInd].ptA] = myConstraints[anInd].ptB;
- anOldConstraints.push_back(myConstraints[anInd]);
- }
- }
-
- FeaturePtr aBaseFeature, aMirrorFeature;
- ResultConstructionPtr aRC;
- std::list<ObjectPtr>::iterator aBaseIter = aBaseList.begin();
- std::list<ObjectPtr>::iterator aMirIter = aMirroredList.begin();
- for ( ; aBaseIter != aBaseList.end(); aBaseIter++, aMirIter++) {
- aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aBaseIter);
- aBaseFeature = aRC ? aRC->document()->feature(aRC) :
- std::dynamic_pointer_cast<ModelAPI_Feature>(*aBaseIter);
- aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aMirIter);
- aMirrorFeature = aRC ? aRC->document()->feature(aRC) :
- std::dynamic_pointer_cast<ModelAPI_Feature>(*aMirIter);
-
- if (!aBaseFeature || !aMirrorFeature ||
- aBaseFeature->getKind() != aMirrorFeature->getKind())
- return false;
- Slvs_hEntity aBaseEnt = changeEntityFeature(aBaseFeature);
- Slvs_hEntity aMirrorEnt = changeEntityFeature(aMirrorFeature);
- // Make aMirrorEnt parameters to be symmetric with aBaseEnt
- makeMirrorEntity(aBaseEnt, aMirrorEnt, aMirrorLineEnt);
-
- if (aBaseFeature->getKind() == SketchPlugin_Point::ID()) {
- Slvs_hConstraint anID = changeMirrorPoints(aBaseEnt, aMirrorEnt,
- aMirrorLineEnt, anOldConstraints, aMirroredPoints);
- aNewConstraints.push_back(anID);
- } else {
- int aBasePos = Search(aBaseEnt, myEntities);
- int aMirrorPos = Search(aMirrorEnt, myEntities);
- if (aBaseFeature->getKind() == SketchPlugin_Line::ID()) {
- for (int ind = 0; ind < 2; ind++) {
- Slvs_hConstraint anID = changeMirrorPoints(myEntities[aBasePos].point[ind],
- myEntities[aMirrorPos].point[ind], aMirrorLineEnt, anOldConstraints, aMirroredPoints);
- aNewConstraints.push_back(anID);
- }
- } else if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) {
- Slvs_hConstraint anID = changeMirrorPoints(myEntities[aBasePos].point[0],
- myEntities[aMirrorPos].point[0], aMirrorLineEnt, anOldConstraints, aMirroredPoints);
- aNewConstraints.push_back(anID);
- // Additional constraint for equal radii
- Slvs_Constraint anEqRadConstr = Slvs_MakeConstraint(
- ++myConstrMaxID, myID, SLVS_C_EQUAL_RADIUS, myWorkplane.h, 0.0,
- SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aBaseEnt, aMirrorEnt);
- myConstraints.push_back(anEqRadConstr);
- myConstraintMap[theConstraint].push_back(anEqRadConstr.h);
- } else if (aBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
- // Workaround to avoid problems in SolveSpace.
- // The symmetry of two arcs will be done using symmetry of three points on these arcs:
- // start point, end point, and any other point on the arc
- Slvs_hEntity aBaseArcPoints[3] = {
- myEntities[aBasePos].point[1],
- myEntities[aBasePos].point[2],
- SLVS_E_UNKNOWN};
- Slvs_hEntity aMirrorArcPoints[3] = { // indices of points of arc, center corresponds center, first point corresponds last point
- myEntities[aMirrorPos].point[2],
- myEntities[aMirrorPos].point[1],
- SLVS_E_UNKNOWN};
- Slvs_hEntity aBothArcs[2] = {aBaseEnt, aMirrorEnt};
- Slvs_hEntity aBothMiddlePoints[2];
- for (int i = 0; i < 2; i++) {
- double x, y;
- calculateMiddlePoint(aBothArcs[i], x, y);
- std::vector<Slvs_Param>::iterator aParamIter = myParams.end();
- Slvs_hParam u = changeParameter(x, aParamIter);
- Slvs_hParam v = changeParameter(y, aParamIter);
- Slvs_Entity aPoint = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, u, v);
- myEntities.push_back(aPoint);
- myEntOfConstr.push_back(true);
- aBothMiddlePoints[i] = aPoint.h;
- // additional constraint point-on-curve
- Slvs_Constraint aPonCircConstr = Slvs_MakeConstraint(
- ++myConstrMaxID, myID, SLVS_C_PT_ON_CIRCLE, myWorkplane.h, 0.0,
- aPoint.h, SLVS_E_UNKNOWN, aBothArcs[i], SLVS_E_UNKNOWN);
- myConstraints.push_back(aPonCircConstr);
- myConstraintMap[theConstraint].push_back(aPonCircConstr.h);
- aNewConstraints.push_back(aPonCircConstr.h);
- }
-
- aBaseArcPoints[2] = aBothMiddlePoints[0];
- aMirrorArcPoints[2] = aBothMiddlePoints[1];
- for (int ind = 0; ind < 3; ind++) {
- Slvs_hConstraint anID = changeMirrorPoints(aBaseArcPoints[ind], aMirrorArcPoints[ind],
- aMirrorLineEnt, anOldConstraints, aMirroredPoints);
- aNewConstraints.push_back(anID);
- }
- }
- }
- }
-
- // Remove unused constraints
- std::vector<Slvs_Constraint>::const_iterator anOldCIter = anOldConstraints.begin();
- for (; anOldCIter != anOldConstraints.end(); anOldCIter++) {
- int anInd = Search(anOldCIter->h, myConstraints);
- myConstraints.erase(myConstraints.begin() + anInd);
- }
- myConstraintMap[theConstraint] = aNewConstraints;
-
- if (!isExists) {
- // Set the mirror line unchanged during constraint recalculation
- int aMirrorLinePos = Search(aMirrorLineEnt, myEntities);
- // firstly check the line is not fixed yet
- bool isFixed[2] = {false, false};
- std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
- for (; aConstrIter != myConstraints.end() && !(isFixed[0] && isFixed[1]); aConstrIter++)
- if (aConstrIter->type == SLVS_C_WHERE_DRAGGED) {
- if (aConstrIter->ptA == myEntities[aMirrorLinePos].point[0])
- isFixed[0] = true;
- else if (aConstrIter->ptA == myEntities[aMirrorLinePos].point[1])
- isFixed[1] = true;
- }
- // add new rigid constraints
- if (!isFixed[0]) {
- Slvs_Constraint aRigidStart = Slvs_MakeConstraint(
- ++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, myWorkplane.h, 0,
- myEntities[aMirrorLinePos].point[0], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
- myConstraints.push_back(aRigidStart);
- myConstraintMap[theConstraint].push_back(aRigidStart.h);
- }
- if (!isFixed[1]) {
- Slvs_Constraint aRigidEnd = Slvs_MakeConstraint(
- ++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, myWorkplane.h, 0,
- myEntities[aMirrorLinePos].point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
- myConstraints.push_back(aRigidEnd);
- myConstraintMap[theConstraint].push_back(aRigidEnd.h);
- }
-
- // Add temporary constraints for initial objects to be unchanged
- for (aBaseIter = aBaseList.begin(); aBaseIter != aBaseList.end(); aBaseIter++) {
- aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aBaseIter);
- aBaseFeature = aRC ? aRC->document()->feature(aRC) :
- std::dynamic_pointer_cast<ModelAPI_Feature>(*aBaseIter);
- if (!aBaseFeature) continue;
- std::list<AttributePtr> aPoints = aBaseFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
- if (aBaseFeature->getKind() != SketchPlugin_Arc::ID()) {
- std::list<AttributePtr>::iterator anIt = aPoints.begin();
- for ( ; anIt != aPoints.end(); anIt++) {
- addTemporaryConstraintWhereDragged(*anIt);
- }
- } else {
- // Arcs are fixed by center and start points only (to avoid solving errors in SolveSpace)
- AttributePtr aCenterAttr = aBaseFeature->attribute(SketchPlugin_Arc::CENTER_ID());
- std::map<AttributePtr, Slvs_hEntity>::iterator aFound = myEntityAttrMap.find(aCenterAttr);
- Slvs_hEntity anArcPoints[3] = {aFound->second, 0, 0};
- AttributePtr aStartAttr = aBaseFeature->attribute(SketchPlugin_Arc::START_ID());
- aFound = myEntityAttrMap.find(aStartAttr);
- anArcPoints[1] = aFound->second;
- AttributePtr aEndAttr = aBaseFeature->attribute(SketchPlugin_Arc::END_ID());
- aFound = myEntityAttrMap.find(aEndAttr);
- anArcPoints[2] = aFound->second;
-
- bool isFixed[3] = {false, false, false};
- int aNbFixed = 0; // number of already fixed points on the arc
- for (int i = 0; i < 3; i++) {
- std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
- for (; aCoPtIter != myCoincidentPoints.end() && !isFixed[i]; aCoPtIter++) {
- if (aCoPtIter->find(anArcPoints[i]) == aCoPtIter->end())
- continue; // the entity was not found in current set
-
- // Find one of already created SLVS_C_WHERE_DRAGGED constraints in current set of coincident points
- std::vector<Slvs_Constraint>::iterator aConstrIter = myConstraints.begin();
- for (; aConstrIter != myConstraints.end(); aConstrIter++)
- if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
- aCoPtIter->find(aConstrIter->ptA) != aCoPtIter->end()) {
- isFixed[i] = true;
- aNbFixed++;
- break; // the SLVS_C_WHERE_DRAGGED constraint already exists
- }
- }
- }
- if (aNbFixed < 2) { // append constraints
- if (!isFixed[0])
- addTemporaryConstraintWhereDragged(aCenterAttr);
- if (!isFixed[1] && (isFixed[0] || aNbFixed == 0))
- addTemporaryConstraintWhereDragged(aStartAttr);
- }
- }
- }
- }
- return true;
-}
-
-// ============================================================================
-// Function: changeFilletConstraint
-// Class: SketchSolver_ConstraintGroup
-// Purpose: create/update the "Fillet" constraint in the group
-// ============================================================================
-bool SketchSolver_ConstraintGroup::changeFilletConstraint(
- std::shared_ptr<SketchPlugin_Constraint> theConstraint)
-{
- DataPtr aConstrData = theConstraint->data();
-
- // Search this constraint in the current group to update it
- ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
- std::vector<Slvs_Constraint>::iterator aConstrIter;
- if (aConstrMapIter != myConstraintMap.end()) {
- int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
- aConstrIter = myConstraints.begin() + aConstrPos;
- }
-
- // Get constraint type and verify the constraint parameters are correct
- SketchSolver_Constraint aConstraint(theConstraint);
- int aConstrType = aConstraint.getType();
- if (aConstrType == SLVS_C_UNKNOWN)
- return false;
- const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
-
- // Obtain hEntity for basic objects of fillet
- Slvs_hEntity aBaseObject[2];
- FeaturePtr aBaseFeature[2];
- for (unsigned int indAttr = 0; indAttr < 2; indAttr++) {
- AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- aConstrData->attribute(aConstraintAttributes[indAttr]));
- if (!aConstrAttr)
- return false;
- if (aConstrAttr->isObject() && aConstrAttr->object()) {
- ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
- aConstrAttr->object());
- if (!aRC)
- return false;
- std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
- aBaseFeature[indAttr] = aDoc->feature(aRC);
- }
- aBaseObject[indAttr] = aConstrAttr->isObject() ?
- changeEntityFeature(aBaseFeature[indAttr]) : changeEntity(aConstrAttr->attr());
- }
- // Check the base entities have a coincident point
- int aBaseObjInd[2] = {
- Search(aBaseObject[0], myEntities),
- Search(aBaseObject[1], myEntities)
- };
- int aShift[2] = { // shift for calculating correct start and end points for different types of objects
- myEntities[aBaseObjInd[0]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0,
- myEntities[aBaseObjInd[1]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0,
- };
- Slvs_hEntity aFirstObjPoints[2] = { // indices of start and end point of first object
- myEntities[aBaseObjInd[0]].point[aShift[0]],
- myEntities[aBaseObjInd[0]].point[1+aShift[0]]
- };
- Slvs_hEntity aSecondObjPoints[2] = { // indices of start and end point of second object
- myEntities[aBaseObjInd[1]].point[aShift[1]],
- myEntities[aBaseObjInd[1]].point[1+aShift[1]]
- };
- bool isCoincidentFound = false;
- int aBaseCoincInd[2] = {0, 0}; // indices in aFirstObjPoint and aSecondObjPoint identifying coincident points
- std::vector<std::set<Slvs_hEntity> >::iterator aCPIter = myCoincidentPoints.begin();
- for ( ; aCPIter != myCoincidentPoints.end() && !isCoincidentFound; aCPIter++)
- for (int ind1 = 0; ind1 < 2 && !isCoincidentFound; ind1++)
- for (int ind2 = 0; ind2 < 2 && !isCoincidentFound; ind2++)
- if (aCPIter->find(aFirstObjPoints[ind1]) != aCPIter->end() &&
- aCPIter->find(aSecondObjPoints[ind2]) != aCPIter->end()) {
- aBaseCoincInd[0] = ind1;
- aBaseCoincInd[1] = ind2;
- isCoincidentFound = true;
- }
- if (!isCoincidentFound) {
- // There is no coincident points between objects. Generate error message
- Events_Error::send(SketchSolver_Error::NO_COINCIDENT_POINTS(), this);
- return false;
- }
-
- // Create fillet entities
- // - first object is placed on the first base
- // - second object is on the second base
- // - third object is a filleting arc
- static const int aNbFilletEnt = 3;
- Slvs_hEntity aFilletEnt[aNbFilletEnt];
- int aFilletObjInd[aNbFilletEnt];
- AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
- aConstrData->attribute(aConstraintAttributes[2]));
- if (!aFilletRefList)
- return false;
- std::list<ObjectPtr> aFilletList = aFilletRefList->list();
- if (aFilletList.size() < aNbFilletEnt)
- return false;
- FeaturePtr aFilletFeature;
- ResultConstructionPtr aRC;
- std::list<ObjectPtr>::iterator aFilIter = aFilletList.begin();
- for (int indEnt = 0; aFilIter != aFilletList.end(); aFilIter++, indEnt++) {
- aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aFilIter);
- aFilletFeature = aRC ? aRC->document()->feature(aRC) :
- std::dynamic_pointer_cast<ModelAPI_Feature>(*aFilIter);
- if (!aFilletFeature)
- return false;
- aFilletEnt[indEnt] = changeEntityFeature(aFilletFeature);
- if (aFilletEnt[indEnt] == SLVS_E_UNKNOWN)
- return false; // not all attributes are initialized yet
- aFilletObjInd[indEnt] = Search(aFilletEnt[indEnt], myEntities);
- }
- // At first time, for correct result, move floating points of fillet on the middle points of base objects
- if (myConstraintMap.find(theConstraint) == myConstraintMap.end()) {
- double anArcPoints[6];
- for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) {
- int anIndShift = myEntities[aFilletObjInd[indEnt]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0;
- int aPointsPos[2] = {
- Search(myEntities[aFilletObjInd[indEnt]].point[anIndShift], myEntities),
- Search(myEntities[aFilletObjInd[indEnt]].point[1+anIndShift], myEntities)
- };
- int aParamPos[2] = {
- Search(myEntities[aPointsPos[0]].param[0], myParams),
- Search(myEntities[aPointsPos[1]].param[0], myParams)
- };
- int anIndex = aParamPos[aBaseCoincInd[indEnt]];
- if (anIndShift == 0) {
- myParams[anIndex].val =
- 0.5 * (myParams[aParamPos[0]].val + myParams[aParamPos[1]].val);
- myParams[1 + anIndex].val =
- 0.5 * (myParams[1 + aParamPos[0]].val + myParams[1 + aParamPos[1]].val);
- } else { // place the changed point on the arc
- double x = 0, y = 0;
- calculateMiddlePoint(aFilletEnt[indEnt], x, y);
- myParams[anIndex].val = x;
- myParams[1 + anIndex].val = y;
- }
- anArcPoints[indEnt*2+2] = myParams[anIndex].val;
- anArcPoints[indEnt*2+3] = myParams[1 + anIndex].val;
- }
- anArcPoints[0] = 0.5 * (anArcPoints[2] + anArcPoints[4]);
- anArcPoints[1] = 0.5 * (anArcPoints[3] + anArcPoints[5]);
- for (int indArcPt = 0; indArcPt < 3; indArcPt++) {
- int aPtPos = Search(myEntities[aFilletObjInd[2]].point[indArcPt], myEntities);
- int aParamPos = Search(myEntities[aPtPos].param[0], myParams);
- myParams[aParamPos].val = anArcPoints[indArcPt * 2];
- myParams[aParamPos + 1].val = anArcPoints[indArcPt * 2 + 1];
- }
- }
-
- // Create list of constraints to generate fillet
- int aPtInd;
- std::vector<Slvs_hConstraint> aConstrList;
- bool isExists = myConstraintMap.find(theConstraint) != myConstraintMap.end(); // constraint already exists
- std::vector<Slvs_hConstraint>::iterator aCMapIter =
- isExists ? myConstraintMap[theConstraint].begin() : aConstrList.begin();
- std::vector<Slvs_hConstraint>::iterator aCMapEnd =
- isExists ? myConstraintMap[theConstraint].end() : aConstrList.end();
- int aCurConstrPos = isExists ? Search(*aCMapIter, myConstraints) : 0;
- for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) {
- // one point of fillet object should be coincident with the point on base, non-coincident with another base object
- aPtInd = 1-aBaseCoincInd[indEnt]+aShift[indEnt]; // (1-aBaseCoincInd[indEnt]) = index of non-coincident point, aShift is used to process all types of shapes
- Slvs_hEntity aPtBase = myEntities[aBaseObjInd[indEnt]].point[aPtInd];
- Slvs_hEntity aPtFillet = myEntities[aFilletObjInd[indEnt]].point[aPtInd];
- if (isExists) {
- myConstraints[aCurConstrPos].ptA = aPtBase;
- myConstraints[aCurConstrPos].ptB = aPtFillet;
- aCMapIter++;
- aCurConstrPos = Search(*aCMapIter, myConstraints);
- } else if (addCoincidentPoints(aPtBase, aPtFillet)) { // the points are not connected by coincidence yet
- Slvs_Constraint aCoincConstr = Slvs_MakeConstraint(
- ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h,
- 0, aPtBase, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
- myConstraints.push_back(aCoincConstr);
- aConstrList.push_back(aCoincConstr.h);
- }
-
- // another point of fillet object should be placed on the base object
- Slvs_Constraint aPonCurveConstr;
- int aTangentType;
- if (myEntities[aFilletObjInd[indEnt]].type == SLVS_E_ARC_OF_CIRCLE) {
- // centers of arcs should be coincident
- aPtBase = myEntities[aBaseObjInd[indEnt]].point[0];
- aPtFillet = myEntities[aFilletObjInd[indEnt]].point[0];
- if (isExists) {
- myConstraints[aCurConstrPos].ptA = aPtBase;
- myConstraints[aCurConstrPos].ptB = aPtFillet;
- aCMapIter++;
- if (aCMapIter != aCMapEnd)
- aCurConstrPos = Search(*aCMapIter, myConstraints);
- } else if (addCoincidentPoints(aPtBase, aPtFillet)) { // the points are not connected by coincidence yet
- aPonCurveConstr = Slvs_MakeConstraint(
- ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h,
- 0, aPtBase, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
- }
- aPtFillet = myEntities[aFilletObjInd[indEnt]].point[1+aBaseCoincInd[indEnt]]; // !!! will be used below
- aTangentType = SLVS_C_CURVE_CURVE_TANGENT;
- } else {
- aPtInd = aBaseCoincInd[indEnt];
- aPtFillet = myEntities[aFilletObjInd[indEnt]].point[aPtInd];
- if (isExists) {
- myConstraints[aCurConstrPos].ptA = aPtFillet;
- aCMapIter++;
- if (aCMapIter != aCMapEnd)
- aCurConstrPos = Search(*aCMapIter, myConstraints);
- } else {
- aPonCurveConstr = Slvs_MakeConstraint(
- ++myConstrMaxID, myID, SLVS_C_PT_ON_LINE, myWorkplane.h,
- 0, aPtFillet, SLVS_E_UNKNOWN, aBaseObject[indEnt], SLVS_E_UNKNOWN);
- }
- aTangentType = SLVS_C_ARC_LINE_TANGENT;
- }
- if (!isExists) {
- myConstraints.push_back(aPonCurveConstr);
- aConstrList.push_back(aPonCurveConstr.h);
- }
- }
-
- if (!isExists)
- myConstraintMap[theConstraint] = aConstrList;
-
- // Additional temporary constraints for base objects to be fixed
- int aNbArcs = 0;
- for (unsigned int indAttr = 0; indAttr < 2; indAttr++) {
- if (!aBaseFeature[indAttr]) {
- AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- aConstrData->attribute(aConstraintAttributes[indAttr]));
- addTemporaryConstraintWhereDragged(aConstrAttr->attr());
- continue;
- }
- if (aBaseFeature[indAttr]->getKind() == SketchPlugin_Line::ID()) {
- addTemporaryConstraintWhereDragged(
- aBaseFeature[indAttr]->attribute(SketchPlugin_Line::START_ID()));
- addTemporaryConstraintWhereDragged(
- aBaseFeature[indAttr]->attribute(SketchPlugin_Line::END_ID()));
- } else if (aBaseFeature[indAttr]->getKind() == SketchPlugin_Arc::ID()) {
- // Arc should be fixed by its center only (to avoid "conflicting constraints" message)
- // If the fillet is made on two arc, the shared point should be fixed too
- aNbArcs++;
- addTemporaryConstraintWhereDragged(
- aBaseFeature[indAttr]->attribute(SketchPlugin_Arc::CENTER_ID()));
- }
- }
- if (aNbArcs == 2) {
- addTemporaryConstraintWhereDragged(aBaseCoincInd[0] == 0 ?
- aBaseFeature[0]->attribute(SketchPlugin_Arc::START_ID()) :
- aBaseFeature[0]->attribute(SketchPlugin_Arc::END_ID()));
- }
- return true;
-}
-
-// ============================================================================
-// Function: changeEntity
-// Class: SketchSolver_ConstraintGroup
-// Purpose: create/update the element affected by any constraint
-// ============================================================================
-Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity(
- std::shared_ptr<ModelAPI_Attribute> theEntity)
-{
- // If the entity is already in the group, try to find it
- std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator aEntIter =
- myEntityAttrMap.find(theEntity);
- int aEntPos;
- std::vector<Slvs_Param>::iterator aParamIter; // looks at first parameter of already existent entity or at the end of vector otherwise
- if (aEntIter == myEntityAttrMap.end()) // no such entity => should be created
- aParamIter = myParams.end();
- else { // the entity already exists
- aEntPos = Search(aEntIter->second, myEntities);
- int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
- aParamIter = myParams.begin() + aParamPos;
- }
- const bool isEntExists = (aEntIter != myEntityAttrMap.end()); // defines that the entity already exists
- const bool isNeedToSolve = myNeedToSolve;
- myNeedToSolve = false;
-
- if (isEntExists) {
- // Verify that the entity is not used by "Rigid" constraint.
- // If it is used, the object should not move.
- std::vector<std::set<Slvs_hEntity> >::iterator aCoincIter = myCoincidentPoints.begin();
- for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++)
- if (aCoincIter->find(aEntIter->second) != aCoincIter->end())
- break;
- std::set<Slvs_hEntity> aCoincident;
- if (aCoincIter != myCoincidentPoints.end()) {
- aCoincident = *aCoincIter;
- aCoincident.erase(aEntIter->second);
-
- std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
- for (; aConstrIter != myConstraints.end(); aConstrIter++)
- if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
- aCoincident.find(aConstrIter->ptA) != aCoincident.end()) {
- myNeedToSolve = true;
- return aEntIter->second;
- }
- }
- }
-
- // Look over supported types of entities
- Slvs_Entity aNewEntity;
- aNewEntity.h = SLVS_E_UNKNOWN;
-
- // Point in 3D
- std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
- theEntity);
- if (aPoint) {
- Slvs_hParam aX = changeParameter(aPoint->x(), aParamIter);
- Slvs_hParam aY = changeParameter(aPoint->y(), aParamIter);
- Slvs_hParam aZ = changeParameter(aPoint->z(), aParamIter);
- if (!isEntExists) // New entity
- aNewEntity = Slvs_MakePoint3d(++myEntityMaxID, myID, aX, aY, aZ);
- } else {
- // All entities except 3D points are created on workplane. So, if there is no workplane yet, then error
- if (myWorkplane.h == SLVS_E_UNKNOWN)
- return SLVS_E_UNKNOWN;
-
- // Point in 2D
- std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
- if (aPoint2D) {
- Slvs_hParam aU = changeParameter(aPoint2D->x(), aParamIter);
- Slvs_hParam aV = changeParameter(aPoint2D->y(), aParamIter);
- if (!isEntExists) // New entity
- aNewEntity = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, aU, aV);
- } else {
- // Scalar value (used for the distance entities)
- AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theEntity);
- if (aScalar) {
- Slvs_hParam aValue = changeParameter(aScalar->value(), aParamIter);
- if (!isEntExists) // New entity
- aNewEntity = Slvs_MakeDistance(++myEntityMaxID, myID, myWorkplane.h, aValue);
- }
- }
- }
- /// \todo Other types of entities
-
- Slvs_hEntity aResult = SLVS_E_UNKNOWN; // Unsupported or wrong entity type
-
- if (isEntExists) {
- myNeedToSolve = myNeedToSolve || isNeedToSolve;
- aResult = aEntIter->second;
- } else if (aNewEntity.h != SLVS_E_UNKNOWN) {
- myEntities.push_back(aNewEntity);
- myEntOfConstr.push_back(false);
- myEntityAttrMap[theEntity] = aNewEntity.h;
- aResult = aNewEntity.h;
- }
-
- // If the attribute was changed by the user, we need to fix it before solving
- if (myNeedToSolve && theEntity->isImmutable())
- addTemporaryConstraintWhereDragged(theEntity, false);
-
- return aResult;
-}
-
-// ============================================================================
-// Function: changeEntity
-// Class: SketchSolver_ConstraintGroup
-// Purpose: create/update the element defined by the feature affected by any constraint
-// ============================================================================
-Slvs_hEntity SketchSolver_ConstraintGroup::changeEntityFeature(FeaturePtr theEntity)
-{
- if (!theEntity->data()->isValid())
- return SLVS_E_UNKNOWN;
- // If the entity is already in the group, try to find it
- 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());
-
- Slvs_Entity aNewEntity;
- aNewEntity.h = SLVS_E_UNKNOWN;
-
- // SketchPlugin features
- std::shared_ptr<SketchPlugin_Feature> aFeature = std::dynamic_pointer_cast<
- SketchPlugin_Feature>(theEntity);
- if (aFeature) { // Verify the feature by its kind
- const std::string& aFeatureKind = aFeature->getKind();
- AttributePtr anAttribute;
-
- // Line
- if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) {
- anAttribute = aFeature->data()->attribute(SketchPlugin_Line::START_ID());
- if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
- Slvs_hEntity aStart = changeEntity(anAttribute);
-
- anAttribute = aFeature->data()->attribute(SketchPlugin_Line::END_ID());
- if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
- Slvs_hEntity aEnd = changeEntity(anAttribute);
-
- if (!isEntExists) // New entity
- aNewEntity = Slvs_MakeLineSegment(++myEntityMaxID, myID, myWorkplane.h, aStart, aEnd);
- }
- // Circle
- else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) {
- anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::CENTER_ID());
- if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
- Slvs_hEntity aCenter = changeEntity(anAttribute);
-
- anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID());
- if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
- Slvs_hEntity aRadius = changeEntity(anAttribute);
-
- if (!isEntExists) // New entity
- aNewEntity = Slvs_MakeCircle(++myEntityMaxID, myID, myWorkplane.h, aCenter,
- myWorkplane.normal, aRadius);
- }
- // Arc
- else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) {
- anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID());
- if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
- Slvs_hEntity aCenter = changeEntity(anAttribute);
-
- anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::START_ID());
- if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
- Slvs_hEntity aStart = changeEntity(anAttribute);
-
- anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::END_ID());
- if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
- Slvs_hEntity aEnd = changeEntity(anAttribute);
-
- if (!isEntExists)
- aNewEntity = Slvs_MakeArcOfCircle(++myEntityMaxID, myID, myWorkplane.h,
- myWorkplane.normal, aCenter, aStart, aEnd);
- }
- // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
- else if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0) {
- anAttribute = aFeature->data()->attribute(SketchPlugin_Point::COORD_ID());
- if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
- Slvs_hEntity aPoint = changeEntity(anAttribute);
-
- if (isEntExists)
- return aEntIter->second;
-
- // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier
- myEntityFeatMap[theEntity] = aPoint;
- myNeedToSolve = true;
- return aPoint;
- }
- }
- /// \todo Other types of features
-
- if (isEntExists)
- return aEntIter->second;
-
- if (aNewEntity.h != SLVS_E_UNKNOWN) {
- myEntities.push_back(aNewEntity);
- myEntOfConstr.push_back(false);
- myEntityFeatMap[theEntity] = aNewEntity.h;
- myNeedToSolve = true;
- return aNewEntity.h;
- }
-
- // Unsupported or wrong entity type
- return SLVS_E_UNKNOWN;
-}
-
-// ============================================================================
-// Function: changeNormal
-// Class: SketchSolver_ConstraintGroup
-// Purpose: create/update the normal of workplane
-// ============================================================================
-Slvs_hEntity SketchSolver_ConstraintGroup::changeNormal(
- std::shared_ptr<ModelAPI_Attribute> theDirX,
- std::shared_ptr<ModelAPI_Attribute> theNorm)
-{
- std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theNorm);
- std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
- if (!aDirX || (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance))
- return SLVS_E_UNKNOWN;
- // calculate Y direction
- std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aDirX->dir())));
-
- // quaternion parameters of normal vector
- double qw, qx, qy, qz;
- Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), aDirY->x(), aDirY->y(), aDirY->z(), &qw,
- &qx, &qy, &qz);
- double aNormCoord[4] = { qw, qx, qy, qz };
-
- // Try to find existent normal
- std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator aEntIter =
- myEntityAttrMap.find(theNorm);
- std::vector<Slvs_Param>::iterator aParamIter; // looks to the first parameter of already existent entity or to the end of vector otherwise
- if (aEntIter == myEntityAttrMap.end()) // no such entity => should be created
- aParamIter = myParams.end();
- else { // the entity already exists, update it
- int aEntPos = Search(aEntIter->second, myEntities);
- int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
- aParamIter = myParams.begin() + aParamPos;
- }
-
- // Change parameters of the normal
- Slvs_hParam aNormParams[4];
- for (int i = 0; i < 4; i++)
- aNormParams[i] = changeParameter(aNormCoord[i], aParamIter);
-
- if (aEntIter != myEntityAttrMap.end()) // the entity already exists
- return aEntIter->second;
-
- // Create a normal
- Slvs_Entity aNormal = Slvs_MakeNormal3d(++myEntityMaxID, myID, aNormParams[0], aNormParams[1],
- aNormParams[2], aNormParams[3]);
- myEntities.push_back(aNormal);
- myEntOfConstr.push_back(false);
- myEntityAttrMap[theNorm] = aNormal.h;
- return aNormal.h;
-}
-
-// ============================================================================
-// Function: addWorkplane
-// Class: SketchSolver_ConstraintGroup
-// Purpose: create workplane for the group
-// ============================================================================
-bool SketchSolver_ConstraintGroup::addWorkplane(std::shared_ptr<ModelAPI_CompositeFeature> theSketch)
-{
- if (myWorkplane.h || theSketch->getKind().compare(SketchPlugin_Sketch::ID()) != 0)
- return false; // the workplane already exists or the function parameter is not Sketch
-
- mySketch = theSketch;
- updateWorkplane();
- return true;
-}
-
-// ============================================================================
-// Function: updateWorkplane
-// Class: SketchSolver_ConstraintGroup
-// Purpose: update parameters of workplane
-// ============================================================================
-bool SketchSolver_ConstraintGroup::updateWorkplane()
-{
- if (!mySketch->data())
- return false; // case sketch is deleted
- // Get parameters of workplane
- std::shared_ptr<ModelAPI_Attribute> aDirX = mySketch->data()->attribute(
- SketchPlugin_Sketch::DIRX_ID());
- std::shared_ptr<ModelAPI_Attribute> aNorm = mySketch->data()->attribute(
- SketchPlugin_Sketch::NORM_ID());
- std::shared_ptr<ModelAPI_Attribute> anOrigin = mySketch->data()->attribute(
- SketchPlugin_Sketch::ORIGIN_ID());
- // Transform them into SolveSpace format
- Slvs_hEntity aNormalWP = changeNormal(aDirX, aNorm);
- if (!aNormalWP)
- return false;
- Slvs_hEntity anOriginWP = changeEntity(anOrigin);
- if (!anOriginWP)
- return false;
-
- if (!myWorkplane.h) {
- // Create workplane
- myWorkplane = Slvs_MakeWorkplane(++myEntityMaxID, myID, anOriginWP, aNormalWP);
- // Workplane should be added to the list of entities
- myEntities.push_back(myWorkplane);
- myEntOfConstr.push_back(false);
- }
- return true;
-}
-
-// ============================================================================
-// Function: changeParameter
-// Class: SketchSolver_ConstraintGroup
-// Purpose: create/update value of parameter
-// ============================================================================
-Slvs_hParam SketchSolver_ConstraintGroup::changeParameter(
- double theParam, std::vector<Slvs_Param>::iterator& thePrmIter)
-{
- if (thePrmIter != myParams.end()) { // Parameter should be updated
- int aParamPos = thePrmIter - myParams.begin();
- if (fabs(thePrmIter->val - theParam) > tolerance) {
- myNeedToSolve = true; // parameter is changed, need to resolve constraints
- myParams[aParamPos].val = theParam;
- }
- thePrmIter++;
- return myParams[aParamPos].h;
- }
-
- // Newly created parameter
- Slvs_Param aParam = Slvs_MakeParam(++myParamMaxID, myID, theParam);
- myParams.push_back(aParam);
- myNeedToSolve = true;
- // The list of parameters is changed, move iterator to the end of the list to avoid problems
- thePrmIter = myParams.end();
- return aParam.h;
-}
-
-// ============================================================================
-// Function: resolveConstraints
-// Class: SketchSolver_ConstraintGroup
-// Purpose: solve the set of constraints for the current group
-// ============================================================================
-bool SketchSolver_ConstraintGroup::resolveConstraints()
-{
- if (!myNeedToSolve)
- return false;
-
- myConstrSolver.setGroupID(myID);
- myConstrSolver.setParameters(myParams);
- myConstrSolver.setEntities(myEntities);
- myConstrSolver.setConstraints(myConstraints);
- myConstrSolver.setDraggedParameters(myTempPointWhereDragged);
-
- int aResult = myConstrSolver.solve();
- if (aResult == SLVS_RESULT_OKAY) { // solution succeeded, store results into correspondent attributes
- // Obtain result into the same list of parameters
- if (!myConstrSolver.getResult(myParams))
- return true;
-
- // We should go through the attributes map, because only attributes have valued parameters
- std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator anEntIter =
- myEntityAttrMap.begin();
- for (; anEntIter != myEntityAttrMap.end(); anEntIter++) {
- if (anEntIter->first->owner().get() && anEntIter->first->owner()->data().get())
- anEntIter->first->owner()->data()->blockSendAttributeUpdated(true);
- if (updateAttribute(anEntIter->first, anEntIter->second))
- updateRelatedConstraints(anEntIter->first);
- }
- updateFilletConstraints();
- // unblock all features then
- for (anEntIter = myEntityAttrMap.begin(); anEntIter != myEntityAttrMap.end(); anEntIter++) {
- if (anEntIter->first->owner().get() && anEntIter->first->owner()->data().get())
- anEntIter->first->owner()->data()->blockSendAttributeUpdated(false);
- }
- } else if (!myConstraints.empty())
- Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this);
-
- removeTemporaryConstraints();
- myNeedToSolve = false;
- return true;
-}
-
-// ============================================================================
-// Function: mergeGroups
-// Class: SketchSolver_ConstraintGroup
-// Purpose: append specified group to the current group
-// ============================================================================
-void SketchSolver_ConstraintGroup::mergeGroups(const SketchSolver_ConstraintGroup& theGroup)
-{
- // If specified group is empty, no need to merge
- if (theGroup.myConstraintMap.empty())
- return;
-
- // Map between old and new indexes of SolveSpace constraints
- std::map<Slvs_hConstraint, Slvs_hConstraint> aConstrMap;
-
- // Add all constraints from theGroup to the current group
- ConstraintMap::const_iterator aConstrIter = theGroup.myConstraintMap.begin();
- for (; aConstrIter != theGroup.myConstraintMap.end(); aConstrIter++)
- if (changeConstraint(aConstrIter->first))
- aConstrMap[aConstrIter->second.back()] = myConstrMaxID; // the constraint was added => store its ID
-
- // Add temporary constraints from theGroup
- std::list<Slvs_hConstraint>::const_iterator aTempConstrIter = theGroup.myTempConstraints.begin();
- for (; aTempConstrIter != theGroup.myTempConstraints.end(); aTempConstrIter++) {
- std::map<Slvs_hConstraint, Slvs_hConstraint>::iterator aFind = aConstrMap.find(
- *aTempConstrIter);
- if (aFind != aConstrMap.end())
- myTempConstraints.push_back(aFind->second);
- }
-
- if (myTempPointWhereDragged.empty())
- myTempPointWhereDragged = theGroup.myTempPointWhereDragged;
- else if (!theGroup.myTempPointWhereDragged.empty()) { // Need to create additional transient constraint
- std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator aFeatureIter =
- theGroup.myEntityAttrMap.begin();
- for (; aFeatureIter != theGroup.myEntityAttrMap.end(); aFeatureIter++)
- if (aFeatureIter->second == myTempPointWDrgdID) {
- addTemporaryConstraintWhereDragged(aFeatureIter->first);
- break;
- }
- }
-
- myNeedToSolve = myNeedToSolve || theGroup.myNeedToSolve;
-}
-
-// ============================================================================
-// Function: splitGroup
-// Class: SketchSolver_ConstraintGroup
-// Purpose: divide the group into several subgroups
-// ============================================================================
-void SketchSolver_ConstraintGroup::splitGroup(std::vector<SketchSolver_ConstraintGroup*>& theCuts)
-{
- // Divide constraints and entities into several groups
- std::vector<std::set<Slvs_hEntity> > aGroupsEntities;
- std::vector<std::set<Slvs_hConstraint> > aGroupsConstr;
- int aMaxNbEntities = 0; // index of the group with maximal nuber of elements (this group will be left in the current)
- std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
- for (; aConstrIter != myConstraints.end(); aConstrIter++) {
- Slvs_hEntity aConstrEnt[] = { aConstrIter->ptA, aConstrIter->ptB, aConstrIter->entityA,
- aConstrIter->entityB };
- std::vector<int> anIndexes;
- // Go through the groupped entities and find even one of entities of current constraint
- std::vector<std::set<Slvs_hEntity> >::iterator aGrEntIter;
- for (aGrEntIter = aGroupsEntities.begin(); aGrEntIter != aGroupsEntities.end(); aGrEntIter++) {
- bool isFound = false;
- for (int i = 0; i < 4 && !isFound; i++)
- if (aConstrEnt[i] != 0) {
- isFound = (aGrEntIter->find(aConstrEnt[i]) != aGrEntIter->end());
- // Also we need to check sub-entities
- int aEntPos = Search(aConstrEnt[i], myEntities);
- if (aEntPos != myEntities.size()) { // MPV: to fix the crash on close
- Slvs_hEntity* aSub = myEntities[aEntPos].point;
- for (int j = 0; *aSub != 0 && j < 4 && !isFound; aSub++, j++)
- isFound = (aGrEntIter->find(*aSub) != aGrEntIter->end());
- }
- }
- if (isFound)
- anIndexes.push_back(aGrEntIter - aGroupsEntities.begin());
- }
- // Add new group if no one is found
- if (anIndexes.empty()) {
- std::set<Slvs_hEntity> aNewGrEnt;
- for (int i = 0; i < 4; i++)
- if (aConstrEnt[i] != 0) {
- aNewGrEnt.insert(aConstrEnt[i]);
- int aEntPos = Search(aConstrEnt[i], myEntities);
- if (aEntPos != myEntities.size()) { // MPV: to fix the crash on close
- Slvs_hEntity* aSub = myEntities[aEntPos].point;
- for (int j = 0; *aSub != 0 && j < 4; aSub++, j++)
- aNewGrEnt.insert(*aSub);
- }
- }
- std::set<Slvs_hConstraint> aNewGrConstr;
- aNewGrConstr.insert(aConstrIter->h);
-
- aGroupsEntities.push_back(aNewGrEnt);
- aGroupsConstr.push_back(aNewGrConstr);
- if (aNewGrEnt.size() > aGroupsEntities[aMaxNbEntities].size())
- aMaxNbEntities = aGroupsEntities.size() - 1;
- } else { // Add entities indexes into the found group
- aGrEntIter = aGroupsEntities.begin() + anIndexes.front();
- for (int i = 0; i < 4; i++)
- if (aConstrEnt[i] != 0) {
- aGrEntIter->insert(aConstrEnt[i]);
- int aEntPos = Search(aConstrEnt[i], myEntities);
- if (aEntPos != myEntities.size()) { // MPV: to fix the crash on close
- Slvs_hEntity* aSub = myEntities[aEntPos].point;
- for (int j = 0; *aSub != 0 && j < 4; aSub++, j++)
- aGrEntIter->insert(*aSub);
- }
- }
- aGroupsConstr[anIndexes.front()].insert(aConstrIter->h);
- if (aGrEntIter->size() > aGroupsEntities[aMaxNbEntities].size())
- aMaxNbEntities = aGrEntIter - aGroupsEntities.begin();
- if (anIndexes.size() > 1) { // There are found several connected groups, merge them
- std::vector<std::set<Slvs_hEntity> >::iterator aFirstGroup = aGroupsEntities.begin()
- + anIndexes.front();
- std::vector<std::set<Slvs_hConstraint> >::iterator aFirstConstr = aGroupsConstr.begin()
- + anIndexes.front();
- std::vector<int>::iterator anInd = anIndexes.begin();
- for (++anInd; anInd != anIndexes.end(); anInd++) {
- aFirstGroup->insert(aGroupsEntities[*anInd].begin(), aGroupsEntities[*anInd].end());
- aFirstConstr->insert(aGroupsConstr[*anInd].begin(), aGroupsConstr[*anInd].end());
- }
- if (aFirstGroup->size() > aGroupsEntities[aMaxNbEntities].size())
- aMaxNbEntities = anIndexes.front();
- // Remove merged groups
- for (anInd = anIndexes.end() - 1; anInd != anIndexes.begin(); anInd--) {
- aGroupsEntities.erase(aGroupsEntities.begin() + (*anInd));
- aGroupsConstr.erase(aGroupsConstr.begin() + (*anInd));
- }
- }
- }
- }
-
- if (aGroupsEntities.size() <= 1)
- return;
-
- // Remove the group with maximum elements as it will be left in the current group
- aGroupsEntities.erase(aGroupsEntities.begin() + aMaxNbEntities);
- aGroupsConstr.erase(aGroupsConstr.begin() + aMaxNbEntities);
-
- // Add new groups of constraints and divide current group
- std::vector<SketchSolver_ConstraintGroup*> aNewGroups;
- for (int i = aGroupsEntities.size(); i > 0; i--) {
- SketchSolver_ConstraintGroup* aG = new SketchSolver_ConstraintGroup(mySketch);
- aNewGroups.push_back(aG);
- }
- ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.begin();
- int aConstrMapPos = 0; // position of iterator in the map (used to restore iterator after removing constraint)
- while (aConstrMapIter != myConstraintMap.end()) {
- std::vector<std::set<Slvs_hConstraint> >::const_iterator aGIter = aGroupsConstr.begin();
- std::vector<SketchSolver_ConstraintGroup*>::iterator aGroup = aNewGroups.begin();
- for (; aGIter != aGroupsConstr.end(); aGIter++, aGroup++)
- if (aGIter->find(aConstrMapIter->second.front()) != aGIter->end()) {
- (*aGroup)->changeConstraint(aConstrMapIter->first);
- removeConstraint(aConstrMapIter->first);
- // restore iterator
- aConstrMapIter = myConstraintMap.begin();
- for (int i = 0; i < aConstrMapPos; i++)
- aConstrMapIter++;
- break;
- }
- if (aGIter == aGroupsConstr.end()) {
- aConstrMapIter++;
- aConstrMapPos++;
- }
- }
-
- theCuts.insert(theCuts.end(), aNewGroups.begin(), aNewGroups.end());
-}
-
-// ============================================================================
-// Function: updateGroup
-// Class: SketchSolver_ConstraintGroup
-// Purpose: search removed entities and constraints
-// ============================================================================
-bool SketchSolver_ConstraintGroup::updateGroup()
-{
- ConstraintMap::reverse_iterator aConstrIter = myConstraintMap.rbegin();
- bool isAllValid = true;
- bool isCCRemoved = false; // indicates that at least one of coincidence constraints was removed
- int aConstrIndex = 0;
- while (/*isAllValid && */aConstrIter != myConstraintMap.rend()) {
- if (!aConstrIter->first->data() || !aConstrIter->first->data()->isValid()) {
- if (aConstrIter->first->getKind().compare(SketchPlugin_ConstraintCoincidence::ID()) == 0)
- isCCRemoved = true;
- removeConstraint(aConstrIter->first);
- isAllValid = false;
- // Get back the correct position of iterator after the "remove" operation
- aConstrIter = myConstraintMap.rbegin();
- for (int i = 0; i < aConstrIndex && aConstrIter != myConstraintMap.rend(); i++)
- aConstrIter++;
- } else {
- aConstrIter++;
- aConstrIndex++;
- }
- }
-
- // Check if some entities are invalid too
- std::set<Slvs_hEntity> anEntToRemove;
- std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
- anAttrIter = myEntityAttrMap.begin();
- while (anAttrIter != myEntityAttrMap.end()) {
- if (!anAttrIter->first->owner() || !anAttrIter->first->owner()->data() ||
- !anAttrIter->first->owner()->data()->isValid()) {
- anEntToRemove.insert(anAttrIter->second);
- std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
- aRemovedIter = anAttrIter;
- anAttrIter++;
- myEntityAttrMap.erase(aRemovedIter);
- } else
- anAttrIter++;
- }
- std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIter = myEntityFeatMap.begin();
- while (aFeatIter != myEntityFeatMap.end()) {
- if (!aFeatIter->first || !aFeatIter->first->data() ||
- !aFeatIter->first->data()->isValid()) {
- anEntToRemove.insert(aFeatIter->second);
- std::map<FeaturePtr, Slvs_hEntity>::iterator aRemovedIter = aFeatIter;
- aFeatIter++;
- myEntityFeatMap.erase(aRemovedIter);
- } else
- aFeatIter++;
- }
- removeEntitiesById(anEntToRemove);
-
- // Probably, need to update coincidence constraints
- if (isCCRemoved && !myExtraCoincidence.empty()) {
- // Make a copy, because the new list of unused constrtaints will be generated
- std::set<std::shared_ptr<SketchPlugin_Constraint> > anExtraCopy = myExtraCoincidence;
- myExtraCoincidence.clear();
-
- std::set<std::shared_ptr<SketchPlugin_Constraint> >::iterator aCIter = anExtraCopy.begin();
- for (; aCIter != anExtraCopy.end(); aCIter++)
- if ((*aCIter)->data() && (*aCIter)->data()->isValid())
- changeConstraint(*aCIter);
- }
-
- return !isAllValid;
-}
-
-// ============================================================================
-// Function: updateAttribute
-// Class: SketchSolver_ConstraintGroup
-// Purpose: update features of sketch after resolving constraints
-// ============================================================================
-bool SketchSolver_ConstraintGroup::updateAttribute(
- std::shared_ptr<ModelAPI_Attribute> theAttribute, const Slvs_hEntity& theEntityID)
-{
- // Search the position of the first parameter of the entity
- int anEntPos = Search(theEntityID, myEntities);
- int aFirstParamPos = Search(myEntities[anEntPos].param[0], myParams);
-
- // Look over supported types of entities
-
- // Point in 3D
- std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
- theAttribute);
- if (aPoint) {
- 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
- std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
- if (aPoint2D) {
- 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
- AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
- if (aScalar) {
- 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;
-}
-
-// ============================================================================
-// Function: updateEntityIfPossible
-// Class: SketchSolver_ConstraintGroup
-// Purpose: search the entity in this group and update it
-// ============================================================================
-void SketchSolver_ConstraintGroup::updateEntityIfPossible(
- std::shared_ptr<ModelAPI_Attribute> theEntity)
-{
- if (myEntityAttrMap.find(theEntity) != myEntityAttrMap.end()) {
- // If the attribute is a point and it is changed (the group needs to rebuild),
- // probably user has dragged this point into this position,
- // so it is necessary to add constraint which will guarantee the point will not change
-
- // Store myNeedToSolve flag to verify the entity is really changed
- bool aNeedToSolveCopy = myNeedToSolve;
- myNeedToSolve = false;
-
- changeEntity(theEntity);
-
- if (myNeedToSolve) // the entity is changed
- {
- // Verify the entity is a point and add temporary constraint of permanency
- std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
- theEntity);
- std::shared_ptr<GeomDataAPI_Point2D> aPoint2D = std::dynamic_pointer_cast<
- GeomDataAPI_Point2D>(theEntity);
- if (aPoint || aPoint2D)
- addTemporaryConstraintWhereDragged(theEntity);
- }
-
- // Restore flag of changes
- myNeedToSolve = myNeedToSolve || aNeedToSolveCopy;
-
- if (myNeedToSolve)
- updateRelatedConstraints(theEntity);
- }
-}
-
-// ============================================================================
-// Function: addTemporaryConstraintWhereDragged
-// Class: SketchSolver_ConstraintGroup
-// Purpose: add transient constraint SLVS_C_WHERE_DRAGGED for the entity,
-// which was moved by user
-// ============================================================================
-void SketchSolver_ConstraintGroup::addTemporaryConstraintWhereDragged(
- std::shared_ptr<ModelAPI_Attribute> theEntity,
- bool theAllowToFit)
-{
- // Find identifier of the entity
- std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator anEntIter =
- myEntityAttrMap.find(theEntity);
- if (anEntIter == myEntityAttrMap.end())
- return;
-
- // Get identifiers of all dragged points
- std::set<Slvs_hEntity> aDraggedPntID;
- aDraggedPntID.insert(myTempPointWDrgdID);
- std::list<Slvs_hConstraint>::const_iterator aTmpCoIter = myTempConstraints.begin();
- for (; aTmpCoIter != myTempConstraints.end(); aTmpCoIter++) {
- unsigned int aConstrPos = Search(*aTmpCoIter, myConstraints);
- if (aConstrPos < myConstraints.size())
- aDraggedPntID.insert(myConstraints[aConstrPos].ptA);
- }
- std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
- for (; aConstrIter != myConstraints.end(); aConstrIter++)
- if (aConstrIter->type == SLVS_C_WHERE_DRAGGED)
- aDraggedPntID.insert(aConstrIter->ptA);
- // Find whether there is a point coincident with theEntity, which already has SLVS_C_WHERE_DRAGGED
- std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
- for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++) {
- if (aCoPtIter->find(anEntIter->second) == aCoPtIter->end())
- continue; // the entity was not found in current set
-
- // Find one of already created SLVS_C_WHERE_DRAGGED constraints in current set of coincident points
- std::set<Slvs_hEntity>::const_iterator aDrgIter = aDraggedPntID.begin();
- for (; aDrgIter != aDraggedPntID.end(); aDrgIter++)
- if (aCoPtIter->find(*aDrgIter) != aCoPtIter->end())
- return; // the SLVS_C_WHERE_DRAGGED constraint already exists
- }
- if (aDraggedPntID.find(anEntIter->second) != aDraggedPntID.end())
- return;
-
- // If this is a first dragged point, its parameters should be placed
- // into Slvs_System::dragged field to avoid system inconsistense
- if (myTempPointWhereDragged.empty() && theAllowToFit) {
- int anEntPos = Search(anEntIter->second, myEntities);
- Slvs_hParam* aDraggedParam = myEntities[anEntPos].param;
- for (int i = 0; i < 4; i++, aDraggedParam++)
- if (*aDraggedParam != 0)
- myTempPointWhereDragged.push_back(*aDraggedParam);
- myTempPointWDrgdID = myEntities[anEntPos].h;
- return;
- }
-
- // Create additional SLVS_C_WHERE_DRAGGED constraint if myTempPointWhereDragged field is not empty
- Slvs_Constraint aWDConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED,
- myWorkplane.h, 0.0, anEntIter->second, 0, 0, 0);
- myConstraints.push_back(aWDConstr);
- myTempConstraints.push_back(aWDConstr.h);
-}
-
-// ============================================================================
-// Function: removeTemporaryConstraints
-// Class: SketchSolver_ConstraintGroup
-// Purpose: remove all transient SLVS_C_WHERE_DRAGGED constraints after
-// resolving the set of constraints
-// ============================================================================
-void SketchSolver_ConstraintGroup::removeTemporaryConstraints(
- const std::set<Slvs_hConstraint>& theRemoved)
-{
- std::list<Slvs_hConstraint>::reverse_iterator aTmpConstrIter;
- for (aTmpConstrIter = myTempConstraints.rbegin(); aTmpConstrIter != myTempConstraints.rend();
- aTmpConstrIter++) {
- if (!theRemoved.empty() && theRemoved.find(*aTmpConstrIter) == theRemoved.end())
- continue;
- unsigned int aConstrPos = Search(*aTmpConstrIter, myConstraints);
- if (aConstrPos >= myConstraints.size())
- continue;
- myConstraints.erase(myConstraints.begin() + aConstrPos);
-
- // If the removing constraint has higher index, decrease the indexer
- if (*aTmpConstrIter == myConstrMaxID)
- myConstrMaxID--;
- }
- myTempConstraints.clear();
-
- // Clear basic dragged point
- myTempPointWhereDragged.clear();
- myTempPointWDrgdID = SLVS_E_UNKNOWN;
-}
-
-// ============================================================================
-// Function: removeConstraint
-// Class: SketchSolver_ConstraintGroup
-// Purpose: remove constraint and all unused entities
-// ============================================================================
-void SketchSolver_ConstraintGroup::removeConstraint(
- std::shared_ptr<SketchPlugin_Constraint> theConstraint)
-{
- ConstraintMap::iterator anIterToRemove = myConstraintMap.find(theConstraint);
- if (anIterToRemove == myConstraintMap.end())
- return;
-
- std::vector<Slvs_hConstraint> aCnstrToRemove = anIterToRemove->second;
- // Remove constraint from the map
- myConstraintMap.erase(anIterToRemove);
-
- std::set<Slvs_hEntity> anEntToRemove;
-
- // Find unused entities
- std::vector<Slvs_hConstraint>::iterator aCnstrToRemoveIter = aCnstrToRemove.begin();
- for (; aCnstrToRemoveIter != aCnstrToRemove.end(); aCnstrToRemoveIter++) {
- int aConstrPos = Search(*aCnstrToRemoveIter, myConstraints);
- Slvs_hEntity aCnstEnt[] = { myConstraints[aConstrPos].ptA, myConstraints[aConstrPos].ptB,
- myConstraints[aConstrPos].entityA, myConstraints[aConstrPos].entityB };
- for (int i = 0; i < 4; i++)
- if (aCnstEnt[i] != 0)
- anEntToRemove.insert(aCnstEnt[i]);
- myConstraints.erase(myConstraints.begin() + aConstrPos);
- if (*aCnstrToRemoveIter == myConstrMaxID)
- myConstrMaxID--;
- }
-
- // Find all entities which are based on these unused
- std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
- for ( ; anEntIter != myEntities.end(); anEntIter++)
- if (anEntIter->type == SLVS_E_LINE_SEGMENT || anEntIter->type == SLVS_E_CIRCLE ||
- anEntIter->type == SLVS_E_ARC_OF_CIRCLE) {
- for (int i = 0; i < 4; i++)
- if (anEntToRemove.find(anEntIter->point[i]) != anEntToRemove.end()) {
- anEntToRemove.insert(anEntIter->h);
- for (int j = 0; j < 4; j++)
- if (anEntIter->point[j] != 0)
- anEntToRemove.insert(anEntIter->point[j]);
- break;
- }
- }
-
- // Find entities used by remaining constraints and remove them from the list to delete
- std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
- for (; aConstrIter != myConstraints.end(); aConstrIter++) {
- Slvs_hEntity aEnts[] = { aConstrIter->ptA, aConstrIter->ptB, aConstrIter->entityA, aConstrIter
- ->entityB };
- for (int i = 0; i < 4; i++)
- if (aEnts[i] != 0 && anEntToRemove.find(aEnts[i]) != anEntToRemove.end()) {
- anEntToRemove.erase(aEnts[i]);
- // remove from the list all points of current entity
- int aEntPos = Search(aEnts[i], myEntities);
- for (int j = 0; j < 4; j++)
- if (myEntities[aEntPos].point[j] != 0)
- anEntToRemove.erase(myEntities[aEntPos].point[j]);
- }
- }
-
- if (anEntToRemove.empty())
- return;
-
- // Remove unused entities
- std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator anEntAttrIter =
- myEntityAttrMap.begin();
- while (anEntAttrIter != myEntityAttrMap.end()) {
- if (anEntToRemove.find(anEntAttrIter->second) != anEntToRemove.end()) {
- std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator aRemovedIter =
- anEntAttrIter;
- anEntAttrIter++;
- myEntityAttrMap.erase(aRemovedIter);
- } else
- anEntAttrIter++;
- }
- std::map<FeaturePtr, Slvs_hEntity>::iterator anEntFeatIter = myEntityFeatMap.begin();
- while (anEntFeatIter != myEntityFeatMap.end()) {
- if (anEntToRemove.find(anEntFeatIter->second) != anEntToRemove.end()) {
- std::map<FeaturePtr, Slvs_hEntity>::iterator aRemovedIter = anEntFeatIter;
- anEntFeatIter++;
- myEntityFeatMap.erase(aRemovedIter);
- } else
- anEntFeatIter++;
- }
-
- removeEntitiesById(anEntToRemove);
-
- if (myCoincidentPoints.size() == 1 && myCoincidentPoints.front().empty())
- myCoincidentPoints.clear();
-}
-
-// ============================================================================
-// Function: removeEntitiesById
-// Class: SketchSolver_ConstraintGroup
-// Purpose: Removes specified entities and their parameters
-// ============================================================================
-void SketchSolver_ConstraintGroup::removeEntitiesById(const std::set<Slvs_hEntity>& theEntities)
-{
- std::set<Slvs_hEntity>::const_reverse_iterator aRemIter = theEntities.rbegin();
- for (; aRemIter != theEntities.rend(); aRemIter++) {
- unsigned int anEntPos = Search(*aRemIter, myEntities);
- if (anEntPos >= myEntities.size())
- continue;
- if (myEntities[anEntPos].param[0] != 0) {
- unsigned int aParamPos = Search(myEntities[anEntPos].param[0], myParams);
- if (aParamPos >= myParams.size())
- continue;
- int aNbParams = 0;
- while (myEntities[anEntPos].param[aNbParams] != 0)
- aNbParams++;
- if (myEntities[anEntPos].param[aNbParams - 1] == myParamMaxID)
- myParamMaxID -= aNbParams;
- myParams.erase(myParams.begin() + aParamPos, myParams.begin() + aParamPos + aNbParams);
- if (*aRemIter == myEntityMaxID)
- myEntityMaxID--;
- }
- myEntities.erase(myEntities.begin() + anEntPos);
- myEntOfConstr.erase(myEntOfConstr.begin() + anEntPos);
-
- // Remove entity's ID from the lists of conincident points
- std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
- for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++)
- aCoPtIter->erase(*aRemIter);
- }
-}
-
-// ============================================================================
-// Function: addCoincidentPoints
-// Class: SketchSolver_ConstraintGroup
-// Purpose: add coincident point the appropriate list of such points
-// ============================================================================
-bool SketchSolver_ConstraintGroup::addCoincidentPoints(const Slvs_hEntity& thePoint1,
- const Slvs_hEntity& thePoint2)
-{
- std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
- std::vector<std::set<Slvs_hEntity> >::iterator aFirstFound = myCoincidentPoints.end();
- while (aCoPtIter != myCoincidentPoints.end()) {
- bool isFound[2] = { // indicate which point ID was already in coincidence constraint
- aCoPtIter->find(thePoint1) != aCoPtIter->end(), aCoPtIter->find(thePoint2)
- != aCoPtIter->end(), };
- if (isFound[0] && isFound[1]) // points are already connected by coincidence constraints => no need additional one
- return false;
- if ((isFound[0] && !isFound[1]) || (!isFound[0] && isFound[1])) {
- if (aFirstFound != myCoincidentPoints.end()) { // there are two groups of coincident points connected by created constraint => merge them
- int aFirstFoundShift = aFirstFound - myCoincidentPoints.begin();
- int aCurrentShift = aCoPtIter - myCoincidentPoints.begin();
- aFirstFound->insert(aCoPtIter->begin(), aCoPtIter->end());
- myCoincidentPoints.erase(aCoPtIter);
- aFirstFound = myCoincidentPoints.begin() + aFirstFoundShift;
- aCoPtIter = myCoincidentPoints.begin() + aCurrentShift;
- continue;
- } else {
- aCoPtIter->insert(isFound[0] ? thePoint2 : thePoint1);
- aFirstFound = aCoPtIter;
- }
- }
- aCoPtIter++;
- }
- // No points were found, need to create new set
- if (aFirstFound == myCoincidentPoints.end()) {
- std::set<Slvs_hEntity> aNewSet;
- aNewSet.insert(thePoint1);
- aNewSet.insert(thePoint2);
- myCoincidentPoints.push_back(aNewSet);
- }
-
- return true;
-}
-
-// ============================================================================
-// Function: updateRelatedConstraints
-// Class: SketchSolver_ConstraintGroup
-// Purpose: emit the signal to update constraints
-// ============================================================================
-void SketchSolver_ConstraintGroup::updateRelatedConstraints(
- std::shared_ptr<ModelAPI_Attribute> theEntity) const
-{
- ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
- for (; aConstrIter != myConstraintMap.end(); aConstrIter++) {
- std::list<std::shared_ptr<ModelAPI_Attribute> > anAttributes = aConstrIter->first->data()
- ->attributes(std::string());
-
- std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttributes.begin();
- for (; anAttrIter != anAttributes.end(); anAttrIter++) {
- bool isUpd = (*anAttrIter == theEntity);
- std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr = std::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::updateRelatedConstraintsFeature(
- std::shared_ptr<ModelAPI_Feature> theFeature) const
-{
- ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
- for (; aConstrIter != myConstraintMap.end(); aConstrIter++) {
- std::list<std::shared_ptr<ModelAPI_Attribute> > anAttributes = aConstrIter->first->data()
- ->attributes(std::string());
-
- std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttributes.begin();
- for (; anAttrIter != anAttributes.end(); anAttrIter++) {
- std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr = std::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;
- }
- }
- }
-}
-
-// ============================================================================
-// Function: updateFilletConstraints
-// Class: SketchSolver_ConstraintGroup
-// Purpose: change fillet arc to be less than 180 degree
-// ============================================================================
-void SketchSolver_ConstraintGroup::updateFilletConstraints()
-{
- ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
- for (; aConstrIter != myConstraintMap.end(); aConstrIter++)
- if (aConstrIter->first->getKind() == SketchPlugin_ConstraintFillet::ID()) {
- AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
- aConstrIter->first->data()->attribute(SketchPlugin_ConstraintFillet::ENTITY_C()));
- if (!aFilletRefList)
- return;
- ObjectPtr anArcObj = aFilletRefList->object(2);
- std::shared_ptr<GeomDataAPI_Point2D> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- anArcObj->data()->attribute(SketchPlugin_Arc::CENTER_ID()));
- std::shared_ptr<GeomDataAPI_Point2D> aStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- anArcObj->data()->attribute(SketchPlugin_Arc::START_ID()));
- std::shared_ptr<GeomDataAPI_Point2D> aEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- anArcObj->data()->attribute(SketchPlugin_Arc::END_ID()));
- double aCosA = aStart->x() - aCenter->x();
- double aSinA = aStart->y() - aCenter->y();
- double aCosB = aEnd->x() - aCenter->x();
- double aSinB = aEnd->y() - aCenter->y();
- if (aCosA * aSinB - aSinA * aCosB <= 0.0) {
- anArcObj->data()->blockSendAttributeUpdated(true);
- double x = aStart->x();
- double y = aStart->y();
- aStart->setValue(aEnd->x(), aEnd->y());
- aEnd->setValue(x, y);
- // Update constraint data
- changeFilletConstraint(aConstrIter->first);
- anArcObj->data()->blockSendAttributeUpdated(false);
- }
- }
-}
-
-// ============================================================================
-// Function: makeMirrorEntity
-// Class: SketchSolver_ConstraintGroup
-// Purpose: change entities parameters to make them symmetric relating to the mirror line
-// ============================================================================
-void SketchSolver_ConstraintGroup::makeMirrorEntity(const Slvs_hEntity& theBase,
- const Slvs_hEntity& theMirror,
- const Slvs_hEntity& theMirrorLine)
-{
- Slvs_Entity aBase = myEntities[Search(theBase, myEntities)];
- Slvs_Entity aMirror = myEntities[Search(theMirror, myEntities)];
- int i = 0;
- if (aBase.type != SLVS_E_ARC_OF_CIRCLE) {
- while (aBase.point[i] != 0 && aMirror.point[i] != 0) {
- makeMirrorEntity(aBase.point[i], aMirror.point[i], theMirrorLine);
- i++;
- }
- } else {
- // swap mirroring first and last points of an arc
- makeMirrorEntity(aBase.point[0], aMirror.point[0], theMirrorLine);
- makeMirrorEntity(aBase.point[1], aMirror.point[2], theMirrorLine);
- makeMirrorEntity(aBase.point[2], aMirror.point[1], theMirrorLine);
- }
- if (aBase.param[0] != 0 && aMirror.param[0] != 0) { // this is a point, copy it
- Slvs_Entity aMirrorLine = myEntities[Search(theMirrorLine, myEntities)];
- std::shared_ptr<GeomAPI_XY> aLinePoints[2];
- for (i = 0; i < 2; i++) {
- Slvs_Entity aPoint = myEntities[Search(aMirrorLine.point[i], myEntities)];
- int aParamPos = Search(aPoint.param[0], myParams);
- aLinePoints[i] = std::shared_ptr<GeomAPI_XY>(
- new GeomAPI_XY(myParams[aParamPos].val, myParams[1+aParamPos].val));
- }
- int aBaseParamPos = Search(aBase.param[0], myParams);
- int aMirrorParamPos = Search(aMirror.param[0], myParams);
- std::shared_ptr<GeomAPI_XY> aPoint = std::shared_ptr<GeomAPI_XY>(
- new GeomAPI_XY(myParams[aBaseParamPos].val, myParams[1+aBaseParamPos].val));
-
- // direction of a mirror line
- std::shared_ptr<GeomAPI_Dir2d> aDir = std::shared_ptr<GeomAPI_Dir2d>(
- new GeomAPI_Dir2d(aLinePoints[1]->added(aLinePoints[0]->multiplied(-1.0))));
- // orthogonal direction
- aDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aDir->y(), -aDir->x()));
-
- std::shared_ptr<GeomAPI_XY> aVec = std::shared_ptr<GeomAPI_XY>(
- new GeomAPI_XY(aPoint->x() - aLinePoints[0]->x(), aPoint->y() - aLinePoints[0]->y()));
- double aDist = aVec->dot(aDir->xy());
- std::shared_ptr<GeomAPI_XY> aMirrorPoint = aPoint->added(aDir->xy()->multiplied(-2.0 * aDist));
-
- myParams[aMirrorParamPos].val = aMirrorPoint->x();
- myParams[1+aMirrorParamPos].val = aMirrorPoint->y();
- }
-}
-
-// ============================================================================
-// Function: changeMirrorPoints
-// Class: SketchSolver_ConstraintGroup
-// Purpose: creates/updates mirror constraint for two points
-// ============================================================================
-Slvs_hConstraint SketchSolver_ConstraintGroup::changeMirrorPoints(
- const Slvs_hEntity& theBasePoint,
- const Slvs_hEntity& theMirrorPoint,
- const Slvs_hEntity& theMirrorLine,
- std::vector<Slvs_Constraint>& thePrevConstr,
- std::map<Slvs_hEntity, Slvs_hEntity>& thePrevMirror)
-{
- std::map<Slvs_hEntity, Slvs_hEntity>::iterator aMapIter = thePrevMirror.find(theBasePoint);
- if (aMapIter != thePrevMirror.end()) {
- thePrevMirror.erase(aMapIter);
- std::vector<Slvs_Constraint>::iterator anIter = thePrevConstr.begin();
- for (; anIter != thePrevConstr.end(); anIter++)
- if (anIter->ptA == theBasePoint) {
- if (anIter->ptB != theMirrorPoint) {
- int aConstrInd = Search(anIter->h, myConstraints);
- myConstraints[aConstrInd].ptB = theMirrorPoint;
- myConstraints[aConstrInd].entityA = theMirrorLine;
- }
- Slvs_hConstraint aResult = anIter->h;
- thePrevConstr.erase(anIter);
- return aResult;
- }
- }
-
- // Newly created constraint
- Slvs_Constraint aConstraint = Slvs_MakeConstraint(
- ++myConstrMaxID, myID, SLVS_C_SYMMETRIC_LINE, myWorkplane.h, 0.0,
- theBasePoint, theMirrorPoint, theMirrorLine, SLVS_E_UNKNOWN);
- myConstraints.push_back(aConstraint);
- return aConstraint.h;
-}
-
-
-// ============================================================================
-// Function: calculateMiddlePoint
-// Class: SketchSolver_ConstraintGroup
-// Purpose: calculates middle point on line or arc
-// ============================================================================
-void SketchSolver_ConstraintGroup::calculateMiddlePoint(
- const Slvs_hEntity& theEntity,
- double& theX,
- double& theY) const
-{
- int anInd = Search(theEntity, myEntities);
- if (myEntities[anInd].type == SLVS_E_LINE_SEGMENT) {
- int aLineParams[2];
- for (int i = 0; i < 2; i++) {
- int aPtPos = Search(myEntities[anInd].point[i], myEntities);
- aLineParams[i] = Search(myEntities[aPtPos].param[0], myParams);
- }
- theX = 0.5 * (myParams[aLineParams[0]].val + myParams[aLineParams[1]].val);
- theY = 0.5 * (myParams[1 + aLineParams[0]].val + myParams[1 + aLineParams[1]].val);
- } else if (myEntities[anInd].type == SLVS_E_ARC_OF_CIRCLE) {
- double anArcPoint[3][2];
- for (int i = 0; i < 3; i++) {
- int aPtPos = Search(myEntities[anInd].point[i], myEntities);
- int anArcParam = Search(myEntities[aPtPos].param[0], myParams);
- anArcPoint[i][0] = myParams[anArcParam].val;
- anArcPoint[i][1] = myParams[1 + anArcParam].val;
- }
- // project last point of arc on the arc
- double x = anArcPoint[1][0] - anArcPoint[0][0];
- double y = anArcPoint[1][1] - anArcPoint[0][1];
- double aRad = sqrt(x*x + y*y);
- x = anArcPoint[2][0] - anArcPoint[0][0];
- y = anArcPoint[2][1] - anArcPoint[0][1];
- double aNorm = sqrt(x*x + y*y);
- if (aNorm >= tolerance) {
- anArcPoint[2][0] = anArcPoint[0][0] + x * aRad / aNorm;
- anArcPoint[2][1] = anArcPoint[0][1] + y * aRad / aNorm;
- }
-
- x = anArcPoint[1][0] + anArcPoint[2][0] - 2.0 * anArcPoint[0][0];
- y = anArcPoint[1][1] + anArcPoint[2][1] - 2.0 * anArcPoint[0][1];
- aNorm = sqrt(x*x + y*y);
- if (aNorm >= tolerance) {
- x *= aRad / aNorm;
- y *= aRad / aNorm;
- } else { // obtain orthogonal direction
- x = 0.5 * (anArcPoint[2][1] - anArcPoint[1][1]);
- y = -0.5 * (anArcPoint[2][0] - anArcPoint[1][0]);
- }
- theX = anArcPoint[0][0] + x;
- theY = anArcPoint[0][1] + y;
- }
-}
-
-
-// ========================================================
-// ========= Auxiliary functions ===============
-// ========================================================
-
-template<typename T>
-int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
-{
- int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0;
- int aVecSize = theEntities.size();
- while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
- aResIndex--;
- while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
- aResIndex++;
- if (aResIndex == -1)
- aResIndex = aVecSize;
- return aResIndex;
-}
+++ /dev/null
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File: SketchSolver_ConstraintGroup.h
-// Created: 27 May 2014
-// Author: Artem ZHIDKOV
-
-#ifndef SketchSolver_ConstraintGroup_H_
-#define SketchSolver_ConstraintGroup_H_
-
-#include "SketchSolver.h"
-#include <SketchSolver_Solver.h>
-
-#include <SketchPlugin_Constraint.h>
-#include <ModelAPI_Data.h>
-#include <ModelAPI_Feature.h>
-
-
-#include <memory>
-#include <list>
-#include <map>
-#include <vector>
-#include <set>
-
-typedef std::map< std::shared_ptr<SketchPlugin_Constraint>, std::vector<Slvs_hConstraint> >
- ConstraintMap;
-
-/** \class SketchSolver_ConstraintGroup
- * \ingroup Plugins
- * \brief Keeps the group of constraints which based on the same entities
- */
-class SketchSolver_ConstraintGroup
-{
- public:
- /** \brief New group based on specified workplane.
- * Throws an exception if theWorkplane is not an object of SketchPlugin_Sketch type
- * \remark Type of theSketch is not verified inside
- */
- SketchSolver_ConstraintGroup(std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane);
-
- ~SketchSolver_ConstraintGroup();
-
- /// \brief Returns group's unique identifier
- inline const Slvs_hGroup& getId() const
- {
- return myID;
- }
-
- /// \brief Returns true if the group has no constraints yet
- inline bool isEmpty() const
- {
- return myConstraints.empty();
- }
-
- /// \brief Check for valid sketch data
- inline bool isWorkplaneValid() const
- {
- return mySketch->data() && mySketch->data()->isValid();
- }
-
- /** \brief Adds or updates a constraint in the group
- * \param[in] theConstraint constraint to be changed
- * \return \c true if the constraint added or updated successfully
- */
- bool changeConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
- /** \brief Adds or updates a rigid constraint in the group
- * \param[in] theConstraint constraint to be changed
- * \return \c true if the constraint added or updated successfully
- */
- bool changeRigidConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
- /** \brief Adds or updates a mirror constraint in the group
- * \param[in] theConstraint constraint to be changed
- * \return \c true if the constraint added or updated successfully
- */
- bool changeMirrorConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
- /** \brief Adds or updates a fillet constraint in the group
- * \param[in] theConstraint constraint to be changed
- * \return \c true if the constraint added or updated successfully
- */
- bool changeFilletConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
-
- /** \brief Verifies the feature attributes are used in this group
- * \param[in] theFeature constraint or any other object for verification of interaction
- * \return \c true if some of attributes are used in current group
- */
- bool isInteract(std::shared_ptr<SketchPlugin_Feature> theFeature) const;
-
- /** \brief Verifies the specified feature is equal to the base workplane for this group
- * \param[in] theWorkplane the feature to be compared with base workplane
- * \return \c true if workplanes are the same
- */
- bool isBaseWorkplane(std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane) const;
-
- /// Returns the current workplane
- std::shared_ptr<ModelAPI_CompositeFeature> getWorkplane() const
- {
- return mySketch;
- }
-
- /** \brief Update parameters of workplane. Should be called when Update event is coming.
- * \return \c true if workplane updated successfully, \c false if workplane parameters are not consistent
- */
- bool updateWorkplane();
-
- /** \brief If the entity is in this group it will updated
- * \param[in] theEntity attribute, which values should update SolveSpace entity
- */
- void updateEntityIfPossible(std::shared_ptr<ModelAPI_Attribute> theEntity);
-
- /** \brief Searches invalid features and constraints in the group and avoids them
- * \return \c true if the group several constraints were removed
- */
- bool updateGroup();
-
- /** \brief Add specified group to this one
- * \param[in] theGroup group of constraint to be added
- */
- void mergeGroups(const SketchSolver_ConstraintGroup& theGroup);
-
- /** \brief Cut from the group several subgroups, which are not connected to the current one by any constraint
- * \param[out] theCuts enlarge this list by newly created groups
- */
- void splitGroup(std::vector<SketchSolver_ConstraintGroup*>& theCuts);
-
- /** \brief Start solution procedure if necessary and update attributes of features
- * \return \c false when no need to solve constraints
- */
- bool resolveConstraints();
-
- /** \brief Searches the constraints built on the entity and emit the signal to update them
- * \param[in] theEntity attribute of the constraint
- */
- void updateRelatedConstraints(std::shared_ptr<ModelAPI_Attribute> theEntity) const;
- /** \brief Searches the constraints built on the entity and emit the signal to update them
- * \param[in] theFeature feature of the constraint
- */
- void updateRelatedConstraintsFeature(std::shared_ptr<ModelAPI_Feature> theFeature) const;
-
- /** \brief Adds or updates an entity in the group
- *
- * The parameters of entity will be parsed and added to the list of SolveSpace parameters.
- * Parameters of certain entity will be placed sequentially in the list.
- *
- * \param[in] theEntity the object of constraint
- * \return identifier of changed entity or 0 if entity could not be changed
- */
- Slvs_hEntity changeEntity(std::shared_ptr<ModelAPI_Attribute> theEntity);
- Slvs_hEntity changeEntityFeature(std::shared_ptr<ModelAPI_Feature> theEntity);
-
-protected:
- /** \brief Adds or updates a normal in the group
- *
- * Normal is a special entity in SolveSpace, which defines a direction in 3D and
- * a rotation about this direction. So, SolveSpace represents normals as unit quaternions.
- *
- * To define a normal there should be specified two coordinate axis
- * on the plane transversed to created normal.
- *
- * \param[in] theDirX first coordinate axis of the plane
- * \param[in] theNorm attribute for the normal (used to identify newly created entity)
- * \return identifier of created or updated normal
- */
- Slvs_hEntity changeNormal(std::shared_ptr<ModelAPI_Attribute> theDirX,
- std::shared_ptr<ModelAPI_Attribute> theNorm);
-
- /** \brief Adds or updates a parameter in the group
- * \param[in] theParam the value of parameter
- * \param[in] thePrmIter the cell in the list of parameters which should be changed
- * (the iterator will be increased if it does not reach the end of the list)
- * \return identifier of changed parameter; when the parameter cannot be created, returned ID is 0
- */
- Slvs_hParam changeParameter(double theParam,
- std::vector<Slvs_Param>::iterator& thePrmIter);
-
- /** \brief Removes specified entities and their parameters
- * \param[in] theEntities list of IDs of the entities to be removed
- */
- void removeEntitiesById(const std::set<Slvs_hEntity>& theEntities);
-
- /** \brief Removes constraints from the group
- * \param[in] theConstraint constraint to be removed
- */
- void removeConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
-
- /** \brief Change values of attribute by parameters received from SolveSpace solver
- * \param[in,out] theAttribute pointer to the attribute to be changed
- * \param[in] theEntityID identifier of SolveSpace entity, which contains updated data
- * \return \c true if the attribute's value has changed
- */
- bool updateAttribute(std::shared_ptr<ModelAPI_Attribute> theAttribute,
- const Slvs_hEntity& theEntityID);
-
- /// \brief Update arc of fillet to be less than 180 degree
- void updateFilletConstraints();
-
- /** \brief Adds a constraint for a point which should not be changed during computations
- * \param[in] theEntity the base for the constraint
- * \param[in] theAllowToFit this flag shows that the entity may be placed into
- * the 'dragged' field of SolveSpace solver, so this entity
- * may be changed a little during solution
- */
- void addTemporaryConstraintWhereDragged(std::shared_ptr<ModelAPI_Attribute> theEntity,
- bool theAllowToFit = true);
-
- /** \brief Remove all temporary constraint after computation finished
- * \param[in] theRemoved indexes of constraints to be removed. If empty, all temporary constraints should be deleted
- */
- void removeTemporaryConstraints(const std::set<Slvs_hConstraint>& theRemoved =
- std::set<Slvs_hConstraint>());
-
- private:
- /** \brief Creates a workplane from the sketch parameters
- * \param[in] theSketch parameters of workplane are the attributes of this sketch
- * \return \c true if success, \c false if workplane parameters are not consistent
- */
- bool addWorkplane(std::shared_ptr<ModelAPI_CompositeFeature> theSketch);
-
- /** \brief Add the entities of constraint for points coincidence into the appropriate list
- * \param[in] thePoint1 identifier of the first point
- * \param[in] thePoint2 identifier of the second point
- * \return \c true if the points are added successfully, and
- * \c false if the constraint is the extra one (should not be created in SolveSpace)
- */
- bool addCoincidentPoints(const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2);
-
- /** \brief Verifies and changes parameters of constriant,
- * e.g. sign of the distance between line and point
- * \param[in,out] theConstraint SolveSpace constraint to be verified
- */
- void checkConstraintConsistence(Slvs_Constraint& theConstraint);
-
- /** \brief Change entities parameters to make them symmetric relating to the mirror line
- * \param[in] theBase entity to be mirrored
- * \param[in] theMirror a mirrored object
- * \param[in] theMirrorLine a mirror line
- */
- void makeMirrorEntity(const Slvs_hEntity& theBase,
- const Slvs_hEntity& theMirror,
- const Slvs_hEntity& theMirrorLine);
-
- /** \brief Creates/updates mirror constraint for two points
- * \param[in] theBasePoint ID of initial point
- * \param[in] theMirrorPoint ID of the mirroring point
- * \param[in] theMirrorLine ID of the mirror line
- * \param[in] thePrevConstr list of previous constraints (the items will be deleted from the list if they are updated)
- * \param[in,out] thePrevMirror list of previously mirrored points (the items will be deleted from the list if they are updated)
- * \return ID of created/updated constraint
- */
- Slvs_hConstraint changeMirrorPoints(const Slvs_hEntity& theBasePoint,
- const Slvs_hEntity& theMirrorPoint,
- const Slvs_hEntity& theMirrorLine,
- std::vector<Slvs_Constraint>& thePrevConstr,
- std::map<Slvs_hEntity, Slvs_hEntity>& thePrevMirror);
-
- /** \brief Calculates middle point on line or arc
- * \param[in] theEntity identifier of line or arc
- * \param[out] theX X value of middle point
- * \param[out] theY Y value of middle point
- */
- void calculateMiddlePoint(const Slvs_hEntity& theEntity,
- double& theX, double& theY) const;
-
- private:
- // SolveSpace entities
- Slvs_hGroup myID; ///< the index of the group
- Slvs_Entity myWorkplane; ///< Workplane for the current group
- std::vector<Slvs_Param> myParams; ///< List of parameters of the constraints
- Slvs_hParam myParamMaxID; ///< Actual maximal ID of parameters (not equal to myParams size)
- std::vector<Slvs_Entity> myEntities; ///< List of entities of the constaints
- std::vector<bool> myEntOfConstr; ///< Flags show that certain entity used in constraints
- Slvs_hEntity myEntityMaxID; ///< Actual maximal ID of entities (not equal to myEntities size)
- std::vector<Slvs_Constraint> myConstraints; ///< List of constraints in SolveSpace format
- Slvs_hConstraint myConstrMaxID; ///< Actual maximal ID of constraints (not equal to myConstraints size)
- bool myNeedToSolve; ///< Indicator that something changed in the group and constraint system need to be rebuilt
-
- SketchSolver_Solver myConstrSolver; ///< Solver for set of equations obtained by constraints
-
- std::vector<Slvs_hParam> myTempPointWhereDragged; ///< Parameters of one of the points which is moved by user
- Slvs_hEntity myTempPointWDrgdID; ///< Identifier of such point
- std::list<Slvs_hConstraint> myTempConstraints; ///< The list of identifiers of temporary constraints (SLVS_C_WHERE_DRAGGED) applied for all other points moved by user
-
- // SketchPlugin entities
- std::shared_ptr<ModelAPI_CompositeFeature> mySketch; ///< Equivalent to workplane
- ConstraintMap myConstraintMap; ///< The map between SketchPlugin and SolveSpace constraints
- std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity> myEntityAttrMap; ///< The map between "attribute" parameters of constraints and their equivalent SolveSpace entities
- std::map<FeaturePtr, Slvs_hEntity> myEntityFeatMap; ///< The map between "feature" parameters of constraints and their equivalent SolveSpace entities
-
- // Conincident items
- std::vector<std::set<Slvs_hEntity> > myCoincidentPoints; ///< Stores the lists of identifiers of coincident points (to avoid unnecessary coincidence constraints)
- std::set<std::shared_ptr<SketchPlugin_Constraint> > myExtraCoincidence; ///< Additional coincidence constraints which are not necessary (coincidence between points already done
- ///< by other constraints) but created by GUI tools. Useful when some coincidence constraints were removed
-};
-
-#endif
// Author: Artem ZHIDKOV
#include "SketchSolver_ConstraintManager.h"
-#include <SketchSolver_ConstraintGroup.h>
#include <Events_Loop.h>
#include <ModelAPI_AttributeDouble.h>
std::shared_ptr<SketchPlugin_Feature> aSFeature =
std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
if (aSFeature)
- updateEntity(aSFeature);
+ moveEntity(aSFeature);
}
} else {
std::set<ObjectPtr>::iterator aFeatIter;
break;
if (aFGrIter != aFeatureGroups.end()) {
- std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter = myGroups.begin();
- std::vector<SketchSolver_ConstraintGroup*> aSeparatedGroups;
+ std::vector<SketchSolver_Group*>::iterator aGroupIter = myGroups.begin();
+ std::vector<SketchSolver_Group*> aSeparatedGroups;
while (aGroupIter != myGroups.end()) {
if (!(*aGroupIter)->isWorkplaneValid()) { // the group should be removed
delete *aGroupIter;
aGroupIter = myGroups.begin() + aShift;
continue;
}
- if ((*aGroupIter)->updateGroup()) { // some constraints were removed, try to split the group
+ if (!(*aGroupIter)->isConsistent()) { // some constraints were removed, try to split the group
(*aGroupIter)->splitGroup(aSeparatedGroups);
}
aGroupIter++;
// Class: SketchSolver_Session
// Purpose: update workplane by given parameters of the sketch
// ============================================================================
-bool SketchSolver_ConstraintManager::changeWorkplane(
- std::shared_ptr<ModelAPI_CompositeFeature> theSketch)
+bool SketchSolver_ConstraintManager::changeWorkplane(CompositeFeaturePtr theSketch)
{
bool aResult = true; // changed when a workplane wrongly updated
bool isUpdated = false;
// Try to update specified workplane in all groups
- std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
+ std::vector<SketchSolver_Group*>::iterator aGroupIter;
for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
if ((*aGroupIter)->isBaseWorkplane(theSketch)) {
isUpdated = true;
}
// If the workplane is not updated, so this is a new workplane
if (!isUpdated) {
- SketchSolver_ConstraintGroup* aNewGroup = new SketchSolver_ConstraintGroup(theSketch);
+ SketchSolver_Group* aNewGroup = new SketchSolver_Group(theSketch);
// Verify that the group is created successfully
if (!aNewGroup->isBaseWorkplane(theSketch) || !aNewGroup->isWorkplaneValid()) {
delete aNewGroup;
std::shared_ptr<ModelAPI_CompositeFeature> aWP = findWorkplane(aConstraint);
if (!aWP)
return false;
- SketchSolver_ConstraintGroup* aGroup = new SketchSolver_ConstraintGroup(aWP);
+ SketchSolver_Group* aGroup = new SketchSolver_Group(aWP);
if (!aGroup->changeConstraint(aConstraint)) {
delete aGroup;
return false;
return true;
} else if (aGroups.size() == 1) { // Only one group => add feature into it
Slvs_hGroup aGroupId = *(aGroups.begin());
- std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
+ std::vector<SketchSolver_Group*>::iterator aGroupIter;
for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
if ((*aGroupIter)->getId() == aGroupId) {
// If the group is empty, the feature is not added (the constraint only)
- if (!aConstraint && !(*aGroupIter)->isEmpty())
- return (*aGroupIter)->changeEntityFeature(theFeature) != SLVS_E_UNKNOWN;
+//// if (!aConstraint && !(*aGroupIter)->isEmpty())
+//// return (*aGroupIter)->changeEntityFeature(theFeature) != SLVS_E_UNKNOWN;
return (*aGroupIter)->changeConstraint(aConstraint);
}
} else if (aGroups.size() > 1) { // Several groups applicable for this feature => need to merge them
std::set<Slvs_hGroup>::const_iterator aGroupsIter = aGroups.begin();
// Search first group
- std::vector<SketchSolver_ConstraintGroup*>::iterator aFirstGroupIter;
+ std::vector<SketchSolver_Group*>::iterator aFirstGroupIter;
for (aFirstGroupIter = myGroups.begin(); aFirstGroupIter != myGroups.end(); aFirstGroupIter++)
if ((*aFirstGroupIter)->getId() == *aGroupsIter)
break;
return false;
// Append other groups to the first one
- std::vector<SketchSolver_ConstraintGroup*>::iterator anOtherGroupIter = aFirstGroupIter + 1;
+ std::vector<SketchSolver_Group*>::iterator anOtherGroupIter = aFirstGroupIter + 1;
for (aGroupsIter++; aGroupsIter != aGroups.end(); aGroupsIter++) {
for (; anOtherGroupIter != myGroups.end(); anOtherGroupIter++)
if ((*anOtherGroupIter)->getId() == *aGroupsIter)
if (aConstraint)
return (*aFirstGroupIter)->changeConstraint(aConstraint);
- return (*aFirstGroupIter)->changeEntityFeature(theFeature) != SLVS_E_UNKNOWN;
+//// return (*aFirstGroupIter)->changeEntityFeature(theFeature) != SLVS_E_UNKNOWN;
}
// Something goes wrong
}
// ============================================================================
-// Function: updateEntity
+// Function: moveEntity
// Class: SketchSolver_Session
-// Purpose: update any element on the sketch, which is used by constraints
+// Purpose: update element moved on the sketch, which is used by constraints
// ============================================================================
-void SketchSolver_ConstraintManager::updateEntity(
+void SketchSolver_ConstraintManager::moveEntity(
std::shared_ptr<SketchPlugin_Feature> theFeature)
{
- // Create list of attributes depending on type of the feature
- std::vector<std::string> anAttrList;
- const std::string& aFeatureKind = theFeature->getKind();
- // Point
- if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0)
- anAttrList.push_back(SketchPlugin_Point::COORD_ID());
- // Line
- else if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) {
- anAttrList.push_back(SketchPlugin_Line::START_ID());
- anAttrList.push_back(SketchPlugin_Line::END_ID());
- }
- // Circle
- else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) {
- anAttrList.push_back(SketchPlugin_Circle::CENTER_ID());
- anAttrList.push_back(SketchPlugin_Circle::RADIUS_ID());
- }
- // Arc
- else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) {
- anAttrList.push_back(SketchPlugin_Arc::CENTER_ID());
- anAttrList.push_back(SketchPlugin_Arc::START_ID());
- anAttrList.push_back(SketchPlugin_Arc::END_ID());
- }
- /// \todo Other types of features should be implemented
-
- // Check changing of feature's attributes (go through the groups and search usage of the attributes)
- std::vector<std::string>::const_iterator anAttrIter;
- for (anAttrIter = anAttrList.begin(); anAttrIter != anAttrList.end(); anAttrIter++) {
- std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
- for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) {
- if ((*aGroupIter)->isEmpty())
- continue;
- std::shared_ptr<ModelAPI_Attribute> anAttribute = std::dynamic_pointer_cast<
- ModelAPI_Attribute>(theFeature->data()->attribute(*anAttrIter));
- (*aGroupIter)->updateEntityIfPossible(anAttribute);
- }
- }
-
- std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
- for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
- if (!(*aGroupIter)->isEmpty())
- (*aGroupIter)->updateRelatedConstraintsFeature(theFeature);
+ std::vector<SketchSolver_Group*>::iterator aGroupIt = myGroups.begin();
+ for (; aGroupIt != myGroups.end(); aGroupIt++)
+ if (!(*aGroupIt)->isEmpty() && (*aGroupIt)->isInteract(theFeature))
+ (*aGroupIt)->moveFeature(theFeature);
+
+//// // Create list of attributes depending on type of the feature
+//// std::vector<std::string> anAttrList;
+//// const std::string& aFeatureKind = theFeature->getKind();
+//// // Point
+//// if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0)
+//// anAttrList.push_back(SketchPlugin_Point::COORD_ID());
+//// // Line
+//// else if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) {
+//// anAttrList.push_back(SketchPlugin_Line::START_ID());
+//// anAttrList.push_back(SketchPlugin_Line::END_ID());
+//// }
+//// // Circle
+//// else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) {
+//// anAttrList.push_back(SketchPlugin_Circle::CENTER_ID());
+//// anAttrList.push_back(SketchPlugin_Circle::RADIUS_ID());
+//// }
+//// // Arc
+//// else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) {
+//// anAttrList.push_back(SketchPlugin_Arc::CENTER_ID());
+//// anAttrList.push_back(SketchPlugin_Arc::START_ID());
+//// anAttrList.push_back(SketchPlugin_Arc::END_ID());
+//// }
+//// /// \todo Other types of features should be implemented
+////
+//// // Check changing of feature's attributes (go through the groups and search usage of the attributes)
+//// std::vector<std::string>::const_iterator anAttrIter;
+//// for (anAttrIter = anAttrList.begin(); anAttrIter != anAttrList.end(); anAttrIter++) {
+//// std::vector<SketchSolver_Group*>::iterator aGroupIter;
+//// for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) {
+//// if ((*aGroupIter)->isEmpty())
+//// continue;
+//// std::shared_ptr<ModelAPI_Attribute> anAttribute = std::dynamic_pointer_cast<
+//// ModelAPI_Attribute>(theFeature->data()->attribute(*anAttrIter));
+//// (*aGroupIter)->updateEntityIfPossible(anAttribute);
+//// }
+//// }
+////
+//// std::vector<SketchSolver_Group*>::iterator aGroupIter;
+//// for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+//// if (!(*aGroupIter)->isEmpty())
+//// (*aGroupIter)->updateRelatedConstraintsFeature(theFeature);
}
// ============================================================================
{
std::shared_ptr<ModelAPI_CompositeFeature> aWP = findWorkplane(theFeature);
- SketchSolver_ConstraintGroup* anEmptyGroup = 0; // appropriate empty group for specified constraint
- std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
+ SketchSolver_Group* anEmptyGroup = 0; // appropriate empty group for specified constraint
+ std::vector<SketchSolver_Group*>::const_iterator aGroupIter;
for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
if (aWP == (*aGroupIter)->getWorkplane() && (*aGroupIter)->isInteract(theFeature)) {
if (!(*aGroupIter)->isEmpty())
// Already verified workplanes
std::set<std::shared_ptr<ModelAPI_CompositeFeature> > aVerified;
- std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
+ std::vector<SketchSolver_Group*>::const_iterator aGroupIter;
for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) {
std::shared_ptr<ModelAPI_CompositeFeature> aWP = (*aGroupIter)->getWorkplane();
if (aVerified.find(aWP) != aVerified.end())
Events_Loop::loop()->setFlushed(anUpdateEvent, false);
}
- std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
+ std::vector<SketchSolver_Group*>::iterator aGroupIter;
for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
if ((*aGroupIter)->resolveConstraints())
needToUpdate = true;
#include "SketchSolver.h"
#include <SketchSolver_Solver.h>
-#include <SketchSolver_ConstraintGroup.h>
+#include <SketchSolver_Group.h>
#include <Events_Listener.h>
#include <SketchPlugin_Constraint.h>
* \return \c true if the workplane changed successfully
* \remark Type of theSketch is not verified inside
*/
- bool changeWorkplane(std::shared_ptr<ModelAPI_CompositeFeature> theSketch);
+ bool changeWorkplane(CompositeFeaturePtr theSketch);
/** \brief Removes a workplane from the manager.
* All groups based on such workplane will be removed too.
*/
bool removeWorkplane(std::shared_ptr<SketchPlugin_Sketch> theSketch);
- /** \brief Updates entity which is neither workplane nor constraint
+ /** \brief Updates entity which is moved in GUI
* \param[in] theFeature entity to be updated
*/
- void updateEntity(std::shared_ptr<SketchPlugin_Feature> theFeature);
+ void moveEntity(std::shared_ptr<SketchPlugin_Feature> theFeature);
/** \brief Goes through the list of groups and solve the constraints
* \param theForceUpdate flushes the update event in any case: something changed or not
private:
static SketchSolver_ConstraintManager* _self; ///< Self pointer to implement singleton functionality
- std::vector<SketchSolver_ConstraintGroup*> myGroups; ///< Groups of constraints
+ std::vector<SketchSolver_Group*> myGroups; ///< Groups of constraints
/// true if computation is performed and all "updates" are generated by this algo
/// and needs no recomputation
bool myIsComputed;
--- /dev/null
+#include <SketchSolver_ConstraintRigid.h>
+#include <SketchSolver_Error.h>
+#include <SketchSolver_Group.h>
+
+#include <SketchPlugin_ConstraintRigid.h>
+
+SketchSolver_ConstraintRigid::SketchSolver_ConstraintRigid(FeaturePtr theFeature)
+ : SketchSolver_Constraint(),
+ myBaseFeature(theFeature)
+{
+ process();
+}
+
+void SketchSolver_ConstraintRigid::process()
+{
+ cleanErrorMsg();
+ if ((!myBaseConstraint && !myBaseFeature) || !myStorage || myGroup == 0) {
+ /// TODO: Put error message here
+ return;
+ }
+ if (!mySlvsConstraints.empty()) // some data is changed, update constraint
+ update(myBaseConstraint);
+
+ double aValue;
+ std::vector<Slvs_hEntity> anEntities;
+ getAttributes(aValue, anEntities);
+
+ Slvs_Constraint aConstraint;
+ std::vector<Slvs_hConstraint>::iterator aConstrIter = mySlvsConstraints.begin();
+ bool isEmpty = aConstrIter == mySlvsConstraints.end();
+ std::vector<Slvs_hEntity>::const_iterator anEntIter = anEntities.begin();
+ for (; anEntIter != anEntities.end(); anEntIter++) {
+ if (isEmpty) { // create new constraint
+ aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(),
+ aValue, *anEntIter, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+ aConstraint.h = myStorage->addConstraint(aConstraint);
+ mySlvsConstraints.push_back(aConstraint.h);
+ if (!myBaseConstraint)
+ myStorage->addTemporaryConstraint(aConstraint.h);
+ } else { // update already existent constraint
+ aConstraint = myStorage->getConstraint(*aConstrIter);
+ aConstraint.ptA = *anEntIter;
+ myStorage->addConstraint(aConstraint);
+ aConstrIter++;
+ isEmpty = aConstrIter == mySlvsConstraints.end();
+ }
+ }
+}
+
+
+void SketchSolver_ConstraintRigid::getAttributes(
+ double& theValue,
+ std::vector<Slvs_hEntity>& theAttributes)
+{
+ theValue = 0.0;
+ int aType = SLVS_E_UNKNOWN; // type of created entity
+ Slvs_hEntity anEntityID = SLVS_E_UNKNOWN;
+ if (myBaseConstraint) {
+ // Get the attribute of constraint
+ AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ myBaseConstraint->attribute(SketchPlugin_ConstraintRigid::ENTITY_A()));
+ if (!aRefAttr) {
+ myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+ return;
+ }
+ anEntityID = myGroup->getAttributeId(aRefAttr);
+ if (anEntityID == SLVS_E_UNKNOWN)
+ anEntityID = changeEntity(aRefAttr, aType);
+ } else {
+ anEntityID = myGroup->getFeatureId(myBaseFeature);
+ if (anEntityID == SLVS_E_UNKNOWN)
+ anEntityID = changeEntity(myBaseFeature, aType);
+ }
+
+ // Check the entity is complex
+ Slvs_Entity anEntity = myStorage->getEntity(anEntityID);
+ if (anEntity.point[0] != SLVS_E_UNKNOWN) {
+ for (int i = 0; i < 4 && anEntity.point[i]; i++)
+ theAttributes.push_back(anEntity.point[i]);
+ } else // simple entity
+ theAttributes.push_back(anEntityID);
+}
+
+bool SketchSolver_ConstraintRigid::remove(ConstraintPtr theConstraint)
+{
+ cleanErrorMsg();
+ if (theConstraint && theConstraint != myBaseConstraint)
+ return false;
+ bool isFullyRemoved = true;
+ std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
+ for (; aCIter != mySlvsConstraints.end(); aCIter++)
+ isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved;
+
+ if (isFullyRemoved) {
+ myFeatureMap.clear();
+ myAttributeMap.clear();
+ myValueMap.clear();
+ } else
+ cleanRemovedEntities();
+ return true;
+}
+
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_ConstraintRigid.h
+// Created: 30 Mar 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SketchSolver_ConstraintRigid_H_
+#define SketchSolver_ConstraintRigid_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+
+/** \class SketchSolver_ConstraintRigid
+ * \ingroup Plugins
+ * \brief Stores data of Rigid (Fixed) constraint
+ *
+ * Rigid constraint may have NULL basic SketchPlugin constraint,
+ * because the Rigid constraint may be temporary for correct moving of objects
+ */
+class SketchSolver_ConstraintRigid : public SketchSolver_Constraint
+{
+public:
+ /// Creates constraint to manage the given constraint from plugin
+ SketchSolver_ConstraintRigid(ConstraintPtr theConstraint)
+ : SketchSolver_Constraint(theConstraint)
+ {}
+ /// Creates temporary constraint based on feature
+ SketchSolver_ConstraintRigid(FeaturePtr theFeature);
+
+ /// \brief Tries to remove constraint
+ /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
+ virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
+
+ /// \brief Returns the type of constraint
+ virtual int getType() const
+ { return SLVS_C_WHERE_DRAGGED; }
+
+protected:
+ /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+ virtual void process();
+
+ /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
+ /// \param[out] theValue numerical characteristic of constraint (e.g. distance)
+ /// \param[out] theAttributes list of attributes to be filled
+ virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes);
+
+protected:
+ FeaturePtr myBaseFeature; ///< fixed feature (when it is set, myBaseConstraint should be NULL)
+};
+
+#endif
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_Error.h
+// Created: 29 Mar 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SketchSolver_Error_H_
+#define SketchSolver_Error_H_
+
+#include <string>
+
+/** \class SketchSolver_Error
+ * \ingroup Plugins
+ * \brief Collects all sketch solver error' codes
+ * as inline static functions
+ */
+class SketchSolver_Error
+{
+ public:
+ /// The value parameter for the constraint
+ inline static const std::string& CONSTRAINTS()
+ {
+ static const std::string MY_ERROR_VALUE("Conflicting constraints");
+ return MY_ERROR_VALUE;
+ }
+ /// The entities need to have shared point, but they have not
+ inline static const std::string& NO_COINCIDENT_POINTS()
+ {
+ static const std::string MY_ERROR_VALUE("Objects should have coincident point");
+ return MY_ERROR_VALUE;
+ }
+ /// Attribute of a feature is not initialized
+ inline static const std::string& NOT_INITIALIZED()
+ {
+ static const std::string MY_ERROR_VALUE("Attribute is not initialized");
+ return MY_ERROR_VALUE;
+ }
+};
+
+#endif
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_FeatureStorage.cpp
+// Created: 23 Mar 2015
+// Author: Artem ZHIDKOV
+
+#include <SketchSolver_FeatureStorage.h>
+
+#include <ModelAPI_AttributeRefAttr.h>
+#include <ModelAPI_AttributeRefList.h>
+#include <ModelAPI_ResultConstruction.h>
+
+void SketchSolver_FeatureStorage::changeConstraint(ConstraintPtr theConstraint)
+{
+ std::list<AttributePtr> anAttributes = theConstraint->data()->attributes(std::string());
+ std::list<AttributePtr>::iterator anIter = anAttributes.begin();
+ for (; anIter != anAttributes.end(); anIter++) {
+ AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+ if (aRefAttr) {
+ if (!aRefAttr->isObject()) {
+ changeAttribute(aRefAttr->attr(), theConstraint);
+ continue;
+ }
+ ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+ aRefAttr->object());
+ FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
+ std::dynamic_pointer_cast<ModelAPI_Feature>(aRefAttr->object());
+ if (aFeature)
+ changeFeature(aFeature, theConstraint);
+ continue;
+ }
+ AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anIter);
+ if (aRefList) {
+ std::list<ObjectPtr> aList = aRefList->list();
+ std::list<ObjectPtr>::iterator aListIter = aList.begin();
+ for (; aListIter != aList.end(); aListIter++) {
+ ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+ *aListIter);
+ FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
+ std::dynamic_pointer_cast<ModelAPI_Feature>(*aListIter);
+ if (aFeature)
+ changeFeature(aFeature, theConstraint);
+ }
+ continue;
+ }
+ changeAttribute(*anIter, theConstraint);
+ }
+ myConstraints.insert(theConstraint);
+}
+
+void SketchSolver_FeatureStorage::removeConstraint(ConstraintPtr theConstraint)
+{
+ DataPtr aData = theConstraint->data();
+ if (aData) { // Constraint has data. Iterate through its attributes and remove them
+ std::list<AttributePtr> anAttributes = aData->attributes(std::string());
+ std::list<AttributePtr>::iterator anIter = anAttributes.begin();
+ for (; anIter != anAttributes.end(); anIter++) {
+ AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+ if (aRefAttr) {
+ if (!aRefAttr->isObject()) {
+ removeAttribute(aRefAttr->attr(), theConstraint);
+ continue;
+ }
+ ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+ aRefAttr->object());
+ FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
+ std::dynamic_pointer_cast<ModelAPI_Feature>(aRefAttr->object());
+ if (aFeature)
+ removeFeature(aFeature, theConstraint);
+ continue;
+ }
+ AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anIter);
+ if (aRefList) {
+ std::list<ObjectPtr> aList = aRefList->list();
+ std::list<ObjectPtr>::iterator aListIter = aList.begin();
+ for (; aListIter != aList.end(); aListIter++) {
+ ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+ *aListIter);
+ FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
+ std::dynamic_pointer_cast<ModelAPI_Feature>(*aListIter);
+ if (aFeature)
+ removeFeature(aFeature, theConstraint);
+ }
+ continue;
+ }
+ removeAttribute(*anIter, theConstraint);
+ }
+ } else { // Constraint has no data. Search the links on it in the lists of back references for features and attributes
+ std::set<ConstraintPtr>::iterator aCIter;
+ MapFeatureConstraint::iterator aFeatIter = myFeatures.begin();
+ while (aFeatIter != myFeatures.end()) {
+ aCIter = aFeatIter->second.find(theConstraint);
+ if (aCIter != aFeatIter->second.end()) {
+ aFeatIter->second.erase(aCIter);
+ if (aFeatIter->second.empty()) {
+ MapFeatureConstraint::iterator aTmpIter = aFeatIter; // stores iterator for the next element, while the current is deleting
+ aTmpIter++;
+ myFeatures.erase(aFeatIter);
+ aFeatIter = aTmpIter;
+ continue;
+ }
+ }
+ aFeatIter++;
+ }
+ std::set<FeaturePtr>::iterator aFIter;
+ MapAttributeFeature::iterator anAttrIter = myAttributes.begin();
+ while (anAttrIter != myAttributes.end()) {
+ aFIter = anAttrIter->second.find(theConstraint);
+ if (aFIter != anAttrIter->second.end()) {
+ anAttrIter->second.erase(aFIter);
+ if (anAttrIter->second.empty()) {
+ MapAttributeFeature::iterator aTmpIter = anAttrIter; // stores iterator for the next element, while the current is deleting
+ aTmpIter++;
+ myAttributes.erase(anAttrIter);
+ anAttrIter = aTmpIter;
+ continue;
+ }
+ }
+ anAttrIter++;
+ }
+ }
+ myConstraints.erase(theConstraint);
+}
+
+bool SketchSolver_FeatureStorage::isInteract(ConstraintPtr theConstraint) const
+{
+ if (myConstraints.empty() || myConstraints.find(theConstraint) != myConstraints.end())
+ return true;
+
+ DataPtr aData = theConstraint->data();
+ if (!aData)
+ return false;
+
+ std::list<AttributePtr> anAttributes = aData->attributes(std::string());
+ std::list<AttributePtr>::iterator anIter = anAttributes.begin();
+ for (; anIter != anAttributes.end(); anIter++) {
+ AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+ if (aRefAttr) {
+ if (!aRefAttr->isObject()) {
+ if (isInteract(aRefAttr->attr()))
+ return true;
+ continue;
+ }
+ ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+ aRefAttr->object());
+ FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
+ std::dynamic_pointer_cast<ModelAPI_Feature>(aRefAttr->object());
+ if (aFeature)
+ if (isInteract(aFeature))
+ return true;
+ continue;
+ }
+ AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anIter);
+ if (aRefList) {
+ std::list<ObjectPtr> aList = aRefList->list();
+ std::list<ObjectPtr>::iterator aListIter = aList.begin();
+ for (; aListIter != aList.end(); aListIter++) {
+ ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+ *aListIter);
+ FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
+ std::dynamic_pointer_cast<ModelAPI_Feature>(*aListIter);
+ if (aFeature)
+ if (isInteract(aFeature))
+ return true;
+ }
+ continue;
+ }
+ if (isInteract(*anIter))
+ return true;
+ }
+ return false;
+}
+
+
+void SketchSolver_FeatureStorage::changeFeature(FeaturePtr theFeature)
+{
+ std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
+ std::list<AttributePtr>::iterator anIter = anAttributes.begin();
+ for (; anIter != anAttributes.end(); anIter++) {
+ AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+ if (aRefAttr) {
+ if (!aRefAttr->isObject())
+ changeAttribute(aRefAttr->attr(), theFeature);
+ continue;
+ }
+ changeAttribute(*anIter, theFeature);
+ }
+ if (myFeatures.find(theFeature) == myFeatures.end())
+ myFeatures[theFeature] = std::set<ConstraintPtr>();
+}
+
+void SketchSolver_FeatureStorage::changeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint)
+{
+ // Change all attributes of the feature
+ changeFeature(theFeature);
+ // Add back reference feature to constraint
+ myFeatures[theFeature].insert(theConstraint);
+}
+
+void SketchSolver_FeatureStorage::removeFeature(FeaturePtr theFeature)
+{
+ MapFeatureConstraint::iterator aFeatIter = myFeatures.find(theFeature);
+ if (aFeatIter != myFeatures.end())
+ return; // no such feature
+
+ std::set<ConstraintPtr> aConstraints = aFeatIter->second;
+ std::set<ConstraintPtr>::iterator aCIter = aConstraints.begin();
+ for (; aCIter != aConstraints.end(); aCIter++)
+ removeFeature(theFeature, *aCIter);
+}
+
+void SketchSolver_FeatureStorage::removeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint)
+{
+ MapFeatureConstraint::iterator aFeatIter = myFeatures.find(theFeature);
+ if (aFeatIter != myFeatures.end())
+ return; // no such feature
+
+ std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
+ std::list<AttributePtr>::iterator anIter = anAttributes.begin();
+ for (; anIter != anAttributes.end(); anIter++) {
+ AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+ if (aRefAttr) {
+ if (!aRefAttr->isObject())
+ removeAttribute(aRefAttr->attr(), theFeature);
+ continue;
+ }
+ removeAttribute(*anIter, theFeature);
+ }
+
+ aFeatIter->second.erase(theConstraint);
+ if (aFeatIter->second.empty())
+ myFeatures.erase(aFeatIter);
+}
+
+bool SketchSolver_FeatureStorage::isInteract(FeaturePtr theFeature) const
+{
+ if (myFeatures.find(theFeature) != myFeatures.end())
+ return true;
+
+ std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
+ std::list<AttributePtr>::iterator anIter = anAttributes.begin();
+ for (; anIter != anAttributes.end(); anIter++) {
+ AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+ if (aRefAttr) {
+ if (!aRefAttr->isObject())
+ if (isInteract(aRefAttr->attr()))
+ return true;
+ continue;
+ }
+ if (isInteract(*anIter))
+ return true;
+ }
+ return false;
+}
+
+
+void SketchSolver_FeatureStorage::changeAttribute(AttributePtr theAttribute)
+{
+ if (myAttributes.find(theAttribute) == myAttributes.end())
+ myAttributes[theAttribute] = std::set<FeaturePtr>();
+}
+
+void SketchSolver_FeatureStorage::changeAttribute(AttributePtr theAttribute, FeaturePtr theFeature)
+{
+ MapAttributeFeature::iterator anAttrIter = myAttributes.find(theAttribute);
+ if (anAttrIter == myAttributes.end()) {
+ std::set<FeaturePtr> aFeatures;
+ aFeatures.insert(theFeature);
+ myAttributes[theAttribute] = aFeatures;
+ return;
+ }
+ anAttrIter->second.insert(theFeature);
+}
+
+void SketchSolver_FeatureStorage::removeAttribute(AttributePtr theAttribute)
+{
+ MapAttributeFeature::iterator anAttrIter = myAttributes.find(theAttribute);
+ if (anAttrIter == myAttributes.end())
+ return;
+
+ std::set<FeaturePtr> aFeatures = anAttrIter->second;
+ std::set<FeaturePtr>::iterator aFeatIter = aFeatures.begin();
+ for (; aFeatIter != aFeatures.end(); aFeatIter++)
+ removeAttribute(theAttribute, *aFeatIter);
+}
+
+void SketchSolver_FeatureStorage::removeAttribute(AttributePtr theAttribute, FeaturePtr theFeature)
+{
+ MapAttributeFeature::iterator anAttrIter = myAttributes.find(theAttribute);
+ if (anAttrIter != myAttributes.end())
+ return; // no such attribute
+
+ anAttrIter->second.erase(theFeature);
+ if (anAttrIter->second.empty())
+ myAttributes.erase(anAttrIter);
+}
+
+bool SketchSolver_FeatureStorage::isInteract(AttributePtr theAttribute) const
+{
+ return myAttributes.find(theAttribute) != myAttributes.end();
+}
+
+
+bool SketchSolver_FeatureStorage::isConsistent() const
+{
+ // Check the constraints are valid
+ std::set<ConstraintPtr>::const_iterator aCIter = myConstraints.begin();
+ for (; aCIter != myConstraints.end(); aCIter++)
+ if (!(*aCIter)->data() || !(*aCIter)->data()->isValid())
+ return false;
+ // Check the features are valid
+ MapFeatureConstraint::const_iterator aFIter = myFeatures.begin();
+ for (; aFIter != myFeatures.end(); aFIter++)
+ if (!aFIter->first->data() || !aFIter->first->data()->isValid())
+ return false;
+ // Check the attributes are valid
+ MapAttributeFeature::const_iterator aTIter = myAttributes.begin();
+ for (; aTIter != myAttributes.end(); aTIter++)
+ if (!aTIter->first->isInitialized())
+ return false;
+ return true;
+}
+
+std::set<ConstraintPtr> SketchSolver_FeatureStorage::getConstraints(FeaturePtr theFeature) const
+{
+ std::set<ConstraintPtr> aResult;
+ MapFeatureConstraint::const_iterator aFeatIter = myFeatures.find(theFeature);
+ if (aFeatIter != myFeatures.end())
+ aResult.insert(aFeatIter->second.begin(), aFeatIter->second.end());
+
+ std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
+ std::list<AttributePtr>::const_iterator anAttrIter = anAttributes.begin();
+ for (; anAttrIter != anAttributes.end(); anAttrIter++) {
+ MapAttributeFeature::const_iterator anIt = myAttributes.find(*anAttrIter);
+ if (anIt == myAttributes.end())
+ continue;
+ std::set<FeaturePtr>::const_iterator aFIter = anIt->second.begin();
+ for (; aFIter != anIt->second.end(); aFIter++) {
+ aFeatIter = myFeatures.find(*aFIter);
+ if (aFeatIter != myFeatures.end())
+ aResult.insert(aFeatIter->second.begin(), aFeatIter->second.end());
+ else {
+ ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(*aFIter);
+ if (aConstraint)
+ aResult.insert(aConstraint);
+ }
+ }
+ }
+ return aResult;
+}
+
+std::set<ConstraintPtr> SketchSolver_FeatureStorage::getConstraints(AttributePtr theAttribute) const
+{
+ std::set<ConstraintPtr> aResult;
+ MapAttributeFeature::const_iterator anIt = myAttributes.find(theAttribute);
+ if (anIt == myAttributes.end())
+ return aResult;
+ std::set<FeaturePtr>::const_iterator aFIter = anIt->second.begin();
+ MapFeatureConstraint::const_iterator aFeatIter;
+ for (; aFIter != anIt->second.end(); aFIter++) {
+ aFeatIter = myFeatures.find(*aFIter);
+ if (aFeatIter != myFeatures.end())
+ aResult.insert(aFeatIter->second.begin(), aFeatIter->second.end());
+ else {
+ ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(*aFIter);
+ if (aConstraint)
+ aResult.insert(aConstraint);
+ }
+ }
+ return aResult;
+}
+
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_FeatureStorage.h
+// Created: 23 Mar 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SketchSolver_FeatureStorage_H_
+#define SketchSolver_FeatureStorage_H_
+
+#include <SketchSolver.h>
+#include <SketchPlugin_Feature.h>
+#include <SketchPlugin_Constraint.h>
+
+#include <set>
+#include <map>
+
+typedef std::map<FeaturePtr, std::set<ConstraintPtr> > MapFeatureConstraint;
+typedef std::map<AttributePtr, std::set<FeaturePtr> > MapAttributeFeature;
+
+/** \class SketchSolver_FeatureStorage
+ * \ingroup Plugins
+ * \brief Collects information about SketchPlugin constraints used in specific group
+ */
+class SketchSolver_FeatureStorage
+{
+public:
+ SketchSolver_FeatureStorage() {}
+
+ /// \brief Adds or changes a constraint and all features it uses in the storage
+ void changeConstraint(ConstraintPtr theConstraint);
+ /// \brief Removes a constraint and all its features not used by other constraints
+ void removeConstraint(ConstraintPtr theConstraint);
+ /// \brief Verifies a constraint is used in the current storage
+ bool isInteract(ConstraintPtr theConstraint) const;
+
+ /// \brief Adds or changes a feature in the storage
+ void changeFeature(FeaturePtr theFeature);
+ /// \brief Adds or changes a feature in the storage. The feature is used in specified constraint
+ void changeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint);
+ /// \brief Removes a feature
+ void removeFeature(FeaturePtr theFeature);
+ /// \brief Removes a feature according to a given constraint
+ void removeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint);
+ /// \brief Verifies a feature is used in the current storage
+ bool isInteract(FeaturePtr theFeature) const;
+
+ /// \brief Adds or changes an attribute in the storage
+ void changeAttribute(AttributePtr theAttribute);
+ /// \brief Adds or changes a attribute in the storage.
+ /// The attribute is used in specified feature or constraint (theFeature)
+ void changeAttribute(AttributePtr theAttribute, FeaturePtr theFeature);
+ /// \brief Removes an attribute
+ void removeAttribute(AttributePtr theAttribute);
+ /// \brief Removes an attribute according to a given feature
+ void removeAttribute(AttributePtr theAttribute, FeaturePtr theFeature);
+ /// \brief Verifies an attribute is used in the current storage
+ bool isInteract(AttributePtr theAttribute) const;
+
+ /// \brief Check the features is not removed
+ bool isConsistent() const;
+
+ /// \brief Prepares list of constraints, which using specified feature or its attributes
+ std::set<ConstraintPtr> getConstraints(FeaturePtr theFeature) const;
+ /// \brief Prepares list of constraints, which using specified attribute
+ std::set<ConstraintPtr> getConstraints(AttributePtr theAttribute) const;
+
+private:
+ std::set<ConstraintPtr> myConstraints; ///< list of SketchPlugin constraints used in the current group
+ MapFeatureConstraint myFeatures; ///< list of features used in the group and corresponding constraints which use the feature
+ MapAttributeFeature myAttributes; ///< list of attributes used in the group and corresponding features which are based on the attribute
+};
+
+typedef std::shared_ptr<SketchSolver_FeatureStorage> FeatureStoragePtr;
+
+#endif // SketchSolver_FeatureStorage_H_
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_Group.cpp
+// Created: 27 May 2014
+// Author: Artem ZHIDKOV
+
+#include "SketchSolver_Group.h"
+
+#include <SketchSolver_Builder.h>
+#include <SketchSolver_Constraint.h>
+#include <SketchSolver_ConstraintCoincidence.h>
+#include <SketchSolver_Error.h>
+
+#include <Events_Error.h>
+#include <Events_Loop.h>
+#include <GeomAPI_XY.h>
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Pnt2d.h>
+#include <GeomDataAPI_Dir.h>
+#include <GeomDataAPI_Point.h>
+#include <GeomDataAPI_Point2D.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeRefList.h>
+#include <ModelAPI_Document.h>
+#include <ModelAPI_Events.h>
+#include <ModelAPI_ResultConstruction.h>
+
+#include <SketchPlugin_Constraint.h>
+#include <SketchPlugin_ConstraintFillet.h>
+#include <SketchPlugin_ConstraintLength.h>
+#include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintMirror.h>
+#include <SketchPlugin_ConstraintRigid.h>
+
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
+#include <SketchPlugin_Sketch.h>
+
+#include <math.h>
+#include <assert.h>
+
+
+/// \brief This class is used to give unique index to the groups
+class GroupIndexer
+{
+public:
+ /// \brief Return vacant index
+ static Slvs_hGroup NEW_GROUP() { return ++myGroupIndex; }
+ /// \brief Removes the index
+ static void REMOVE_GROUP(const Slvs_hGroup& theIndex) {
+ if (myGroupIndex == theIndex)
+ myGroupIndex--;
+ }
+
+private:
+ GroupIndexer() {};
+
+ static Slvs_hGroup myGroupIndex; ///< index of the group
+};
+
+Slvs_hGroup GroupIndexer::myGroupIndex = 0;
+
+
+/** \brief Search the entity/parameter with specified ID in the list of elements
+ * \param[in] theEntityID unique ID of the element
+ * \param[in] theEntities list of elements
+ * \return position of the found element or -1 if the element is not found
+ */
+template<typename T>
+static int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities);
+
+// ========================================================
+// ========= SketchSolver_Group ===============
+// ========================================================
+
+SketchSolver_Group::SketchSolver_Group(
+ std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane)
+ : myID(GroupIndexer::NEW_GROUP())
+{
+ // Initialize workplane
+ myWorkplaneID = SLVS_E_UNKNOWN;
+#ifndef NDEBUG
+ assert(addWorkplane(theWorkplane));
+#else
+ addWorkplane(theWorkplane);
+#endif
+}
+
+SketchSolver_Group::~SketchSolver_Group()
+{
+ myConstraints.clear();
+ GroupIndexer::REMOVE_GROUP(myID);
+}
+
+// ============================================================================
+// Function: isBaseWorkplane
+// Class: SketchSolver_Group
+// Purpose: verify the group is based on the given workplane
+// ============================================================================
+bool SketchSolver_Group::isBaseWorkplane(CompositeFeaturePtr theWorkplane) const
+{
+ return theWorkplane == mySketch;
+}
+
+// ============================================================================
+// Function: isInteract
+// Class: SketchSolver_Group
+// Purpose: verify are there any entities in the group used by given constraint
+// ============================================================================
+bool SketchSolver_Group::isInteract(
+ std::shared_ptr<SketchPlugin_Feature> theFeature) const
+{
+ // Empty group interacts with everything
+ if (isEmpty()) return true;
+ ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
+ if (aConstraint)
+ return myFeatureStorage->isInteract(aConstraint);
+ return myFeatureStorage->isInteract(theFeature);
+}
+
+// ============================================================================
+// Function: getFeatureId
+// Class: SketchSolver_Group
+// Purpose: Find the identifier of the feature, if it already exists in the group
+// ============================================================================
+Slvs_hEntity SketchSolver_Group::getFeatureId(FeaturePtr theFeature) const
+{
+ if (!myFeatureStorage)
+ return SLVS_E_UNKNOWN;
+ std::set<ConstraintPtr> aConstraints = myFeatureStorage->getConstraints(theFeature);
+ if (aConstraints.empty())
+ return SLVS_E_UNKNOWN;
+ ConstraintConstraintMap::const_iterator aCIter = myConstraints.find(*aConstraints.begin());
+ if (aCIter == myConstraints.end())
+ return SLVS_E_UNKNOWN;
+ return aCIter->second->getId(theFeature);
+}
+
+// ============================================================================
+// Function: getAttributeId
+// Class: SketchSolver_Group
+// Purpose: Find the identifier of the attribute, if it already exists in the group
+// ============================================================================
+Slvs_hEntity SketchSolver_Group::getAttributeId(AttributePtr theAttribute) const
+{
+ if (!myFeatureStorage)
+ return SLVS_E_UNKNOWN;
+ std::set<ConstraintPtr> aConstraints = myFeatureStorage->getConstraints(theAttribute);
+ if (aConstraints.empty())
+ return SLVS_E_UNKNOWN;
+ ConstraintConstraintMap::const_iterator aCIter = myConstraints.find(*aConstraints.begin());
+ if (aCIter == myConstraints.end())
+ return SLVS_E_UNKNOWN;
+ return aCIter->second->getId(theAttribute);
+}
+
+
+////// ============================================================================
+////// Function: checkConstraintConsistence
+////// Class: SketchSolver_Group
+////// Purpose: verifies and changes parameters of the constraint
+////// ============================================================================
+////void SketchSolver_Group::checkConstraintConsistence(Slvs_Constraint& theConstraint)
+////{
+//// if (theConstraint.type == SLVS_C_PT_LINE_DISTANCE) {
+//// // Get constraint parameters and check the sign of constraint value
+////
+//// // point coordinates
+//// int aPtPos = Search(theConstraint.ptA, myEntities);
+//// int aPtParamPos = Search(myEntities[aPtPos].param[0], myParams);
+//// std::shared_ptr<GeomAPI_XY> aPoint(
+//// new GeomAPI_XY(myParams[aPtParamPos].val, myParams[aPtParamPos + 1].val));
+////
+//// // line coordinates
+//// int aLnPos = Search(theConstraint.entityA, myEntities);
+//// aPtPos = Search(myEntities[aLnPos].point[0], myEntities);
+//// aPtParamPos = Search(myEntities[aPtPos].param[0], myParams);
+//// std::shared_ptr<GeomAPI_XY> aStart(
+//// new GeomAPI_XY(-myParams[aPtParamPos].val, -myParams[aPtParamPos + 1].val));
+//// aPtPos = Search(myEntities[aLnPos].point[1], myEntities);
+//// aPtParamPos = Search(myEntities[aPtPos].param[0], myParams);
+//// std::shared_ptr<GeomAPI_XY> aEnd(
+//// new GeomAPI_XY(myParams[aPtParamPos].val, myParams[aPtParamPos + 1].val));
+////
+//// aEnd = aEnd->added(aStart);
+//// aPoint = aPoint->added(aStart);
+//// if (aPoint->cross(aEnd) * theConstraint.valA < 0.0)
+//// theConstraint.valA *= -1.0;
+//// }
+////}
+
+// ============================================================================
+// Function: changeConstraint
+// Class: SketchSolver_Group
+// Purpose: create/update the constraint in the group
+// ============================================================================
+bool SketchSolver_Group::changeConstraint(
+ std::shared_ptr<SketchPlugin_Constraint> theConstraint)
+{
+ // There is no workplane yet, something wrong
+ if (myWorkplaneID == SLVS_E_UNKNOWN)
+ return false;
+
+ if (!theConstraint)
+ return false;
+
+ if (myConstraints.find(theConstraint) == myConstraints.end()) {
+ // Add constraint to the current group
+ SolverConstraintPtr aConstraint =
+ SketchSolver_Builder::getInstance()->createConstraint(theConstraint);
+ if (!aConstraint)
+ return false;
+ aConstraint->setGroup(this);
+ aConstraint->setStorage(myStorage);
+ if (!aConstraint->error().empty()) {
+ if (aConstraint->error() == SketchSolver_Error::NOT_INITIALIZED())
+ return false; // some attribute are not initialized yet, don't show message
+ Events_Error::send(aConstraint->error(), this);
+ }
+
+ // Additional verification of coincidence of several points
+ if (theConstraint->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
+ ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
+ for (; aCIter != myConstraints.end(); aCIter++) {
+ std::shared_ptr<SketchSolver_ConstraintCoincidence> aCoincidence =
+ std::dynamic_pointer_cast<SketchSolver_ConstraintCoincidence>(aCIter->second);
+ if (!aCoincidence)
+ continue;
+ std::shared_ptr<SketchSolver_ConstraintCoincidence> aCoinc2 =
+ std::dynamic_pointer_cast<SketchSolver_ConstraintCoincidence>(aConstraint);
+ if (aCoincidence != aCoinc2 && aCoincidence->isCoincide(aCoinc2)) {
+ aCoincidence->attach(aCoinc2);
+ aConstraint = aCoincidence;
+ }
+ }
+ }
+ myConstraints[theConstraint] = aConstraint;
+ }
+ else
+ myConstraints[theConstraint]->update();
+
+ if (!myFeatureStorage)
+ myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage);
+ myFeatureStorage->changeConstraint(theConstraint);
+
+//// if (theConstraint) {
+//// if (theConstraint->getKind() == SketchPlugin_ConstraintRigid::ID())
+//// return changeRigidConstraint(theConstraint);
+//// if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID())
+//// return changeMirrorConstraint(theConstraint);
+//// if (theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID())
+//// return changeFilletConstraint(theConstraint);
+//// }
+////
+//// // Search this constraint in the current group to update it
+//// ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
+//// std::vector<Slvs_Constraint>::iterator aConstrIter;
+//// if (aConstrMapIter != myConstraintMap.end()) {
+//// int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
+//// aConstrIter = myConstraints.begin() + aConstrPos;
+//// }
+////
+//// // Get constraint type and verify the constraint parameters are correct
+//// SketchSolver_Constraint aConstraint(theConstraint);
+//// int aConstrType = aConstraint.getType();
+//// if (aConstrType == SLVS_C_UNKNOWN
+//// || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
+//// return false;
+//// const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
+////
+//// // Create constraint parameters
+//// double aDistance = 0.0; // scalar value of the constraint
+//// AttributeDoublePtr aDistAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+//// theConstraint->data()->attribute(SketchPlugin_Constraint::VALUE()));
+//// if (aDistAttr) {
+//// aDistance = aDistAttr->value();
+//// // Issue #196: checking the positivity of the distance constraint
+//// if (aDistance < tolerance &&
+//// (aConstrType == SLVS_C_PT_PT_DISTANCE || aConstrType == SLVS_C_PT_LINE_DISTANCE))
+//// return false;
+//// // 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;
+//// }
+//// }
+////
+//// size_t aNbTmpConstraints = myTempConstraints.size();
+//// Slvs_hEntity aConstrEnt[CONSTRAINT_ATTR_SIZE]; // parameters of the constraint
+//// for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
+//// aConstrEnt[indAttr] = SLVS_E_UNKNOWN;
+//// std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
+//// ModelAPI_AttributeRefAttr>(
+//// theConstraint->data()->attribute(aConstraintAttributes[indAttr]));
+//// if (!aConstrAttr)
+//// continue;
+////
+//// // Convert the object of the attribute to the feature
+//// FeaturePtr aFeature;
+//// if (aConstrAttr->isObject() && aConstrAttr->object()) {
+//// ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+//// aConstrAttr->object());
+//// if (!aRC)
+//// continue;
+//// std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
+//// aFeature = aDoc->feature(aRC);
+//// }
+////
+//// // 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(SketchPlugin_ConstraintLength::ID()) == 0) {
+//// Slvs_hEntity aLineEnt = changeEntityFeature(aFeature);
+//// int aEntPos = Search(aLineEnt, myEntities);
+//// aConstrEnt[indAttr++] = myEntities[aEntPos].point[0];
+//// aConstrEnt[indAttr++] = myEntities[aEntPos].point[1];
+//// while (indAttr < CONSTRAINT_ATTR_SIZE)
+//// aConstrEnt[indAttr++] = 0;
+//// break; // there should be no other entities
+//// } else if (aConstrAttr->isObject())
+//// aConstrEnt[indAttr] = changeEntityFeature(aFeature);
+//// else
+//// aConstrEnt[indAttr] = changeEntity(aConstrAttr->attr());
+//// }
+////
+//// if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
+//// // 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) {
+//// 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;
+//// }
+//// if (aNbTmpConstraints < myTempConstraints.size()) {
+//// // There was added temporary constraint. Check that there is no coincident points which already rigid.
+////
+//// // Get list of already fixed points
+//// std::set<Slvs_hEntity> anAlreadyFixed;
+//// std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
+//// for (; aCIter != myConstraints.end(); aCIter++)
+//// if (aCIter->type == SLVS_C_WHERE_DRAGGED) {
+//// std::list<Slvs_hConstraint>::const_iterator aTmpIt = myTempConstraints.begin();
+//// for (; aTmpIt != myTempConstraints.end(); aTmpIt++)
+//// if (*aTmpIt == aCIter->h)
+//// break;
+//// if (aTmpIt == myTempConstraints.end())
+//// anAlreadyFixed.insert(aCIter->ptA);
+//// }
+////
+//// std::set<Slvs_hConstraint> aTmpConstrToDelete;
+//// std::list<Slvs_hConstraint>::reverse_iterator aTmpIter = myTempConstraints.rbegin();
+//// size_t aCurSize = myTempConstraints.size();
+//// for (; aCurSize > aNbTmpConstraints && aTmpIter != myTempConstraints.rend();
+//// aTmpIter++, aCurSize--) {
+//// int aConstrPos = Search(*aTmpIter, myConstraints);
+//// std::vector<std::set<Slvs_hEntity> >::const_iterator
+//// aCoincIter = myCoincidentPoints.begin();
+//// for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++)
+//// if (aCoincIter->find(myConstraints[aConstrPos].ptA) != aCoincIter->end()) {
+//// std::set<Slvs_hEntity>::const_iterator anIt;
+//// for (anIt = aCoincIter->begin(); anIt != aCoincIter->end(); anIt++)
+//// if (anAlreadyFixed.find(*anIt) != anAlreadyFixed.end()) {
+//// aTmpConstrToDelete.insert(*aTmpIter);
+//// break;
+//// }
+//// break;
+//// }
+//// }
+//// if (!aTmpConstrToDelete.empty())
+//// removeTemporaryConstraints(aTmpConstrToDelete);
+//// }
+//// }
+//// // For the tangency constraints it is necessary to identify which points of entities are coincident
+//// int aSlvsOtherFlag = 0;
+//// int aSlvsOther2Flag = 0;
+//// if (aConstrType == SLVS_C_ARC_LINE_TANGENT || aConstrType == SLVS_C_CURVE_CURVE_TANGENT) {
+//// // Search entities used by constraint
+//// int anEnt1Pos = Search(aConstrEnt[2], myEntities);
+//// int anEnt2Pos = Search(aConstrEnt[3], myEntities);
+//// // Obtain start and end points of entities
+//// Slvs_hEntity aPointsToFind[4];
+//// aPointsToFind[0] = myEntities[anEnt1Pos].point[1];
+//// aPointsToFind[1]= myEntities[anEnt1Pos].point[2];
+//// bool hasLine = (myEntities[anEnt2Pos].type == SLVS_E_LINE_SEGMENT);
+//// aPointsToFind[2]= myEntities[anEnt2Pos].point[hasLine ? 0 : 1];
+//// aPointsToFind[3]= myEntities[anEnt2Pos].point[hasLine ? 1 : 2];
+//// // Search coincident points
+//// bool isPointFound[4];
+//// std::vector<std::set<Slvs_hEntity> >::const_iterator aCPIter = myCoincidentPoints.begin();
+//// for ( ; aCPIter != myCoincidentPoints.end(); aCPIter++) {
+//// for (int i = 0; i < 4; i++)
+//// isPointFound[i] = (aCPIter->find(aPointsToFind[i]) != aCPIter->end());
+//// if ((isPointFound[0] || isPointFound[1]) && (isPointFound[2] || isPointFound[3])) {
+//// // the arc is tangent by end point
+//// if (isPointFound[1]) aSlvsOtherFlag = 1;
+//// // the second item is an arc and it is tangent by end point too
+//// if (!hasLine && isPointFound[3]) aSlvsOther2Flag = 1;
+//// break;
+//// }
+//// }
+//// if (aCPIter == myCoincidentPoints.end()) {
+//// // There is no coincident points between tangential objects. Generate error message
+//// Events_Error::send(SketchSolver_Error::NO_COINCIDENT_POINTS(), this);
+//// return false;
+//// }
+//// }
+////
+//// // Create SolveSpace constraint structure
+//// Slvs_Constraint aSlvsConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType,
+//// myWorkplane.h, aDistance, aConstrEnt[0],
+//// aConstrEnt[1], aConstrEnt[2], aConstrEnt[3]);
+//// if (aSlvsOtherFlag != 0) aSlvsConstr.other = aSlvsOtherFlag;
+//// if (aSlvsOther2Flag != 0) aSlvsConstr.other2 = aSlvsOther2Flag;
+//// myConstraints.push_back(aSlvsConstr);
+//// myConstraintMap[theConstraint] = std::vector<Slvs_hEntity>(1, aSlvsConstr.h);
+//// int aConstrPos = Search(aSlvsConstr.h, myConstraints);
+//// aConstrIter = myConstraints.begin() + aConstrPos;
+//// myNeedToSolve = true;
+//// } else { // Attributes of constraint may be changed => update constraint
+//// Slvs_hEntity* aCurrentAttr[] = {&aConstrIter->ptA, &aConstrIter->ptB,
+//// &aConstrIter->entityA, &aConstrIter->entityB,
+//// &aConstrIter->entityC, &aConstrIter->entityD};
+//// for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
+//// if (*(aCurrentAttr[indAttr]) != aConstrEnt[indAttr])
+//// {
+//// *(aCurrentAttr[indAttr]) = aConstrEnt[indAttr];
+//// myNeedToSolve = true;
+//// }
+//// }
+//// }
+////
+//// // Update flags of entities to be used by constraints
+//// for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++)
+//// if (aConstrEnt[indAttr] != 0) {
+//// int aPos = Search(aConstrEnt[indAttr], myEntities);
+//// myEntOfConstr[aPos] = true;
+//// // Sub-entities should be used implcitly
+//// Slvs_hEntity* aEntPtr = myEntities[aPos].point;
+//// while (*aEntPtr != 0) {
+//// aPos = Search(*aEntPtr, myEntities);
+//// myEntOfConstr[aPos] = true;
+//// aEntPtr++;
+//// }
+//// }
+////
+//// checkConstraintConsistence(*aConstrIter);
+ return true;
+}
+
+void SketchSolver_Group::moveFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
+{
+ std::set<ConstraintPtr> aConstraints = myFeatureStorage->getConstraints(theFeature);
+ std::set<ConstraintPtr>::iterator aCIter = aConstraints.begin();
+ for (; aCIter != aConstraints.end(); aCIter++) {
+ ConstraintConstraintMap::iterator aSolConIter = myConstraints.find(*aCIter);
+ aSolConIter->second->update();
+ }
+
+ // Temporary rigid constraint
+ SolverConstraintPtr aConstraint =
+ SketchSolver_Builder::getInstance()->createRigidConstraint(theFeature);
+ if (!aConstraint)
+ return;
+ aConstraint->setGroup(this);
+ aConstraint->setStorage(myStorage);
+ myTempConstraints.insert(aConstraint);
+}
+
+////// ============================================================================
+////// Function: changeRigidConstraint
+////// Class: SketchSolver_Group
+////// Purpose: create/update the "Rigid" constraint in the group
+////// ============================================================================
+////bool SketchSolver_Group::changeRigidConstraint(
+//// std::shared_ptr<SketchPlugin_Constraint> theConstraint)
+////{
+//// // Search this constraint in the current group to update it
+//// ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
+//// std::vector<Slvs_Constraint>::iterator aConstrIter;
+//// if (aConstrMapIter != myConstraintMap.end()) {
+//// int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
+//// aConstrIter = myConstraints.begin() + aConstrPos;
+//// }
+////
+//// // Get constraint type and verify the constraint parameters are correct
+//// SketchSolver_Constraint aConstraint(theConstraint);
+//// int aConstrType = aConstraint.getType();
+//// if (aConstrType == SLVS_C_UNKNOWN
+//// || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
+//// return false;
+//// const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
+////
+//// Slvs_hEntity aConstrEnt = SLVS_E_UNKNOWN;
+//// std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
+//// ModelAPI_AttributeRefAttr>(
+//// theConstraint->data()->attribute(aConstraintAttributes[0]));
+//// if (!aConstrAttr)
+//// return false;
+////
+//// // Convert the object of the attribute to the feature
+//// FeaturePtr aFeature;
+//// if (aConstrAttr->isObject() && aConstrAttr->object()) {
+//// ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+//// aConstrAttr->object());
+//// if (!aRC)
+//// return false;
+//// std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
+//// aFeature = aDoc->feature(aRC);
+//// }
+////
+//// aConstrEnt = aConstrAttr->isObject() ? changeEntityFeature(aFeature) : changeEntity(aConstrAttr->attr());
+////
+//// if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
+//// // Check the fixed entity is not a point.
+//// std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
+//// ModelAPI_AttributeRefAttr>(theConstraint->data()->attribute(aConstraintAttributes[0]));
+//// std::shared_ptr<GeomDataAPI_Point> aPoint =
+//// std::dynamic_pointer_cast<GeomDataAPI_Point>(aConstrAttr->attr());
+//// std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+//// std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aConstrAttr->attr());
+//// if (aPoint || aPoint2D) {
+//// // Create SolveSpace constraint structure
+//// Slvs_Constraint aConstraint = Slvs_MakeConstraint(
+//// ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
+//// aConstrEnt, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+//// myConstraints.push_back(aConstraint);
+//// myConstraintMap[theConstraint] = std::vector<Slvs_hEntity>(1, aConstraint.h);
+//// int aConstrPos = Search(aConstraint.h, myConstraints);
+//// aConstrIter = myConstraints.begin() + aConstrPos;
+//// myNeedToSolve = true;
+//// } else {
+//// myConstraintMap[theConstraint] = std::vector<Slvs_hConstraint>();
+////
+//// // To avoid SolveSpace problems:
+//// // * if the circle is rigid, we will fix its center and radius;
+//// // * if the arc is rigid, we will fix its start and end points and radius.
+//// double aRadius = 0.0;
+//// bool isArc = false;
+//// bool isCircle = false;
+//// if (aFeature) {
+//// if (aFeature->getKind() == SketchPlugin_Arc::ID()) {
+//// std::shared_ptr<GeomDataAPI_Point2D> aCenter =
+//// std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+//// aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID()));
+//// std::shared_ptr<GeomDataAPI_Point2D> aStart =
+//// std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+//// aFeature->data()->attribute(SketchPlugin_Arc::START_ID()));
+//// aRadius = aStart->pnt()->distance(aCenter->pnt());
+//// isArc = true;
+//// } else if (aFeature->getKind() == SketchPlugin_Circle::ID()) {
+//// aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+//// aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID()))->value();
+//// isCircle = true;
+//// }
+//// }
+////
+//// // Get list of already fixed points
+//// std::set<Slvs_hEntity> anAlreadyFixed;
+//// std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
+//// for (; aCIter != myConstraints.end(); aCIter++)
+//// if (aCIter->type == SLVS_C_WHERE_DRAGGED)
+//// anAlreadyFixed.insert(aCIter->ptA);
+////
+//// // Create constraints to fix the parameters of the entity
+//// int aEntPos = Search(aConstrEnt, myEntities);
+//// Slvs_hEntity* aPointsPtr = myEntities[aEntPos].point;
+//// if (isArc) aPointsPtr++; // avoid to fix center of arc
+//// while (*aPointsPtr != 0) {
+//// // Avoid to create additional "Rigid" constraints for coincident points
+//// bool isCoincAlreadyFixed = false;
+//// if (!anAlreadyFixed.empty()) {
+//// if (anAlreadyFixed.find(*aPointsPtr) != anAlreadyFixed.end())
+//// isCoincAlreadyFixed = true;
+////
+//// std::vector<std::set<Slvs_hEntity> >::const_iterator aCoincIter =
+//// myCoincidentPoints.begin();
+//// for (; !isCoincAlreadyFixed && aCoincIter != myCoincidentPoints.end(); aCoincIter++) {
+//// if (aCoincIter->find(*aPointsPtr) == aCoincIter->end())
+//// continue;
+//// std::set<Slvs_hEntity>::const_iterator anIter = anAlreadyFixed.begin();
+//// for (; !isCoincAlreadyFixed && anIter != anAlreadyFixed.end(); anIter++)
+//// if (aCoincIter->find(*anIter) != aCoincIter->end())
+//// isCoincAlreadyFixed = true;
+//// }
+//// }
+////
+//// if (!isCoincAlreadyFixed) {
+//// Slvs_Constraint aConstraint = Slvs_MakeConstraint(
+//// ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
+//// *aPointsPtr, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+//// myConstraints.push_back(aConstraint);
+//// myConstraintMap[theConstraint].push_back(aConstraint.h);
+//// }
+//// aPointsPtr++;
+//// }
+////
+//// if (isArc || isCircle) { // add radius constraint
+//// Slvs_Constraint aConstraint = Slvs_MakeConstraint(
+//// ++myConstrMaxID, myID, SLVS_C_DIAMETER, myWorkplane.h, 2.0 * aRadius,
+//// SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aConstrEnt, SLVS_E_UNKNOWN);
+//// myConstraints.push_back(aConstraint);
+//// myConstraintMap[theConstraint].push_back(aConstraint.h);
+//// }
+////
+//// // The object is already rigid, so there is no constraints added
+//// if (myConstraintMap[theConstraint].empty()) {
+//// myConstraintMap.erase(theConstraint);
+//// myNeedToSolve = false;
+//// }
+//// else
+//// myNeedToSolve = true;
+//// }
+//// }
+//// return true;
+////}
+////
+////// ============================================================================
+////// Function: changeMirrorConstraint
+////// Class: SketchSolver_Group
+////// Purpose: create/update the "Mirror" constraint in the group
+////// ============================================================================
+////bool SketchSolver_Group::changeMirrorConstraint(
+//// std::shared_ptr<SketchPlugin_Constraint> theConstraint)
+////{
+//// DataPtr aConstrData = theConstraint->data();
+////
+//// // Search this constraint in the current group to update it
+//// ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
+//// std::vector<Slvs_Constraint>::iterator aConstrIter;
+//// if (aConstrMapIter != myConstraintMap.end()) {
+//// int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
+//// aConstrIter = myConstraints.begin() + aConstrPos;
+//// }
+////
+//// // Get constraint type and verify the constraint parameters are correct
+//// SketchSolver_Constraint aConstraint(theConstraint);
+//// int aConstrType = aConstraint.getType();
+//// if (aConstrType == SLVS_C_UNKNOWN
+//// || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
+//// return false;
+//// const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
+////
+//// Slvs_hEntity aMirrorLineEnt = SLVS_E_UNKNOWN;
+//// AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+//// aConstrData->attribute(aConstraintAttributes[0]));
+//// if (!aConstrAttr)
+//// return false;
+////
+//// // Convert the object of the attribute to the feature
+//// FeaturePtr aMirrorLineFeat;
+//// if (aConstrAttr->isObject() && aConstrAttr->object()) {
+//// ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+//// aConstrAttr->object());
+//// if (!aRC)
+//// return false;
+//// std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
+//// aMirrorLineFeat = aDoc->feature(aRC);
+//// }
+//// aMirrorLineEnt = aConstrAttr->isObject() ?
+//// changeEntityFeature(aMirrorLineFeat) : changeEntity(aConstrAttr->attr());
+////
+//// if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
+//// // Append symmetric constraint for each point of mirroring features
+//// AttributeRefListPtr aBaseRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+//// aConstrData->attribute(aConstraintAttributes[1]));
+//// AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+//// aConstrData->attribute(aConstraintAttributes[2]));
+//// if (!aBaseRefList || !aMirroredRefList)
+//// return false;
+////
+//// std::list<ObjectPtr> aBaseList = aBaseRefList->list();
+//// std::list<ObjectPtr> aMirroredList = aMirroredRefList->list();
+//// if (aBaseList.size() != aMirroredList.size())
+//// return false;
+////
+//// myConstraintMap[theConstraint] = std::vector<Slvs_hConstraint>();
+////
+//// FeaturePtr aBaseFeature, aMirrorFeature;
+//// ResultConstructionPtr aRC;
+//// std::list<ObjectPtr>::iterator aBaseIter = aBaseList.begin();
+//// std::list<ObjectPtr>::iterator aMirIter = aMirroredList.begin();
+//// for ( ; aBaseIter != aBaseList.end(); aBaseIter++, aMirIter++) {
+//// aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aBaseIter);
+//// aBaseFeature = aRC ? aRC->document()->feature(aRC) :
+//// std::dynamic_pointer_cast<SketchPlugin_Feature>(*aBaseIter);
+//// aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aMirIter);
+//// aMirrorFeature = aRC ? aRC->document()->feature(aRC) :
+//// std::dynamic_pointer_cast<SketchPlugin_Feature>(*aMirIter);
+////
+//// if (!aBaseFeature || !aMirrorFeature ||
+//// aBaseFeature->getKind() != aMirrorFeature->getKind())
+//// return false;
+//// Slvs_hEntity aBaseEnt = changeEntityFeature(aBaseFeature);
+//// Slvs_hEntity aMirrorEnt = changeEntityFeature(aMirrorFeature);
+//// // Make aMirrorEnt parameters to be symmetric with aBaseEnt
+//// makeMirrorEntity(aBaseEnt, aMirrorEnt, aMirrorLineEnt);
+////
+//// if (aBaseFeature->getKind() == SketchPlugin_Point::ID()) {
+//// Slvs_Constraint aConstraint = Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType,
+//// myWorkplane.h, 0.0, aBaseEnt, aMirrorEnt, aMirrorLineEnt, SLVS_E_UNKNOWN);
+//// myConstraints.push_back(aConstraint);
+//// myConstraintMap[theConstraint].push_back(aConstraint.h);
+//// } else {
+//// int aBasePos = Search(aBaseEnt, myEntities);
+//// int aMirrorPos = Search(aMirrorEnt, myEntities);
+//// if (aBaseFeature->getKind() == SketchPlugin_Line::ID()) {
+//// for (int ind = 0; ind < 2; ind++) {
+//// Slvs_Constraint aConstraint = Slvs_MakeConstraint(
+//// ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
+//// myEntities[aBasePos].point[ind], myEntities[aMirrorPos].point[ind],
+//// aMirrorLineEnt, SLVS_E_UNKNOWN);
+//// myConstraints.push_back(aConstraint);
+//// myConstraintMap[theConstraint].push_back(aConstraint.h);
+//// }
+//// } else if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) {
+//// Slvs_Constraint aConstraint = Slvs_MakeConstraint(
+//// ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
+//// myEntities[aBasePos].point[0], myEntities[aMirrorPos].point[0],
+//// aMirrorLineEnt, SLVS_E_UNKNOWN);
+//// myConstraints.push_back(aConstraint);
+//// myConstraintMap[theConstraint].push_back(aConstraint.h);
+//// // Additional constraint for equal radii
+//// Slvs_Constraint anEqRadConstr = Slvs_MakeConstraint(
+//// ++myConstrMaxID, myID, SLVS_C_EQUAL_RADIUS, myWorkplane.h, 0.0,
+//// SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aBaseEnt, aMirrorEnt);
+//// myConstraints.push_back(anEqRadConstr);
+//// myConstraintMap[theConstraint].push_back(anEqRadConstr.h);
+//// } else if (aBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
+//// // Workaround to avoid problems in SolveSpace.
+//// // The symmetry of two arcs will be done using symmetry of three points on these arcs:
+//// // start point, end point, and any other point on the arc
+//// Slvs_hEntity aBaseArcPoints[3] = {
+//// myEntities[aBasePos].point[1],
+//// myEntities[aBasePos].point[2],
+//// SLVS_E_UNKNOWN};
+//// Slvs_hEntity aMirrorArcPoints[3] = { // indices of points of arc, center corresponds center, first point corresponds last point
+//// myEntities[aMirrorPos].point[2],
+//// myEntities[aMirrorPos].point[1],
+//// SLVS_E_UNKNOWN};
+//// Slvs_hEntity aBothArcs[2] = {aBaseEnt, aMirrorEnt};
+//// Slvs_hEntity aBothMiddlePoints[2];
+//// for (int i = 0; i < 2; i++) {
+//// double x, y;
+//// calculateMiddlePoint(aBothArcs[i], x, y);
+//// std::vector<Slvs_Param>::iterator aParamIter = myParams.end();
+//// Slvs_hParam u = changeParameter(x, aParamIter);
+//// Slvs_hParam v = changeParameter(y, aParamIter);
+//// Slvs_Entity aPoint = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, u, v);
+//// myEntities.push_back(aPoint);
+//// aBothMiddlePoints[i] = aPoint.h;
+//// // additional constraint point-on-curve
+//// Slvs_Constraint aPonCircConstr = Slvs_MakeConstraint(
+//// ++myConstrMaxID, myID, SLVS_C_PT_ON_CIRCLE, myWorkplane.h, 0.0,
+//// aPoint.h, SLVS_E_UNKNOWN, aBothArcs[i], SLVS_E_UNKNOWN);
+//// myConstraints.push_back(aPonCircConstr);
+//// myConstraintMap[theConstraint].push_back(aPonCircConstr.h);
+//// }
+////
+//// aBaseArcPoints[2] = aBothMiddlePoints[0];
+//// aMirrorArcPoints[2] = aBothMiddlePoints[1];
+//// for (int ind = 0; ind < 3; ind++) {
+//// Slvs_Constraint aConstraint = Slvs_MakeConstraint(
+//// ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
+//// aBaseArcPoints[ind], aMirrorArcPoints[ind], aMirrorLineEnt, SLVS_E_UNKNOWN);
+//// myConstraints.push_back(aConstraint);
+//// myConstraintMap[theConstraint].push_back(aConstraint.h);
+//// }
+//// }
+//// }
+//// }
+////
+//// // Set the mirror line unchanged during constraint recalculation
+//// int aMirrorLinePos = Search(aMirrorLineEnt, myEntities);
+//// Slvs_Constraint aRigidStart = Slvs_MakeConstraint(
+//// ++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, myWorkplane.h, 0,
+//// myEntities[aMirrorLinePos].point[0], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+//// myConstraints.push_back(aRigidStart);
+//// myConstraintMap[theConstraint].push_back(aRigidStart.h);
+//// Slvs_Constraint aRigidEnd = Slvs_MakeConstraint(
+//// ++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, myWorkplane.h, 0,
+//// myEntities[aMirrorLinePos].point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+//// myConstraints.push_back(aRigidEnd);
+//// myConstraintMap[theConstraint].push_back(aRigidEnd.h);
+////
+//// // Add temporary constraints for initial objects to be unchanged
+//// for (aBaseIter = aBaseList.begin(); aBaseIter != aBaseList.end(); aBaseIter++) {
+//// aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aBaseIter);
+//// aBaseFeature = aRC ? aRC->document()->feature(aRC) :
+//// std::dynamic_pointer_cast<SketchPlugin_Feature>(*aBaseIter);
+//// if (!aBaseFeature) continue;
+//// std::list<AttributePtr> aPoints = aBaseFeature->data()->attributes(GeomDataAPI_Point2D::type());
+//// std::list<AttributePtr>::iterator anIt = aPoints.begin();
+//// for ( ; anIt != aPoints.end(); anIt++) {
+//// // Arcs are fixed by center and start points only (to avoid solving errors in SolveSpace)
+//// if (aBaseFeature->getKind() == SketchPlugin_Arc::ID() &&
+//// (*anIt)->id() == SketchPlugin_Arc::END_ID())
+//// continue;
+//// addTemporaryConstraintWhereDragged(*anIt);
+//// }
+//// }
+//// }
+//// return true;
+////}
+////
+////// ============================================================================
+////// Function: changeFilletConstraint
+////// Class: SketchSolver_Group
+////// Purpose: create/update the "Fillet" constraint in the group
+////// ============================================================================
+////bool SketchSolver_Group::changeFilletConstraint(
+//// std::shared_ptr<SketchPlugin_Constraint> theConstraint)
+////{
+//// DataPtr aConstrData = theConstraint->data();
+////
+//// // Search this constraint in the current group to update it
+//// ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
+//// std::vector<Slvs_Constraint>::iterator aConstrIter;
+//// if (aConstrMapIter != myConstraintMap.end()) {
+//// int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
+//// aConstrIter = myConstraints.begin() + aConstrPos;
+//// }
+////
+//// // Get constraint type and verify the constraint parameters are correct
+//// SketchSolver_Constraint aConstraint(theConstraint);
+//// int aConstrType = aConstraint.getType();
+//// if (aConstrType == SLVS_C_UNKNOWN)
+//// return false;
+//// const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
+////
+//// // Obtain hEntity for basic objects of fillet
+//// Slvs_hEntity aBaseObject[2];
+//// FeaturePtr aBaseFeature[2];
+//// for (unsigned int indAttr = 0; indAttr < 2; indAttr++) {
+//// AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+//// aConstrData->attribute(aConstraintAttributes[indAttr]));
+//// if (!aConstrAttr)
+//// return false;
+//// if (aConstrAttr->isObject() && aConstrAttr->object()) {
+//// ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+//// aConstrAttr->object());
+//// if (!aRC)
+//// return false;
+//// std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
+//// aBaseFeature[indAttr] = aDoc->feature(aRC);
+//// }
+//// aBaseObject[indAttr] = aConstrAttr->isObject() ?
+//// changeEntityFeature(aBaseFeature[indAttr]) : changeEntity(aConstrAttr->attr());
+//// }
+//// // Check the base entities have a coincident point
+//// int aBaseObjInd[2] = {
+//// Search(aBaseObject[0], myEntities),
+//// Search(aBaseObject[1], myEntities)
+//// };
+//// int aShift[2] = { // shift for calculating correct start and end points for different types of objects
+//// myEntities[aBaseObjInd[0]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0,
+//// myEntities[aBaseObjInd[1]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0,
+//// };
+//// Slvs_hEntity aFirstObjPoints[2] = { // indices of start and end point of first object
+//// myEntities[aBaseObjInd[0]].point[aShift[0]],
+//// myEntities[aBaseObjInd[0]].point[1+aShift[0]]
+//// };
+//// Slvs_hEntity aSecondObjPoints[2] = { // indices of start and end point of second object
+//// myEntities[aBaseObjInd[1]].point[aShift[1]],
+//// myEntities[aBaseObjInd[1]].point[1+aShift[1]]
+//// };
+//// bool isCoincidentFound = false;
+//// int aBaseCoincInd[2] = {0, 0}; // indices in aFirstObjPoint and aSecondObjPoint identifying coincident points
+//// std::vector<std::set<Slvs_hEntity> >::iterator aCPIter = myCoincidentPoints.begin();
+//// for ( ; aCPIter != myCoincidentPoints.end() && !isCoincidentFound; aCPIter++)
+//// for (int ind1 = 0; ind1 < 2 && !isCoincidentFound; ind1++)
+//// for (int ind2 = 0; ind2 < 2 && !isCoincidentFound; ind2++)
+//// if (aCPIter->find(aFirstObjPoints[ind1]) != aCPIter->end() &&
+//// aCPIter->find(aSecondObjPoints[ind2]) != aCPIter->end()) {
+//// aBaseCoincInd[0] = ind1;
+//// aBaseCoincInd[1] = ind2;
+//// isCoincidentFound = true;
+//// }
+//// if (!isCoincidentFound) {
+//// // There is no coincident points between objects. Generate error message
+//// Events_Error::send(SketchSolver_Error::NO_COINCIDENT_POINTS(), this);
+//// return false;
+//// }
+////
+//// // Create fillet entities
+//// // - first object is placed on the first base
+//// // - second object is on the second base
+//// // - third object is a filleting arc
+//// static const int aNbFilletEnt = 3;
+//// Slvs_hEntity aFilletEnt[aNbFilletEnt];
+//// int aFilletObjInd[aNbFilletEnt];
+//// AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+//// aConstrData->attribute(aConstraintAttributes[2]));
+//// if (!aFilletRefList)
+//// return false;
+//// std::list<ObjectPtr> aFilletList = aFilletRefList->list();
+//// if (aFilletList.size() < aNbFilletEnt)
+//// return false;
+//// FeaturePtr aFilletFeature;
+//// ResultConstructionPtr aRC;
+//// std::list<ObjectPtr>::iterator aFilIter = aFilletList.begin();
+//// for (int indEnt = 0; aFilIter != aFilletList.end(); aFilIter++, indEnt++) {
+//// aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aFilIter);
+//// aFilletFeature = aRC ? aRC->document()->feature(aRC) :
+//// std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFilIter);
+//// if (!aFilletFeature)
+//// return false;
+//// aFilletEnt[indEnt] = changeEntityFeature(aFilletFeature);
+//// aFilletObjInd[indEnt] = Search(aFilletEnt[indEnt], myEntities);
+//// }
+//// // At first time, for correct result, move floating points of fillet on the middle points of base objects
+//// if (myConstraintMap.find(theConstraint) == myConstraintMap.end()) {
+//// double anArcPoints[6];
+//// for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) {
+//// int anIndShift = myEntities[aFilletObjInd[indEnt]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0;
+//// int aPointsPos[2] = {
+//// Search(myEntities[aFilletObjInd[indEnt]].point[anIndShift], myEntities),
+//// Search(myEntities[aFilletObjInd[indEnt]].point[1+anIndShift], myEntities)
+//// };
+//// int aParamPos[2] = {
+//// Search(myEntities[aPointsPos[0]].param[0], myParams),
+//// Search(myEntities[aPointsPos[1]].param[0], myParams)
+//// };
+//// int anIndex = aParamPos[aBaseCoincInd[indEnt]];
+//// if (anIndShift == 0) {
+//// myParams[anIndex].val =
+//// 0.5 * (myParams[aParamPos[0]].val + myParams[aParamPos[1]].val);
+//// myParams[1 + anIndex].val =
+//// 0.5 * (myParams[1 + aParamPos[0]].val + myParams[1 + aParamPos[1]].val);
+//// } else { // place the changed point on the arc
+//// double x = 0, y = 0;
+//// calculateMiddlePoint(aFilletEnt[indEnt], x, y);
+//// myParams[anIndex].val = x;
+//// myParams[1 + anIndex].val = y;
+//// }
+//// anArcPoints[indEnt*2+2] = myParams[anIndex].val;
+//// anArcPoints[indEnt*2+3] = myParams[1 + anIndex].val;
+//// }
+//// anArcPoints[0] = 0.5 * (anArcPoints[2] + anArcPoints[4]);
+//// anArcPoints[1] = 0.5 * (anArcPoints[3] + anArcPoints[5]);
+//// for (int indArcPt = 0; indArcPt < 3; indArcPt++) {
+//// int aPtPos = Search(myEntities[aFilletObjInd[2]].point[indArcPt], myEntities);
+//// int aParamPos = Search(myEntities[aPtPos].param[0], myParams);
+//// myParams[aParamPos].val = anArcPoints[indArcPt * 2];
+//// myParams[aParamPos + 1].val = anArcPoints[indArcPt * 2 + 1];
+//// }
+//// }
+////
+//// // Check the fillet arc which point to be connected to
+//// bool isArcInversed = false; // indicates that start and end points of arc should be connected to second and first object respectively
+//// Slvs_hEntity hEnt = myEntities[aFilletObjInd[2]].point[1];
+//// int aPos = Search(hEnt, myEntities);
+//// Slvs_hParam anArcStartPoint = myEntities[aPos].param[0];
+//// aPos = Search(anArcStartPoint, myParams);
+//// double anArcPtCoord[2] = {myParams[aPos].val, myParams[aPos+1].val};
+//// double aSqDistances[2];
+//// int aPtInd;
+//// for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) {
+//// aPtInd = aBaseCoincInd[indEnt]+aShift[indEnt];
+//// hEnt = myEntities[aFilletObjInd[indEnt]].point[aPtInd];
+//// aPos = Search(hEnt, myEntities);
+//// Slvs_hParam anObjectPoint = myEntities[aPos].param[0];
+//// aPos = Search(anObjectPoint, myParams);
+//// double aPtCoord[2] = {myParams[aPos].val, myParams[aPos+1].val};
+//// aSqDistances[indEnt] =
+//// (anArcPtCoord[0] - aPtCoord[0]) * (anArcPtCoord[0] - aPtCoord[0]) +
+//// (anArcPtCoord[1] - aPtCoord[1]) * (anArcPtCoord[1] - aPtCoord[1]);
+//// }
+//// if (aSqDistances[1] < aSqDistances[0])
+//// isArcInversed = true;
+////
+//// // Create list of constraints to generate fillet
+//// std::vector<Slvs_hConstraint> aConstrList;
+//// bool isExists = myConstraintMap.find(theConstraint) != myConstraintMap.end(); // constraint already exists
+//// std::vector<Slvs_hConstraint>::iterator aCMapIter =
+//// isExists ? myConstraintMap[theConstraint].begin() : aConstrList.begin();
+//// int aCurConstrPos = isExists ? Search(*aCMapIter, myConstraints) : 0;
+//// for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) {
+//// // one point of fillet object should be coincident with the point on base, non-coincident with another base object
+//// aPtInd = 1-aBaseCoincInd[indEnt]+aShift[indEnt]; // (1-aBaseCoincInd[indEnt]) = index of non-coincident point, aShift is used to process all types of shapes
+//// Slvs_hEntity aPtBase = myEntities[aBaseObjInd[indEnt]].point[aPtInd];
+//// Slvs_hEntity aPtFillet = myEntities[aFilletObjInd[indEnt]].point[aPtInd];
+//// if (isExists) {
+//// myConstraints[aCurConstrPos].ptA = aPtBase;
+//// myConstraints[aCurConstrPos].ptB = aPtFillet;
+//// aCMapIter++;
+//// aCurConstrPos = Search(*aCMapIter, myConstraints);
+//// } else {
+//// Slvs_Constraint aCoincConstr = Slvs_MakeConstraint(
+//// ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h,
+//// 0, aPtBase, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+//// myConstraints.push_back(aCoincConstr);
+//// aConstrList.push_back(aCoincConstr.h);
+//// }
+////
+//// // another point of fillet object should be placed on the base object
+//// Slvs_Constraint aPonCurveConstr;
+//// int aTangentType;
+//// if (myEntities[aFilletObjInd[indEnt]].type == SLVS_E_ARC_OF_CIRCLE) {
+//// // centers of arcs should be coincident
+//// aPtBase = myEntities[aBaseObjInd[indEnt]].point[0];
+//// aPtFillet = myEntities[aFilletObjInd[indEnt]].point[0];
+//// if (isExists) {
+//// myConstraints[aCurConstrPos].ptA = aPtBase;
+//// myConstraints[aCurConstrPos].ptB = aPtFillet;
+//// aCMapIter++;
+//// aCurConstrPos = Search(*aCMapIter, myConstraints);
+//// } else {
+//// aPonCurveConstr = Slvs_MakeConstraint(
+//// ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h,
+//// 0, aPtBase, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+//// }
+//// aPtFillet = myEntities[aFilletObjInd[indEnt]].point[1+aBaseCoincInd[indEnt]]; // !!! will be used below
+//// aTangentType = SLVS_C_CURVE_CURVE_TANGENT;
+//// } else {
+//// aPtInd = aBaseCoincInd[indEnt];
+//// aPtFillet = myEntities[aFilletObjInd[indEnt]].point[aPtInd];
+//// if (isExists) {
+//// myConstraints[aCurConstrPos].ptA = aPtFillet;
+//// aCMapIter++;
+//// aCurConstrPos = Search(*aCMapIter, myConstraints);
+//// } else {
+//// aPonCurveConstr = Slvs_MakeConstraint(
+//// ++myConstrMaxID, myID, SLVS_C_PT_ON_LINE, myWorkplane.h,
+//// 0, aPtFillet, SLVS_E_UNKNOWN, aBaseObject[indEnt], SLVS_E_UNKNOWN);
+//// }
+//// aTangentType = SLVS_C_ARC_LINE_TANGENT;
+//// }
+//// if (!isExists) {
+//// myConstraints.push_back(aPonCurveConstr);
+//// aConstrList.push_back(aPonCurveConstr.h);
+//// }
+////
+//// // Bound point of fillet arc should be tangently coincident with a bound point of fillet object
+//// aPtInd = 1 + (isArcInversed ? 1-indEnt : indEnt);
+//// Slvs_hEntity aPtArc = myEntities[aFilletObjInd[2]].point[aPtInd];
+//// if (isExists) {
+//// myConstraints[aCurConstrPos].ptA = aPtArc;
+//// myConstraints[aCurConstrPos].ptB = aPtFillet;
+//// aCMapIter++;
+//// aCurConstrPos = Search(*aCMapIter, myConstraints);
+//// myConstraints[aCurConstrPos].entityA = aFilletEnt[2];
+//// myConstraints[aCurConstrPos].entityB = aFilletEnt[indEnt];
+//// myConstraints[aCurConstrPos].other = (isArcInversed ? 1-indEnt : indEnt);
+//// aCMapIter++;
+//// aCurConstrPos = Search(*aCMapIter, myConstraints);
+//// } else {
+//// Slvs_Constraint aCoincConstr = Slvs_MakeConstraint(
+//// ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h,
+//// 0, aPtArc, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+//// myConstraints.push_back(aCoincConstr);
+//// aConstrList.push_back(aCoincConstr.h);
+//// Slvs_Constraint aTangency = Slvs_MakeConstraint(
+//// ++myConstrMaxID, myID, aTangentType, myWorkplane.h,
+//// 0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aFilletEnt[2], aFilletEnt[indEnt]);
+//// aTangency.other = (isArcInversed ? 1-indEnt : indEnt);
+//// aTangency.other2 = aTangentType == SLVS_C_CURVE_CURVE_TANGENT ? aBaseCoincInd[indEnt] : 0;
+//// myConstraints.push_back(aTangency);
+//// aConstrList.push_back(aTangency.h);
+//// }
+//// }
+////
+//// // Additional constraint for fillet diameter
+//// double aRadius = 0.0; // scalar value of the constraint
+//// AttributeDoublePtr aDistAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+//// aConstrData->attribute(SketchPlugin_Constraint::VALUE()));
+//// aRadius = aDistAttr->value();
+//// if (isExists) {
+//// myConstraints[aCurConstrPos].entityA = aFilletEnt[2];
+//// myConstraints[aCurConstrPos].valA = aRadius * 2.0;
+//// aCMapIter++;
+//// } else {
+//// Slvs_Constraint aDiamConstr = Slvs_MakeConstraint(
+//// ++myConstrMaxID, myID, SLVS_C_DIAMETER, myWorkplane.h, aRadius * 2.0,
+//// SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aFilletEnt[2], SLVS_E_UNKNOWN);
+//// myConstraints.push_back(aDiamConstr);
+//// aConstrList.push_back(aDiamConstr.h);
+////
+//// myConstraintMap[theConstraint] = aConstrList;
+//// }
+////
+//// // Additional temporary constraints for base objects to be fixed
+//// for (unsigned int indAttr = 0; indAttr < 2; indAttr++) {
+//// if (!aBaseFeature[indAttr]) {
+//// AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+//// aConstrData->attribute(aConstraintAttributes[indAttr]));
+//// addTemporaryConstraintWhereDragged(aConstrAttr->attr());
+//// continue;
+//// }
+//// std::list<AttributePtr> anAttributes =
+//// aBaseFeature[indAttr]->data()->attributes(GeomDataAPI_Point2D::type());
+//// std::list<AttributePtr>::iterator anIt = anAttributes.begin();
+//// for ( ; anIt != anAttributes.end(); anIt++) {
+//// // Arc should be fixed by center and start points only (to avoid "conflicting constraints" message)
+//// if (aBaseFeature[indAttr]->getKind() == SketchPlugin_Arc::ID() &&
+//// (*anIt)->id() == SketchPlugin_Arc::END_ID())
+//// continue;
+//// addTemporaryConstraintWhereDragged(*anIt);
+//// }
+//// }
+//// return true;
+////}
+////
+////// ============================================================================
+////// Function: changeEntity
+////// Class: SketchSolver_Group
+////// Purpose: create/update the element affected by any constraint
+////// ============================================================================
+////Slvs_hEntity SketchSolver_Group::changeEntity(
+//// std::shared_ptr<ModelAPI_Attribute> theEntity)
+////{
+//// // If the entity is already in the group, try to find it
+//// std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator aEntIter =
+//// myEntityAttrMap.find(theEntity);
+//// int aEntPos;
+//// std::vector<Slvs_Param>::const_iterator aParamIter; // looks at first parameter of already existent entity or at the end of vector otherwise
+//// if (aEntIter == myEntityAttrMap.end()) // no such entity => should be created
+//// aParamIter = myParams.end();
+//// else { // the entity already exists
+//// aEntPos = Search(aEntIter->second, myEntities);
+//// int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
+//// aParamIter = myParams.begin() + aParamPos;
+//// }
+//// const bool isEntExists = (aEntIter != myEntityAttrMap.end()); // defines that the entity already exists
+//// const bool isNeedToSolve = myNeedToSolve;
+//// myNeedToSolve = false;
+////
+//// if (isEntExists) {
+//// // Verify that the entity is not used by "Rigid" constraint.
+//// // If it is used, the object should not move.
+//// std::vector<std::set<Slvs_hEntity> >::iterator aCoincIter = myCoincidentPoints.begin();
+//// for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++)
+//// if (aCoincIter->find(aEntIter->second) != aCoincIter->end())
+//// break;
+//// std::set<Slvs_hEntity> aCoincident;
+//// if (aCoincIter != myCoincidentPoints.end()) {
+//// aCoincident = *aCoincIter;
+//// aCoincident.erase(aEntIter->second);
+////
+//// std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
+//// for (; aConstrIter != myConstraints.end(); aConstrIter++)
+//// if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
+//// aCoincident.find(aConstrIter->ptA) != aCoincident.end()) {
+//// myNeedToSolve = true;
+//// return aEntIter->second;
+//// }
+//// }
+//// }
+////
+//// // Look over supported types of entities
+//// Slvs_Entity aNewEntity;
+//// aNewEntity.h = SLVS_E_UNKNOWN;
+////
+//// // Point in 3D
+//// std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
+//// theEntity);
+//// if (aPoint) {
+//// Slvs_hParam aX = changeParameter(aPoint->x(), aParamIter);
+//// Slvs_hParam aY = changeParameter(aPoint->y(), aParamIter);
+//// Slvs_hParam aZ = changeParameter(aPoint->z(), aParamIter);
+//// if (!isEntExists) // New entity
+//// aNewEntity = Slvs_MakePoint3d(++myEntityMaxID, myID, aX, aY, aZ);
+//// } else {
+//// // All entities except 3D points are created on workplane. So, if there is no workplane yet, then error
+//// if (myWorkplane.h == SLVS_E_UNKNOWN)
+//// return SLVS_E_UNKNOWN;
+////
+//// // Point in 2D
+//// std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+//// std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
+//// if (aPoint2D) {
+//// Slvs_hParam aU = changeParameter(aPoint2D->x(), aParamIter);
+//// Slvs_hParam aV = changeParameter(aPoint2D->y(), aParamIter);
+//// if (!isEntExists) // New entity
+//// aNewEntity = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, aU, aV);
+//// } else {
+//// // Scalar value (used for the distance entities)
+//// AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theEntity);
+//// if (aScalar) {
+//// Slvs_hParam aValue = changeParameter(aScalar->value(), aParamIter);
+//// if (!isEntExists) // New entity
+//// aNewEntity = Slvs_MakeDistance(++myEntityMaxID, myID, myWorkplane.h, aValue);
+//// }
+//// }
+//// }
+//// /// \todo Other types of entities
+////
+//// Slvs_hEntity aResult = SLVS_E_UNKNOWN; // Unsupported or wrong entity type
+////
+//// if (isEntExists) {
+//// myNeedToSolve = myNeedToSolve || isNeedToSolve;
+//// aResult = aEntIter->second;
+//// } else if (aNewEntity.h != SLVS_E_UNKNOWN) {
+//// myEntities.push_back(aNewEntity);
+//// myEntOfConstr.push_back(false);
+//// myEntityAttrMap[theEntity] = aNewEntity.h;
+//// aResult = aNewEntity.h;
+//// }
+////
+//// // If the attribute was changed by the user, we need to fix it before solving
+//// if (myNeedToSolve && theEntity->isImmutable())
+//// addTemporaryConstraintWhereDragged(theEntity, false);
+////
+//// return aResult;
+////}
+////
+////// ============================================================================
+////// Function: changeEntity
+////// Class: SketchSolver_Group
+////// Purpose: create/update the element defined by the feature affected by any constraint
+////// ============================================================================
+////Slvs_hEntity SketchSolver_Group::changeEntityFeature(FeaturePtr theEntity)
+////{
+//// if (!theEntity->data()->isValid())
+//// return SLVS_E_UNKNOWN;
+//// // If the entity is already in the group, try to find it
+//// 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());
+////
+//// Slvs_Entity aNewEntity;
+//// aNewEntity.h = SLVS_E_UNKNOWN;
+////
+//// // SketchPlugin features
+//// std::shared_ptr<SketchPlugin_Feature> aFeature = std::dynamic_pointer_cast<
+//// SketchPlugin_Feature>(theEntity);
+//// if (aFeature) { // Verify the feature by its kind
+//// const std::string& aFeatureKind = aFeature->getKind();
+//// AttributePtr anAttribute;
+////
+//// // Line
+//// if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) {
+//// anAttribute = aFeature->data()->attribute(SketchPlugin_Line::START_ID());
+//// if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+//// Slvs_hEntity aStart = changeEntity(anAttribute);
+////
+//// anAttribute = aFeature->data()->attribute(SketchPlugin_Line::END_ID());
+//// if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+//// Slvs_hEntity aEnd = changeEntity(anAttribute);
+////
+//// if (!isEntExists) // New entity
+//// aNewEntity = Slvs_MakeLineSegment(++myEntityMaxID, myID, myWorkplane.h, aStart, aEnd);
+//// }
+//// // Circle
+//// else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) {
+//// anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::CENTER_ID());
+//// if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+//// Slvs_hEntity aCenter = changeEntity(anAttribute);
+////
+//// anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID());
+//// if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+//// Slvs_hEntity aRadius = changeEntity(anAttribute);
+////
+//// if (!isEntExists) // New entity
+//// aNewEntity = Slvs_MakeCircle(++myEntityMaxID, myID, myWorkplane.h, aCenter,
+//// myWorkplane.normal, aRadius);
+//// }
+//// // Arc
+//// else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) {
+//// anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID());
+//// if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+//// Slvs_hEntity aCenter = changeEntity(anAttribute);
+////
+//// anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::START_ID());
+//// if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+//// Slvs_hEntity aStart = changeEntity(anAttribute);
+////
+//// anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::END_ID());
+//// if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+//// Slvs_hEntity aEnd = changeEntity(anAttribute);
+////
+//// if (!isEntExists)
+//// aNewEntity = Slvs_MakeArcOfCircle(++myEntityMaxID, myID, myWorkplane.h,
+//// myWorkplane.normal, aCenter, aStart, aEnd);
+//// }
+//// // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
+//// else if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0) {
+//// anAttribute = aFeature->data()->attribute(SketchPlugin_Point::COORD_ID());
+//// if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
+//// Slvs_hEntity aPoint = changeEntity(anAttribute);
+////
+//// if (isEntExists)
+//// return aEntIter->second;
+////
+//// // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier
+//// myEntityFeatMap[theEntity] = aPoint;
+//// myNeedToSolve = true;
+//// return aPoint;
+//// }
+//// }
+//// /// \todo Other types of features
+////
+//// if (isEntExists)
+//// return aEntIter->second;
+////
+//// if (aNewEntity.h != SLVS_E_UNKNOWN) {
+//// myEntities.push_back(aNewEntity);
+//// myEntOfConstr.push_back(false);
+//// myEntityFeatMap[theEntity] = aNewEntity.h;
+//// myNeedToSolve = true;
+//// return aNewEntity.h;
+//// }
+////
+//// // Unsupported or wrong entity type
+//// return SLVS_E_UNKNOWN;
+////}
+
+// ============================================================================
+// Function: addWorkplane
+// Class: SketchSolver_Group
+// Purpose: create workplane for the group
+// ============================================================================
+bool SketchSolver_Group::addWorkplane(CompositeFeaturePtr theSketch)
+{
+ if (myWorkplaneID != SLVS_E_UNKNOWN || theSketch->getKind() != SketchPlugin_Sketch::ID())
+ return false; // the workplane already exists or the function parameter is not Sketch
+
+ mySketch = theSketch;
+ updateWorkplane();
+ return true;
+}
+
+// ============================================================================
+// Function: updateWorkplane
+// Class: SketchSolver_Group
+// Purpose: update parameters of workplane
+// ============================================================================
+bool SketchSolver_Group::updateWorkplane()
+{
+ if (!myStorage) // Create storage if not exists
+ myStorage = StoragePtr(new SketchSolver_Storage);
+ SketchSolver_Builder* aBuilder = SketchSolver_Builder::getInstance();
+
+ std::vector<Slvs_Entity> anEntities;
+ std::vector<Slvs_Param> aParams;
+ if (!aBuilder->createWorkplane(mySketch, anEntities, aParams))
+ return false;
+
+ if (myWorkplaneID == SLVS_E_UNKNOWN) {
+ myWorkplaneID = anEntities.back().h;
+ // Add new workplane elements
+ std::vector<Slvs_Param>::iterator aParIter = aParams.begin();
+ for (; aParIter != aParams.end(); aParIter++) {
+ aParIter->h = SLVS_E_UNKNOWN; // the ID should be generated by storage
+ aParIter->group = myID;
+ aParIter->h = myStorage->addParameter(*aParIter);
+ }
+ std::vector<Slvs_Entity>::iterator anEntIter = anEntities.begin();
+ for (; anEntIter != anEntities.end(); anEntIter++) {
+ anEntIter->h = SLVS_E_UNKNOWN; // the ID should be generated by storage
+ anEntIter->group = myID;
+ anEntIter->wrkpl = myWorkplaneID;
+ for (int i = 0; i < 4; i++)
+ if (anEntIter->param[i] != SLVS_E_UNKNOWN)
+ anEntIter->param[i] = aParams[anEntIter->param[i]-1].h;
+ for (int i = 0; i < 4; i++)
+ if (anEntIter->point[i] != SLVS_E_UNKNOWN)
+ anEntIter->point[i] = anEntities[anEntIter->point[i]-1].h;
+ anEntIter->h = myStorage->addEntity(*anEntIter);
+ }
+ } else {
+ // Update existent workplane
+ const Slvs_Entity& aWP = myStorage->getEntity(myWorkplaneID);
+ const Slvs_Entity& anOrigin = myStorage->getEntity(aWP.point[0]);
+ const Slvs_Entity& aNormal = myStorage->getEntity(aWP.normal);
+ // Get parameters and update them
+ Slvs_hParam aWPParams[7] = {
+ anOrigin.param[0], anOrigin.param[1], anOrigin.param[2],
+ aNormal.param[0], aNormal.param[1], aNormal.param[2], aNormal.param[3]
+ };
+ std::vector<Slvs_Param>::iterator aParIter = aParams.begin();
+ for (int i = 0; aParIter != aParams.end(); aParIter++, i++) {
+ Slvs_Param aParam = myStorage->getParameter(aWPParams[i]);
+ aParam.val = aParIter->val;
+ myStorage->updateParameter(aParam);
+ }
+ }
+ return myWorkplaneID > 0;
+}
+
+////// ============================================================================
+////// Function: changeParameter
+////// Class: SketchSolver_Group
+////// Purpose: create/update value of parameter
+////// ============================================================================
+////Slvs_hParam SketchSolver_Group::changeParameter(
+//// const double& theParam, std::vector<Slvs_Param>::const_iterator& thePrmIter)
+////{
+//// if (thePrmIter != myParams.end()) { // Parameter should be updated
+//// int aParamPos = thePrmIter - myParams.begin();
+//// if (fabs(thePrmIter->val - theParam) > tolerance) {
+//// myNeedToSolve = true; // parameter is changed, need to resolve constraints
+//// myParams[aParamPos].val = theParam;
+//// }
+//// thePrmIter++;
+//// return myParams[aParamPos].h;
+//// }
+////
+//// // Newly created parameter
+//// Slvs_Param aParam = Slvs_MakeParam(++myParamMaxID, myID, theParam);
+//// myParams.push_back(aParam);
+//// myNeedToSolve = true;
+//// // The list of parameters is changed, move iterator to the end of the list to avoid problems
+//// thePrmIter = myParams.end();
+//// return aParam.h;
+////}
+
+// ============================================================================
+// Function: resolveConstraints
+// Class: SketchSolver_Group
+// Purpose: solve the set of constraints for the current group
+// ============================================================================
+bool SketchSolver_Group::resolveConstraints()
+{
+ if (!myStorage->isNeedToResolve() || isEmpty())
+ return false;
+
+ myConstrSolver.setGroupID(myID);
+ myStorage->initializeSolver(myConstrSolver);
+
+//// theSolver.setDraggedParameters(myTempPointWhereDragged);
+////
+ int aResult = myConstrSolver.solve();
+ if (aResult == SLVS_RESULT_OKAY) { // solution succeeded, store results into correspondent attributes
+ ConstraintConstraintMap::iterator aConstrIter = myConstraints.begin();
+ for (; aConstrIter != myConstraints.end(); aConstrIter++)
+ aConstrIter->second->refresh();
+
+//// // Obtain result into the same list of parameters
+//// if (!myConstrSolver.getResult(myParams))
+//// return true;
+////
+//// // We should go through the attributes map, because only attributes have valued parameters
+//// std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator anEntIter =
+//// myEntityAttrMap.begin();
+//// for (; anEntIter != myEntityAttrMap.end(); anEntIter++) {
+//// if (anEntIter->first->owner().get() && anEntIter->first->owner()->data().get())
+//// anEntIter->first->owner()->data()->blockSendAttributeUpdated(true);
+//// if (updateAttribute(anEntIter->first, anEntIter->second))
+//// updateRelatedConstraints(anEntIter->first);
+//// }
+//// updateFilletConstraints();
+//// // unblock all features then
+//// for (anEntIter = myEntityAttrMap.begin(); anEntIter != myEntityAttrMap.end(); anEntIter++) {
+//// if (anEntIter->first->owner().get() && anEntIter->first->owner()->data().get())
+//// anEntIter->first->owner()->data()->blockSendAttributeUpdated(false);
+//// }
+ } else if (!myConstraints.empty())
+ Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this);
+
+ removeTemporaryConstraints();
+//// myNeedToSolve = false;
+ myStorage->setNeedToResolve(false);
+ return true;
+}
+
+// ============================================================================
+// Function: mergeGroups
+// Class: SketchSolver_Group
+// Purpose: append specified group to the current group
+// ============================================================================
+void SketchSolver_Group::mergeGroups(const SketchSolver_Group& theGroup)
+{
+ // If specified group is empty, no need to merge
+ if (theGroup.isEmpty())
+ return;
+ if (!myFeatureStorage)
+ myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage);
+
+ ConstraintConstraintMap::const_iterator aConstrIter = theGroup.myConstraints.begin();
+ for (; aConstrIter != theGroup.myConstraints.end(); aConstrIter++)
+ changeConstraint(aConstrIter->first);
+}
+
+// ============================================================================
+// Function: splitGroup
+// Class: SketchSolver_Group
+// Purpose: divide the group into several subgroups
+// ============================================================================
+void SketchSolver_Group::splitGroup(std::vector<SketchSolver_Group*>& theCuts)
+{
+ // Obtain constraints, which should be separated
+ FeatureStoragePtr aNewFeatStorage(new SketchSolver_FeatureStorage);
+ std::vector<ConstraintPtr> anUnusedConstraints;
+ ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
+ for ( ; aCIter != myConstraints.end(); aCIter++) {
+ std::list<ConstraintPtr> aBaseConstraints = aCIter->second->constraints();
+ std::list<ConstraintPtr>::iterator anIter = aBaseConstraints.begin();
+ for (; anIter != aBaseConstraints.end(); anIter++)
+ if (aNewFeatStorage->isInteract(*anIter)) {
+ aNewFeatStorage->changeConstraint(*anIter);
+ } else
+ anUnusedConstraints.push_back(*anIter);
+ }
+
+ std::vector<SketchSolver_Group*>::iterator aCutsIter;
+ std::vector<ConstraintPtr>::iterator aUnuseIt = anUnusedConstraints.begin();
+ for ( ; aUnuseIt != anUnusedConstraints.end(); aUnuseIt++) {
+ // Remove unused constraints
+ removeConstraint(*aUnuseIt);
+ // Try to append constraint to already existent group
+ for (aCutsIter = theCuts.begin(); aCutsIter != theCuts.end(); aCutsIter++)
+ if ((*aCutsIter)->isInteract(*aUnuseIt)) {
+ (*aCutsIter)->changeConstraint(*aUnuseIt);
+ break;
+ }
+ if (aCutsIter == theCuts.end()) {
+ // Add new group
+ SketchSolver_Group* aGroup = new SketchSolver_Group(mySketch);
+ aGroup->changeConstraint(*aUnuseIt);
+ theCuts.push_back(aGroup);
+ }
+ }
+}
+
+// ============================================================================
+// Function: isConsistent
+// Class: SketchSolver_Group
+// Purpose: search removed entities and constraints
+// ============================================================================
+bool SketchSolver_Group::isConsistent()
+{
+ if (!myFeatureStorage) // no one constraint is initialized yet
+ return true;
+
+ bool aResult = myFeatureStorage->isConsistent();
+ if (!aResult) {
+ // remove invalid entities
+ ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
+ while (aCIter != myConstraints.end()) {
+ std::list<ConstraintPtr> aConstraints = aCIter->second->constraints();
+ std::list<ConstraintPtr>::iterator anIt = aConstraints.begin();
+ for (; anIt != aConstraints.end(); anIt++)
+ if (!(*anIt)->data() || !(*anIt)->data()->isValid())
+ if (aCIter->second->remove(*anIt)) {
+ // the constraint is fully removed, detach it from the list
+ ConstraintConstraintMap::iterator aTmpIt = aCIter++;
+ myFeatureStorage->removeConstraint(aTmpIt->first);
+ myConstraints.erase(aTmpIt);
+ break;
+ }
+ if (anIt == aConstraints.end())
+ aCIter++;
+ }
+ }
+ return aResult;
+}
+
+////// ============================================================================
+////// Function: updateAttribute
+////// Class: SketchSolver_Group
+////// Purpose: update features of sketch after resolving constraints
+////// ============================================================================
+////bool SketchSolver_Group::updateAttribute(
+//// std::shared_ptr<ModelAPI_Attribute> theAttribute, const Slvs_hEntity& theEntityID)
+////{
+//// // Search the position of the first parameter of the entity
+//// int anEntPos = Search(theEntityID, myEntities);
+//// int aFirstParamPos = Search(myEntities[anEntPos].param[0], myParams);
+////
+//// // Look over supported types of entities
+////
+//// // Point in 3D
+//// std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
+//// theAttribute);
+//// if (aPoint) {
+//// 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
+//// std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+//// std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
+//// if (aPoint2D) {
+//// 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
+//// AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
+//// if (aScalar) {
+//// 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;
+////}
+////
+////// ============================================================================
+////// Function: updateEntityIfPossible
+////// Class: SketchSolver_Group
+////// Purpose: search the entity in this group and update it
+////// ============================================================================
+////void SketchSolver_Group::updateEntityIfPossible(
+//// std::shared_ptr<ModelAPI_Attribute> theEntity)
+////{
+//// if (myEntityAttrMap.find(theEntity) != myEntityAttrMap.end()) {
+//// // If the attribute is a point and it is changed (the group needs to rebuild),
+//// // probably user has dragged this point into this position,
+//// // so it is necessary to add constraint which will guarantee the point will not change
+////
+//// // Store myNeedToSolve flag to verify the entity is really changed
+//// bool aNeedToSolveCopy = myNeedToSolve;
+//// myNeedToSolve = false;
+////
+//// changeEntity(theEntity);
+////
+//// if (myNeedToSolve) // the entity is changed
+//// {
+//// // Verify the entity is a point and add temporary constraint of permanency
+//// std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
+//// theEntity);
+//// std::shared_ptr<GeomDataAPI_Point2D> aPoint2D = std::dynamic_pointer_cast<
+//// GeomDataAPI_Point2D>(theEntity);
+//// if (aPoint || aPoint2D)
+//// addTemporaryConstraintWhereDragged(theEntity);
+//// }
+////
+//// // Restore flag of changes
+//// myNeedToSolve = myNeedToSolve || aNeedToSolveCopy;
+////
+//// if (myNeedToSolve)
+//// updateRelatedConstraints(theEntity);
+//// }
+////}
+////
+////// ============================================================================
+////// Function: addTemporaryConstraintWhereDragged
+////// Class: SketchSolver_Group
+////// Purpose: add transient constraint SLVS_C_WHERE_DRAGGED for the entity,
+////// which was moved by user
+////// ============================================================================
+////void SketchSolver_Group::addTemporaryConstraintWhereDragged(
+//// std::shared_ptr<ModelAPI_Attribute> theEntity,
+//// bool theAllowToFit)
+////{
+//// // Find identifier of the entity
+//// std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator anEntIter =
+//// myEntityAttrMap.find(theEntity);
+//// if (anEntIter == myEntityAttrMap.end())
+//// return;
+////
+//// // Get identifiers of all dragged points
+//// std::set<Slvs_hEntity> aDraggedPntID;
+//// aDraggedPntID.insert(myTempPointWDrgdID);
+//// std::list<Slvs_hConstraint>::const_iterator aTmpCoIter = myTempConstraints.begin();
+//// for (; aTmpCoIter != myTempConstraints.end(); aTmpCoIter++) {
+//// unsigned int aConstrPos = Search(*aTmpCoIter, myConstraints);
+//// if (aConstrPos < myConstraints.size())
+//// aDraggedPntID.insert(myConstraints[aConstrPos].ptA);
+//// }
+//// std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
+//// for (; aConstrIter != myConstraints.end(); aConstrIter++)
+//// if (aConstrIter->type == SLVS_C_WHERE_DRAGGED)
+//// aDraggedPntID.insert(aConstrIter->ptA);
+//// // Find whether there is a point coincident with theEntity, which already has SLVS_C_WHERE_DRAGGED
+//// std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
+//// for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++) {
+//// if (aCoPtIter->find(anEntIter->second) == aCoPtIter->end())
+//// continue; // the entity was not found in current set
+////
+//// // Find one of already created SLVS_C_WHERE_DRAGGED constraints in current set of coincident points
+//// std::set<Slvs_hEntity>::const_iterator aDrgIter = aDraggedPntID.begin();
+//// for (; aDrgIter != aDraggedPntID.end(); aDrgIter++)
+//// if (aCoPtIter->find(*aDrgIter) != aCoPtIter->end())
+//// return; // the SLVS_C_WHERE_DRAGGED constraint already exists
+//// }
+//// if (aDraggedPntID.find(anEntIter->second) != aDraggedPntID.end())
+//// return;
+////
+//// // If this is a first dragged point, its parameters should be placed
+//// // into Slvs_System::dragged field to avoid system inconsistense
+//// if (myTempPointWhereDragged.empty() && theAllowToFit) {
+//// int anEntPos = Search(anEntIter->second, myEntities);
+//// Slvs_hParam* aDraggedParam = myEntities[anEntPos].param;
+//// for (int i = 0; i < 4; i++, aDraggedParam++)
+//// if (*aDraggedParam != 0)
+//// myTempPointWhereDragged.push_back(*aDraggedParam);
+//// myTempPointWDrgdID = myEntities[anEntPos].h;
+//// return;
+//// }
+////
+//// // Create additional SLVS_C_WHERE_DRAGGED constraint if myTempPointWhereDragged field is not empty
+//// Slvs_Constraint aWDConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED,
+//// myWorkplane.h, 0.0, anEntIter->second, 0, 0, 0);
+//// myConstraints.push_back(aWDConstr);
+//// myTempConstraints.push_back(aWDConstr.h);
+////}
+
+// ============================================================================
+// Function: removeTemporaryConstraints
+// Class: SketchSolver_Group
+// Purpose: remove all transient SLVS_C_WHERE_DRAGGED constraints after
+// resolving the set of constraints
+// ============================================================================
+void SketchSolver_Group::removeTemporaryConstraints()
+{
+ myTempConstraints.clear();
+ // Clean lists of removed entities in the storage
+ std::set<Slvs_hParam> aRemPar;
+ std::set<Slvs_hEntity> aRemEnt;
+ std::set<Slvs_hConstraint> aRemCon;
+ myStorage->getRemoved(aRemPar, aRemEnt, aRemCon);
+}
+
+// ============================================================================
+// Function: removeConstraint
+// Class: SketchSolver_Group
+// Purpose: remove constraint and all unused entities
+// ============================================================================
+void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
+{
+ myFeatureStorage->removeConstraint(theConstraint);
+ ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
+ for (; aCIter != myConstraints.end(); aCIter++)
+ if (aCIter->second->hasConstraint(theConstraint)) {
+ if (!aCIter->second->remove(theConstraint)) // the constraint is not fully removed
+ aCIter = myConstraints.end();
+ break;
+ }
+ if (aCIter != myConstraints.end())
+ myConstraints.erase(aCIter);
+}
+
+////// ============================================================================
+////// Function: removeEntitiesById
+////// Class: SketchSolver_Group
+////// Purpose: Removes specified entities and their parameters
+////// ============================================================================
+////void SketchSolver_Group::removeEntitiesById(const std::set<Slvs_hEntity>& theEntities)
+////{
+//// std::set<Slvs_hEntity>::const_reverse_iterator aRemIter = theEntities.rbegin();
+//// for (; aRemIter != theEntities.rend(); aRemIter++) {
+//// unsigned int anEntPos = Search(*aRemIter, myEntities);
+//// if (anEntPos >= myEntities.size())
+//// continue;
+//// if (myEntities[anEntPos].param[0] != 0) {
+//// unsigned int aParamPos = Search(myEntities[anEntPos].param[0], myParams);
+//// if (aParamPos >= myParams.size())
+//// continue;
+//// int aNbParams = 0;
+//// while (myEntities[anEntPos].param[aNbParams] != 0)
+//// aNbParams++;
+//// if (myEntities[anEntPos].param[aNbParams - 1] == myParamMaxID)
+//// myParamMaxID -= aNbParams;
+//// myParams.erase(myParams.begin() + aParamPos, myParams.begin() + aParamPos + aNbParams);
+//// if (*aRemIter == myEntityMaxID)
+//// myEntityMaxID--;
+//// }
+//// myEntities.erase(myEntities.begin() + anEntPos);
+//// myEntOfConstr.erase(myEntOfConstr.begin() + anEntPos);
+////
+//// // Remove entity's ID from the lists of conincident points
+//// std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
+//// for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++)
+//// aCoPtIter->erase(*aRemIter);
+//// }
+////}
+////
+////// ============================================================================
+////// Function: addCoincidentPoints
+////// Class: SketchSolver_Group
+////// Purpose: add coincident point the appropriate list of such points
+////// ============================================================================
+////bool SketchSolver_Group::addCoincidentPoints(const Slvs_hEntity& thePoint1,
+//// const Slvs_hEntity& thePoint2)
+////{
+//// std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
+//// std::vector<std::set<Slvs_hEntity> >::iterator aFirstFound = myCoincidentPoints.end();
+//// while (aCoPtIter != myCoincidentPoints.end()) {
+//// bool isFound[2] = { // indicate which point ID was already in coincidence constraint
+//// aCoPtIter->find(thePoint1) != aCoPtIter->end(), aCoPtIter->find(thePoint2)
+//// != aCoPtIter->end(), };
+//// if (isFound[0] && isFound[1]) // points are already connected by coincidence constraints => no need additional one
+//// return false;
+//// if ((isFound[0] && !isFound[1]) || (!isFound[0] && isFound[1])) {
+//// if (aFirstFound != myCoincidentPoints.end()) { // there are two groups of coincident points connected by created constraint => merge them
+//// int aFirstFoundShift = aFirstFound - myCoincidentPoints.begin();
+//// int aCurrentShift = aCoPtIter - myCoincidentPoints.begin();
+//// aFirstFound->insert(aCoPtIter->begin(), aCoPtIter->end());
+//// myCoincidentPoints.erase(aCoPtIter);
+//// aFirstFound = myCoincidentPoints.begin() + aFirstFoundShift;
+//// aCoPtIter = myCoincidentPoints.begin() + aCurrentShift;
+//// continue;
+//// } else {
+//// aCoPtIter->insert(isFound[0] ? thePoint2 : thePoint1);
+//// aFirstFound = aCoPtIter;
+//// }
+//// }
+//// aCoPtIter++;
+//// }
+//// // No points were found, need to create new set
+//// if (aFirstFound == myCoincidentPoints.end()) {
+//// std::set<Slvs_hEntity> aNewSet;
+//// aNewSet.insert(thePoint1);
+//// aNewSet.insert(thePoint2);
+//// myCoincidentPoints.push_back(aNewSet);
+//// }
+////
+//// return true;
+////}
+////
+////// ============================================================================
+////// Function: updateRelatedConstraints
+////// Class: SketchSolver_Group
+////// Purpose: emit the signal to update constraints
+////// ============================================================================
+////void SketchSolver_Group::updateRelatedConstraints(
+//// std::shared_ptr<ModelAPI_Attribute> theEntity) const
+////{
+//// ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
+//// for (; aConstrIter != myConstraintMap.end(); aConstrIter++) {
+//// std::list<std::shared_ptr<ModelAPI_Attribute> > anAttributes = aConstrIter->first->data()
+//// ->attributes(std::string());
+////
+//// std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttributes.begin();
+//// for (; anAttrIter != anAttributes.end(); anAttrIter++) {
+//// bool isUpd = (*anAttrIter == theEntity);
+//// std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr = std::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_Group::updateRelatedConstraintsFeature(
+//// std::shared_ptr<ModelAPI_Feature> theFeature) const
+////{
+//// ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
+//// for (; aConstrIter != myConstraintMap.end(); aConstrIter++) {
+//// std::list<std::shared_ptr<ModelAPI_Attribute> > anAttributes = aConstrIter->first->data()
+//// ->attributes(std::string());
+////
+//// std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttributes.begin();
+//// for (; anAttrIter != anAttributes.end(); anAttrIter++) {
+//// std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr = std::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;
+//// }
+//// }
+//// }
+////}
+////
+////// ============================================================================
+////// Function: updateFilletConstraints
+////// Class: SketchSolver_Group
+////// Purpose: change fillet arc to be less than 180 degree
+////// ============================================================================
+////void SketchSolver_Group::updateFilletConstraints()
+////{
+//// ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
+//// for (; aConstrIter != myConstraintMap.end(); aConstrIter++)
+//// if (aConstrIter->first->getKind() == SketchPlugin_ConstraintFillet::ID()) {
+//// AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+//// aConstrIter->first->data()->attribute(SketchPlugin_ConstraintFillet::ENTITY_C()));
+//// if (!aFilletRefList)
+//// return;
+//// ObjectPtr anArcObj = aFilletRefList->object(2);
+//// std::shared_ptr<GeomDataAPI_Point2D> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+//// anArcObj->data()->attribute(SketchPlugin_Arc::CENTER_ID()));
+//// std::shared_ptr<GeomDataAPI_Point2D> aStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+//// anArcObj->data()->attribute(SketchPlugin_Arc::START_ID()));
+//// std::shared_ptr<GeomDataAPI_Point2D> aEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+//// anArcObj->data()->attribute(SketchPlugin_Arc::END_ID()));
+//// double aCosA = aStart->x() - aCenter->x();
+//// double aSinA = aStart->y() - aCenter->y();
+//// double aCosB = aEnd->x() - aCenter->x();
+//// double aSinB = aEnd->y() - aCenter->y();
+//// if (aCosA * aSinB - aSinA * aCosB <= 0.0) {
+//// anArcObj->data()->blockSendAttributeUpdated(true);
+//// double x = aStart->x();
+//// double y = aStart->y();
+//// aStart->setValue(aEnd->x(), aEnd->y());
+//// aEnd->setValue(x, y);
+//// // Update constraint data
+//// changeFilletConstraint(aConstrIter->first);
+//// anArcObj->data()->blockSendAttributeUpdated(false);
+//// }
+//// }
+////}
+////
+////// ============================================================================
+////// Function: makeMirrorEntity
+////// Class: SketchSolver_Group
+////// Purpose: change entities parameters to make them symmetric relating to the mirror line
+////// ============================================================================
+////void SketchSolver_Group::makeMirrorEntity(const Slvs_hEntity& theBase,
+//// const Slvs_hEntity& theMirror,
+//// const Slvs_hEntity& theMirrorLine)
+////{
+//// Slvs_Entity aBase = myEntities[Search(theBase, myEntities)];
+//// Slvs_Entity aMirror = myEntities[Search(theMirror, myEntities)];
+//// int i = 0;
+//// while (aBase.point[i] != 0 && aMirror.point[i] != 0) {
+//// makeMirrorEntity(aBase.point[i], aMirror.point[i], theMirrorLine);
+//// i++;
+//// }
+//// if (aBase.param[0] != 0 && aMirror.param[0] != 0) { // this is a point, copy it
+//// Slvs_Entity aMirrorLine = myEntities[Search(theMirrorLine, myEntities)];
+//// std::shared_ptr<GeomAPI_XY> aLinePoints[2];
+//// for (i = 0; i < 2; i++) {
+//// Slvs_Entity aPoint = myEntities[Search(aMirrorLine.point[i], myEntities)];
+//// int aParamPos = Search(aPoint.param[0], myParams);
+//// aLinePoints[i] = std::shared_ptr<GeomAPI_XY>(
+//// new GeomAPI_XY(myParams[aParamPos].val, myParams[1+aParamPos].val));
+//// }
+//// int aBaseParamPos = Search(aBase.param[0], myParams);
+//// int aMirrorParamPos = Search(aMirror.param[0], myParams);
+//// std::shared_ptr<GeomAPI_XY> aPoint = std::shared_ptr<GeomAPI_XY>(
+//// new GeomAPI_XY(myParams[aBaseParamPos].val, myParams[1+aBaseParamPos].val));
+////
+//// // direction of a mirror line
+//// std::shared_ptr<GeomAPI_Dir2d> aDir = std::shared_ptr<GeomAPI_Dir2d>(
+//// new GeomAPI_Dir2d(aLinePoints[1]->added(aLinePoints[0]->multiplied(-1.0))));
+//// // orthogonal direction
+//// aDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aDir->y(), -aDir->x()));
+////
+//// std::shared_ptr<GeomAPI_XY> aVec = std::shared_ptr<GeomAPI_XY>(
+//// new GeomAPI_XY(aPoint->x() - aLinePoints[0]->x(), aPoint->y() - aLinePoints[0]->y()));
+//// double aDist = aVec->dot(aDir->xy());
+//// std::shared_ptr<GeomAPI_XY> aMirrorPoint = aPoint->added(aDir->xy()->multiplied(-2.0 * aDist));
+////
+//// myParams[aMirrorParamPos].val = aMirrorPoint->x();
+//// myParams[1+aMirrorParamPos].val = aMirrorPoint->y();
+//// }
+////}
+////
+////// ============================================================================
+////// Function: calculateMiddlePoint
+////// Class: SketchSolver_Group
+////// Purpose: calculates middle point on line or arc
+////// ============================================================================
+////void SketchSolver_Group::calculateMiddlePoint(
+//// const Slvs_hEntity& theEntity,
+//// double& theX,
+//// double& theY) const
+////{
+//// int anInd = Search(theEntity, myEntities);
+//// if (myEntities[anInd].type == SLVS_E_LINE_SEGMENT) {
+//// int aLineParams[2];
+//// for (int i = 0; i < 2; i++) {
+//// int aPtPos = Search(myEntities[anInd].point[i], myEntities);
+//// aLineParams[i] = Search(myEntities[aPtPos].param[0], myParams);
+//// }
+//// theX = 0.5 * (myParams[aLineParams[0]].val + myParams[aLineParams[1]].val);
+//// theY = 0.5 * (myParams[1 + aLineParams[0]].val + myParams[1 + aLineParams[1]].val);
+//// } else if (myEntities[anInd].type == SLVS_E_ARC_OF_CIRCLE) {
+//// double anArcPoint[3][2];
+//// for (int i = 0; i < 3; i++) {
+//// int aPtPos = Search(myEntities[anInd].point[i], myEntities);
+//// int anArcParam = Search(myEntities[aPtPos].param[0], myParams);
+//// anArcPoint[i][0] = myParams[anArcParam].val;
+//// anArcPoint[i][1] = myParams[1 + anArcParam].val;
+//// }
+//// // project last point of arc on the arc
+//// double x = anArcPoint[1][0] - anArcPoint[0][0];
+//// double y = anArcPoint[1][1] - anArcPoint[0][1];
+//// double aRad = sqrt(x*x + y*y);
+//// x = anArcPoint[2][0] - anArcPoint[0][0];
+//// y = anArcPoint[2][1] - anArcPoint[0][1];
+//// double aNorm = sqrt(x*x + y*y);
+//// if (aNorm >= tolerance) {
+//// anArcPoint[2][0] = anArcPoint[0][0] + x * aRad / aNorm;
+//// anArcPoint[2][1] = anArcPoint[0][1] + y * aRad / aNorm;
+//// }
+////
+//// x = anArcPoint[1][0] + anArcPoint[2][0] - 2.0 * anArcPoint[0][0];
+//// y = anArcPoint[1][1] + anArcPoint[2][1] - 2.0 * anArcPoint[0][1];
+//// aNorm = sqrt(x*x + y*y);
+//// if (aNorm >= tolerance) {
+//// x *= aRad / aNorm;
+//// y *= aRad / aNorm;
+//// } else { // obtain orthogonal direction
+//// x = 0.5 * (anArcPoint[2][1] - anArcPoint[1][1]);
+//// y = -0.5 * (anArcPoint[2][0] - anArcPoint[1][0]);
+//// }
+//// theX = anArcPoint[0][0] + x;
+//// theY = anArcPoint[0][1] + y;
+//// }
+////}
+
+
+// ========================================================
+// ========= Auxiliary functions ===============
+// ========================================================
+
+template<typename T>
+int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
+{
+ int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0;
+ int aVecSize = theEntities.size();
+ while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
+ aResIndex--;
+ while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
+ aResIndex++;
+ if (aResIndex == -1)
+ aResIndex = aVecSize;
+ return aResIndex;
+}
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_Group.h
+// Created: 27 May 2014
+// Author: Artem ZHIDKOV
+
+#ifndef SketchSolver_Group_H_
+#define SketchSolver_Group_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+#include <SketchSolver_Storage.h>
+#include <SketchSolver_FeatureStorage.h>
+#include <SketchSolver_Solver.h>
+
+#include <SketchPlugin_Constraint.h>
+#include <ModelAPI_Data.h>
+#include <ModelAPI_Feature.h>
+
+
+#include <memory>
+#include <list>
+#include <map>
+#include <vector>
+#include <set>
+
+typedef std::map<ConstraintPtr, SolverConstraintPtr> ConstraintConstraintMap;
+
+/** \class SketchSolver_Group
+ * \ingroup Plugins
+ * \brief Keeps the group of constraints which based on the same entities
+ */
+class SketchSolver_Group
+{
+ public:
+ /** \brief New group based on specified workplane.
+ * Throws an exception if theWorkplane is not an object of SketchPlugin_Sketch type
+ * \remark Type of theSketch is not verified inside
+ */
+ SketchSolver_Group(std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane);
+
+ ~SketchSolver_Group();
+
+ /// \brief Returns group's unique identifier
+ inline const Slvs_hGroup& getId() const
+ {
+ return myID;
+ }
+
+ /// \brief Returns identifier of the workplane
+ inline const Slvs_hEntity& getWorkplaneId() const
+ {
+ return myWorkplaneID;
+ }
+
+ /// \brief Find the identifier of the feature, if it already exists in the group
+ Slvs_hEntity getFeatureId(FeaturePtr theFeature) const;
+ /// \brief Find the identifier of the attribute, if it already exists in the group
+ Slvs_hEntity getAttributeId(AttributePtr theAttribute) const;
+
+ /// \brief Returns true if the group has no constraints yet
+ inline bool isEmpty() const
+ {
+ return myConstraints.empty();
+ }
+
+ /// \brief Check for valid sketch data
+ inline bool isWorkplaneValid() const
+ {
+ return mySketch->data() && mySketch->data()->isValid();
+ }
+
+ /** \brief Adds or updates a constraint in the group
+ * \param[in] theConstraint constraint to be changed
+ * \return \c true if the constraint added or updated successfully
+ */
+ bool changeConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
+//// /** \brief Adds or updates a rigid constraint in the group
+//// * \param[in] theConstraint constraint to be changed
+//// * \return \c true if the constraint added or updated successfully
+//// */
+//// bool changeRigidConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
+//// /** \brief Adds or updates a mirror constraint in the group
+//// * \param[in] theConstraint constraint to be changed
+//// * \return \c true if the constraint added or updated successfully
+//// */
+//// bool changeMirrorConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
+//// /** \brief Adds or updates a fillet constraint in the group
+//// * \param[in] theConstraint constraint to be changed
+//// * \return \c true if the constraint added or updated successfully
+//// */
+//// bool changeFilletConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
+
+ /** \brief Updates the data corresponding the specified feature moved in GUI.
+ * Additional Fixed constraints are created.
+ * \param[in] theFeature the feature to be updated
+ */
+ void moveFeature(std::shared_ptr<SketchPlugin_Feature> theFeature);
+
+ /** \brief Verifies the feature attributes are used in this group
+ * \param[in] theFeature constraint or any other object for verification of interaction
+ * \return \c true if some of attributes are used in current group
+ */
+ bool isInteract(std::shared_ptr<SketchPlugin_Feature> theFeature) const;
+
+ /** \brief Verifies the specified feature is equal to the base workplane for this group
+ * \param[in] theWorkplane the feature to be compared with base workplane
+ * \return \c true if workplanes are the same
+ */
+ bool isBaseWorkplane(CompositeFeaturePtr theWorkplane) const;
+
+ /// Returns the current workplane
+ std::shared_ptr<ModelAPI_CompositeFeature> getWorkplane() const
+ {
+ return mySketch;
+ }
+
+ /** \brief Update parameters of workplane. Should be called when Update event is coming.
+ * \return \c true if workplane updated successfully, \c false if workplane parameters are not consistent
+ */
+ bool updateWorkplane();
+////
+//// /** \brief If the entity is in this group it will updated
+//// * \param[in] theEntity attribute, which values should update SolveSpace entity
+//// */
+//// void updateEntityIfPossible(std::shared_ptr<ModelAPI_Attribute> theEntity);
+
+ /** \brief Searches invalid features and constraints in the group and removes them
+ * \return \c false if the group several constraints were removed
+ */
+ bool isConsistent();
+
+ /** \brief Add specified group to this one
+ * \param[in] theGroup group of constraint to be added
+ */
+ void mergeGroups(const SketchSolver_Group& theGroup);
+
+ /** \brief Cut from the group several subgroups, which are not connected to the current one by any constraint
+ * \param[out] theCuts enlarge this list by newly created groups
+ */
+ void splitGroup(std::vector<SketchSolver_Group*>& theCuts);
+
+ /** \brief Start solution procedure if necessary and update attributes of features
+ * \return \c false when no need to solve constraints
+ */
+ bool resolveConstraints();
+////
+//// /** \brief Searches the constraints built on the entity and emit the signal to update them
+//// * \param[in] theEntity attribute of the constraint
+//// */
+//// void updateRelatedConstraints(std::shared_ptr<ModelAPI_Attribute> theEntity) const;
+//// /** \brief Searches the constraints built on the entity and emit the signal to update them
+//// * \param[in] theFeature feature of the constraint
+//// */
+//// void updateRelatedConstraintsFeature(std::shared_ptr<ModelAPI_Feature> theFeature) const;
+////
+//// /** \brief Adds or updates an entity in the group
+//// *
+//// * The parameters of entity will be parsed and added to the list of SolveSpace parameters.
+//// * Parameters of certain entity will be placed sequentially in the list.
+//// *
+//// * \param[in] theEntity the object of constraint
+//// * \return identifier of changed entity or 0 if entity could not be changed
+//// */
+//// Slvs_hEntity changeEntity(std::shared_ptr<ModelAPI_Attribute> theEntity);
+//// Slvs_hEntity changeEntityFeature(std::shared_ptr<ModelAPI_Feature> theEntity);
+
+protected:
+//// /** \brief Adds or updates a normal in the group
+//// *
+//// * Normal is a special entity in SolveSpace, which defines a direction in 3D and
+//// * a rotation about this direction. So, SolveSpace represents normals as unit quaternions.
+//// *
+//// * To define a normal there should be specified two coordinate axis
+//// * on the plane transversed to created normal.
+//// *
+//// * \param[in] theDirX first coordinate axis of the plane
+//// * \param[in] theNorm attribute for the normal (used to identify newly created entity)
+//// * \return identifier of created or updated normal
+//// */
+//// Slvs_hEntity changeNormal(std::shared_ptr<ModelAPI_Attribute> theDirX,
+//// std::shared_ptr<ModelAPI_Attribute> theNorm);
+////
+//// /** \brief Adds or updates a parameter in the group
+//// * \param[in] theParam the value of parameter
+//// * \param[in] thePrmIter the cell in the list of parameters which should be changed
+//// * (the iterator will be increased if it does not reach the end of the list)
+//// * \return identifier of changed parameter; when the parameter cannot be created, returned ID is 0
+//// */
+//// Slvs_hParam changeParameter(const double& theParam,
+//// std::vector<Slvs_Param>::const_iterator& thePrmIter);
+////
+//// /** \brief Removes specified entities and their parameters
+//// * \param[in] theEntities list of IDs of the entities to be removed
+//// */
+//// void removeEntitiesById(const std::set<Slvs_hEntity>& theEntities);
+
+ /** \brief Removes constraints from the group
+ * \param[in] theConstraint constraint to be removed
+ */
+ void removeConstraint(ConstraintPtr theConstraint);
+////
+//// /** \brief Change values of attribute by parameters received from SolveSpace solver
+//// * \param[in,out] theAttribute pointer to the attribute to be changed
+//// * \param[in] theEntityID identifier of SolveSpace entity, which contains updated data
+//// * \return \c true if the attribute's value has changed
+//// */
+//// bool updateAttribute(std::shared_ptr<ModelAPI_Attribute> theAttribute,
+//// const Slvs_hEntity& theEntityID);
+////
+//// /// \brief Update arc of fillet to be less than 180 degree
+//// void updateFilletConstraints();
+////
+//// /** \brief Adds a constraint for a point which should not be changed during computations
+//// * \param[in] theEntity the base for the constraint
+//// * \param[in] theAllowToFit this flag shows that the entity may be placed into
+//// * the 'dragged' field of SolveSpace solver, so this entity
+//// * may be changed a little during solution
+//// */
+//// void addTemporaryConstraintWhereDragged(std::shared_ptr<ModelAPI_Attribute> theEntity,
+//// bool theAllowToFit = true);
+
+ /** \brief Remove all temporary constraint after computation finished
+ * \param[in] theRemoved indexes of constraints to be removed. If empty, all temporary constraints should be deleted
+ */
+ void removeTemporaryConstraints();
+
+private:
+ /** \brief Creates a workplane from the sketch parameters
+ * \param[in] theSketch parameters of workplane are the attributes of this sketch
+ * \return \c true if success, \c false if workplane parameters are not consistent
+ */
+ bool addWorkplane(CompositeFeaturePtr theSketch);
+////
+//// /** \brief Add the entities of constraint for points coincidence into the appropriate list
+//// * \param[in] thePoint1 identifier of the first point
+//// * \param[in] thePoint2 identifier of the second point
+//// * \return \c true if the points are added successfully, and
+//// * \c false if the constraint is the extra one (should not be created in SolveSpace)
+//// */
+//// bool addCoincidentPoints(const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2);
+////
+//// /** \brief Verifies and changes parameters of constriant,
+//// * e.g. sign of the distance between line and point
+//// * \param[in,out] theConstraint SolveSpace constraint to be verified
+//// */
+//// void checkConstraintConsistence(Slvs_Constraint& theConstraint);
+////
+//// /** \brief Change entities parameters to make them symmetric relating to the mirror line
+//// * \param[in] theBase entity to be mirrored
+//// * \param[in] theMirror a mirrored object
+//// * \param[in] theMirrorLine a mirror line
+//// */
+//// void makeMirrorEntity(const Slvs_hEntity& theBase,
+//// const Slvs_hEntity& theMirror,
+//// const Slvs_hEntity& theMirrorLine);
+////
+//// /** \brief Calculates middle point on line or arc
+//// * \param[in] theEntity identifier of line or arc
+//// * \param[out] theX X value of middle point
+//// * \param[out] theY Y value of middle point
+//// */
+//// void calculateMiddlePoint(const Slvs_hEntity& theEntity,
+//// double& theX, double& theY) const;
+////
+//// private:
+//// // SolveSpace entities
+//// Slvs_hGroup myID; ///< the index of the group
+//// Slvs_Entity myWorkplane; ///< Workplane for the current group
+//// std::vector<Slvs_Param> myParams; ///< List of parameters of the constraints
+//// Slvs_hParam myParamMaxID; ///< Actual maximal ID of parameters (not equal to myParams size)
+//// std::vector<Slvs_Entity> myEntities; ///< List of entities of the constaints
+//// std::vector<bool> myEntOfConstr; ///< Flags show that certain entity used in constraints
+//// Slvs_hEntity myEntityMaxID; ///< Actual maximal ID of entities (not equal to myEntities size)
+//// std::vector<Slvs_Constraint> myConstraints; ///< List of constraints in SolveSpace format
+//// Slvs_hConstraint myConstrMaxID; ///< Actual maximal ID of constraints (not equal to myConstraints size)
+//// bool myNeedToSolve; ///< Indicator that something changed in the group and constraint system need to be rebuilt
+////
+//// SketchSolver_Solver myConstrSolver; ///< Solver for set of equations obtained by constraints
+////
+//// std::vector<Slvs_hParam> myTempPointWhereDragged; ///< Parameters of one of the points which is moved by user
+//// Slvs_hEntity myTempPointWDrgdID; ///< Identifier of such point
+//// std::list<Slvs_hConstraint> myTempConstraints; ///< The list of identifiers of temporary constraints (SLVS_C_WHERE_DRAGGED) applied for all other points moved by user
+////
+//// // SketchPlugin entities
+//// std::shared_ptr<ModelAPI_CompositeFeature> mySketch; ///< Equivalent to workplane
+//// ConstraintMap myConstraintMap; ///< The map between SketchPlugin and SolveSpace constraints
+//// std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity> myEntityAttrMap; ///< The map between "attribute" parameters of constraints and their equivalent SolveSpace entities
+//// std::map<FeaturePtr, Slvs_hEntity> myEntityFeatMap; ///< The map between "feature" parameters of constraints and their equivalent SolveSpace entities
+////
+//// // Conincident items
+//// std::vector<std::set<Slvs_hEntity> > myCoincidentPoints; ///< Stores the lists of identifiers of coincident points (to avoid unnecessary coincidence constraints)
+//// std::set<std::shared_ptr<SketchPlugin_Constraint> > myExtraCoincidence; ///< Additional coincidence constraints which are not necessary (coincidence between points already done
+//// ///< by other constraints) but created by GUI tools. Useful when some coincidence constraints were removed
+
+private:
+ Slvs_hGroup myID; ///< Index of the group
+ Slvs_hEntity myWorkplaneID; ///< Index of workplane, the group is based on
+ CompositeFeaturePtr mySketch; ///< Sketch is equivalent to workplane
+ ConstraintConstraintMap myConstraints; ///< List of constraints
+ std::set<SolverConstraintPtr> myTempConstraints; ///< List of temporary constraints
+
+ StoragePtr myStorage; ///< Container for the set of SolveSpace constraints and their entities
+ FeatureStoragePtr myFeatureStorage; ///< Container for the set of SketchPlugin features and their dependencies
+
+ SketchSolver_Solver myConstrSolver; ///< Solver for set of equations obtained by constraints
+};
+
+#endif
SketchSolver_Solver::~SketchSolver_Solver()
{
- if (myEquationsSystem.param)
- delete[] myEquationsSystem.param;
- if (myEquationsSystem.entity)
- delete[] myEquationsSystem.entity;
- if (myEquationsSystem.constraint)
- delete[] myEquationsSystem.constraint;
if (myEquationsSystem.failed)
delete[] myEquationsSystem.failed;
}
-void SketchSolver_Solver::setParameters(const std::vector<Slvs_Param>& theParameters)
+void SketchSolver_Solver::setParameters(Slvs_Param* theParameters, int theSize)
{
- if (theParameters.size() != myEquationsSystem.params) // number of parameters was changed => reallocate the memory
- {
- if (myEquationsSystem.param)
- delete[] myEquationsSystem.param;
- myEquationsSystem.params = theParameters.size();
- myEquationsSystem.param = new Slvs_Param[theParameters.size()];
- }
-
- // Copy data
- std::vector<Slvs_Param>::const_iterator aParamIter = theParameters.begin();
- for (int i = 0; i < myEquationsSystem.params; i++, aParamIter++)
- myEquationsSystem.param[i] = *aParamIter;
+ myEquationsSystem.param = theParameters;
+ myEquationsSystem.params = theSize;
}
-void SketchSolver_Solver::setDraggedParameters(const std::vector<Slvs_hParam>& theDragged)
+
+void SketchSolver_Solver::setDraggedParameters(const Slvs_hParam* theDragged)
{
- if (theDragged.size() == 0) {
- myEquationsSystem.dragged[0] = 0;
- myEquationsSystem.dragged[1] = 0;
- myEquationsSystem.dragged[2] = 0;
- myEquationsSystem.dragged[3] = 0;
- return;
- }
- for (unsigned int i = 0; i < theDragged.size(); i++)
+ for (unsigned int i = 0; i < 4; i++)
myEquationsSystem.dragged[i] = theDragged[i];
}
-void SketchSolver_Solver::setEntities(const std::vector<Slvs_Entity>& theEntities)
+void SketchSolver_Solver::setEntities(Slvs_Entity* theEntities, int theSize)
{
- if (theEntities.size() != myEquationsSystem.entities) // number of entities was changed => reallocate the memory
- {
- if (myEquationsSystem.entity)
- delete[] myEquationsSystem.entity;
- myEquationsSystem.entities = theEntities.size();
- myEquationsSystem.entity = new Slvs_Entity[theEntities.size()];
- }
-
- // Copy data
- std::vector<Slvs_Entity>::const_iterator aEntIter = theEntities.begin();
- for (int i = 0; i < myEquationsSystem.entities; i++, aEntIter++)
- myEquationsSystem.entity[i] = *aEntIter;
+ myEquationsSystem.entity = theEntities;
+ myEquationsSystem.entities = theSize;
}
-void SketchSolver_Solver::setConstraints(const std::vector<Slvs_Constraint>& theConstraints)
+void SketchSolver_Solver::setConstraints(Slvs_Constraint* theConstraints, int theSize)
{
- if (theConstraints.size() != myEquationsSystem.constraints) // number of constraints was changed => reallocate the memory
- {
- if (myEquationsSystem.constraint)
- delete[] myEquationsSystem.constraint;
- myEquationsSystem.constraints = theConstraints.size();
- myEquationsSystem.constraint = new Slvs_Constraint[theConstraints.size()];
-
- // Assign the memory for the failed constraints
- if (myEquationsSystem.failed)
- delete[] myEquationsSystem.failed;
- myEquationsSystem.failed = new Slvs_hConstraint[theConstraints.size()];
- myEquationsSystem.faileds = theConstraints.size();
- }
-
- // Copy data
- std::vector<Slvs_Constraint>::const_iterator aConstrIter = theConstraints.begin();
- for (int i = 0; i < myEquationsSystem.constraints; i++, aConstrIter++)
- myEquationsSystem.constraint[i] = *aConstrIter;
+ myEquationsSystem.constraint = theConstraints;
+ myEquationsSystem.constraints = theSize;
}
+
int SketchSolver_Solver::solve()
{
if (myEquationsSystem.constraints <= 0)
#define SLVS_C_FILLET 100100
// Unknown entity
#define SLVS_E_UNKNOWN 0
+// Unknown group
+#define SLVS_G_UNKNOWN 0
/**
* The main class that performs the high-level operations for connection to the SolveSpace.
}
/** \brief Change array of parameters
- * \param[in] theParameters vector of parameters
+ * \param[in] theParameters pointer to the array of parameters
+ * \param[in] theSize size of this array
*/
- void setParameters(const std::vector<Slvs_Param>& theParameters);
+ void setParameters(Slvs_Param* theParameters, int theSize);
/** \brief Change array of entities
- * \param[in] theEntities vector of entities
+ * \param[in] theEntities pointer to the array of entities
+ * \param[in] theSize size of this array
*/
- void setEntities(const std::vector<Slvs_Entity>& theEntities);
+ void setEntities(Slvs_Entity* theEntities, int theSize);
/** \brief Change array of constraints
- * \param[in] theConstraints vector of constraints
+ * \param[in] theConstraints pointer to the array of constraints
+ * \param[in] theSize size of this array
*/
- void setConstraints(const std::vector<Slvs_Constraint>& theConstraints);
+ void setConstraints(Slvs_Constraint* theConstraints, int theSize);
/** \brief Store the parameters of the point which was moved by user.
* The solver will watch this items to be constant
* \param[in] theDragged list of parameters (not more than 4) which should not be changed during solving
*/
- void setDraggedParameters(const std::vector<Slvs_hParam>& theDragged);
+ void setDraggedParameters(const Slvs_hParam* theDragged);
/** \brief Solve the set of equations
* \return identifier whether solution succeeded
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_Storage.cpp
+// Created: 18 Mar 2015
+// Author: Artem ZHIDKOV
+
+#include <SketchSolver_Storage.h>
+
+/** \brief Search the entity/parameter with specified ID in the list of elements
+ * \param[in] theEntityID unique ID of the element
+ * \param[in] theEntities list of elements
+ * \return position of the found element or -1 if the element is not found
+ */
+template<typename T>
+static int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities);
+
+/// \brief Compare two parameters to be different
+static bool IsNotEqual(const Slvs_Param& theParam1, const Slvs_Param& theParam2);
+/// \brief Compare two entities to be different
+static bool IsNotEqual(const Slvs_Entity& theEntity1, const Slvs_Entity& theEntity2);
+/// \brief Compare two constriants to be different
+static bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2);
+
+
+SketchSolver_Storage::SketchSolver_Storage()
+ : myParamMaxID(SLVS_E_UNKNOWN),
+ myEntityMaxID(SLVS_E_UNKNOWN),
+ myConstrMaxID(SLVS_C_UNKNOWN),
+ myNeedToResolve(false)
+{
+}
+
+Slvs_hParam SketchSolver_Storage::addParameter(const Slvs_Param& theParam)
+{
+ if (theParam.h > 0 && theParam.h <= myParamMaxID) {
+ // parameter is already used, rewrite it
+ return updateParameter(theParam);
+ }
+
+ Slvs_Param aParam = theParam;
+ if (aParam.h > myParamMaxID)
+ myParamMaxID = aParam.h;
+ else
+ aParam.h = ++myParamMaxID;
+ myParameters.push_back(aParam);
+ myNeedToResolve = true;
+ return aParam.h;
+}
+
+Slvs_hParam SketchSolver_Storage::updateParameter(const Slvs_Param& theParam)
+{
+ if (theParam.h > 0 && theParam.h <= myParamMaxID) {
+ // parameter already used, rewrite it
+ int aPos = Search(theParam.h, myParameters);
+ if (aPos >= 0 && aPos < (int)myParameters.size()) {
+ myNeedToResolve = myNeedToResolve || IsNotEqual(myParameters[aPos], theParam);
+ myParameters[aPos] = theParam;
+ return theParam.h;
+ }
+ }
+
+ // Parameter is not found, add new one
+ Slvs_Param aParam = theParam;
+ aParam.h = 0;
+ return addParameter(aParam);
+}
+
+bool SketchSolver_Storage::removeParameter(const Slvs_hParam& theParamID)
+{
+ int aPos = Search(theParamID, myParameters);
+ if (aPos >= 0 && aPos < (int)myParameters.size()) {
+ // Firstly, search the parametes is not used elsewhere
+ std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
+ for (; anEntIter != myEntities.end(); anEntIter++) {
+ for (int i = 0; i < 4; i++)
+ if (anEntIter->param[i] == theParamID)
+ return false;
+ }
+ // Remove parameter
+ myParameters.erase(myParameters.begin() + aPos);
+ myNeedToResolve = true;
+ myRemovedParameters.insert(theParamID);
+ return true;
+ }
+ return false;
+}
+
+const Slvs_Param& SketchSolver_Storage::getParameter(const Slvs_hParam& theParamID) const
+{
+ int aPos = Search(theParamID, myParameters);
+ if (aPos >= 0 && aPos < (int)myParameters.size())
+ return myParameters[aPos];
+
+ // Parameter is not found, return empty object
+ static Slvs_Param aDummy;
+ aDummy.h = 0;
+ return aDummy;
+}
+
+
+Slvs_hEntity SketchSolver_Storage::addEntity(const Slvs_Entity& theEntity)
+{
+ if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) {
+ // Entity is already used, rewrite it
+ return updateEntity(theEntity);
+ }
+
+ Slvs_Entity aEntity = theEntity;
+ if (aEntity.h > myEntityMaxID)
+ myEntityMaxID = aEntity.h;
+ else
+ aEntity.h = ++myEntityMaxID;
+ myEntities.push_back(aEntity);
+ myNeedToResolve = true;
+ return aEntity.h;
+}
+
+Slvs_hEntity SketchSolver_Storage::updateEntity(const Slvs_Entity& theEntity)
+{
+ if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) {
+ // Entity already used, rewrite it
+ int aPos = Search(theEntity.h, myEntities);
+ if (aPos >= 0 && aPos < (int)myEntities.size()) {
+ myNeedToResolve = myNeedToResolve || IsNotEqual(myEntities[aPos], theEntity);
+ myEntities[aPos] = theEntity;
+ return theEntity.h;
+ }
+ }
+
+ // Entity is not found, add new one
+ Slvs_Entity aEntity = theEntity;
+ aEntity.h = 0;
+ return addEntity(aEntity);
+}
+
+bool SketchSolver_Storage::removeEntity(const Slvs_hEntity& theEntityID)
+{
+ bool aResult = true;
+ int aPos = Search(theEntityID, myEntities);
+ if (aPos >= 0 && aPos < (int)myEntities.size()) {
+ // Firstly, check the entity is not used elsewhere
+ std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
+ for (; anEntIter != myEntities.end(); anEntIter++) {
+ for (int i = 0; i < 4; i++)
+ if (anEntIter->point[i] == theEntityID)
+ return false;
+ if (anEntIter->distance == theEntityID)
+ return false;
+ }
+ std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
+ for (; aConstrIter != myConstraints.end(); aConstrIter++) {
+ Slvs_hEntity anEntIDs[6] = {aConstrIter->ptA, aConstrIter->ptB,
+ aConstrIter->entityA, aConstrIter->entityB,
+ aConstrIter->entityC, aConstrIter->entityD};
+ for (int i = 0; i < 6; i++)
+ if (anEntIDs[i] == theEntityID)
+ return false;
+ }
+ // The entity is not used, remove it and its parameters
+ Slvs_Entity anEntity = myEntities[aPos];
+ myEntities.erase(myEntities.begin() + aPos);
+ if (anEntity.distance != SLVS_E_UNKNOWN)
+ aResult = aResult && removeParameter(anEntity.distance);
+ for (int i = 0; i < 4; i++)
+ if (anEntity.param[i] != SLVS_E_UNKNOWN)
+ aResult = removeParameter(anEntity.param[i]) && aResult;
+ for (int i = 0; i < 4; i++)
+ if (anEntity.point[i] != SLVS_E_UNKNOWN)
+ aResult = removeEntity(anEntity.point[i]) && aResult;
+ myNeedToResolve = true;
+ myRemovedEntities.insert(theEntityID);
+ }
+ return aResult;
+}
+
+const Slvs_Entity& SketchSolver_Storage::getEntity(const Slvs_hEntity& theEntityID) const
+{
+ int aPos = Search(theEntityID, myEntities);
+ if (aPos >= 0 && aPos < (int)myEntities.size())
+ return myEntities[aPos];
+
+ // Entity is not found, return empty object
+ static Slvs_Entity aDummy;
+ aDummy.h = 0;
+ return aDummy;
+}
+
+
+Slvs_hConstraint SketchSolver_Storage::addConstraint(const Slvs_Constraint& theConstraint)
+{
+ if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) {
+ // Constraint is already used, rewrite it
+ return updateConstraint(theConstraint);
+ }
+
+ Slvs_Constraint aConstraint = theConstraint;
+ if (aConstraint.h > myConstrMaxID)
+ myConstrMaxID = aConstraint.h;
+ else
+ aConstraint.h = ++myConstrMaxID;
+ myConstraints.push_back(aConstraint);
+ myNeedToResolve = true;
+ return aConstraint.h;
+}
+
+Slvs_hConstraint SketchSolver_Storage::updateConstraint(const Slvs_Constraint& theConstraint)
+{
+ if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) {
+ // Constraint already used, rewrite it
+ int aPos = Search(theConstraint.h, myConstraints);
+ if (aPos >= 0 && aPos < (int)myConstraints.size()) {
+ myNeedToResolve = myNeedToResolve || IsNotEqual(myConstraints[aPos], theConstraint);
+ myConstraints[aPos] = theConstraint;
+ return theConstraint.h;
+ }
+ }
+
+ // Constraint is not found, add new one
+ Slvs_Constraint aConstraint = theConstraint;
+ aConstraint.h = 0;
+ return addConstraint(aConstraint);
+}
+
+bool SketchSolver_Storage::removeConstraint(const Slvs_hConstraint& theConstraintID)
+{
+ bool aResult = true;
+ int aPos = Search(theConstraintID, myConstraints);
+ if (aPos >= 0 && aPos < (int)myConstraints.size()) {
+ Slvs_Constraint aConstraint = myConstraints[aPos];
+ myConstraints.erase(myConstraints.begin() + aPos);
+ myNeedToResolve = true;
+ myRemovedConstraints.insert(theConstraintID);
+ // Remove all entities
+ Slvs_hEntity anEntities[6] = {aConstraint.ptA, aConstraint.ptB,
+ aConstraint.entityA, aConstraint.entityB,
+ aConstraint.entityC, aConstraint.entityD};
+ for (int i = 0; i < 6; i++)
+ if (anEntities[i] != SLVS_E_UNKNOWN) {
+ aResult = removeEntity(anEntities[i]) && aResult;
+ // remove temporary fixed points, if exists
+ std::vector<Slvs_hEntity>::iterator aFPIt = myFixedPoints.begin();
+ for (; aFPIt != myFixedPoints.end(); aFPIt++)
+ if (*aFPIt == anEntities[i]) {
+ myFixedPoints.erase(aFPIt);
+ break;
+ }
+ }
+ }
+ return aResult;
+}
+
+const Slvs_Constraint& SketchSolver_Storage::getConstraint(const Slvs_hConstraint& theConstraintID) const
+{
+ int aPos = Search(theConstraintID, myConstraints);
+ if (aPos >= 0 && aPos < (int)myConstraints.size())
+ return myConstraints[aPos];
+
+ // Constraint is not found, return empty object
+ static Slvs_Constraint aDummy;
+ aDummy.h = 0;
+ return aDummy;
+}
+
+void SketchSolver_Storage::addTemporaryConstraint(const Slvs_hConstraint& theConstraintID)
+{
+ int aPos = Search(theConstraintID, myConstraints);
+ myFixedPoints.push_back(myConstraints[aPos].ptA);
+}
+
+void SketchSolver_Storage::getRemoved(
+ std::set<Slvs_hParam>& theParameters,
+ std::set<Slvs_hEntity>& theEntities,
+ std::set<Slvs_hConstraint>& theConstraints)
+{
+ theParameters = myRemovedParameters;
+ theEntities = myRemovedEntities;
+ theConstraints = myRemovedConstraints;
+
+ myRemovedParameters.clear();
+ myRemovedEntities.clear();
+ myRemovedConstraints.clear();
+}
+
+void SketchSolver_Storage::initializeSolver(SketchSolver_Solver& theSolver)
+{
+ theSolver.setParameters(myParameters.data(), (int)myParameters.size());
+ theSolver.setEntities(myEntities.data(), (int)myEntities.size());
+ theSolver.setConstraints(myConstraints.data(), (int)myConstraints.size());
+
+ // initialize fixed points
+ if (!myFixedPoints.empty()) {
+ int aPos = Search(myFixedPoints.front(), myEntities);
+ theSolver.setDraggedParameters(myEntities[aPos].param);
+ }
+}
+
+
+// ========================================================
+// ========= Auxiliary functions ===============
+// ========================================================
+
+template<typename T>
+int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
+{
+ int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0;
+ int aVecSize = theEntities.size();
+ while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
+ aResIndex--;
+ while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
+ aResIndex++;
+ if (aResIndex == -1)
+ aResIndex = aVecSize;
+ return aResIndex;
+}
+
+bool IsNotEqual(const Slvs_Param& theParam1, const Slvs_Param& theParam2)
+{
+ return fabs(theParam1.val - theParam2.val) > tolerance;
+}
+
+bool IsNotEqual(const Slvs_Entity& theEntity1, const Slvs_Entity& theEntity2)
+{
+ int i = 0;
+ for (; theEntity1.param[i] != 0 && i < 4; i++)
+ if (theEntity1.param[i] != theEntity2.param[i])
+ return true;
+ i = 0;
+ for (; theEntity1.point[i] != 0 && i < 4; i++)
+ if (theEntity1.point[i] != theEntity2.point[i])
+ return true;
+ return false;
+}
+
+bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2)
+{
+ return theConstraint1.ptA != theConstraint2.ptA ||
+ theConstraint1.ptB != theConstraint2.ptB ||
+ theConstraint1.entityA != theConstraint2.entityA ||
+ theConstraint1.entityB != theConstraint2.entityB ||
+ theConstraint1.entityC != theConstraint2.entityC ||
+ theConstraint1.entityD != theConstraint2.entityD ||
+ fabs(theConstraint1.valA - theConstraint2.valA) > tolerance;
+}
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_Storage.h
+// Created: 18 Mar 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SketchSolver_Storage_H_
+#define SketchSolver_Storage_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Solver.h>
+
+#include <memory>
+#include <set>
+#include <vector>
+
+/** \class SketchSolver_Storage
+ * \ingroup Plugins
+ * \brief Contains all necessary data in SolveSpace format to solve a single group of constraints
+ */
+class SketchSolver_Storage
+{
+public:
+ SketchSolver_Storage();
+
+ /** \brief Add new parameter to the current group
+ * \param[in] theParam SolveSpace parameter
+ * \return the ID of added parameter
+ */
+ Slvs_hParam addParameter(const Slvs_Param& theParam);
+ /** \brief Updates parameter in the current group. If the ID of parameter is zero, the new item will be added
+ * \param[in] theParam SolveSpace parameter
+ * \return the ID of updated/added parameter
+ */
+ Slvs_hParam updateParameter(const Slvs_Param& theParam);
+ /** \brief Removes the parameter by its ID
+ * \param[in] theParamID index of parameter to be removed
+ * \return \c true if the parameter was successfully removed
+ */
+ bool removeParameter(const Slvs_hParam& theParamID);
+ /// \brief Returns the parameter by its ID
+ const Slvs_Param& getParameter(const Slvs_hParam& theParamID) const;
+
+ /** \brief Add new entity to the current group
+ * \param[in] theEntity SolveSpace entity
+ * \return the ID of added entity
+ */
+ Slvs_hEntity addEntity(const Slvs_Entity& theEntity);
+ /** \brief Updates entity in the current group. If the ID of entity is zero, the new item will be added
+ * \param[in] theEntity SolveSpace entity
+ * \return the ID of updated/added entity
+ */
+ Slvs_hEntity updateEntity(const Slvs_Entity& theEntity);
+ /** \brief Removes the entity by its ID. All parameters used in this entity,
+ * and not used in other constraints, will be removed too.
+ * \param[in] theEntityID index of entity to be removed
+ * \return \c true if the entity was successfully removed
+ */
+ bool removeEntity(const Slvs_hEntity& theEntityID);
+ /// \brief Returns the entity by its ID
+ const Slvs_Entity& getEntity(const Slvs_hEntity& theEntityID) const;
+
+ /** \brief Add new constraint to the current group
+ * \param[in] theConstraint SolveSpace constraint
+ * \return the ID of added constraint
+ */
+ Slvs_hConstraint addConstraint(const Slvs_Constraint& theConstraint);
+ /** \brief Updates constraint in the current group.
+ * If the ID of constraint is zero, the new item will be added
+ * \param[in] theConstraint SolveSpace constraint
+ * \return the ID of updated/added constraint
+ */
+ Slvs_hConstraint updateConstraint(const Slvs_Constraint& theConstraint);
+ /** \brief Removes the constraint by its ID. All entities and parameters depending on this
+ * constraint, which are not used in other constraints, will be removed too.
+ * \param[in] theConstraintID index of constraint to be removed
+ * \return \c true if the constraint was successfully removed
+ */
+ bool removeConstraint(const Slvs_hConstraint& theConstraintID);
+ /// \brief Returns the constraint by its ID
+ const Slvs_Constraint& getConstraint(const Slvs_hConstraint& theConstraintID) const;
+
+ /// \brief Attach temporary constraint to this storage. It need to make precise calculations
+ void addTemporaryConstraint(const Slvs_hConstraint& theConstraintID);
+
+ /// \brief Shows the sketch should be resolved
+ bool isNeedToResolve() const
+ { return myNeedToResolve; }
+
+ /// \brief Changes the flag of group to be resolved
+ void setNeedToResolve(bool theFlag)
+ { myNeedToResolve = theFlag; }
+
+ /// \brief Returns lists of removed elements
+ void getRemoved(std::set<Slvs_hParam>& theParameters,
+ std::set<Slvs_hEntity>& theEntities,
+ std::set<Slvs_hConstraint>& theConstraints);
+
+ /// \brief Initialize constraint solver by the entities collected by current storage
+ void initializeSolver(SketchSolver_Solver& theSolver);
+
+private:
+ Slvs_hParam myParamMaxID; ///< current parameter index (may differs with the number of parameters)
+ std::vector<Slvs_Param> myParameters; ///< list of parameters used in the current group of constraints
+ Slvs_hEntity myEntityMaxID; ///< current entity index (may differs with the number of entities)
+ std::vector<Slvs_Entity> myEntities; ///< list of entities used in the current group of constraints
+ Slvs_hConstraint myConstrMaxID; ///< current constraint index (may differs with the number of constraints)
+ std::vector<Slvs_Constraint> myConstraints; ///< list of constraints used in the current group
+
+ std::vector<Slvs_hEntity> myFixedPoints; ///< identifiers of entities which relate to temporary constraints
+
+ bool myNeedToResolve; ///< parameters are changed and group needs to be resolved
+
+ std::set<Slvs_hParam> myRemovedParameters; ///< list of just removed parameters (cleared when returning to applicant)
+ std::set<Slvs_hEntity> myRemovedEntities; ///< list of just removed entities (cleared when returning to applicant)
+ std::set<Slvs_hConstraint> myRemovedConstraints; ///< list of just removed constraints (cleared when returning to applicant)
+};
+
+typedef std::shared_ptr<SketchSolver_Storage> StoragePtr;
+
+#endif