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);
55 /// \brief Transform points to be symmetric regarding to the mirror line
56 static void makeMirrorPoints(EntityWrapperPtr theOriginal,
57 EntityWrapperPtr theMirrored,
58 EntityWrapperPtr theMirrorLine);
62 // Initialization of constraint builder self pointer
63 BuilderPtr SolveSpaceSolver_Builder::mySelf = SolveSpaceSolver_Builder::getInstance();
65 BuilderPtr SolveSpaceSolver_Builder::getInstance()
68 mySelf = BuilderPtr(new SolveSpaceSolver_Builder);
69 SketchSolver_Manager::instance()->setBuilder(mySelf);
74 StoragePtr SolveSpaceSolver_Builder::createStorage(const GroupID& theGroup) const
76 return StoragePtr(new SolveSpaceSolver_Storage(theGroup));
79 SolverPtr SolveSpaceSolver_Builder::createSolver() const
81 return SolverPtr(new SolveSpaceSolver_Solver);
85 std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createConstraint(
86 ConstraintPtr theConstraint,
87 const GroupID& theGroupID,
88 const EntityID& theSketchID,
89 const SketchSolver_ConstraintType& theType,
90 const double& theValue,
91 const EntityWrapperPtr& thePoint1,
92 const EntityWrapperPtr& thePoint2,
93 const EntityWrapperPtr& theEntity1,
94 const EntityWrapperPtr& theEntity2) const
96 if (theType == CONSTRAINT_SYMMETRIC)
97 return createMirror(theConstraint, theGroupID, theSketchID,
98 thePoint1, thePoint2, theEntity1);
100 int aType = ConstraintType::toSolveSpace(theType);
101 if (aType == SLVS_C_UNKNOWN)
102 return std::list<ConstraintWrapperPtr>();
104 Slvs_hEntity aSlvsEntities[4] = {SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN};
105 EntityWrapperPtr anOriginal[4] = {thePoint1, thePoint2, theEntity1, theEntity2};
106 std::list<EntityWrapperPtr> aConstrAttrList; // to be filled
107 for (int i = 0; i < 4; ++i) {
110 aSlvsEntities[i] = (Slvs_hEntity)anOriginal[i]->id();
111 if (aSlvsEntities[i] == SLVS_E_UNKNOWN)
112 return std::list<ConstraintWrapperPtr>(); // entity is not added into a storage, constraint can not be created
113 aConstrAttrList.push_back(anOriginal[i]);
116 Slvs_Constraint aConstraint = Slvs_MakeConstraint(
117 SLVS_C_UNKNOWN, (Slvs_hGroup)theGroupID, aType, (Slvs_hEntity)theSketchID,
118 theValue, aSlvsEntities[0], aSlvsEntities[1], aSlvsEntities[2], aSlvsEntities[3]);
119 ConstraintWrapperPtr aResult(new SolveSpaceSolver_ConstraintWrapper(theConstraint, aConstraint));
120 aResult->setGroup(theGroupID);
121 aResult->setValue(theValue);
122 aResult->setEntities(aConstrAttrList);
123 adjustConstraint(aResult);
125 return std::list<ConstraintWrapperPtr>(1, aResult);
128 std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createConstraint(
129 ConstraintPtr theConstraint,
130 const GroupID& theGroupID,
131 const EntityID& theSketchID,
132 const SketchSolver_ConstraintType& theType,
133 const double& theValue,
134 const bool theFullValue,
135 const EntityWrapperPtr& thePoint1,
136 const EntityWrapperPtr& thePoint2,
137 const std::list<EntityWrapperPtr>& theTrsfEnt) const
139 if (theType != CONSTRAINT_MULTI_ROTATION && theType != CONSTRAINT_MULTI_TRANSLATION)
140 return std::list<ConstraintWrapperPtr>();
142 int aType = ConstraintType::toSolveSpace(theType);
143 if (aType == SLVS_C_UNKNOWN)
144 return std::list<ConstraintWrapperPtr>();
146 Slvs_Constraint aConstraint =
147 Slvs_MakeConstraint(SLVS_C_UNKNOWN, (Slvs_hGroup)theGroupID, aType, (Slvs_hEntity)theSketchID,
148 theValue, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
150 std::list<EntityWrapperPtr> aConstrAttrList = theTrsfEnt;
152 aConstrAttrList.push_front(thePoint2);
153 aConstrAttrList.push_front(thePoint1);
155 ConstraintWrapperPtr aResult(new SolveSpaceSolver_ConstraintWrapper(theConstraint, aConstraint));
156 aResult->setGroup(theGroupID);
157 aResult->setValue(theValue);
158 aResult->setIsFullValue(theFullValue);
159 aResult->setEntities(aConstrAttrList);
160 return std::list<ConstraintWrapperPtr>(1, aResult);
164 std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createMirror(
165 ConstraintPtr theConstraint,
166 const GroupID& theGroupID,
167 const EntityID& theSketchID,
168 const EntityWrapperPtr& theEntity1,
169 const EntityWrapperPtr& theEntity2,
170 const EntityWrapperPtr& theMirrorLine) const
172 Slvs_Constraint aConstraint;
173 std::list<ConstraintWrapperPtr> aResult;
174 std::list<EntityWrapperPtr> aConstrAttrList;
175 if (theEntity1->type() == ENTITY_POINT) {
176 if (theEntity2->group() == theGroupID) // theEntity2 is not fixed
177 makeMirrorPoints(theEntity1, theEntity2, theMirrorLine);
179 aConstraint = Slvs_MakeConstraint(
180 SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID, SLVS_C_SYMMETRIC_LINE, (Slvs_hEntity)theSketchID,
181 0.0, (Slvs_hEntity)theEntity1->id(), (Slvs_hEntity)theEntity2->id(),
182 (Slvs_hEntity)theMirrorLine->id(), SLVS_E_UNKNOWN);
184 aConstrAttrList.push_back(theEntity1);
185 aConstrAttrList.push_back(theEntity2);
186 aConstrAttrList.push_back(theMirrorLine);
188 ConstraintWrapperPtr aWrapper(new SolveSpaceSolver_ConstraintWrapper(
189 theConstraint, aConstraint));
190 aWrapper->setGroup(theGroupID);
191 aWrapper->setEntities(aConstrAttrList);
192 aResult.push_back(aWrapper);
194 else if (theEntity1->type() == ENTITY_LINE) {
195 const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
196 const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
197 std::list<EntityWrapperPtr>::const_iterator anIt1 = aPoints1.begin();
198 std::list<EntityWrapperPtr>::const_iterator anIt2 = aPoints2.begin();
199 for (; anIt1 != aPoints1.end() && anIt2 != aPoints2.end(); ++anIt1, ++anIt2) {
200 std::list<ConstraintWrapperPtr> aMrrList =
201 createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
202 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
205 else if (theEntity1->type() == ENTITY_CIRCLE) {
206 const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
207 std::list<EntityWrapperPtr>::const_iterator anIt1 = aPoints1.begin();
208 for (; anIt1 != aPoints1.end(); ++anIt1)
209 if ((*anIt1)->type() == ENTITY_POINT)
211 const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
212 std::list<EntityWrapperPtr>::const_iterator anIt2 = aPoints2.begin();
213 for (; anIt2 != aPoints2.end(); ++anIt2)
214 if ((*anIt2)->type() == ENTITY_POINT)
217 std::list<ConstraintWrapperPtr> aMrrList =
218 createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
219 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
221 // Additional constraint for equal radii
222 aMrrList = createConstraint(theConstraint, theGroupID, theSketchID, CONSTRAINT_EQUAL_RADIUS,
223 0.0, EntityWrapperPtr(), EntityWrapperPtr(), theEntity1, theEntity2);
224 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
226 else if (theEntity1->type() == ENTITY_ARC) {
227 // Do not allow mirrored arc recalculate its position until coordinated of all points recalculated
228 FeaturePtr aMirrArc = theEntity2->baseFeature();
229 aMirrArc->data()->blockSendAttributeUpdated(true);
231 std::list<ConstraintWrapperPtr> aMrrList;
232 std::list<EntityWrapperPtr>::const_iterator anIt1 = theEntity1->subEntities().begin();
233 std::list<EntityWrapperPtr>::const_iterator anIt2 = theEntity2->subEntities().begin();
234 if ((*anIt2)->group() == theGroupID) // mirrored point is not fixed
235 makeMirrorPoints(*anIt1, *anIt2, theMirrorLine);
237 // Workaround to avoid problems in SolveSpace.
238 // The symmetry of two arcs will be done using symmetry of three points on these arcs:
239 // start point, end point, and any other point on the arc
240 std::list<EntityWrapperPtr> aBaseArcPoints(++anIt1, theEntity1->subEntities().end());
241 std::list<EntityWrapperPtr> aMirrorArcPoints(++anIt2, theEntity2->subEntities().end());
242 // indices of points of arc, center corresponds center, first point corresponds last point
243 aMirrorArcPoints.reverse();
245 anIt1 = aBaseArcPoints.begin();
246 anIt2 = aMirrorArcPoints.begin();
247 for (; anIt1 != aBaseArcPoints.end(); ++anIt1, ++anIt2) {
248 aMrrList = createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
249 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
251 // Restore event sending
252 aMirrArc->data()->blockSendAttributeUpdated(false);
257 void SolveSpaceSolver_Builder::adjustConstraint(ConstraintWrapperPtr theConstraint) const
259 SketchSolver_ConstraintType aType = theConstraint->type();
260 // Update flags in constraints
261 if (aType == CONSTRAINT_TANGENT_ARC_ARC || aType == CONSTRAINT_TANGENT_ARC_LINE)
262 adjustTangency(theConstraint);
263 else if (aType == CONSTRAINT_ANGLE)
264 adjustAngle(theConstraint);
265 else if (aType == CONSTRAINT_SYMMETRIC)
266 adjustMirror(theConstraint);
269 EntityWrapperPtr SolveSpaceSolver_Builder::createFeature(
270 FeaturePtr theFeature,
271 const std::list<EntityWrapperPtr>& theAttributes,
272 const GroupID& theGroupID,
273 const EntityID& theSketchID) const
275 static EntityWrapperPtr aDummy;
276 if (!theFeature->data()->isValid())
280 CompositeFeaturePtr aSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
282 return createSketchEntity(aSketch, theGroupID);
284 // SketchPlugin features
285 std::shared_ptr<SketchPlugin_Feature> aFeature =
286 std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
290 // Verify the feature by its kind
291 const std::string& aFeatureKind = aFeature->getKind();
293 if (aFeatureKind == SketchPlugin_Line::ID())
294 return createLine(theFeature, theAttributes, theGroupID, theSketchID);
296 else if (aFeatureKind == SketchPlugin_Circle::ID())
297 return createCircle(theFeature, theAttributes,theGroupID, theSketchID);
299 else if (aFeatureKind == SketchPlugin_Arc::ID())
300 return createArc(theFeature, theAttributes,theGroupID, theSketchID);
301 // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
302 else if (aFeatureKind == SketchPlugin_Point::ID()) {
303 AttributePtr aPoint = theFeature->attribute(SketchPlugin_Point::COORD_ID());
304 if (!aPoint->isInitialized())
306 EntityWrapperPtr aSub = theAttributes.empty() ? createAttribute(aPoint, theGroupID, theSketchID) :
307 theAttributes.front();
311 const Slvs_Entity& aSubEnt =
312 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(aSub)->entity();
313 EntityWrapperPtr aResult(new SolveSpaceSolver_EntityWrapper(theFeature, aPoint, aSubEnt));
314 aResult->setSubEntities(theAttributes);
322 EntityWrapperPtr SolveSpaceSolver_Builder::createAttribute(
323 AttributePtr theAttribute,
324 const GroupID& theGroupID,
325 const EntityID& theSketchID) const
327 AttributePtr anAttribute = theAttribute;
328 AttributeRefAttrPtr aRefAttr =
329 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
331 if (aRefAttr->isObject()) {
332 // do not create features here
333 return EntityWrapperPtr();
335 anAttribute = aRefAttr->attr();
338 std::list<ParameterWrapperPtr> aParameters;
339 Slvs_Entity anEntity;
343 std::shared_ptr<GeomDataAPI_Point> aPoint =
344 std::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
346 aParameters.push_back(createParameter(theGroupID, aPoint->x(), !aPoint->textX().empty()));
347 aParameters.push_back(createParameter(theGroupID, aPoint->y(), !aPoint->textY().empty()));
348 aParameters.push_back(createParameter(theGroupID, aPoint->z(), !aPoint->textZ().empty()));
349 // Create entity (parameters are not filled)
350 anEntity = Slvs_MakePoint3d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
351 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
354 std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
355 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
357 aParameters.push_back(createParameter(theGroupID, aPoint2D->x(), !aPoint2D->textX().empty()));
358 aParameters.push_back(createParameter(theGroupID, aPoint2D->y(), !aPoint2D->textY().empty()));
359 // Create entity (parameters are not filled)
360 anEntity = Slvs_MakePoint2d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
361 (Slvs_hEntity)theSketchID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
363 // Scalar value (used for the distance entities)
364 AttributeDoublePtr aScalar =
365 std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
367 aParameters.push_back(createParameter(theGroupID, aScalar->value(), !aScalar->text().empty()));
368 // Create entity (parameter is not filled)
369 anEntity = Slvs_MakeDistance(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
370 (Slvs_hEntity)theSketchID, SLVS_E_UNKNOWN);
375 if (anEntity.type == 0) {
376 // unknown attribute type
377 return EntityWrapperPtr();
380 EntityWrapperPtr aResult(new SolveSpaceSolver_EntityWrapper(theAttribute, anEntity));
381 aResult->setParameters(aParameters);
387 EntityWrapperPtr SolveSpaceSolver_Builder::createSketchEntity(
388 CompositeFeaturePtr theSketch,
389 const GroupID& theGroupID) const
391 DataPtr aSketchData = theSketch->data();
392 if (!aSketchData || !aSketchData->isValid())
393 return EntityWrapperPtr(); // the sketch is incorrect
395 // Get parameters of workplane
396 AttributePtr aDirX = aSketchData->attribute(SketchPlugin_Sketch::DIRX_ID());
397 AttributePtr aNorm = aSketchData->attribute(SketchPlugin_Sketch::NORM_ID());
398 AttributePtr anOrigin = aSketchData->attribute(SketchPlugin_Sketch::ORIGIN_ID());
399 if (!anOrigin->isInitialized() || !aNorm->isInitialized() || !aDirX->isInitialized())
400 return EntityWrapperPtr();
402 EntityWrapperPtr aNewEnt;
403 std::list<EntityWrapperPtr> aSubs;
405 // Create SolveSpace entity corresponding to the sketch origin
406 aNewEnt = createAttribute(anOrigin, theGroupID);
408 return EntityWrapperPtr();
409 aSubs.push_back(aNewEnt);
411 // Create SolveSpace entity corresponding the the sketch normal
412 aNewEnt = createNormal(aNorm, aDirX, theGroupID);
414 return EntityWrapperPtr();
415 aSubs.push_back(aNewEnt);
418 Slvs_Entity aWorkplane = Slvs_MakeWorkplane(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
419 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
421 aNewEnt = EntityWrapperPtr(
422 new SolveSpaceSolver_EntityWrapper(FeaturePtr(theSketch), aWorkplane));
423 aNewEnt->setSubEntities(aSubs);
427 EntityWrapperPtr SolveSpaceSolver_Builder::createNormal(
428 AttributePtr theNormal,
429 AttributePtr theDirX,
430 const GroupID& theGroupID) const
432 std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theNormal);
433 std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
434 if (!aDirX || !aNorm ||
435 (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance) ||
436 !aNorm->isInitialized())
437 return EntityWrapperPtr();
438 // calculate Y direction
439 std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aDirX->dir())));
441 // quaternion parameters of normal vector
442 double qw, qx, qy, qz;
443 Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), aDirY->x(), aDirY->y(), aDirY->z(), &qw,
445 double aNormCoord[4] = { qw, qx, qy, qz };
447 // Create parameters of the normal
448 std::list<ParameterWrapperPtr> aParameters;
449 for (int i = 0; i < 4; i++)
450 aParameters.push_back(createParameter(theGroupID, aNormCoord[i]));
452 // Create a normal with empty parameters
453 Slvs_Entity aNormalEnt = Slvs_MakeNormal3d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
454 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
455 EntityWrapperPtr aNormal(new SolveSpaceSolver_EntityWrapper(theNormal, aNormalEnt));
456 aNormal->setParameters(aParameters);
460 ParameterWrapperPtr SolveSpaceSolver_Builder::createParameter(
461 const GroupID& theGroup, const double theValue, const bool theExpr) const
463 Slvs_Param aParam = Slvs_MakeParam(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroup, theValue);
464 ParameterWrapperPtr aWrapper(new SolveSpaceSolver_ParameterWrapper(aParam));
465 aWrapper->setIsParametric(theExpr);
473 // ================ Auxiliary functions ==========================
474 EntityWrapperPtr createLine(FeaturePtr theFeature,
475 const std::list<EntityWrapperPtr>& theAttributes,
476 const GroupID& theGroupID,
477 const EntityID& theSketchID)
479 EntityWrapperPtr aNewEntity;
480 std::list<EntityWrapperPtr> aSubs;
482 AttributePtr aStart = theFeature->attribute(SketchPlugin_Line::START_ID());
483 AttributePtr aEnd = theFeature->attribute(SketchPlugin_Line::END_ID());
484 if (!aStart->isInitialized() || !aEnd->isInitialized())
487 EntityWrapperPtr aStartEnt, aEndEnt;
488 std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
489 for (; anIt != theAttributes.end(); ++anIt) {
490 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
491 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
492 if (aSlvsEntity->isBase(aStart))
493 aStartEnt = aSlvsEntity;
494 else if (aSlvsEntity->isBase(aEnd))
495 aEndEnt = aSlvsEntity;
497 if (!aStartEnt || !aEndEnt)
500 aSubs.push_back(aStartEnt);
501 aSubs.push_back(aEndEnt);
502 Slvs_Entity anEntity = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
503 (Slvs_hEntity)theSketchID, (Slvs_hEntity)aStartEnt->id(), (Slvs_hEntity)aEndEnt->id());
505 aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
506 aNewEntity->setSubEntities(aSubs);
510 EntityWrapperPtr createCircle(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 aCenter = theFeature->attribute(SketchPlugin_Circle::CENTER_ID());
519 AttributePtr aRadius = theFeature->attribute(SketchPlugin_Circle::RADIUS_ID());
520 if (!aCenter->isInitialized() || !aRadius->isInitialized())
523 EntityWrapperPtr aCenterEnt, aRadiusEnt, aNormalEnt;
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(aCenter))
529 aCenterEnt = aSlvsEntity;
530 else if (aSlvsEntity->isBase(aRadius))
531 aRadiusEnt = aSlvsEntity;
532 else if (aSlvsEntity->type() == ENTITY_NORMAL)
533 aNormalEnt = aSlvsEntity;
535 if (!aCenterEnt || !aRadiusEnt || !aNormalEnt)
538 aSubs.push_back(aCenterEnt);
539 aSubs.push_back(aRadiusEnt);
540 Slvs_Entity anEntity = Slvs_MakeCircle(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
541 (Slvs_hEntity)theSketchID, (Slvs_hEntity)aCenterEnt->id(),
542 (Slvs_hEntity)aNormalEnt->id(), (Slvs_hEntity)aRadiusEnt->id());
544 aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
545 aNewEntity->setSubEntities(aSubs);
549 EntityWrapperPtr createArc(FeaturePtr theFeature,
550 const std::list<EntityWrapperPtr>& theAttributes,
551 const GroupID& theGroupID,
552 const EntityID& theSketchID)
554 EntityWrapperPtr aNewEntity;
555 std::list<EntityWrapperPtr> aSubs;
557 AttributePtr aCenter = theFeature->attribute(SketchPlugin_Arc::CENTER_ID());
558 AttributePtr aStart = theFeature->attribute(SketchPlugin_Arc::START_ID());
559 AttributePtr aEnd = theFeature->attribute(SketchPlugin_Arc::END_ID());
560 if (!aCenter->isInitialized() || !aStart->isInitialized() || !aEnd->isInitialized())
563 EntityWrapperPtr aCenterEnt, aStartEnt, aEndEnt, aNormalEnt;
564 std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
565 for (; anIt != theAttributes.end(); ++anIt) {
566 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
567 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
568 if (aSlvsEntity->isBase(aCenter))
569 aCenterEnt = aSlvsEntity;
570 else if (aSlvsEntity->isBase(aStart))
571 aStartEnt = aSlvsEntity;
572 else if (aSlvsEntity->isBase(aEnd))
573 aEndEnt = aSlvsEntity;
574 else if (aSlvsEntity->type() == ENTITY_NORMAL)
575 aNormalEnt = aSlvsEntity;
577 if (!aCenterEnt || !aStartEnt || !aEndEnt || !aNormalEnt)
580 aSubs.push_back(aCenterEnt);
581 aSubs.push_back(aStartEnt);
582 aSubs.push_back(aEndEnt);
583 Slvs_Entity anEntity = Slvs_MakeArcOfCircle(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
584 (Slvs_hEntity)theSketchID, (Slvs_hEntity)aNormalEnt->id(),
585 (Slvs_hEntity)aCenterEnt->id(), (Slvs_hEntity)aStartEnt->id(), (Slvs_hEntity)aEndEnt->id());
587 aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
588 aNewEntity->setSubEntities(aSubs);
593 void adjustTangency(ConstraintWrapperPtr theConstraint)
595 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
597 std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
598 std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
600 // Collect start, end points of entities
601 std::shared_ptr<GeomAPI_Pnt2d> aStartEntPoints[2][2];
602 bool isCoinc[2][2] = {false};
603 const std::list<EntityWrapperPtr>& aSubs = aConstraint->entities();
604 std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
605 for (int i = 0; aSIt != aSubs.end(); ++aSIt, ++i) {
606 const std::list<EntityWrapperPtr>& aPoints = (*aSIt)->subEntities();
607 std::list<EntityWrapperPtr>::const_iterator aPIt = aPoints.begin();
608 if ((*aSIt)->type() == ENTITY_ARC)
610 for (int j = 0; aPIt != aPoints.end(); ++aPIt, ++j) {
611 aStartEntPoints[i][j] = aBuilder->point(*aPIt);
612 if (i > 0) { // check coincidence
613 for (int k = 0; k < 2; ++k)
614 if (aStartEntPoints[i][j]->distance(aStartEntPoints[0][k]) < tolerance)
615 isCoinc[0][k] = isCoinc[i][j] = true;
620 Slvs_Constraint& aSlvsConstraint = aConstraint->changeConstraint();
621 if (isCoinc[0][0] == false && isCoinc[0][1] == true)
622 aSlvsConstraint.other = 1;
623 else aSlvsConstraint.other = 0;
624 if (isCoinc[1][0] == false && isCoinc[1][1] == true)
625 aSlvsConstraint.other2 = 1;
626 else aSlvsConstraint.other2 = 0;
629 void adjustAngle(ConstraintWrapperPtr theConstraint)
631 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
633 std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
634 std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
637 std::shared_ptr<GeomAPI_Pnt2d> aPoints[2][2]; // start and end points of lines
638 const std::list<EntityWrapperPtr>& aConstrLines = aConstraint->entities();
639 std::list<EntityWrapperPtr>::const_iterator aCLIt = aConstrLines.begin();
640 for (int i = 0; aCLIt != aConstrLines.end(); ++i, ++aCLIt) {
641 const std::list<EntityWrapperPtr>& aLinePoints = (*aCLIt)->subEntities();
642 std::list<EntityWrapperPtr>::const_iterator aLPIt = aLinePoints.begin();
643 for (int j = 0; aLPIt != aLinePoints.end(); ++j, ++aLPIt) {
644 isFixed[i][j] = ((*aLPIt)->group() != theConstraint->group());
645 aPoints[i][j] = aBuilder->point(*aLPIt);
649 if (isFixed[0][0] && isFixed[0][1] && isFixed[1][0] && isFixed[1][1])
650 return; // both lines are fixed => no need to update them
652 std::shared_ptr<GeomAPI_Lin2d> aLine[2] = {
653 std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[0][0], aPoints[0][1])),
654 std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[1][0], aPoints[1][1]))
656 std::shared_ptr<GeomAPI_Pnt2d> anIntersection = aLine[0]->intersect(aLine[1]);
660 for (int i = 0; i < 2; i++) {
661 for (int j = 0; j < 2; j++) {
662 aDist[i][j] = anIntersection->distance(aPoints[i][j]);
663 if (fabs(aDist[i][j]) <= tolerance)
666 if (aDist[i][0] > tolerance && aDist[i][1] > tolerance &&
667 aDist[i][0] + aDist[i][1] < aPoints[i][0]->distance(aPoints[i][1]) + 2.0 * tolerance) {
668 // the intersection point is an inner point of the line,
669 // we change the sign of distance till start point to calculate correct coordinates
674 std::shared_ptr<GeomAPI_Dir2d> aDir[2];
675 for (int i = 0; i < 2; i++) {
676 if (aDist[i][1] > fabs(aDist[i][0]))
677 aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(
678 aPoints[i][1]->xy()->decreased(anIntersection->xy())));
680 aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(
681 aPoints[i][0]->xy()->decreased(anIntersection->xy())));
682 // main direction is opposite => change signs
683 if (aDist[i][0] < 0.0) {
690 Slvs_Constraint& aSlvsConstraint = aConstraint->changeConstraint();
691 aSlvsConstraint.other = false;
692 for (int i = 0; i < 2; i++)
693 if (aLine[i]->direction()->dot(aDir[i]) < 0.0)
694 aSlvsConstraint.other = !aSlvsConstraint.other;
696 // Recalculate positions of lines to avoid conflicting constraints
697 // while changing angle value several times
698 double cosA = cos(aConstraint->value() * PI / 180.0);
699 double sinA = sin(aConstraint->value() * PI / 180.0);
700 if (aDir[0]->cross(aDir[1]) < 0.0)
703 if (isFixed[1][0] && isFixed[1][1]) {
707 double x = aDir[1-aLineToUpd]->x() * cosA - aDir[1-aLineToUpd]->y() * sinA;
708 double y = aDir[1-aLineToUpd]->x() * sinA + aDir[1-aLineToUpd]->y() * cosA;
710 std::shared_ptr<GeomAPI_Pnt2d> aNewPoints[2];
711 for (int i = 0; i < 2; i++) {
712 aNewPoints[i] = std::shared_ptr<GeomAPI_Pnt2d>(
713 new GeomAPI_Pnt2d(anIntersection->x() + x * aDist[aLineToUpd][i],
714 anIntersection->y() + y * aDist[aLineToUpd][i]));
717 std::shared_ptr<GeomAPI_XY> aDelta;
718 if (isFixed[aLineToUpd][0] && !isFixed[aLineToUpd][1])
719 aDelta = aPoints[aLineToUpd][0]->xy()->decreased(aNewPoints[0]->xy());
720 else if (!isFixed[aLineToUpd][0] && isFixed[aLineToUpd][1])
721 aDelta = aPoints[aLineToUpd][1]->xy()->decreased(aNewPoints[1]->xy());
723 for (int i = 0; i < 2; i++) {
724 aNewPoints[i]->setX(aNewPoints[i]->x() + aDelta->x());
725 aNewPoints[i]->setY(aNewPoints[i]->y() + aDelta->y());
729 // Update positions of points
730 std::list<EntityWrapperPtr>::const_iterator anUpdLine = aConstrLines.begin();
731 if (aLineToUpd > 0) ++anUpdLine;
732 const std::list<EntityWrapperPtr>& anUpdPoints = (*anUpdLine)->subEntities();
733 std::list<EntityWrapperPtr>::const_iterator aPIt = anUpdPoints.begin();
734 for (int i = 0; aPIt != anUpdPoints.end(); ++aPIt, ++i) {
735 double aCoord[2] = {aNewPoints[i]->x(), aNewPoints[i]->y()};
736 const std::list<ParameterWrapperPtr>& aParams = (*aPIt)->parameters();
737 std::list<ParameterWrapperPtr>::const_iterator aParIt = aParams.begin();
738 for (int j = 0; aParIt != aParams.end(); ++j, ++aParIt)
739 (*aParIt)->setValue(aCoord[j]);
743 void adjustMirror(ConstraintWrapperPtr theConstraint)
745 std::vector<EntityWrapperPtr> aPoints;
746 EntityWrapperPtr aMirrorLine;
748 const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
749 std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
750 for (; anIt != aSubs.end(); ++anIt) {
751 if ((*anIt)->type() == ENTITY_POINT)
752 aPoints.push_back(*anIt);
753 else if ((*anIt)->type() == ENTITY_LINE)
757 makeMirrorPoints(aPoints[0], aPoints[1], aMirrorLine);
760 void makeMirrorPoints(EntityWrapperPtr theOriginal,
761 EntityWrapperPtr theMirrored,
762 EntityWrapperPtr theMirrorLine)
764 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
766 std::shared_ptr<GeomAPI_Lin2d> aMirrorLine = aBuilder->line(theMirrorLine);
767 std::shared_ptr<GeomAPI_Dir2d> aMLDir = aMirrorLine->direction();
768 // orthogonal direction
769 aMLDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aMLDir->y(), -aMLDir->x()));
771 std::shared_ptr<GeomAPI_Pnt2d> aPoint = aBuilder->point(theOriginal);
772 std::shared_ptr<GeomAPI_XY> aVec = aPoint->xy()->decreased(aMirrorLine->location()->xy());
773 double aDist = aVec->dot(aMLDir->xy());
774 aVec = aPoint->xy()->added(aMLDir->xy()->multiplied(-2.0 * aDist));
775 double aCoord[2] = {aVec->x(), aVec->y()};
776 std::list<ParameterWrapperPtr>::const_iterator aMIt = theMirrored->parameters().begin();
777 for (int i = 0; aMIt != theMirrored->parameters().end(); ++aMIt, ++i)
778 (*aMIt)->setValue(aCoord[i]);
780 // update corresponding attribute
781 AttributePtr anAttr = std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theMirrored)->baseAttribute();
783 std::shared_ptr<GeomDataAPI_Point2D> aMirroredPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
784 aMirroredPnt->setValue(aCoord[0], aCoord[1]);