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_Dir2d.h>
18 #include <GeomAPI_Pnt2d.h>
19 #include <GeomAPI_XY.h>
20 #include <GeomDataAPI_Dir.h>
21 #include <GeomDataAPI_Point.h>
22 #include <GeomDataAPI_Point2D.h>
23 #include <ModelAPI_Attribute.h>
24 #include <ModelAPI_AttributeRefAttr.h>
26 #include <SketchPlugin_Arc.h>
27 #include <SketchPlugin_Circle.h>
28 #include <SketchPlugin_Line.h>
29 #include <SketchPlugin_Point.h>
34 static EntityWrapperPtr createLine(FeaturePtr theFeature,
35 const std::list<EntityWrapperPtr>& theAttributes,
36 const GroupID& theGroupID,
37 const EntityID& theSketchID);
38 static EntityWrapperPtr createCircle(FeaturePtr theFeature,
39 const std::list<EntityWrapperPtr>& theAttributes,
40 const GroupID& theGroupID,
41 const EntityID& theSketchID);
42 static EntityWrapperPtr createArc(FeaturePtr theFeature,
43 const std::list<EntityWrapperPtr>& theAttributes,
44 const GroupID& theGroupID,
45 const EntityID& theSketchID);
47 /// \brief Set flags of constraint to identify which points are coincident in the Tangency
48 /// (for more information, see SolveSpace documentation)
49 static void adjustTangency(ConstraintWrapperPtr theConstraint);
50 /// \brief Set flags for angle constraint
51 static void adjustAngle(ConstraintWrapperPtr theConstraint);
52 /// \brief Update mirror points
53 static void adjustMirror(ConstraintWrapperPtr theConstraint);
54 /// \brief Update a sign of the point-line distance constraint
55 static void adjustPtLineDistance(ConstraintWrapperPtr theConstraint);
57 /// \brief Transform points to be symmetric regarding to the mirror line
58 static void makeMirrorPoints(EntityWrapperPtr theOriginal,
59 EntityWrapperPtr theMirrored,
60 EntityWrapperPtr theMirrorLine);
64 // Initialization of constraint builder self pointer
65 BuilderPtr SolveSpaceSolver_Builder::mySelf = SolveSpaceSolver_Builder::getInstance();
67 BuilderPtr SolveSpaceSolver_Builder::getInstance()
70 mySelf = BuilderPtr(new SolveSpaceSolver_Builder);
71 SketchSolver_Manager::instance()->setBuilder(mySelf);
76 StoragePtr SolveSpaceSolver_Builder::createStorage(const GroupID& theGroup) const
78 return StoragePtr(new SolveSpaceSolver_Storage(theGroup));
81 SolverPtr SolveSpaceSolver_Builder::createSolver() const
83 return SolverPtr(new SolveSpaceSolver_Solver);
87 std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createConstraint(
88 ConstraintPtr theConstraint,
89 const GroupID& theGroupID,
90 const EntityID& theSketchID,
91 const SketchSolver_ConstraintType& theType,
92 const double& theValue,
93 const EntityWrapperPtr& thePoint1,
94 const EntityWrapperPtr& thePoint2,
95 const EntityWrapperPtr& theEntity1,
96 const EntityWrapperPtr& theEntity2) const
98 if (theType == CONSTRAINT_SYMMETRIC)
99 return createMirror(theConstraint, theGroupID, theSketchID,
100 thePoint1, thePoint2, theEntity1);
101 else if (theType == CONSTRAINT_TANGENT_CIRCLE_LINE) {
102 // replace by distance from center of circle to the line
103 const std::list<EntityWrapperPtr>& aSubs = theEntity1->subEntities();
104 EntityWrapperPtr aCenter = aSubs.front();
105 AttributeDoublePtr aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
106 aSubs.back()->baseAttribute());
107 return createConstraint(theConstraint, theGroupID, theSketchID,
108 CONSTRAINT_PT_LINE_DISTANCE, aRadius->value(), aCenter, EntityWrapperPtr(), theEntity2);
111 int aType = ConstraintType::toSolveSpace(theType);
112 if (aType == SLVS_C_UNKNOWN)
113 return std::list<ConstraintWrapperPtr>();
115 Slvs_hEntity aSlvsEntities[4] = {SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN};
116 EntityWrapperPtr anOriginal[4] = {thePoint1, thePoint2, theEntity1, theEntity2};
117 std::list<EntityWrapperPtr> aConstrAttrList; // to be filled
118 for (int i = 0; i < 4; ++i) {
121 aSlvsEntities[i] = (Slvs_hEntity)anOriginal[i]->id();
122 if (aSlvsEntities[i] == SLVS_E_UNKNOWN)
123 return std::list<ConstraintWrapperPtr>(); // entity is not added into a storage, constraint can not be created
124 aConstrAttrList.push_back(anOriginal[i]);
127 Slvs_Constraint aConstraint = Slvs_MakeConstraint(
128 SLVS_C_UNKNOWN, (Slvs_hGroup)theGroupID, aType, (Slvs_hEntity)theSketchID,
129 theValue, aSlvsEntities[0], aSlvsEntities[1], aSlvsEntities[2], aSlvsEntities[3]);
130 ConstraintWrapperPtr aResult(new SolveSpaceSolver_ConstraintWrapper(theConstraint, aConstraint));
131 aResult->setGroup(theGroupID);
132 aResult->setValue(theValue);
133 aResult->setEntities(aConstrAttrList);
134 adjustConstraint(aResult);
136 return std::list<ConstraintWrapperPtr>(1, aResult);
139 std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createConstraint(
140 ConstraintPtr theConstraint,
141 const GroupID& theGroupID,
142 const EntityID& theSketchID,
143 const SketchSolver_ConstraintType& theType,
144 const double& theValue,
145 const bool theFullValue,
146 const EntityWrapperPtr& thePoint1,
147 const EntityWrapperPtr& thePoint2,
148 const std::list<EntityWrapperPtr>& theTrsfEnt) const
150 if (theType != CONSTRAINT_MULTI_ROTATION && theType != CONSTRAINT_MULTI_TRANSLATION)
151 return std::list<ConstraintWrapperPtr>();
153 int aType = ConstraintType::toSolveSpace(theType);
154 if (aType == SLVS_C_UNKNOWN)
155 return std::list<ConstraintWrapperPtr>();
157 Slvs_Constraint aConstraint =
158 Slvs_MakeConstraint(SLVS_C_UNKNOWN, (Slvs_hGroup)theGroupID, aType, (Slvs_hEntity)theSketchID,
159 theValue, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
161 std::list<EntityWrapperPtr> aConstrAttrList = theTrsfEnt;
163 aConstrAttrList.push_front(thePoint2);
164 aConstrAttrList.push_front(thePoint1);
166 ConstraintWrapperPtr aResult(new SolveSpaceSolver_ConstraintWrapper(theConstraint, aConstraint));
167 aResult->setGroup(theGroupID);
168 aResult->setValue(theValue);
169 aResult->setIsFullValue(theFullValue);
170 aResult->setEntities(aConstrAttrList);
171 return std::list<ConstraintWrapperPtr>(1, aResult);
175 std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createMirror(
176 ConstraintPtr theConstraint,
177 const GroupID& theGroupID,
178 const EntityID& theSketchID,
179 const EntityWrapperPtr& theEntity1,
180 const EntityWrapperPtr& theEntity2,
181 const EntityWrapperPtr& theMirrorLine) const
183 Slvs_Constraint aConstraint;
184 std::list<ConstraintWrapperPtr> aResult;
185 std::list<EntityWrapperPtr> aConstrAttrList;
186 if (theEntity1->type() == ENTITY_POINT) {
187 if (theEntity2->group() == theGroupID) // theEntity2 is not fixed
188 makeMirrorPoints(theEntity1, theEntity2, theMirrorLine);
190 aConstraint = Slvs_MakeConstraint(
191 SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID, SLVS_C_SYMMETRIC_LINE, (Slvs_hEntity)theSketchID,
192 0.0, (Slvs_hEntity)theEntity1->id(), (Slvs_hEntity)theEntity2->id(),
193 (Slvs_hEntity)theMirrorLine->id(), SLVS_E_UNKNOWN);
195 aConstrAttrList.push_back(theEntity1);
196 aConstrAttrList.push_back(theEntity2);
197 aConstrAttrList.push_back(theMirrorLine);
199 ConstraintWrapperPtr aWrapper(new SolveSpaceSolver_ConstraintWrapper(
200 theConstraint, aConstraint));
201 aWrapper->setGroup(theGroupID);
202 aWrapper->setEntities(aConstrAttrList);
203 aResult.push_back(aWrapper);
205 else if (theEntity1->type() == ENTITY_LINE) {
206 const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
207 const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
208 std::list<EntityWrapperPtr>::const_iterator anIt1 = aPoints1.begin();
209 std::list<EntityWrapperPtr>::const_iterator anIt2 = aPoints2.begin();
210 for (; anIt1 != aPoints1.end() && anIt2 != aPoints2.end(); ++anIt1, ++anIt2) {
211 std::list<ConstraintWrapperPtr> aMrrList =
212 createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
213 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
216 else if (theEntity1->type() == ENTITY_CIRCLE) {
217 const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
218 std::list<EntityWrapperPtr>::const_iterator anIt1 = aPoints1.begin();
219 for (; anIt1 != aPoints1.end(); ++anIt1)
220 if ((*anIt1)->type() == ENTITY_POINT)
222 const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
223 std::list<EntityWrapperPtr>::const_iterator anIt2 = aPoints2.begin();
224 for (; anIt2 != aPoints2.end(); ++anIt2)
225 if ((*anIt2)->type() == ENTITY_POINT)
228 std::list<ConstraintWrapperPtr> aMrrList =
229 createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
230 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
232 // Additional constraint for equal radii
233 aMrrList = createConstraint(theConstraint, theGroupID, theSketchID, CONSTRAINT_EQUAL_RADIUS,
234 0.0, EntityWrapperPtr(), EntityWrapperPtr(), theEntity1, theEntity2);
235 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
237 else if (theEntity1->type() == ENTITY_ARC) {
238 // Do not allow mirrored arc recalculate its position until coordinated of all points recalculated
239 FeaturePtr aMirrArc = theEntity2->baseFeature();
240 aMirrArc->data()->blockSendAttributeUpdated(true);
242 std::list<ConstraintWrapperPtr> aMrrList;
243 std::list<EntityWrapperPtr>::const_iterator anIt1 = theEntity1->subEntities().begin();
244 std::list<EntityWrapperPtr>::const_iterator anIt2 = theEntity2->subEntities().begin();
245 if ((*anIt2)->group() == theGroupID) // mirrored point is not fixed
246 makeMirrorPoints(*anIt1, *anIt2, theMirrorLine);
248 // Workaround to avoid problems in SolveSpace.
249 // The symmetry of two arcs will be done using symmetry of three points on these arcs:
250 // start point, end point, and any other point on the arc
251 std::list<EntityWrapperPtr> aBaseArcPoints(++anIt1, theEntity1->subEntities().end());
252 std::list<EntityWrapperPtr> aMirrorArcPoints(++anIt2, theEntity2->subEntities().end());
253 // indices of points of arc, center corresponds center, first point corresponds last point
254 aMirrorArcPoints.reverse();
256 anIt1 = aBaseArcPoints.begin();
257 anIt2 = aMirrorArcPoints.begin();
258 for (; anIt1 != aBaseArcPoints.end(); ++anIt1, ++anIt2) {
259 aMrrList = createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
260 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
262 // Restore event sending
263 aMirrArc->data()->blockSendAttributeUpdated(false);
268 void SolveSpaceSolver_Builder::adjustConstraint(ConstraintWrapperPtr theConstraint) const
270 SketchSolver_ConstraintType aType = theConstraint->type();
271 // Update flags in constraints
272 if (aType == CONSTRAINT_TANGENT_ARC_ARC || aType == CONSTRAINT_TANGENT_ARC_LINE)
273 adjustTangency(theConstraint);
274 else if (aType == CONSTRAINT_ANGLE)
275 adjustAngle(theConstraint);
276 else if (aType == CONSTRAINT_SYMMETRIC)
277 adjustMirror(theConstraint);
278 else if (aType == CONSTRAINT_PT_LINE_DISTANCE)
279 adjustPtLineDistance(theConstraint);
282 EntityWrapperPtr SolveSpaceSolver_Builder::createFeature(
283 FeaturePtr theFeature,
284 const std::list<EntityWrapperPtr>& theAttributes,
285 const GroupID& theGroupID,
286 const EntityID& theSketchID) const
288 static EntityWrapperPtr aDummy;
289 if (!theFeature->data()->isValid())
293 CompositeFeaturePtr aSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
295 return createSketchEntity(aSketch, theGroupID);
297 // SketchPlugin features
298 std::shared_ptr<SketchPlugin_Feature> aFeature =
299 std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
303 // Verify the feature by its kind
304 const std::string& aFeatureKind = aFeature->getKind();
306 if (aFeatureKind == SketchPlugin_Line::ID())
307 return createLine(theFeature, theAttributes, theGroupID, theSketchID);
309 else if (aFeatureKind == SketchPlugin_Circle::ID())
310 return createCircle(theFeature, theAttributes, theGroupID, theSketchID);
312 else if (aFeatureKind == SketchPlugin_Arc::ID())
313 return createArc(theFeature, theAttributes, theGroupID, theSketchID);
314 // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
315 else if (aFeatureKind == SketchPlugin_Point::ID()) {
316 AttributePtr aPoint = theFeature->attribute(SketchPlugin_Point::COORD_ID());
317 if (!aPoint->isInitialized())
319 EntityWrapperPtr aSub = theAttributes.empty() ? createAttribute(aPoint, theGroupID, theSketchID) :
320 theAttributes.front();
324 const Slvs_Entity& aSubEnt =
325 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(aSub)->entity();
326 EntityWrapperPtr aResult(new SolveSpaceSolver_EntityWrapper(theFeature, aPoint, aSubEnt));
327 aResult->setSubEntities(theAttributes);
335 EntityWrapperPtr SolveSpaceSolver_Builder::createAttribute(
336 AttributePtr theAttribute,
337 const GroupID& theGroupID,
338 const EntityID& theSketchID) const
340 AttributePtr anAttribute = theAttribute;
341 AttributeRefAttrPtr aRefAttr =
342 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
344 if (aRefAttr->isObject()) {
345 // do not create features here
346 return EntityWrapperPtr();
348 anAttribute = aRefAttr->attr();
351 std::list<ParameterWrapperPtr> aParameters;
352 Slvs_Entity anEntity;
356 std::shared_ptr<GeomDataAPI_Point> aPoint =
357 std::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
359 aParameters.push_back(createParameter(theGroupID, aPoint->x(), !aPoint->textX().empty()));
360 aParameters.push_back(createParameter(theGroupID, aPoint->y(), !aPoint->textY().empty()));
361 aParameters.push_back(createParameter(theGroupID, aPoint->z(), !aPoint->textZ().empty()));
362 // Create entity (parameters are not filled)
363 anEntity = Slvs_MakePoint3d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
364 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
367 std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
368 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
370 aParameters.push_back(createParameter(theGroupID, aPoint2D->x(), !aPoint2D->textX().empty()));
371 aParameters.push_back(createParameter(theGroupID, aPoint2D->y(), !aPoint2D->textY().empty()));
372 // Create entity (parameters are not filled)
373 anEntity = Slvs_MakePoint2d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
374 (Slvs_hEntity)theSketchID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
376 // Scalar value (used for the distance entities)
377 AttributeDoublePtr aScalar =
378 std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
380 aParameters.push_back(createParameter(theGroupID, aScalar->value(), !aScalar->text().empty()));
381 // Create entity (parameter is not filled)
382 anEntity = Slvs_MakeDistance(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
383 (Slvs_hEntity)theSketchID, SLVS_E_UNKNOWN);
388 if (anEntity.type == 0) {
389 // unknown attribute type
390 return EntityWrapperPtr();
393 EntityWrapperPtr aResult(new SolveSpaceSolver_EntityWrapper(theAttribute, anEntity));
394 aResult->setParameters(aParameters);
400 EntityWrapperPtr SolveSpaceSolver_Builder::createSketchEntity(
401 CompositeFeaturePtr theSketch,
402 const GroupID& theGroupID) const
404 DataPtr aSketchData = theSketch->data();
405 if (!aSketchData || !aSketchData->isValid())
406 return EntityWrapperPtr(); // the sketch is incorrect
408 // Get parameters of workplane
409 AttributePtr aDirX = aSketchData->attribute(SketchPlugin_Sketch::DIRX_ID());
410 AttributePtr aNorm = aSketchData->attribute(SketchPlugin_Sketch::NORM_ID());
411 AttributePtr anOrigin = aSketchData->attribute(SketchPlugin_Sketch::ORIGIN_ID());
412 if (!anOrigin->isInitialized() || !aNorm->isInitialized() || !aDirX->isInitialized())
413 return EntityWrapperPtr();
415 EntityWrapperPtr aNewEnt;
416 std::list<EntityWrapperPtr> aSubs;
418 // Create SolveSpace entity corresponding to the sketch origin
419 aNewEnt = createAttribute(anOrigin, theGroupID);
421 return EntityWrapperPtr();
422 aSubs.push_back(aNewEnt);
424 // Create SolveSpace entity corresponding the the sketch normal
425 aNewEnt = createNormal(aNorm, aDirX, theGroupID);
427 return EntityWrapperPtr();
428 aSubs.push_back(aNewEnt);
431 Slvs_Entity aWorkplane = Slvs_MakeWorkplane(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
432 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
434 aNewEnt = EntityWrapperPtr(
435 new SolveSpaceSolver_EntityWrapper(FeaturePtr(theSketch), aWorkplane));
436 aNewEnt->setSubEntities(aSubs);
440 EntityWrapperPtr SolveSpaceSolver_Builder::createNormal(
441 AttributePtr theNormal,
442 AttributePtr theDirX,
443 const GroupID& theGroupID) const
445 std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theNormal);
446 std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
447 if (!aDirX || !aNorm ||
448 (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance) ||
449 !aNorm->isInitialized())
450 return EntityWrapperPtr();
451 // calculate Y direction
452 std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aDirX->dir())));
454 // quaternion parameters of normal vector
455 double qw, qx, qy, qz;
456 Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), aDirY->x(), aDirY->y(), aDirY->z(), &qw,
458 double aNormCoord[4] = { qw, qx, qy, qz };
460 // Create parameters of the normal
461 std::list<ParameterWrapperPtr> aParameters;
462 for (int i = 0; i < 4; i++)
463 aParameters.push_back(createParameter(theGroupID, aNormCoord[i]));
465 // Create a normal with empty parameters
466 Slvs_Entity aNormalEnt = Slvs_MakeNormal3d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
467 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
468 EntityWrapperPtr aNormal(new SolveSpaceSolver_EntityWrapper(theNormal, aNormalEnt));
469 aNormal->setParameters(aParameters);
473 ParameterWrapperPtr SolveSpaceSolver_Builder::createParameter(
474 const GroupID& theGroup, const double theValue, const bool theExpr) const
476 Slvs_Param aParam = Slvs_MakeParam(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroup, theValue);
477 ParameterWrapperPtr aWrapper(new SolveSpaceSolver_ParameterWrapper(aParam));
478 aWrapper->setIsParametric(theExpr);
486 // ================ Auxiliary functions ==========================
487 EntityWrapperPtr createLine(FeaturePtr theFeature,
488 const std::list<EntityWrapperPtr>& theAttributes,
489 const GroupID& theGroupID,
490 const EntityID& theSketchID)
492 EntityWrapperPtr aNewEntity;
493 std::list<EntityWrapperPtr> aSubs;
495 AttributePtr aStart = theFeature->attribute(SketchPlugin_Line::START_ID());
496 AttributePtr aEnd = theFeature->attribute(SketchPlugin_Line::END_ID());
497 if (!aStart->isInitialized() || !aEnd->isInitialized())
500 EntityWrapperPtr aStartEnt, aEndEnt;
501 std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
502 for (; anIt != theAttributes.end(); ++anIt) {
503 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
504 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
505 if (aSlvsEntity->isBase(aStart))
506 aStartEnt = aSlvsEntity;
507 else if (aSlvsEntity->isBase(aEnd))
508 aEndEnt = aSlvsEntity;
510 if (!aStartEnt || !aEndEnt)
513 aSubs.push_back(aStartEnt);
514 aSubs.push_back(aEndEnt);
515 Slvs_Entity anEntity = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
516 (Slvs_hEntity)theSketchID, (Slvs_hEntity)aStartEnt->id(), (Slvs_hEntity)aEndEnt->id());
518 aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
519 aNewEntity->setSubEntities(aSubs);
523 EntityWrapperPtr createCircle(FeaturePtr theFeature,
524 const std::list<EntityWrapperPtr>& theAttributes,
525 const GroupID& theGroupID,
526 const EntityID& theSketchID)
528 EntityWrapperPtr aNewEntity;
529 std::list<EntityWrapperPtr> aSubs;
531 AttributePtr aCenter = theFeature->attribute(SketchPlugin_Circle::CENTER_ID());
532 AttributePtr aRadius = theFeature->attribute(SketchPlugin_Circle::RADIUS_ID());
533 if (!aCenter->isInitialized() || !aRadius->isInitialized())
536 EntityWrapperPtr aCenterEnt, aRadiusEnt, aNormalEnt;
537 std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
538 for (; anIt != theAttributes.end(); ++anIt) {
539 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
540 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
541 if (aSlvsEntity->isBase(aCenter))
542 aCenterEnt = aSlvsEntity;
543 else if (aSlvsEntity->isBase(aRadius))
544 aRadiusEnt = aSlvsEntity;
545 else if (aSlvsEntity->type() == ENTITY_NORMAL)
546 aNormalEnt = aSlvsEntity;
548 if (!aCenterEnt || !aRadiusEnt || !aNormalEnt)
551 aSubs.push_back(aCenterEnt);
552 aSubs.push_back(aRadiusEnt);
553 Slvs_Entity anEntity = Slvs_MakeCircle(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
554 (Slvs_hEntity)theSketchID, (Slvs_hEntity)aCenterEnt->id(),
555 (Slvs_hEntity)aNormalEnt->id(), (Slvs_hEntity)aRadiusEnt->id());
557 aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
558 aNewEntity->setSubEntities(aSubs);
562 EntityWrapperPtr createArc(FeaturePtr theFeature,
563 const std::list<EntityWrapperPtr>& theAttributes,
564 const GroupID& theGroupID,
565 const EntityID& theSketchID)
567 EntityWrapperPtr aNewEntity;
568 std::list<EntityWrapperPtr> aSubs;
570 AttributePtr aCenter = theFeature->attribute(SketchPlugin_Arc::CENTER_ID());
571 AttributePtr aStart = theFeature->attribute(SketchPlugin_Arc::START_ID());
572 AttributePtr aEnd = theFeature->attribute(SketchPlugin_Arc::END_ID());
573 if (!aCenter->isInitialized() || !aStart->isInitialized() || !aEnd->isInitialized())
576 EntityWrapperPtr aCenterEnt, aStartEnt, aEndEnt, aNormalEnt;
577 std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
578 for (; anIt != theAttributes.end(); ++anIt) {
579 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
580 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
581 if (aSlvsEntity->isBase(aCenter))
582 aCenterEnt = aSlvsEntity;
583 else if (aSlvsEntity->isBase(aStart))
584 aStartEnt = aSlvsEntity;
585 else if (aSlvsEntity->isBase(aEnd))
586 aEndEnt = aSlvsEntity;
587 else if (aSlvsEntity->type() == ENTITY_NORMAL)
588 aNormalEnt = aSlvsEntity;
590 if (!aCenterEnt || !aStartEnt || !aEndEnt || !aNormalEnt)
593 aSubs.push_back(aCenterEnt);
594 aSubs.push_back(aStartEnt);
595 aSubs.push_back(aEndEnt);
596 Slvs_Entity anEntity = Slvs_MakeArcOfCircle(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
597 (Slvs_hEntity)theSketchID, (Slvs_hEntity)aNormalEnt->id(),
598 (Slvs_hEntity)aCenterEnt->id(), (Slvs_hEntity)aStartEnt->id(), (Slvs_hEntity)aEndEnt->id());
600 aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
601 aNewEntity->setSubEntities(aSubs);
606 void adjustTangency(ConstraintWrapperPtr theConstraint)
608 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
610 std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
611 std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
613 // Collect start, end points of entities
614 std::shared_ptr<GeomAPI_Pnt2d> aStartEntPoints[2][2];
615 bool isCoinc[2][2] = {false};
616 const std::list<EntityWrapperPtr>& aSubs = aConstraint->entities();
617 std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
618 for (int i = 0; aSIt != aSubs.end(); ++aSIt, ++i) {
619 const std::list<EntityWrapperPtr>& aPoints = (*aSIt)->subEntities();
620 std::list<EntityWrapperPtr>::const_iterator aPIt = aPoints.begin();
621 if ((*aSIt)->type() == ENTITY_ARC)
623 for (int j = 0; aPIt != aPoints.end(); ++aPIt, ++j) {
624 aStartEntPoints[i][j] = aBuilder->point(*aPIt);
625 if (i > 0) { // check coincidence
626 for (int k = 0; k < 2; ++k)
627 if (aStartEntPoints[i][j]->distance(aStartEntPoints[0][k]) < tolerance)
628 isCoinc[0][k] = isCoinc[i][j] = true;
633 Slvs_Constraint& aSlvsConstraint = aConstraint->changeConstraint();
634 if (isCoinc[0][0] == false && isCoinc[0][1] == true)
635 aSlvsConstraint.other = 1;
636 else aSlvsConstraint.other = 0;
637 if (isCoinc[1][0] == false && isCoinc[1][1] == true)
638 aSlvsConstraint.other2 = 1;
639 else aSlvsConstraint.other2 = 0;
642 void adjustAngle(ConstraintWrapperPtr theConstraint)
644 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
646 std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
647 std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
650 std::shared_ptr<GeomAPI_Pnt2d> aPoints[2][2]; // start and end points of lines
651 const std::list<EntityWrapperPtr>& aConstrLines = aConstraint->entities();
652 std::list<EntityWrapperPtr>::const_iterator aCLIt = aConstrLines.begin();
653 for (int i = 0; aCLIt != aConstrLines.end(); ++i, ++aCLIt) {
654 const std::list<EntityWrapperPtr>& aLinePoints = (*aCLIt)->subEntities();
655 std::list<EntityWrapperPtr>::const_iterator aLPIt = aLinePoints.begin();
656 for (int j = 0; aLPIt != aLinePoints.end(); ++j, ++aLPIt) {
657 isFixed[i][j] = ((*aLPIt)->group() != theConstraint->group());
658 aPoints[i][j] = aBuilder->point(*aLPIt);
662 if (isFixed[0][0] && isFixed[0][1] && isFixed[1][0] && isFixed[1][1])
663 return; // both lines are fixed => no need to update them
665 std::shared_ptr<GeomAPI_Lin2d> aLine[2] = {
666 std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[0][0], aPoints[0][1])),
667 std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[1][0], aPoints[1][1]))
669 std::shared_ptr<GeomAPI_Pnt2d> anIntersection = aLine[0]->intersect(aLine[1]);
673 for (int i = 0; i < 2; i++) {
674 for (int j = 0; j < 2; j++) {
675 aDist[i][j] = anIntersection->distance(aPoints[i][j]);
676 if (fabs(aDist[i][j]) <= tolerance)
679 if (aDist[i][0] > tolerance && aDist[i][1] > tolerance &&
680 aDist[i][0] + aDist[i][1] < aPoints[i][0]->distance(aPoints[i][1]) + 2.0 * tolerance) {
681 // the intersection point is an inner point of the line,
682 // we change the sign of distance till start point to calculate correct coordinates
687 std::shared_ptr<GeomAPI_Dir2d> aDir[2];
688 for (int i = 0; i < 2; i++) {
689 if (aDist[i][1] > fabs(aDist[i][0]))
690 aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(
691 aPoints[i][1]->xy()->decreased(anIntersection->xy())));
693 aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(
694 aPoints[i][0]->xy()->decreased(anIntersection->xy())));
695 // main direction is opposite => change signs
696 if (aDist[i][0] < 0.0) {
703 Slvs_Constraint& aSlvsConstraint = aConstraint->changeConstraint();
704 aSlvsConstraint.other = false;
705 for (int i = 0; i < 2; i++)
706 if (aLine[i]->direction()->dot(aDir[i]) < 0.0)
707 aSlvsConstraint.other = !aSlvsConstraint.other;
709 // Recalculate positions of lines to avoid conflicting constraints
710 // while changing angle value several times
711 double cosA = cos(aConstraint->value() * PI / 180.0);
712 double sinA = sin(aConstraint->value() * PI / 180.0);
713 if (aDir[0]->cross(aDir[1]) < 0.0)
716 if (isFixed[1][0] && isFixed[1][1]) {
720 double x = aDir[1-aLineToUpd]->x() * cosA - aDir[1-aLineToUpd]->y() * sinA;
721 double y = aDir[1-aLineToUpd]->x() * sinA + aDir[1-aLineToUpd]->y() * cosA;
723 std::shared_ptr<GeomAPI_Pnt2d> aNewPoints[2];
724 for (int i = 0; i < 2; i++) {
725 aNewPoints[i] = std::shared_ptr<GeomAPI_Pnt2d>(
726 new GeomAPI_Pnt2d(anIntersection->x() + x * aDist[aLineToUpd][i],
727 anIntersection->y() + y * aDist[aLineToUpd][i]));
730 std::shared_ptr<GeomAPI_XY> aDelta;
731 if (isFixed[aLineToUpd][0] && !isFixed[aLineToUpd][1])
732 aDelta = aPoints[aLineToUpd][0]->xy()->decreased(aNewPoints[0]->xy());
733 else if (!isFixed[aLineToUpd][0] && isFixed[aLineToUpd][1])
734 aDelta = aPoints[aLineToUpd][1]->xy()->decreased(aNewPoints[1]->xy());
736 for (int i = 0; i < 2; i++) {
737 aNewPoints[i]->setX(aNewPoints[i]->x() + aDelta->x());
738 aNewPoints[i]->setY(aNewPoints[i]->y() + aDelta->y());
742 // Update positions of points
743 std::list<EntityWrapperPtr>::const_iterator anUpdLine = aConstrLines.begin();
744 if (aLineToUpd > 0) ++anUpdLine;
745 const std::list<EntityWrapperPtr>& anUpdPoints = (*anUpdLine)->subEntities();
746 std::list<EntityWrapperPtr>::const_iterator aPIt = anUpdPoints.begin();
747 for (int i = 0; aPIt != anUpdPoints.end(); ++aPIt, ++i) {
748 double aCoord[2] = {aNewPoints[i]->x(), aNewPoints[i]->y()};
749 const std::list<ParameterWrapperPtr>& aParams = (*aPIt)->parameters();
750 std::list<ParameterWrapperPtr>::const_iterator aParIt = aParams.begin();
751 for (int j = 0; aParIt != aParams.end(); ++j, ++aParIt)
752 (*aParIt)->setValue(aCoord[j]);
756 void adjustMirror(ConstraintWrapperPtr theConstraint)
758 std::vector<EntityWrapperPtr> aPoints;
759 EntityWrapperPtr aMirrorLine;
761 const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
762 std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
763 for (; anIt != aSubs.end(); ++anIt) {
764 if ((*anIt)->type() == ENTITY_POINT)
765 aPoints.push_back(*anIt);
766 else if ((*anIt)->type() == ENTITY_LINE)
770 makeMirrorPoints(aPoints[0], aPoints[1], aMirrorLine);
773 void makeMirrorPoints(EntityWrapperPtr theOriginal,
774 EntityWrapperPtr theMirrored,
775 EntityWrapperPtr theMirrorLine)
777 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
779 std::shared_ptr<GeomAPI_Lin2d> aMirrorLine = aBuilder->line(theMirrorLine);
780 std::shared_ptr<GeomAPI_Dir2d> aMLDir = aMirrorLine->direction();
781 // orthogonal direction
782 aMLDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aMLDir->y(), -aMLDir->x()));
784 std::shared_ptr<GeomAPI_Pnt2d> aPoint = aBuilder->point(theOriginal);
785 std::shared_ptr<GeomAPI_XY> aVec = aPoint->xy()->decreased(aMirrorLine->location()->xy());
786 double aDist = aVec->dot(aMLDir->xy());
787 aVec = aPoint->xy()->added(aMLDir->xy()->multiplied(-2.0 * aDist));
788 double aCoord[2] = {aVec->x(), aVec->y()};
789 std::list<ParameterWrapperPtr>::const_iterator aMIt = theMirrored->parameters().begin();
790 for (int i = 0; aMIt != theMirrored->parameters().end(); ++aMIt, ++i)
791 (*aMIt)->setValue(aCoord[i]);
793 // update corresponding attribute
794 AttributePtr anAttr = std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theMirrored)->baseAttribute();
796 std::shared_ptr<GeomDataAPI_Point2D> aMirroredPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
797 aMirroredPnt->setValue(aCoord[0], aCoord[1]);
801 void adjustPtLineDistance(ConstraintWrapperPtr theConstraint)
803 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
805 std::shared_ptr<GeomAPI_Pnt2d> aPoint;
806 std::shared_ptr<GeomAPI_Lin2d> aLine;
807 std::list<EntityWrapperPtr> aSubs = theConstraint->entities();
808 std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
809 for (; aSIt != aSubs.end(); ++aSIt) {
810 if ((*aSIt)->type() == ENTITY_POINT)
811 aPoint = aBuilder->point(*aSIt);
812 else if ((*aSIt)->type() == ENTITY_LINE)
813 aLine = aBuilder->line(*aSIt);
816 std::shared_ptr<GeomAPI_XY> aLineVec = aLine->direction()->xy();
817 std::shared_ptr<GeomAPI_XY> aPtLineVec = aPoint->xy()->decreased(aLine->location()->xy());
818 if (aPtLineVec->cross(aLineVec) * theConstraint->value() < 0.0)
819 theConstraint->setValue(theConstraint->value() * (-1.0));