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 positions of rotated features
55 static void adjustMultiRotation(ConstraintWrapperPtr theConstraint);
56 /// \brief Update positions of translated features
57 static void adjustMultiTranslation(ConstraintWrapperPtr theConstraint);
59 /// \brief Transform points to be symmetric regarding to the mirror line
60 static void makeMirrorPoints(EntityWrapperPtr theOriginal,
61 EntityWrapperPtr theMirrored,
62 EntityWrapperPtr theMirrorLine);
66 // Initialization of constraint builder self pointer
67 BuilderPtr SolveSpaceSolver_Builder::mySelf = SolveSpaceSolver_Builder::getInstance();
69 BuilderPtr SolveSpaceSolver_Builder::getInstance()
72 mySelf = BuilderPtr(new SolveSpaceSolver_Builder);
73 SketchSolver_Manager::instance()->setBuilder(mySelf);
78 StoragePtr SolveSpaceSolver_Builder::createStorage(const GroupID& theGroup) const
80 return StoragePtr(new SolveSpaceSolver_Storage(theGroup));
83 SolverPtr SolveSpaceSolver_Builder::createSolver() const
85 return SolverPtr(new SolveSpaceSolver_Solver);
89 std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createConstraint(
90 ConstraintPtr theConstraint,
91 const GroupID& theGroupID,
92 const EntityID& theSketchID,
93 const SketchSolver_ConstraintType& theType,
94 const double& theValue,
95 const EntityWrapperPtr& thePoint1,
96 const EntityWrapperPtr& thePoint2,
97 const EntityWrapperPtr& theEntity1,
98 const EntityWrapperPtr& theEntity2) const
100 if (theType == CONSTRAINT_SYMMETRIC)
101 return createMirror(theConstraint, theGroupID, theSketchID,
102 thePoint1, thePoint2, theEntity1);
104 int aType = ConstraintType::toSolveSpace(theType);
105 if (aType == SLVS_C_UNKNOWN)
106 return std::list<ConstraintWrapperPtr>();
108 Slvs_hEntity aSlvsEntities[4] = {SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN};
109 EntityWrapperPtr anOriginal[4] = {thePoint1, thePoint2, theEntity1, theEntity2};
110 std::list<EntityWrapperPtr> aConstrAttrList; // to be filled
111 for (int i = 0; i < 4; ++i) {
114 aSlvsEntities[i] = (Slvs_hEntity)anOriginal[i]->id();
115 if (aSlvsEntities[i] == SLVS_E_UNKNOWN)
116 return std::list<ConstraintWrapperPtr>(); // entity is not added into a storage, constraint can not be created
117 aConstrAttrList.push_back(anOriginal[i]);
120 Slvs_Constraint aConstraint = Slvs_MakeConstraint(
121 SLVS_C_UNKNOWN, (Slvs_hGroup)theGroupID, aType, (Slvs_hEntity)theSketchID,
122 theValue, aSlvsEntities[0], aSlvsEntities[1], aSlvsEntities[2], aSlvsEntities[3]);
123 ConstraintWrapperPtr aResult(new SolveSpaceSolver_ConstraintWrapper(theConstraint, aConstraint));
124 aResult->setValue(theValue);
125 aResult->setEntities(aConstrAttrList);
126 adjustConstraint(aResult);
128 return std::list<ConstraintWrapperPtr>(1, aResult);
131 std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createConstraint(
132 ConstraintPtr theConstraint,
133 const GroupID& theGroupID,
134 const EntityID& theSketchID,
135 const SketchSolver_ConstraintType& theType,
136 const double& theValue,
137 const bool theFullValue,
138 const EntityWrapperPtr& thePoint1,
139 const EntityWrapperPtr& thePoint2,
140 const std::list<EntityWrapperPtr>& theTrsfEnt) const
142 if (theType != CONSTRAINT_MULTI_ROTATION && theType != CONSTRAINT_MULTI_TRANSLATION)
143 return std::list<ConstraintWrapperPtr>();
145 int aType = ConstraintType::toSolveSpace(theType);
146 if (aType == SLVS_C_UNKNOWN)
147 return std::list<ConstraintWrapperPtr>();
149 Slvs_Constraint aConstraint =
150 Slvs_MakeConstraint(SLVS_C_UNKNOWN, (Slvs_hGroup)theGroupID, aType, (Slvs_hEntity)theSketchID,
151 theValue, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
153 std::list<EntityWrapperPtr> aConstrAttrList = theTrsfEnt;
155 aConstrAttrList.push_front(thePoint2);
156 aConstrAttrList.push_front(thePoint1);
158 ConstraintWrapperPtr aResult(new SolveSpaceSolver_ConstraintWrapper(theConstraint, aConstraint));
159 aResult->setValue(theValue);
160 aResult->setIsFullValue(theFullValue);
161 aResult->setEntities(aConstrAttrList);
162 return std::list<ConstraintWrapperPtr>(1, aResult);
166 std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createMirror(
167 ConstraintPtr theConstraint,
168 const GroupID& theGroupID,
169 const EntityID& theSketchID,
170 const EntityWrapperPtr& theEntity1,
171 const EntityWrapperPtr& theEntity2,
172 const EntityWrapperPtr& theMirrorLine) const
174 Slvs_Constraint aConstraint;
175 std::list<ConstraintWrapperPtr> aResult;
176 std::list<EntityWrapperPtr> aConstrAttrList;
177 if (theEntity1->type() == ENTITY_POINT) {
178 if (theEntity2->group() == theGroupID) // theEntity2 is not fixed
179 makeMirrorPoints(theEntity1, theEntity2, theMirrorLine);
181 aConstraint = Slvs_MakeConstraint(
182 SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID, SLVS_C_SYMMETRIC_LINE, (Slvs_hEntity)theSketchID,
183 0.0, (Slvs_hEntity)theEntity1->id(), (Slvs_hEntity)theEntity2->id(),
184 (Slvs_hEntity)theMirrorLine->id(), SLVS_E_UNKNOWN);
186 aConstrAttrList.push_back(theEntity1);
187 aConstrAttrList.push_back(theEntity2);
188 aConstrAttrList.push_back(theMirrorLine);
190 ConstraintWrapperPtr aWrapper(new SolveSpaceSolver_ConstraintWrapper(
191 theConstraint, aConstraint));
192 aWrapper->setEntities(aConstrAttrList);
193 aResult.push_back(aWrapper);
195 else if (theEntity1->type() == ENTITY_LINE) {
196 const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
197 const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
198 std::list<EntityWrapperPtr>::const_iterator anIt1 = aPoints1.begin();
199 std::list<EntityWrapperPtr>::const_iterator anIt2 = aPoints2.begin();
200 for (; anIt1 != aPoints1.end() && anIt2 != aPoints2.end(); ++anIt1, ++anIt2) {
201 std::list<ConstraintWrapperPtr> aMrrList =
202 createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
203 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
206 else if (theEntity1->type() == ENTITY_CIRCLE) {
207 const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
208 std::list<EntityWrapperPtr>::const_iterator anIt1 = aPoints1.begin();
209 for (; anIt1 != aPoints1.end(); ++anIt1)
210 if ((*anIt1)->type() == ENTITY_POINT)
212 const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
213 std::list<EntityWrapperPtr>::const_iterator anIt2 = aPoints2.begin();
214 for (; anIt2 != aPoints2.end(); ++anIt2)
215 if ((*anIt2)->type() == ENTITY_POINT)
218 std::list<ConstraintWrapperPtr> aMrrList =
219 createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
220 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
222 // Additional constraint for equal radii
223 aMrrList = createConstraint(theConstraint, theGroupID, theSketchID, CONSTRAINT_EQUAL_RADIUS,
224 0.0, EntityWrapperPtr(), EntityWrapperPtr(), theEntity1, theEntity2);
225 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
227 else if (theEntity1->type() == ENTITY_ARC) {
228 // Do not allow mirrored arc recalculate its position until coordinated of all points recalculated
229 FeaturePtr aMirrArc = theEntity2->baseFeature();
230 aMirrArc->data()->blockSendAttributeUpdated(true);
232 std::list<ConstraintWrapperPtr> aMrrList;
233 std::list<EntityWrapperPtr>::const_iterator anIt1 = theEntity1->subEntities().begin();
234 std::list<EntityWrapperPtr>::const_iterator anIt2 = theEntity2->subEntities().begin();
235 if ((*anIt2)->group() == theGroupID) // mirrored point is not fixed
236 makeMirrorPoints(*anIt1, *anIt2, theMirrorLine);
238 // Workaround to avoid problems in SolveSpace.
239 // The symmetry of two arcs will be done using symmetry of three points on these arcs:
240 // start point, end point, and any other point on the arc
241 std::list<EntityWrapperPtr> aBaseArcPoints(++anIt1, theEntity1->subEntities().end());
242 std::list<EntityWrapperPtr> aMirrorArcPoints(++anIt2, theEntity2->subEntities().end());
243 // indices of points of arc, center corresponds center, first point corresponds last point
244 aMirrorArcPoints.reverse();
246 anIt1 = aBaseArcPoints.begin();
247 anIt2 = aMirrorArcPoints.begin();
248 for (; anIt1 != aBaseArcPoints.end(); ++anIt1, ++anIt2) {
249 aMrrList = createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
250 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
252 // Restore event sending
253 aMirrArc->data()->blockSendAttributeUpdated(false);
258 void SolveSpaceSolver_Builder::adjustConstraint(ConstraintWrapperPtr theConstraint) const
260 SketchSolver_ConstraintType aType = theConstraint->type();
261 // Update flags in constraints
262 if (aType == CONSTRAINT_TANGENT_ARC_ARC || aType == CONSTRAINT_TANGENT_ARC_LINE)
263 adjustTangency(theConstraint);
264 else if (aType == CONSTRAINT_ANGLE)
265 adjustAngle(theConstraint);
266 else if (aType == CONSTRAINT_SYMMETRIC)
267 adjustMirror(theConstraint);
268 else if (aType == CONSTRAINT_MULTI_ROTATION)
269 adjustMultiRotation(theConstraint);
270 else if (aType == CONSTRAINT_MULTI_TRANSLATION)
271 adjustMultiTranslation(theConstraint);
274 EntityWrapperPtr SolveSpaceSolver_Builder::createFeature(
275 FeaturePtr theFeature,
276 const std::list<EntityWrapperPtr>& theAttributes,
277 const GroupID& theGroupID,
278 const EntityID& theSketchID) const
280 static EntityWrapperPtr aDummy;
281 if (!theFeature->data()->isValid())
285 CompositeFeaturePtr aSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
287 return createSketchEntity(aSketch, theGroupID);
289 // SketchPlugin features
290 std::shared_ptr<SketchPlugin_Feature> aFeature =
291 std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
295 // Verify the feature by its kind
296 const std::string& aFeatureKind = aFeature->getKind();
298 if (aFeatureKind == SketchPlugin_Line::ID())
299 return createLine(theFeature, theAttributes, theGroupID, theSketchID);
301 else if (aFeatureKind == SketchPlugin_Circle::ID())
302 return createCircle(theFeature, theAttributes,theGroupID, theSketchID);
304 else if (aFeatureKind == SketchPlugin_Arc::ID())
305 return createArc(theFeature, theAttributes,theGroupID, theSketchID);
306 // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
307 else if (aFeatureKind == SketchPlugin_Point::ID()) {
308 AttributePtr aPoint = theFeature->attribute(SketchPlugin_Point::COORD_ID());
309 if (!aPoint->isInitialized())
311 EntityWrapperPtr aSub = theAttributes.empty() ? createAttribute(aPoint, theGroupID, theSketchID) :
312 theAttributes.front();
316 const Slvs_Entity& aSubEnt =
317 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(aSub)->entity();
318 EntityWrapperPtr aResult(new SolveSpaceSolver_EntityWrapper(theFeature, aPoint, aSubEnt));
319 aResult->setSubEntities(theAttributes);
327 EntityWrapperPtr SolveSpaceSolver_Builder::createAttribute(
328 AttributePtr theAttribute,
329 const GroupID& theGroupID,
330 const EntityID& theSketchID) const
332 AttributePtr anAttribute = theAttribute;
333 AttributeRefAttrPtr aRefAttr =
334 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
336 if (aRefAttr->isObject()) {
337 // do not create features here
338 return EntityWrapperPtr();
340 anAttribute = aRefAttr->attr();
343 std::list<ParameterWrapperPtr> aParameters;
344 Slvs_Entity anEntity;
348 std::shared_ptr<GeomDataAPI_Point> aPoint =
349 std::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
351 aParameters.push_back(createParameter(theGroupID, aPoint->x(), !aPoint->textX().empty()));
352 aParameters.push_back(createParameter(theGroupID, aPoint->y(), !aPoint->textY().empty()));
353 aParameters.push_back(createParameter(theGroupID, aPoint->z(), !aPoint->textZ().empty()));
354 // Create entity (parameters are not filled)
355 anEntity = Slvs_MakePoint3d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
356 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
359 std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
360 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
362 aParameters.push_back(createParameter(theGroupID, aPoint2D->x(), !aPoint2D->textX().empty()));
363 aParameters.push_back(createParameter(theGroupID, aPoint2D->y(), !aPoint2D->textY().empty()));
364 // Create entity (parameters are not filled)
365 anEntity = Slvs_MakePoint2d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
366 (Slvs_hEntity)theSketchID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
368 // Scalar value (used for the distance entities)
369 AttributeDoublePtr aScalar =
370 std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
372 aParameters.push_back(createParameter(theGroupID, aScalar->value(), !aScalar->text().empty()));
373 // Create entity (parameter is not filled)
374 anEntity = Slvs_MakeDistance(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
375 (Slvs_hEntity)theSketchID, SLVS_E_UNKNOWN);
380 if (anEntity.type == 0) {
381 // unknown attribute type
382 return EntityWrapperPtr();
385 EntityWrapperPtr aResult(new SolveSpaceSolver_EntityWrapper(theAttribute, anEntity));
386 aResult->setParameters(aParameters);
392 EntityWrapperPtr SolveSpaceSolver_Builder::createSketchEntity(
393 CompositeFeaturePtr theSketch,
394 const GroupID& theGroupID) const
396 DataPtr aSketchData = theSketch->data();
397 if (!aSketchData || !aSketchData->isValid())
398 return EntityWrapperPtr(); // the sketch is incorrect
400 // Get parameters of workplane
401 AttributePtr aDirX = aSketchData->attribute(SketchPlugin_Sketch::DIRX_ID());
402 AttributePtr aNorm = aSketchData->attribute(SketchPlugin_Sketch::NORM_ID());
403 AttributePtr anOrigin = aSketchData->attribute(SketchPlugin_Sketch::ORIGIN_ID());
404 if (!anOrigin->isInitialized() || !aNorm->isInitialized() || !aDirX->isInitialized())
405 return EntityWrapperPtr();
407 EntityWrapperPtr aNewEnt;
408 std::list<EntityWrapperPtr> aSubs;
410 // Create SolveSpace entity corresponding to the sketch origin
411 aNewEnt = createAttribute(anOrigin, theGroupID);
413 return EntityWrapperPtr();
414 aSubs.push_back(aNewEnt);
416 // Create SolveSpace entity corresponding the the sketch normal
417 aNewEnt = createNormal(aNorm, aDirX, theGroupID);
419 return EntityWrapperPtr();
420 aSubs.push_back(aNewEnt);
423 Slvs_Entity aWorkplane = Slvs_MakeWorkplane(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
424 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
426 aNewEnt = EntityWrapperPtr(
427 new SolveSpaceSolver_EntityWrapper(FeaturePtr(theSketch), aWorkplane));
428 aNewEnt->setSubEntities(aSubs);
432 EntityWrapperPtr SolveSpaceSolver_Builder::createNormal(
433 AttributePtr theNormal,
434 AttributePtr theDirX,
435 const GroupID& theGroupID) const
437 std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theNormal);
438 std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
439 if (!aDirX || !aNorm ||
440 (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance) ||
441 !aNorm->isInitialized())
442 return EntityWrapperPtr();
443 // calculate Y direction
444 std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aDirX->dir())));
446 // quaternion parameters of normal vector
447 double qw, qx, qy, qz;
448 Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), aDirY->x(), aDirY->y(), aDirY->z(), &qw,
450 double aNormCoord[4] = { qw, qx, qy, qz };
452 // Create parameters of the normal
453 std::list<ParameterWrapperPtr> aParameters;
454 for (int i = 0; i < 4; i++)
455 aParameters.push_back(createParameter(theGroupID, aNormCoord[i]));
457 // Create a normal with empty parameters
458 Slvs_Entity aNormalEnt = Slvs_MakeNormal3d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
459 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
460 EntityWrapperPtr aNormal(new SolveSpaceSolver_EntityWrapper(theNormal, aNormalEnt));
461 aNormal->setParameters(aParameters);
465 ParameterWrapperPtr SolveSpaceSolver_Builder::createParameter(
466 const GroupID& theGroup, const double theValue, const bool theExpr) const
468 Slvs_Param aParam = Slvs_MakeParam(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroup, theValue);
469 ParameterWrapperPtr aWrapper(new SolveSpaceSolver_ParameterWrapper(aParam));
470 aWrapper->setIsParametric(theExpr);
478 // ================ Auxiliary functions ==========================
479 EntityWrapperPtr createLine(FeaturePtr theFeature,
480 const std::list<EntityWrapperPtr>& theAttributes,
481 const GroupID& theGroupID,
482 const EntityID& theSketchID)
484 EntityWrapperPtr aNewEntity;
485 std::list<EntityWrapperPtr> aSubs;
487 AttributePtr aStart = theFeature->attribute(SketchPlugin_Line::START_ID());
488 AttributePtr aEnd = theFeature->attribute(SketchPlugin_Line::END_ID());
489 if (!aStart->isInitialized() || !aEnd->isInitialized())
492 EntityWrapperPtr aStartEnt, aEndEnt;
493 std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
494 for (; anIt != theAttributes.end(); ++anIt) {
495 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
496 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
497 if (aSlvsEntity->isBase(aStart))
498 aStartEnt = aSlvsEntity;
499 else if (aSlvsEntity->isBase(aEnd))
500 aEndEnt = aSlvsEntity;
502 if (!aStartEnt || !aEndEnt)
505 aSubs.push_back(aStartEnt);
506 aSubs.push_back(aEndEnt);
507 Slvs_Entity anEntity = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
508 (Slvs_hEntity)theSketchID, (Slvs_hEntity)aStartEnt->id(), (Slvs_hEntity)aEndEnt->id());
510 aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
511 aNewEntity->setSubEntities(aSubs);
515 EntityWrapperPtr createCircle(FeaturePtr theFeature,
516 const std::list<EntityWrapperPtr>& theAttributes,
517 const GroupID& theGroupID,
518 const EntityID& theSketchID)
520 EntityWrapperPtr aNewEntity;
521 std::list<EntityWrapperPtr> aSubs;
523 AttributePtr aCenter = theFeature->attribute(SketchPlugin_Circle::CENTER_ID());
524 AttributePtr aRadius = theFeature->attribute(SketchPlugin_Circle::RADIUS_ID());
525 if (!aCenter->isInitialized() || !aRadius->isInitialized())
528 EntityWrapperPtr aCenterEnt, aRadiusEnt, aNormalEnt;
529 std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
530 for (; anIt != theAttributes.end(); ++anIt) {
531 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
532 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
533 if (aSlvsEntity->isBase(aCenter))
534 aCenterEnt = aSlvsEntity;
535 else if (aSlvsEntity->isBase(aRadius))
536 aRadiusEnt = aSlvsEntity;
537 else if (aSlvsEntity->type() == ENTITY_NORMAL)
538 aNormalEnt = aSlvsEntity;
540 if (!aCenterEnt || !aRadiusEnt || !aNormalEnt)
543 aSubs.push_back(aCenterEnt);
544 aSubs.push_back(aRadiusEnt);
545 Slvs_Entity anEntity = Slvs_MakeCircle(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
546 (Slvs_hEntity)theSketchID, (Slvs_hEntity)aCenterEnt->id(),
547 (Slvs_hEntity)aNormalEnt->id(), (Slvs_hEntity)aRadiusEnt->id());
549 aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
550 aNewEntity->setSubEntities(aSubs);
554 EntityWrapperPtr createArc(FeaturePtr theFeature,
555 const std::list<EntityWrapperPtr>& theAttributes,
556 const GroupID& theGroupID,
557 const EntityID& theSketchID)
559 EntityWrapperPtr aNewEntity;
560 std::list<EntityWrapperPtr> aSubs;
562 AttributePtr aCenter = theFeature->attribute(SketchPlugin_Arc::CENTER_ID());
563 AttributePtr aStart = theFeature->attribute(SketchPlugin_Arc::START_ID());
564 AttributePtr aEnd = theFeature->attribute(SketchPlugin_Arc::END_ID());
565 if (!aCenter->isInitialized() || !aStart->isInitialized() || !aEnd->isInitialized())
568 EntityWrapperPtr aCenterEnt, aStartEnt, aEndEnt, aNormalEnt;
569 std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
570 for (; anIt != theAttributes.end(); ++anIt) {
571 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
572 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
573 if (aSlvsEntity->isBase(aCenter))
574 aCenterEnt = aSlvsEntity;
575 else if (aSlvsEntity->isBase(aStart))
576 aStartEnt = aSlvsEntity;
577 else if (aSlvsEntity->isBase(aEnd))
578 aEndEnt = aSlvsEntity;
579 else if (aSlvsEntity->type() == ENTITY_NORMAL)
580 aNormalEnt = aSlvsEntity;
582 if (!aCenterEnt || !aStartEnt || !aEndEnt || !aNormalEnt)
585 aSubs.push_back(aCenterEnt);
586 aSubs.push_back(aStartEnt);
587 aSubs.push_back(aEndEnt);
588 Slvs_Entity anEntity = Slvs_MakeArcOfCircle(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
589 (Slvs_hEntity)theSketchID, (Slvs_hEntity)aNormalEnt->id(),
590 (Slvs_hEntity)aCenterEnt->id(), (Slvs_hEntity)aStartEnt->id(), (Slvs_hEntity)aEndEnt->id());
592 aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
593 aNewEntity->setSubEntities(aSubs);
598 void adjustTangency(ConstraintWrapperPtr theConstraint)
600 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
602 std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
603 std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
605 // Collect start, end points of entities
606 std::shared_ptr<GeomAPI_Pnt2d> aStartEntPoints[2][2];
607 bool isCoinc[2][2] = {false};
608 const std::list<EntityWrapperPtr>& aSubs = aConstraint->entities();
609 std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
610 for (int i = 0; aSIt != aSubs.end(); ++aSIt, ++i) {
611 const std::list<EntityWrapperPtr>& aPoints = (*aSIt)->subEntities();
612 std::list<EntityWrapperPtr>::const_iterator aPIt = aPoints.begin();
613 if ((*aSIt)->type() == ENTITY_ARC)
615 for (int j = 0; aPIt != aPoints.end(); ++aPIt, ++j) {
616 aStartEntPoints[i][j] = aBuilder->point(*aPIt);
617 if (i > 0) { // check coincidence
618 for (int k = 0; k < 2; ++k)
619 if (aStartEntPoints[i][j]->distance(aStartEntPoints[0][k]) < tolerance)
620 isCoinc[0][k] = isCoinc[i][j] = true;
625 Slvs_Constraint& aSlvsConstraint = aConstraint->changeConstraint();
626 if (isCoinc[0][0] == false && isCoinc[0][1] == true)
627 aSlvsConstraint.other = 1;
628 else aSlvsConstraint.other = 0;
629 if (isCoinc[1][0] == false && isCoinc[1][1] == true)
630 aSlvsConstraint.other2 = 1;
631 else aSlvsConstraint.other2 = 0;
634 void adjustAngle(ConstraintWrapperPtr theConstraint)
636 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
638 std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
639 std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
642 std::shared_ptr<GeomAPI_Pnt2d> aPoints[2][2]; // start and end points of lines
643 const std::list<EntityWrapperPtr>& aConstrLines = aConstraint->entities();
644 std::list<EntityWrapperPtr>::const_iterator aCLIt = aConstrLines.begin();
645 for (int i = 0; aCLIt != aConstrLines.end(); ++i, ++aCLIt) {
646 const std::list<EntityWrapperPtr>& aLinePoints = (*aCLIt)->subEntities();
647 std::list<EntityWrapperPtr>::const_iterator aLPIt = aLinePoints.begin();
648 for (int j = 0; aLPIt != aLinePoints.end(); ++j, ++aLPIt) {
649 isFixed[i][j] = ((*aLPIt)->group() != theConstraint->group());
650 aPoints[i][j] = aBuilder->point(*aLPIt);
654 if (isFixed[0][0] && isFixed[0][1] && isFixed[1][0] && isFixed[1][1])
655 return; // both lines are fixed => no need to update them
657 std::shared_ptr<GeomAPI_Lin2d> aLine[2] = {
658 std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[0][0], aPoints[0][1])),
659 std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[1][0], aPoints[1][1]))
661 std::shared_ptr<GeomAPI_Pnt2d> anIntersection = aLine[0]->intersect(aLine[1]);
665 for (int i = 0; i < 2; i++) {
666 for (int j = 0; j < 2; j++) {
667 aDist[i][j] = anIntersection->distance(aPoints[i][j]);
668 if (fabs(aDist[i][j]) <= tolerance)
671 if (aDist[i][0] > tolerance && aDist[i][1] > tolerance &&
672 aDist[i][0] + aDist[i][1] < aPoints[i][0]->distance(aPoints[i][1]) + 2.0 * tolerance) {
673 // the intersection point is an inner point of the line,
674 // we change the sign of distance till start point to calculate correct coordinates
679 std::shared_ptr<GeomAPI_Dir2d> aDir[2];
680 for (int i = 0; i < 2; i++) {
681 if (aDist[i][1] > fabs(aDist[i][0]))
682 aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(
683 aPoints[i][1]->xy()->decreased(anIntersection->xy())));
685 aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(
686 aPoints[i][0]->xy()->decreased(anIntersection->xy())));
687 // main direction is opposite => change signs
688 if (aDist[i][0] < 0.0) {
695 Slvs_Constraint& aSlvsConstraint = aConstraint->changeConstraint();
696 aSlvsConstraint.other = false;
697 for (int i = 0; i < 2; i++)
698 if (aLine[i]->direction()->dot(aDir[i]) < 0.0)
699 aSlvsConstraint.other = !aSlvsConstraint.other;
701 // Recalculate positions of lines to avoid conflicting constraints
702 // while changing angle value several times
703 double cosA = cos(aConstraint->value() * PI / 180.0);
704 double sinA = sin(aConstraint->value() * PI / 180.0);
705 if (aDir[0]->cross(aDir[1]) < 0.0)
708 if (isFixed[1][0] && isFixed[1][1]) {
712 double x = aDir[1-aLineToUpd]->x() * cosA - aDir[1-aLineToUpd]->y() * sinA;
713 double y = aDir[1-aLineToUpd]->x() * sinA + aDir[1-aLineToUpd]->y() * cosA;
715 std::shared_ptr<GeomAPI_Pnt2d> aNewPoints[2];
716 for (int i = 0; i < 2; i++) {
717 aNewPoints[i] = std::shared_ptr<GeomAPI_Pnt2d>(
718 new GeomAPI_Pnt2d(anIntersection->x() + x * aDist[aLineToUpd][i],
719 anIntersection->y() + y * aDist[aLineToUpd][i]));
722 std::shared_ptr<GeomAPI_XY> aDelta;
723 if (isFixed[aLineToUpd][0] && !isFixed[aLineToUpd][1])
724 aDelta = aPoints[aLineToUpd][0]->xy()->decreased(aNewPoints[0]->xy());
725 else if (!isFixed[aLineToUpd][0] && isFixed[aLineToUpd][1])
726 aDelta = aPoints[aLineToUpd][1]->xy()->decreased(aNewPoints[1]->xy());
728 for (int i = 0; i < 2; i++) {
729 aNewPoints[i]->setX(aNewPoints[i]->x() + aDelta->x());
730 aNewPoints[i]->setY(aNewPoints[i]->y() + aDelta->y());
734 // Update positions of points
735 std::list<EntityWrapperPtr>::const_iterator anUpdLine = aConstrLines.begin();
736 if (aLineToUpd > 0) ++anUpdLine;
737 const std::list<EntityWrapperPtr>& anUpdPoints = (*anUpdLine)->subEntities();
738 std::list<EntityWrapperPtr>::const_iterator aPIt = anUpdPoints.begin();
739 for (int i = 0; aPIt != anUpdPoints.end(); ++aPIt, ++i) {
740 double aCoord[2] = {aNewPoints[i]->x(), aNewPoints[i]->y()};
741 const std::list<ParameterWrapperPtr>& aParams = (*aPIt)->parameters();
742 std::list<ParameterWrapperPtr>::const_iterator aParIt = aParams.begin();
743 for (int j = 0; aParIt != aParams.end(); ++j, ++aParIt)
744 (*aParIt)->setValue(aCoord[j]);
748 void adjustMirror(ConstraintWrapperPtr theConstraint)
750 std::vector<EntityWrapperPtr> aPoints;
751 EntityWrapperPtr aMirrorLine;
753 const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
754 std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
755 for (; anIt != aSubs.end(); ++anIt) {
756 if ((*anIt)->type() == ENTITY_POINT)
757 aPoints.push_back(*anIt);
758 else if ((*anIt)->type() == ENTITY_LINE)
762 makeMirrorPoints(aPoints[0], aPoints[1], aMirrorLine);
765 void makeMirrorPoints(EntityWrapperPtr theOriginal,
766 EntityWrapperPtr theMirrored,
767 EntityWrapperPtr theMirrorLine)
769 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
771 std::shared_ptr<GeomAPI_Lin2d> aMirrorLine = aBuilder->line(theMirrorLine);
772 std::shared_ptr<GeomAPI_Dir2d> aMLDir = aMirrorLine->direction();
773 // orthogonal direction
774 aMLDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aMLDir->y(), -aMLDir->x()));
776 std::shared_ptr<GeomAPI_Pnt2d> aPoint = aBuilder->point(theOriginal);
777 std::shared_ptr<GeomAPI_XY> aVec = aPoint->xy()->decreased(aMirrorLine->location()->xy());
778 double aDist = aVec->dot(aMLDir->xy());
779 aVec = aPoint->xy()->added(aMLDir->xy()->multiplied(-2.0 * aDist));
780 double aCoord[2] = {aVec->x(), aVec->y()};
781 std::list<ParameterWrapperPtr>::const_iterator aMIt = theMirrored->parameters().begin();
782 for (int i = 0; aMIt != theMirrored->parameters().end(); ++aMIt, ++i)
783 (*aMIt)->setValue(aCoord[i]);
785 // update corresponding attribute
786 AttributePtr anAttr = std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theMirrored)->baseAttribute();
788 std::shared_ptr<GeomDataAPI_Point2D> aMirroredPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
789 aMirroredPnt->setValue(aCoord[0], aCoord[1]);
793 static void rotate(EntityWrapperPtr theSource, EntityWrapperPtr theDest,
794 std::shared_ptr<GeomAPI_Pnt2d> theCenter,
795 double theSin, double theCos)
797 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSource =
798 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theSource);
799 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aDest =
800 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theDest);
802 if (theSource->type() == ENTITY_POINT) {
803 // Rotate single point
804 std::shared_ptr<GeomDataAPI_Point2D> aSrcAttr =
805 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aSource->baseAttribute());
806 std::shared_ptr<GeomDataAPI_Point2D> aDstAttr =
807 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aDest->baseAttribute());
808 if (aSrcAttr && aDstAttr) {
809 std::shared_ptr<GeomAPI_XY> aVec = aSrcAttr->pnt()->xy()->decreased(theCenter->xy());
810 double aNewX = aVec->x() * theCos - aVec->y() * theSin;
811 double aNewY = aVec->x() * theSin + aVec->y() * theCos;
812 aDstAttr->setValue(theCenter->x() + aNewX, theCenter->y() + aNewY);
817 FeaturePtr aDestFeature = aDest->baseFeature();
819 aDestFeature->data()->blockSendAttributeUpdated(true);
821 // Rotate points of the feature
822 const std::list<EntityWrapperPtr>& aSrcSubs = theSource->subEntities();
823 const std::list<EntityWrapperPtr>& aDstSubs = theDest->subEntities();
824 std::list<EntityWrapperPtr>::const_iterator aSrcIt, aDstIt;
825 for (aSrcIt = aSrcSubs.begin(), aDstIt = aDstSubs.begin();
826 aSrcIt != aSrcSubs.end() && aDstIt != aDstSubs.end(); ++aSrcIt, ++aDstIt)
827 rotate(*aSrcIt, *aDstIt, theCenter, theSin, theCos);
830 aDestFeature->data()->blockSendAttributeUpdated(false);
833 static void translate(EntityWrapperPtr theSource, EntityWrapperPtr theDest,
834 std::shared_ptr<GeomAPI_XY> theDelta)
836 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSource =
837 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theSource);
838 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aDest =
839 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theDest);
841 if (theSource->type() == ENTITY_POINT) {
842 // Translate single point
843 std::shared_ptr<GeomDataAPI_Point2D> aSrcAttr =
844 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aSource->baseAttribute());
845 std::shared_ptr<GeomDataAPI_Point2D> aDstAttr =
846 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aDest->baseAttribute());
847 if (aSrcAttr && aDstAttr)
848 aDstAttr->setValue(aSrcAttr->x() + theDelta->x(), aSrcAttr->y() + theDelta->y());
852 FeaturePtr aDestFeature = aDest->baseFeature();
854 aDestFeature->data()->blockSendAttributeUpdated(true);
856 // Translate points of the feature
857 const std::list<EntityWrapperPtr>& aSrcSubs = theSource->subEntities();
858 const std::list<EntityWrapperPtr>& aDstSubs = theDest->subEntities();
859 std::list<EntityWrapperPtr>::const_iterator aSrcIt, aDstIt;
860 for (aSrcIt = aSrcSubs.begin(), aDstIt = aDstSubs.begin();
861 aSrcIt != aSrcSubs.end() && aDstIt != aDstSubs.end(); ++aSrcIt, ++aDstIt)
862 translate(*aSrcIt, *aDstIt, theDelta);
865 aDestFeature->data()->blockSendAttributeUpdated(false);
868 void adjustMultiRotation(ConstraintWrapperPtr theConstraint)
870 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
872 double anAngleValue = theConstraint->value();
873 const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
875 bool isFullValue = theConstraint->isFullValue();
876 int aNbObjects = aSubs.size()-2;
877 if (isFullValue && aNbObjects > 0) {
878 anAngleValue /= aNbObjects;
881 double anAngleRad = anAngleValue * PI / 180.0;
882 double aSin = sin(anAngleRad);
883 double aCos = cos(anAngleRad);
885 std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
887 std::shared_ptr<GeomAPI_Pnt2d> aCenter = aBuilder->point(*aSIt++);
888 std::list<EntityWrapperPtr>::const_iterator aPrevIt = aSIt++;
889 for (; aSIt != aSubs.end(); ++aPrevIt, ++aSIt)
890 rotate(*aPrevIt, *aSIt, aCenter, aSin, aCos);
893 void adjustMultiTranslation(ConstraintWrapperPtr theConstraint)
895 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
897 const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
898 std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
900 std::shared_ptr<GeomAPI_Pnt2d> aStartPnt = aBuilder->point(*aSIt++);
901 std::shared_ptr<GeomAPI_Pnt2d> aEndPnt = aBuilder->point(*aSIt++);
902 std::shared_ptr<GeomAPI_XY> aDelta = aEndPnt->xy()->decreased(aStartPnt->xy());
904 bool isFullValue = theConstraint->isFullValue();
905 int aNbObjects = aSubs.size()-3;
906 if (isFullValue && aNbObjects > 0) {
907 aDelta->setX(aDelta->x()/aNbObjects);
908 aDelta->setY(aDelta->y()/aNbObjects);
911 std::list<EntityWrapperPtr>::const_iterator aPrevIt = aSIt++;
912 for (; aSIt != aSubs.end(); ++aPrevIt, ++aSIt)
913 translate(*aPrevIt, *aSIt, aDelta);