1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
3 // File: SolveSpaceSolver_Builder.cpp
4 // Created: 25 Mar 2015
5 // Author: Artem ZHIDKOV
7 #include <SolveSpaceSolver_Builder.h>
8 #include <SolveSpaceSolver_Solver.h>
9 #include <SolveSpaceSolver_Storage.h>
10 #include <SolveSpaceSolver_ParameterWrapper.h>
11 #include <SolveSpaceSolver_EntityWrapper.h>
12 #include <SolveSpaceSolver_ConstraintWrapper.h>
13 #include <SolveSpaceSolver_ConstraintType.h>
15 #include <SketchSolver_Manager.h>
17 #include <GeomAPI_Angle2d.h>
18 #include <GeomAPI_Dir2d.h>
19 #include <GeomAPI_Pnt2d.h>
20 #include <GeomAPI_XY.h>
21 #include <GeomDataAPI_Dir.h>
22 #include <GeomDataAPI_Point.h>
23 #include <GeomDataAPI_Point2D.h>
24 #include <ModelAPI_Attribute.h>
25 #include <ModelAPI_AttributeRefAttr.h>
27 #include <SketchPlugin_Arc.h>
28 #include <SketchPlugin_Circle.h>
29 #include <SketchPlugin_Line.h>
30 #include <SketchPlugin_Point.h>
31 #include <SketchPlugin_IntersectionPoint.h>
32 #include <SketchPlugin_ConstraintAngle.h>
37 static EntityWrapperPtr createLine(FeaturePtr theFeature,
38 const std::list<EntityWrapperPtr>& theAttributes,
39 const GroupID& theGroupID,
40 const EntityID& theSketchID);
41 static EntityWrapperPtr createCircle(FeaturePtr theFeature,
42 const std::list<EntityWrapperPtr>& theAttributes,
43 const GroupID& theGroupID,
44 const EntityID& theSketchID);
45 static EntityWrapperPtr createArc(FeaturePtr theFeature,
46 const std::list<EntityWrapperPtr>& theAttributes,
47 const GroupID& theGroupID,
48 const EntityID& theSketchID);
50 /// \brief Set flags of constraint to identify which points are coincident in the Tangency
51 /// (for more information, see SolveSpace documentation)
52 static void adjustTangency(ConstraintWrapperPtr theConstraint);
53 /// \brief Set flags for angle constraint
54 static void adjustAngle(ConstraintWrapperPtr theConstraint);
55 /// \brief Update mirror points
56 static void adjustMirror(ConstraintWrapperPtr theConstraint);
57 /// \brief Update a sign of the point-line distance constraint
58 static void adjustPtLineDistance(ConstraintWrapperPtr theConstraint);
60 /// \brief Transform points to be symmetric regarding to the mirror line
61 static void makeMirrorPoints(EntityWrapperPtr theOriginal,
62 EntityWrapperPtr theMirrored,
63 EntityWrapperPtr theMirrorLine);
67 // Initialization of constraint builder self pointer
68 BuilderPtr SolveSpaceSolver_Builder::mySelf = SolveSpaceSolver_Builder::getInstance();
70 BuilderPtr SolveSpaceSolver_Builder::getInstance()
73 mySelf = BuilderPtr(new SolveSpaceSolver_Builder);
74 SketchSolver_Manager::instance()->setBuilder(mySelf);
79 StoragePtr SolveSpaceSolver_Builder::createStorage(const GroupID& theGroup) const
81 return StoragePtr(new SolveSpaceSolver_Storage(theGroup));
84 SolverPtr SolveSpaceSolver_Builder::createSolver() const
86 return SolverPtr(new SolveSpaceSolver_Solver);
90 std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createConstraint(
91 ConstraintPtr theConstraint,
92 const GroupID& theGroupID,
93 const EntityID& theSketchID,
94 const SketchSolver_ConstraintType& theType,
95 const double& theValue,
96 const EntityWrapperPtr& thePoint1,
97 const EntityWrapperPtr& thePoint2,
98 const EntityWrapperPtr& theEntity1,
99 const EntityWrapperPtr& theEntity2) const
101 if (theType == CONSTRAINT_SYMMETRIC)
102 return createMirror(theConstraint, theGroupID, theSketchID,
103 thePoint1, thePoint2, theEntity1);
104 else if (theType == CONSTRAINT_TANGENT_CIRCLE_LINE) {
105 // replace by distance from center of circle to the line
106 const std::list<EntityWrapperPtr>& aSubs = theEntity1->subEntities();
107 EntityWrapperPtr aCenter = aSubs.front();
108 AttributeDoublePtr aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
109 aSubs.back()->baseAttribute());
110 return createConstraint(theConstraint, theGroupID, theSketchID,
111 CONSTRAINT_PT_LINE_DISTANCE, aRadius->value(), aCenter, EntityWrapperPtr(), theEntity2);
113 else if (theType == CONSTRAINT_COLLINEAR) {
114 // replace by two constraints point-on-line
115 std::list<ConstraintWrapperPtr> aConstraints;
116 const std::list<EntityWrapperPtr>& aSubs1 = theEntity1->subEntities();
117 const std::list<EntityWrapperPtr>& aSubs2 = theEntity2->subEntities();
118 std::list<EntityWrapperPtr>::const_iterator anIt1, anIt2;
119 for (anIt2 = aSubs2.begin(); anIt2 != aSubs2.end(); ++anIt2) {
120 for (anIt1 = aSubs1.begin(); anIt1 != aSubs1.end(); ++anIt1)
121 if ((*anIt1)->id() == (*anIt2)->id())
123 if (anIt1 != aSubs1.end())
124 continue; // the lines have coincident point
126 std::list<ConstraintWrapperPtr> aC = createConstraint(theConstraint, theGroupID,
127 theSketchID, CONSTRAINT_PT_ON_LINE, theValue, *anIt2, EntityWrapperPtr(), theEntity1);
128 aConstraints.insert(aConstraints.end(), aC.begin(), aC.end());
133 int aType = ConstraintType::toSolveSpace(theType);
134 if (aType == SLVS_C_UNKNOWN)
135 return std::list<ConstraintWrapperPtr>();
137 Slvs_hEntity aSlvsEntities[4] = {SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN};
138 EntityWrapperPtr anOriginal[4] = {thePoint1, thePoint2, theEntity1, theEntity2};
139 std::list<EntityWrapperPtr> aConstrAttrList; // to be filled
140 for (int i = 0; i < 4; ++i) {
143 aSlvsEntities[i] = (Slvs_hEntity)anOriginal[i]->id();
144 if (aSlvsEntities[i] == SLVS_E_UNKNOWN)
145 return std::list<ConstraintWrapperPtr>(); // entity is not added into a storage, constraint can not be created
146 aConstrAttrList.push_back(anOriginal[i]);
149 Slvs_Constraint aConstraint = Slvs_MakeConstraint(
150 SLVS_C_UNKNOWN, (Slvs_hGroup)theGroupID, aType, (Slvs_hEntity)theSketchID,
151 theValue, aSlvsEntities[0], aSlvsEntities[1], aSlvsEntities[2], aSlvsEntities[3]);
152 ConstraintWrapperPtr aResult(new SolveSpaceSolver_ConstraintWrapper(theConstraint, aConstraint));
153 aResult->setGroup(theGroupID);
154 aResult->setValue(theValue);
155 aResult->setEntities(aConstrAttrList);
156 adjustConstraint(aResult);
158 return std::list<ConstraintWrapperPtr>(1, aResult);
161 std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createConstraint(
162 ConstraintPtr theConstraint,
163 const GroupID& theGroupID,
164 const EntityID& theSketchID,
165 const SketchSolver_ConstraintType& theType,
166 const double& theValue,
167 const bool theFullValue,
168 const EntityWrapperPtr& thePoint1,
169 const EntityWrapperPtr& thePoint2,
170 const std::list<EntityWrapperPtr>& theTrsfEnt) const
172 if (theType != CONSTRAINT_MULTI_ROTATION && theType != CONSTRAINT_MULTI_TRANSLATION)
173 return std::list<ConstraintWrapperPtr>();
175 int aType = ConstraintType::toSolveSpace(theType);
176 if (aType == SLVS_C_UNKNOWN)
177 return std::list<ConstraintWrapperPtr>();
179 Slvs_Constraint aConstraint =
180 Slvs_MakeConstraint(SLVS_C_UNKNOWN, (Slvs_hGroup)theGroupID, aType, (Slvs_hEntity)theSketchID,
181 theValue, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
183 std::list<EntityWrapperPtr> aConstrAttrList = theTrsfEnt;
185 aConstrAttrList.push_front(thePoint2);
186 aConstrAttrList.push_front(thePoint1);
188 ConstraintWrapperPtr aResult(new SolveSpaceSolver_ConstraintWrapper(theConstraint, aConstraint));
189 aResult->setGroup(theGroupID);
190 aResult->setValue(theValue);
191 aResult->setIsFullValue(theFullValue);
192 aResult->setEntities(aConstrAttrList);
193 return std::list<ConstraintWrapperPtr>(1, aResult);
197 std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createMirror(
198 ConstraintPtr theConstraint,
199 const GroupID& theGroupID,
200 const EntityID& theSketchID,
201 const EntityWrapperPtr& theEntity1,
202 const EntityWrapperPtr& theEntity2,
203 const EntityWrapperPtr& theMirrorLine) const
205 Slvs_Constraint aConstraint;
206 std::list<ConstraintWrapperPtr> aResult;
207 std::list<EntityWrapperPtr> aConstrAttrList;
208 if (theEntity1->type() == ENTITY_POINT) {
209 if (theEntity2->group() == theGroupID) // theEntity2 is not fixed
210 makeMirrorPoints(theEntity1, theEntity2, theMirrorLine);
212 aConstraint = Slvs_MakeConstraint(
213 SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID, SLVS_C_SYMMETRIC_LINE, (Slvs_hEntity)theSketchID,
214 0.0, (Slvs_hEntity)theEntity1->id(), (Slvs_hEntity)theEntity2->id(),
215 (Slvs_hEntity)theMirrorLine->id(), SLVS_E_UNKNOWN);
217 aConstrAttrList.push_back(theEntity1);
218 aConstrAttrList.push_back(theEntity2);
219 aConstrAttrList.push_back(theMirrorLine);
221 ConstraintWrapperPtr aWrapper(new SolveSpaceSolver_ConstraintWrapper(
222 theConstraint, aConstraint));
223 aWrapper->setGroup(theGroupID);
224 aWrapper->setEntities(aConstrAttrList);
225 aResult.push_back(aWrapper);
227 else if (theEntity1->type() == ENTITY_LINE) {
228 const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
229 const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
230 std::list<EntityWrapperPtr>::const_iterator anIt1 = aPoints1.begin();
231 std::list<EntityWrapperPtr>::const_iterator anIt2 = aPoints2.begin();
232 for (; anIt1 != aPoints1.end() && anIt2 != aPoints2.end(); ++anIt1, ++anIt2) {
233 std::list<ConstraintWrapperPtr> aMrrList =
234 createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
235 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
238 else if (theEntity1->type() == ENTITY_CIRCLE) {
239 const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
240 std::list<EntityWrapperPtr>::const_iterator anIt1 = aPoints1.begin();
241 for (; anIt1 != aPoints1.end(); ++anIt1)
242 if ((*anIt1)->type() == ENTITY_POINT)
244 const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
245 std::list<EntityWrapperPtr>::const_iterator anIt2 = aPoints2.begin();
246 for (; anIt2 != aPoints2.end(); ++anIt2)
247 if ((*anIt2)->type() == ENTITY_POINT)
250 std::list<ConstraintWrapperPtr> aMrrList =
251 createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
252 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
254 // Additional constraint for equal radii
255 aMrrList = createConstraint(theConstraint, theGroupID, theSketchID, CONSTRAINT_EQUAL_RADIUS,
256 0.0, EntityWrapperPtr(), EntityWrapperPtr(), theEntity1, theEntity2);
257 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
259 else if (theEntity1->type() == ENTITY_ARC) {
260 // Do not allow mirrored arc recalculate its position until coordinated of all points recalculated
261 FeaturePtr aMirrArc = theEntity2->baseFeature();
262 aMirrArc->data()->blockSendAttributeUpdated(true);
264 std::list<ConstraintWrapperPtr> aMrrList;
265 std::list<EntityWrapperPtr>::const_iterator anIt1 = theEntity1->subEntities().begin();
266 std::list<EntityWrapperPtr>::const_iterator anIt2 = theEntity2->subEntities().begin();
267 if ((*anIt2)->group() == theGroupID) // mirrored point is not fixed
268 makeMirrorPoints(*anIt1, *anIt2, theMirrorLine);
270 // Workaround to avoid problems in SolveSpace.
271 // The symmetry of two arcs will be done using symmetry of three points on these arcs:
272 // start point, end point, and any other point on the arc
273 std::list<EntityWrapperPtr> aBaseArcPoints(++anIt1, theEntity1->subEntities().end());
274 std::list<EntityWrapperPtr> aMirrorArcPoints(++anIt2, theEntity2->subEntities().end());
275 // indices of points of arc, center corresponds center, first point corresponds last point
276 aMirrorArcPoints.reverse();
278 anIt1 = aBaseArcPoints.begin();
279 anIt2 = aMirrorArcPoints.begin();
280 for (; anIt1 != aBaseArcPoints.end(); ++anIt1, ++anIt2) {
281 aMrrList = createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
282 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
284 // Restore event sending
285 aMirrArc->data()->blockSendAttributeUpdated(false);
290 void SolveSpaceSolver_Builder::adjustConstraint(ConstraintWrapperPtr theConstraint) const
292 SketchSolver_ConstraintType aType = theConstraint->type();
293 // Update flags in constraints
294 if (aType == CONSTRAINT_TANGENT_ARC_ARC || aType == CONSTRAINT_TANGENT_ARC_LINE)
295 adjustTangency(theConstraint);
296 else if (aType == CONSTRAINT_ANGLE)
297 adjustAngle(theConstraint);
298 else if (aType == CONSTRAINT_SYMMETRIC)
299 adjustMirror(theConstraint);
300 else if (aType == CONSTRAINT_PT_LINE_DISTANCE)
301 adjustPtLineDistance(theConstraint);
304 EntityWrapperPtr SolveSpaceSolver_Builder::createFeature(
305 FeaturePtr theFeature,
306 const std::list<EntityWrapperPtr>& theAttributes,
307 const GroupID& theGroupID,
308 const EntityID& theSketchID) const
310 static EntityWrapperPtr aDummy;
311 if (!theFeature->data()->isValid())
315 CompositeFeaturePtr aSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
317 return createSketchEntity(aSketch, theGroupID);
319 // SketchPlugin features
320 std::shared_ptr<SketchPlugin_Feature> aFeature =
321 std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
325 // Verify the feature by its kind
326 const std::string& aFeatureKind = aFeature->getKind();
328 if (aFeatureKind == SketchPlugin_Line::ID())
329 return createLine(theFeature, theAttributes, theGroupID, theSketchID);
331 else if (aFeatureKind == SketchPlugin_Circle::ID())
332 return createCircle(theFeature, theAttributes, theGroupID, theSketchID);
334 else if (aFeatureKind == SketchPlugin_Arc::ID())
335 return createArc(theFeature, theAttributes, theGroupID, theSketchID);
336 // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
337 else if (aFeatureKind == SketchPlugin_Point::ID() ||
338 aFeatureKind == SketchPlugin_IntersectionPoint::ID()) {
339 AttributePtr aPoint = theFeature->attribute(SketchPlugin_Point::COORD_ID());
340 if (!aPoint->isInitialized())
342 EntityWrapperPtr aSub = theAttributes.empty() ? createAttribute(aPoint, theGroupID, theSketchID) :
343 theAttributes.front();
347 const Slvs_Entity& aSubEnt =
348 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(aSub)->entity();
349 EntityWrapperPtr aResult(new SolveSpaceSolver_EntityWrapper(theFeature, aPoint, aSubEnt));
350 aResult->setSubEntities(theAttributes);
358 EntityWrapperPtr SolveSpaceSolver_Builder::createAttribute(
359 AttributePtr theAttribute,
360 const GroupID& theGroupID,
361 const EntityID& theSketchID) const
363 AttributePtr anAttribute = theAttribute;
364 AttributeRefAttrPtr aRefAttr =
365 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
367 if (aRefAttr->isObject()) {
368 // do not create features here
369 return EntityWrapperPtr();
371 anAttribute = aRefAttr->attr();
374 std::list<ParameterWrapperPtr> aParameters;
375 Slvs_Entity anEntity;
379 std::shared_ptr<GeomDataAPI_Point> aPoint =
380 std::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
382 aParameters.push_back(createParameter(theGroupID, aPoint->x(), !aPoint->textX().empty()));
383 aParameters.push_back(createParameter(theGroupID, aPoint->y(), !aPoint->textY().empty()));
384 aParameters.push_back(createParameter(theGroupID, aPoint->z(), !aPoint->textZ().empty()));
385 // Create entity (parameters are not filled)
386 anEntity = Slvs_MakePoint3d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
387 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
390 std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
391 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
393 aParameters.push_back(createParameter(theGroupID, aPoint2D->x(), !aPoint2D->textX().empty()));
394 aParameters.push_back(createParameter(theGroupID, aPoint2D->y(), !aPoint2D->textY().empty()));
395 // Create entity (parameters are not filled)
396 anEntity = Slvs_MakePoint2d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
397 (Slvs_hEntity)theSketchID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
399 // Scalar value (used for the distance entities)
400 AttributeDoublePtr aScalar =
401 std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
403 aParameters.push_back(createParameter(theGroupID, aScalar->value(), !aScalar->text().empty()));
404 // Create entity (parameter is not filled)
405 anEntity = Slvs_MakeDistance(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
406 (Slvs_hEntity)theSketchID, SLVS_E_UNKNOWN);
411 if (anEntity.type == 0) {
412 // unknown attribute type
413 return EntityWrapperPtr();
416 EntityWrapperPtr aResult(new SolveSpaceSolver_EntityWrapper(theAttribute, anEntity));
417 aResult->setParameters(aParameters);
423 EntityWrapperPtr SolveSpaceSolver_Builder::createSketchEntity(
424 CompositeFeaturePtr theSketch,
425 const GroupID& theGroupID) const
427 DataPtr aSketchData = theSketch->data();
428 if (!aSketchData || !aSketchData->isValid())
429 return EntityWrapperPtr(); // the sketch is incorrect
431 // Get parameters of workplane
432 AttributePtr aDirX = aSketchData->attribute(SketchPlugin_Sketch::DIRX_ID());
433 AttributePtr aNorm = aSketchData->attribute(SketchPlugin_Sketch::NORM_ID());
434 AttributePtr anOrigin = aSketchData->attribute(SketchPlugin_Sketch::ORIGIN_ID());
435 if (!anOrigin->isInitialized() || !aNorm->isInitialized() || !aDirX->isInitialized())
436 return EntityWrapperPtr();
438 EntityWrapperPtr aNewEnt;
439 std::list<EntityWrapperPtr> aSubs;
441 // Create SolveSpace entity corresponding to the sketch origin
442 aNewEnt = createAttribute(anOrigin, theGroupID);
444 return EntityWrapperPtr();
445 aSubs.push_back(aNewEnt);
447 // Create SolveSpace entity corresponding the the sketch normal
448 aNewEnt = createNormal(aNorm, aDirX, theGroupID);
450 return EntityWrapperPtr();
451 aSubs.push_back(aNewEnt);
454 Slvs_Entity aWorkplane = Slvs_MakeWorkplane(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
455 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
457 aNewEnt = EntityWrapperPtr(
458 new SolveSpaceSolver_EntityWrapper(FeaturePtr(theSketch), aWorkplane));
459 aNewEnt->setSubEntities(aSubs);
463 EntityWrapperPtr SolveSpaceSolver_Builder::createNormal(
464 AttributePtr theNormal,
465 AttributePtr theDirX,
466 const GroupID& theGroupID) const
468 std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theNormal);
469 std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
470 if (!aDirX || !aNorm ||
471 (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance) ||
472 !aNorm->isInitialized())
473 return EntityWrapperPtr();
474 // calculate Y direction
475 std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aDirX->dir())));
477 // quaternion parameters of normal vector
478 double qw, qx, qy, qz;
479 Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), aDirY->x(), aDirY->y(), aDirY->z(), &qw,
481 double aNormCoord[4] = { qw, qx, qy, qz };
483 // Create parameters of the normal
484 std::list<ParameterWrapperPtr> aParameters;
485 for (int i = 0; i < 4; i++)
486 aParameters.push_back(createParameter(theGroupID, aNormCoord[i]));
488 // Create a normal with empty parameters
489 Slvs_Entity aNormalEnt = Slvs_MakeNormal3d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
490 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
491 EntityWrapperPtr aNormal(new SolveSpaceSolver_EntityWrapper(theNormal, aNormalEnt));
492 aNormal->setParameters(aParameters);
496 ParameterWrapperPtr SolveSpaceSolver_Builder::createParameter(
497 const GroupID& theGroup, const double theValue, const bool theExpr) const
499 Slvs_Param aParam = Slvs_MakeParam(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroup, theValue);
500 ParameterWrapperPtr aWrapper(new SolveSpaceSolver_ParameterWrapper(aParam));
501 aWrapper->setIsParametric(theExpr);
509 // ================ Auxiliary functions ==========================
510 EntityWrapperPtr createLine(FeaturePtr theFeature,
511 const std::list<EntityWrapperPtr>& theAttributes,
512 const GroupID& theGroupID,
513 const EntityID& theSketchID)
515 EntityWrapperPtr aNewEntity;
516 std::list<EntityWrapperPtr> aSubs;
518 AttributePtr aStart = theFeature->attribute(SketchPlugin_Line::START_ID());
519 AttributePtr aEnd = theFeature->attribute(SketchPlugin_Line::END_ID());
520 if (!aStart->isInitialized() || !aEnd->isInitialized())
523 EntityWrapperPtr aStartEnt, aEndEnt;
524 std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
525 for (; anIt != theAttributes.end(); ++anIt) {
526 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
527 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
528 if (aSlvsEntity->isBase(aStart))
529 aStartEnt = aSlvsEntity;
530 else if (aSlvsEntity->isBase(aEnd))
531 aEndEnt = aSlvsEntity;
533 if (!aStartEnt || !aEndEnt)
536 aSubs.push_back(aStartEnt);
537 aSubs.push_back(aEndEnt);
538 Slvs_Entity anEntity = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
539 (Slvs_hEntity)theSketchID, (Slvs_hEntity)aStartEnt->id(), (Slvs_hEntity)aEndEnt->id());
541 aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
542 aNewEntity->setSubEntities(aSubs);
546 EntityWrapperPtr createCircle(FeaturePtr theFeature,
547 const std::list<EntityWrapperPtr>& theAttributes,
548 const GroupID& theGroupID,
549 const EntityID& theSketchID)
551 EntityWrapperPtr aNewEntity;
552 std::list<EntityWrapperPtr> aSubs;
554 AttributePtr aCenter = theFeature->attribute(SketchPlugin_Circle::CENTER_ID());
555 AttributePtr aRadius = theFeature->attribute(SketchPlugin_Circle::RADIUS_ID());
556 if (!aCenter->isInitialized() || !aRadius->isInitialized())
559 EntityWrapperPtr aCenterEnt, aRadiusEnt, aNormalEnt;
560 std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
561 for (; anIt != theAttributes.end(); ++anIt) {
562 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
563 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
564 if (aSlvsEntity->isBase(aCenter))
565 aCenterEnt = aSlvsEntity;
566 else if (aSlvsEntity->isBase(aRadius))
567 aRadiusEnt = aSlvsEntity;
568 else if (aSlvsEntity->type() == ENTITY_NORMAL)
569 aNormalEnt = aSlvsEntity;
571 if (!aCenterEnt || !aRadiusEnt || !aNormalEnt)
574 aSubs.push_back(aCenterEnt);
575 aSubs.push_back(aRadiusEnt);
576 Slvs_Entity anEntity = Slvs_MakeCircle(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
577 (Slvs_hEntity)theSketchID, (Slvs_hEntity)aCenterEnt->id(),
578 (Slvs_hEntity)aNormalEnt->id(), (Slvs_hEntity)aRadiusEnt->id());
580 aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
581 aNewEntity->setSubEntities(aSubs);
585 EntityWrapperPtr createArc(FeaturePtr theFeature,
586 const std::list<EntityWrapperPtr>& theAttributes,
587 const GroupID& theGroupID,
588 const EntityID& theSketchID)
590 EntityWrapperPtr aNewEntity;
591 std::list<EntityWrapperPtr> aSubs;
593 AttributePtr aCenter = theFeature->attribute(SketchPlugin_Arc::CENTER_ID());
594 AttributePtr aStart = theFeature->attribute(SketchPlugin_Arc::START_ID());
595 AttributePtr aEnd = theFeature->attribute(SketchPlugin_Arc::END_ID());
596 if (!aCenter->isInitialized() || !aStart->isInitialized() || !aEnd->isInitialized())
599 EntityWrapperPtr aCenterEnt, aStartEnt, aEndEnt, aNormalEnt;
600 std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
601 for (; anIt != theAttributes.end(); ++anIt) {
602 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
603 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
604 if (aSlvsEntity->isBase(aCenter))
605 aCenterEnt = aSlvsEntity;
606 else if (aSlvsEntity->isBase(aStart))
607 aStartEnt = aSlvsEntity;
608 else if (aSlvsEntity->isBase(aEnd))
609 aEndEnt = aSlvsEntity;
610 else if (aSlvsEntity->type() == ENTITY_NORMAL)
611 aNormalEnt = aSlvsEntity;
613 if (!aCenterEnt || !aStartEnt || !aEndEnt || !aNormalEnt)
616 aSubs.push_back(aCenterEnt);
617 aSubs.push_back(aStartEnt);
618 aSubs.push_back(aEndEnt);
619 Slvs_Entity anEntity = Slvs_MakeArcOfCircle(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
620 (Slvs_hEntity)theSketchID, (Slvs_hEntity)aNormalEnt->id(),
621 (Slvs_hEntity)aCenterEnt->id(), (Slvs_hEntity)aStartEnt->id(), (Slvs_hEntity)aEndEnt->id());
623 aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
624 aNewEntity->setSubEntities(aSubs);
629 void adjustTangency(ConstraintWrapperPtr theConstraint)
631 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
633 std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
634 std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
636 // Collect start, end points of entities
637 std::shared_ptr<GeomAPI_Pnt2d> aStartEntPoints[2][2];
638 bool isCoinc[2][2] = {false};
639 const std::list<EntityWrapperPtr>& aSubs = aConstraint->entities();
640 std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
641 for (int i = 0; aSIt != aSubs.end(); ++aSIt, ++i) {
642 const std::list<EntityWrapperPtr>& aPoints = (*aSIt)->subEntities();
643 std::list<EntityWrapperPtr>::const_iterator aPIt = aPoints.begin();
644 if ((*aSIt)->type() == ENTITY_ARC)
646 for (int j = 0; aPIt != aPoints.end(); ++aPIt, ++j) {
647 aStartEntPoints[i][j] = aBuilder->point(*aPIt);
648 if (i > 0) { // check coincidence
649 for (int k = 0; k < 2; ++k)
650 if (aStartEntPoints[i][j]->distance(aStartEntPoints[0][k]) < tolerance)
651 isCoinc[0][k] = isCoinc[i][j] = true;
656 Slvs_Constraint& aSlvsConstraint = aConstraint->changeConstraint();
657 if (isCoinc[0][0] == false && isCoinc[0][1] == true)
658 aSlvsConstraint.other = 1;
659 else aSlvsConstraint.other = 0;
660 if (isCoinc[1][0] == false && isCoinc[1][1] == true)
661 aSlvsConstraint.other2 = 1;
662 else aSlvsConstraint.other2 = 0;
665 void adjustAngle(ConstraintWrapperPtr theConstraint)
667 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
669 std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
670 std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
673 std::shared_ptr<GeomAPI_Pnt2d> aPoints[2][2]; // start and end points of lines
674 const std::list<EntityWrapperPtr>& aConstrLines = aConstraint->entities();
675 std::list<EntityWrapperPtr>::const_iterator aCLIt = aConstrLines.begin();
676 for (int i = 0; aCLIt != aConstrLines.end(); ++i, ++aCLIt) {
677 const std::list<EntityWrapperPtr>& aLinePoints = (*aCLIt)->subEntities();
678 std::list<EntityWrapperPtr>::const_iterator aLPIt = aLinePoints.begin();
679 for (int j = 0; aLPIt != aLinePoints.end(); ++j, ++aLPIt) {
680 isFixed[i][j] = ((*aLPIt)->group() != theConstraint->group());
681 aPoints[i][j] = aBuilder->point(*aLPIt);
685 if (isFixed[0][0] && isFixed[0][1] && isFixed[1][0] && isFixed[1][1])
686 return; // both lines are fixed => no need to update them
688 std::shared_ptr<GeomAPI_Lin2d> aLine[2] = {
689 std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[0][0], aPoints[0][1])),
690 std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[1][0], aPoints[1][1]))
692 bool isReversed[2] = {
693 aConstraint->baseConstraint()->boolean(
694 SketchPlugin_ConstraintAngle::ANGLE_REVERSED_FIRST_LINE_ID())->value(),
695 aConstraint->baseConstraint()->boolean(
696 SketchPlugin_ConstraintAngle::ANGLE_REVERSED_SECOND_LINE_ID())->value()
698 std::shared_ptr<GeomAPI_Angle2d> anAngle(new GeomAPI_Angle2d(aLine[0], isReversed[0], aLine[1], isReversed[1]));
699 std::shared_ptr<GeomAPI_Pnt2d> aCenter = anAngle->center();
701 std::shared_ptr<GeomAPI_Dir2d> aDir[2];
703 Slvs_Constraint& aSlvsConstraint = aConstraint->changeConstraint();
704 aSlvsConstraint.other = false;
705 for (int i = 0; i < 2; i++) {
706 aDir[i] = aLine[i]->direction();
708 aSlvsConstraint.other = !aSlvsConstraint.other;
714 for (int i = 0; i < 2; i++) {
715 for (int j = 0; j < 2; j++) {
716 aDist[i][j] = aDir[i]->xy()->dot(aPoints[i][j]->xy()->decreased(aCenter->xy()));
717 if (fabs(aDist[i][j]) <= tolerance)
722 // Recalculate positions of lines to avoid conflicting constraints
723 // while changing angle value several times
724 double cosA = cos(aConstraint->value() * PI / 180.0);
725 double sinA = sin(aConstraint->value() * PI / 180.0);
726 //if (aDir[0]->cross(aDir[1]) < 0.0)
729 if (isFixed[1][0] && isFixed[1][1]) {
733 double x = aDir[1-aLineToUpd]->x() * cosA - aDir[1-aLineToUpd]->y() * sinA;
734 double y = aDir[1-aLineToUpd]->x() * sinA + aDir[1-aLineToUpd]->y() * cosA;
736 std::shared_ptr<GeomAPI_Pnt2d> aNewPoints[2];
737 for (int i = 0; i < 2; i++) {
738 aNewPoints[i] = std::shared_ptr<GeomAPI_Pnt2d>(
739 new GeomAPI_Pnt2d(aCenter->x() + x * aDist[aLineToUpd][i],
740 aCenter->y() + y * aDist[aLineToUpd][i]));
743 std::shared_ptr<GeomAPI_XY> aDelta;
744 if (isFixed[aLineToUpd][0] && !isFixed[aLineToUpd][1])
745 aDelta = aPoints[aLineToUpd][0]->xy()->decreased(aNewPoints[0]->xy());
746 else if (!isFixed[aLineToUpd][0] && isFixed[aLineToUpd][1])
747 aDelta = aPoints[aLineToUpd][1]->xy()->decreased(aNewPoints[1]->xy());
749 for (int i = 0; i < 2; i++) {
750 aNewPoints[i]->setX(aNewPoints[i]->x() + aDelta->x());
751 aNewPoints[i]->setY(aNewPoints[i]->y() + aDelta->y());
755 // Update positions of points
756 std::list<EntityWrapperPtr>::const_iterator anUpdLine = aConstrLines.begin();
757 if (aLineToUpd > 0) ++anUpdLine;
758 const std::list<EntityWrapperPtr>& anUpdPoints = (*anUpdLine)->subEntities();
759 std::list<EntityWrapperPtr>::const_iterator aPIt = anUpdPoints.begin();
760 for (int i = 0; aPIt != anUpdPoints.end(); ++aPIt, ++i) {
761 std::shared_ptr<GeomDataAPI_Point2D> aPnt2D =
762 std::dynamic_pointer_cast<GeomDataAPI_Point2D>((*aPIt)->baseAttribute());
763 aPnt2D->setValue(aNewPoints[i]);
767 void adjustMirror(ConstraintWrapperPtr theConstraint)
769 std::vector<EntityWrapperPtr> aPoints;
770 EntityWrapperPtr aMirrorLine;
772 const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
773 std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
774 for (; anIt != aSubs.end(); ++anIt) {
775 if ((*anIt)->type() == ENTITY_POINT)
776 aPoints.push_back(*anIt);
777 else if ((*anIt)->type() == ENTITY_LINE)
781 makeMirrorPoints(aPoints[0], aPoints[1], aMirrorLine);
784 void makeMirrorPoints(EntityWrapperPtr theOriginal,
785 EntityWrapperPtr theMirrored,
786 EntityWrapperPtr theMirrorLine)
788 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
790 std::shared_ptr<GeomAPI_Lin2d> aMirrorLine = aBuilder->line(theMirrorLine);
791 std::shared_ptr<GeomAPI_Dir2d> aMLDir = aMirrorLine->direction();
792 // orthogonal direction
793 aMLDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aMLDir->y(), -aMLDir->x()));
795 std::shared_ptr<GeomAPI_Pnt2d> aPoint = aBuilder->point(theOriginal);
796 std::shared_ptr<GeomAPI_XY> aVec = aPoint->xy()->decreased(aMirrorLine->location()->xy());
797 double aDist = aVec->dot(aMLDir->xy());
798 aVec = aPoint->xy()->added(aMLDir->xy()->multiplied(-2.0 * aDist));
799 double aCoord[2] = {aVec->x(), aVec->y()};
800 std::list<ParameterWrapperPtr>::const_iterator aMIt = theMirrored->parameters().begin();
801 for (int i = 0; aMIt != theMirrored->parameters().end(); ++aMIt, ++i)
802 (*aMIt)->setValue(aCoord[i]);
804 // update corresponding attribute
805 AttributePtr anAttr = std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theMirrored)->baseAttribute();
807 std::shared_ptr<GeomDataAPI_Point2D> aMirroredPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
808 aMirroredPnt->setValue(aCoord[0], aCoord[1]);
812 void adjustPtLineDistance(ConstraintWrapperPtr theConstraint)
814 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
816 std::shared_ptr<GeomAPI_Pnt2d> aPoint;
817 std::shared_ptr<GeomAPI_Lin2d> aLine;
818 std::list<EntityWrapperPtr> aSubs = theConstraint->entities();
819 std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
820 for (; aSIt != aSubs.end(); ++aSIt) {
821 if ((*aSIt)->type() == ENTITY_POINT)
822 aPoint = aBuilder->point(*aSIt);
823 else if ((*aSIt)->type() == ENTITY_LINE)
824 aLine = aBuilder->line(*aSIt);
827 std::shared_ptr<GeomAPI_XY> aLineVec = aLine->direction()->xy();
828 std::shared_ptr<GeomAPI_XY> aPtLineVec = aPoint->xy()->decreased(aLine->location()->xy());
829 if (aPtLineVec->cross(aLineVec) * theConstraint->value() < 0.0)
830 theConstraint->setValue(theConstraint->value() * (-1.0));