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);
110 else if (theType == CONSTRAINT_COLLINEAR) {
111 // replace by two constraints point-on-line
112 std::list<ConstraintWrapperPtr> aConstraints;
113 const std::list<EntityWrapperPtr>& aSubs1 = theEntity1->subEntities();
114 const std::list<EntityWrapperPtr>& aSubs2 = theEntity2->subEntities();
115 std::list<EntityWrapperPtr>::const_iterator anIt1, anIt2;
116 for (anIt2 = aSubs2.begin(); anIt2 != aSubs2.end(); ++anIt2) {
117 for (anIt1 = aSubs1.begin(); anIt1 != aSubs1.end(); ++anIt1)
118 if ((*anIt1)->id() == (*anIt2)->id())
120 if (anIt1 != aSubs1.end())
121 continue; // the lines have coincident point
123 std::list<ConstraintWrapperPtr> aC = createConstraint(theConstraint, theGroupID,
124 theSketchID, CONSTRAINT_PT_ON_LINE, theValue, *anIt2, EntityWrapperPtr(), theEntity1);
125 aConstraints.insert(aConstraints.end(), aC.begin(), aC.end());
130 int aType = ConstraintType::toSolveSpace(theType);
131 if (aType == SLVS_C_UNKNOWN)
132 return std::list<ConstraintWrapperPtr>();
134 Slvs_hEntity aSlvsEntities[4] = {SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN};
135 EntityWrapperPtr anOriginal[4] = {thePoint1, thePoint2, theEntity1, theEntity2};
136 std::list<EntityWrapperPtr> aConstrAttrList; // to be filled
137 for (int i = 0; i < 4; ++i) {
140 aSlvsEntities[i] = (Slvs_hEntity)anOriginal[i]->id();
141 if (aSlvsEntities[i] == SLVS_E_UNKNOWN)
142 return std::list<ConstraintWrapperPtr>(); // entity is not added into a storage, constraint can not be created
143 aConstrAttrList.push_back(anOriginal[i]);
146 Slvs_Constraint aConstraint = Slvs_MakeConstraint(
147 SLVS_C_UNKNOWN, (Slvs_hGroup)theGroupID, aType, (Slvs_hEntity)theSketchID,
148 theValue, aSlvsEntities[0], aSlvsEntities[1], aSlvsEntities[2], aSlvsEntities[3]);
149 ConstraintWrapperPtr aResult(new SolveSpaceSolver_ConstraintWrapper(theConstraint, aConstraint));
150 aResult->setGroup(theGroupID);
151 aResult->setValue(theValue);
152 aResult->setEntities(aConstrAttrList);
153 adjustConstraint(aResult);
155 return std::list<ConstraintWrapperPtr>(1, aResult);
158 std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createConstraint(
159 ConstraintPtr theConstraint,
160 const GroupID& theGroupID,
161 const EntityID& theSketchID,
162 const SketchSolver_ConstraintType& theType,
163 const double& theValue,
164 const bool theFullValue,
165 const EntityWrapperPtr& thePoint1,
166 const EntityWrapperPtr& thePoint2,
167 const std::list<EntityWrapperPtr>& theTrsfEnt) const
169 if (theType != CONSTRAINT_MULTI_ROTATION && theType != CONSTRAINT_MULTI_TRANSLATION)
170 return std::list<ConstraintWrapperPtr>();
172 int aType = ConstraintType::toSolveSpace(theType);
173 if (aType == SLVS_C_UNKNOWN)
174 return std::list<ConstraintWrapperPtr>();
176 Slvs_Constraint aConstraint =
177 Slvs_MakeConstraint(SLVS_C_UNKNOWN, (Slvs_hGroup)theGroupID, aType, (Slvs_hEntity)theSketchID,
178 theValue, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
180 std::list<EntityWrapperPtr> aConstrAttrList = theTrsfEnt;
182 aConstrAttrList.push_front(thePoint2);
183 aConstrAttrList.push_front(thePoint1);
185 ConstraintWrapperPtr aResult(new SolveSpaceSolver_ConstraintWrapper(theConstraint, aConstraint));
186 aResult->setGroup(theGroupID);
187 aResult->setValue(theValue);
188 aResult->setIsFullValue(theFullValue);
189 aResult->setEntities(aConstrAttrList);
190 return std::list<ConstraintWrapperPtr>(1, aResult);
194 std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createMirror(
195 ConstraintPtr theConstraint,
196 const GroupID& theGroupID,
197 const EntityID& theSketchID,
198 const EntityWrapperPtr& theEntity1,
199 const EntityWrapperPtr& theEntity2,
200 const EntityWrapperPtr& theMirrorLine) const
202 Slvs_Constraint aConstraint;
203 std::list<ConstraintWrapperPtr> aResult;
204 std::list<EntityWrapperPtr> aConstrAttrList;
205 if (theEntity1->type() == ENTITY_POINT) {
206 if (theEntity2->group() == theGroupID) // theEntity2 is not fixed
207 makeMirrorPoints(theEntity1, theEntity2, theMirrorLine);
209 aConstraint = Slvs_MakeConstraint(
210 SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID, SLVS_C_SYMMETRIC_LINE, (Slvs_hEntity)theSketchID,
211 0.0, (Slvs_hEntity)theEntity1->id(), (Slvs_hEntity)theEntity2->id(),
212 (Slvs_hEntity)theMirrorLine->id(), SLVS_E_UNKNOWN);
214 aConstrAttrList.push_back(theEntity1);
215 aConstrAttrList.push_back(theEntity2);
216 aConstrAttrList.push_back(theMirrorLine);
218 ConstraintWrapperPtr aWrapper(new SolveSpaceSolver_ConstraintWrapper(
219 theConstraint, aConstraint));
220 aWrapper->setGroup(theGroupID);
221 aWrapper->setEntities(aConstrAttrList);
222 aResult.push_back(aWrapper);
224 else if (theEntity1->type() == ENTITY_LINE) {
225 const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
226 const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
227 std::list<EntityWrapperPtr>::const_iterator anIt1 = aPoints1.begin();
228 std::list<EntityWrapperPtr>::const_iterator anIt2 = aPoints2.begin();
229 for (; anIt1 != aPoints1.end() && anIt2 != aPoints2.end(); ++anIt1, ++anIt2) {
230 std::list<ConstraintWrapperPtr> aMrrList =
231 createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
232 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
235 else if (theEntity1->type() == ENTITY_CIRCLE) {
236 const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
237 std::list<EntityWrapperPtr>::const_iterator anIt1 = aPoints1.begin();
238 for (; anIt1 != aPoints1.end(); ++anIt1)
239 if ((*anIt1)->type() == ENTITY_POINT)
241 const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
242 std::list<EntityWrapperPtr>::const_iterator anIt2 = aPoints2.begin();
243 for (; anIt2 != aPoints2.end(); ++anIt2)
244 if ((*anIt2)->type() == ENTITY_POINT)
247 std::list<ConstraintWrapperPtr> aMrrList =
248 createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
249 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
251 // Additional constraint for equal radii
252 aMrrList = createConstraint(theConstraint, theGroupID, theSketchID, CONSTRAINT_EQUAL_RADIUS,
253 0.0, EntityWrapperPtr(), EntityWrapperPtr(), theEntity1, theEntity2);
254 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
256 else if (theEntity1->type() == ENTITY_ARC) {
257 // Do not allow mirrored arc recalculate its position until coordinated of all points recalculated
258 FeaturePtr aMirrArc = theEntity2->baseFeature();
259 aMirrArc->data()->blockSendAttributeUpdated(true);
261 std::list<ConstraintWrapperPtr> aMrrList;
262 std::list<EntityWrapperPtr>::const_iterator anIt1 = theEntity1->subEntities().begin();
263 std::list<EntityWrapperPtr>::const_iterator anIt2 = theEntity2->subEntities().begin();
264 if ((*anIt2)->group() == theGroupID) // mirrored point is not fixed
265 makeMirrorPoints(*anIt1, *anIt2, theMirrorLine);
267 // Workaround to avoid problems in SolveSpace.
268 // The symmetry of two arcs will be done using symmetry of three points on these arcs:
269 // start point, end point, and any other point on the arc
270 std::list<EntityWrapperPtr> aBaseArcPoints(++anIt1, theEntity1->subEntities().end());
271 std::list<EntityWrapperPtr> aMirrorArcPoints(++anIt2, theEntity2->subEntities().end());
272 // indices of points of arc, center corresponds center, first point corresponds last point
273 aMirrorArcPoints.reverse();
275 anIt1 = aBaseArcPoints.begin();
276 anIt2 = aMirrorArcPoints.begin();
277 for (; anIt1 != aBaseArcPoints.end(); ++anIt1, ++anIt2) {
278 aMrrList = createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
279 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
281 // Restore event sending
282 aMirrArc->data()->blockSendAttributeUpdated(false);
287 void SolveSpaceSolver_Builder::adjustConstraint(ConstraintWrapperPtr theConstraint) const
289 SketchSolver_ConstraintType aType = theConstraint->type();
290 // Update flags in constraints
291 if (aType == CONSTRAINT_TANGENT_ARC_ARC || aType == CONSTRAINT_TANGENT_ARC_LINE)
292 adjustTangency(theConstraint);
293 else if (aType == CONSTRAINT_ANGLE)
294 adjustAngle(theConstraint);
295 else if (aType == CONSTRAINT_SYMMETRIC)
296 adjustMirror(theConstraint);
297 else if (aType == CONSTRAINT_PT_LINE_DISTANCE)
298 adjustPtLineDistance(theConstraint);
301 EntityWrapperPtr SolveSpaceSolver_Builder::createFeature(
302 FeaturePtr theFeature,
303 const std::list<EntityWrapperPtr>& theAttributes,
304 const GroupID& theGroupID,
305 const EntityID& theSketchID) const
307 static EntityWrapperPtr aDummy;
308 if (!theFeature->data()->isValid())
312 CompositeFeaturePtr aSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
314 return createSketchEntity(aSketch, theGroupID);
316 // SketchPlugin features
317 std::shared_ptr<SketchPlugin_Feature> aFeature =
318 std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
322 // Verify the feature by its kind
323 const std::string& aFeatureKind = aFeature->getKind();
325 if (aFeatureKind == SketchPlugin_Line::ID())
326 return createLine(theFeature, theAttributes, theGroupID, theSketchID);
328 else if (aFeatureKind == SketchPlugin_Circle::ID())
329 return createCircle(theFeature, theAttributes, theGroupID, theSketchID);
331 else if (aFeatureKind == SketchPlugin_Arc::ID())
332 return createArc(theFeature, theAttributes, theGroupID, theSketchID);
333 // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
334 else if (aFeatureKind == SketchPlugin_Point::ID()) {
335 AttributePtr aPoint = theFeature->attribute(SketchPlugin_Point::COORD_ID());
336 if (!aPoint->isInitialized())
338 EntityWrapperPtr aSub = theAttributes.empty() ? createAttribute(aPoint, theGroupID, theSketchID) :
339 theAttributes.front();
343 const Slvs_Entity& aSubEnt =
344 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(aSub)->entity();
345 EntityWrapperPtr aResult(new SolveSpaceSolver_EntityWrapper(theFeature, aPoint, aSubEnt));
346 aResult->setSubEntities(theAttributes);
354 EntityWrapperPtr SolveSpaceSolver_Builder::createAttribute(
355 AttributePtr theAttribute,
356 const GroupID& theGroupID,
357 const EntityID& theSketchID) const
359 AttributePtr anAttribute = theAttribute;
360 AttributeRefAttrPtr aRefAttr =
361 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
363 if (aRefAttr->isObject()) {
364 // do not create features here
365 return EntityWrapperPtr();
367 anAttribute = aRefAttr->attr();
370 std::list<ParameterWrapperPtr> aParameters;
371 Slvs_Entity anEntity;
375 std::shared_ptr<GeomDataAPI_Point> aPoint =
376 std::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
378 aParameters.push_back(createParameter(theGroupID, aPoint->x(), !aPoint->textX().empty()));
379 aParameters.push_back(createParameter(theGroupID, aPoint->y(), !aPoint->textY().empty()));
380 aParameters.push_back(createParameter(theGroupID, aPoint->z(), !aPoint->textZ().empty()));
381 // Create entity (parameters are not filled)
382 anEntity = Slvs_MakePoint3d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
383 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
386 std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
387 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
389 aParameters.push_back(createParameter(theGroupID, aPoint2D->x(), !aPoint2D->textX().empty()));
390 aParameters.push_back(createParameter(theGroupID, aPoint2D->y(), !aPoint2D->textY().empty()));
391 // Create entity (parameters are not filled)
392 anEntity = Slvs_MakePoint2d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
393 (Slvs_hEntity)theSketchID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
395 // Scalar value (used for the distance entities)
396 AttributeDoublePtr aScalar =
397 std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
399 aParameters.push_back(createParameter(theGroupID, aScalar->value(), !aScalar->text().empty()));
400 // Create entity (parameter is not filled)
401 anEntity = Slvs_MakeDistance(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
402 (Slvs_hEntity)theSketchID, SLVS_E_UNKNOWN);
407 if (anEntity.type == 0) {
408 // unknown attribute type
409 return EntityWrapperPtr();
412 EntityWrapperPtr aResult(new SolveSpaceSolver_EntityWrapper(theAttribute, anEntity));
413 aResult->setParameters(aParameters);
419 EntityWrapperPtr SolveSpaceSolver_Builder::createSketchEntity(
420 CompositeFeaturePtr theSketch,
421 const GroupID& theGroupID) const
423 DataPtr aSketchData = theSketch->data();
424 if (!aSketchData || !aSketchData->isValid())
425 return EntityWrapperPtr(); // the sketch is incorrect
427 // Get parameters of workplane
428 AttributePtr aDirX = aSketchData->attribute(SketchPlugin_Sketch::DIRX_ID());
429 AttributePtr aNorm = aSketchData->attribute(SketchPlugin_Sketch::NORM_ID());
430 AttributePtr anOrigin = aSketchData->attribute(SketchPlugin_Sketch::ORIGIN_ID());
431 if (!anOrigin->isInitialized() || !aNorm->isInitialized() || !aDirX->isInitialized())
432 return EntityWrapperPtr();
434 EntityWrapperPtr aNewEnt;
435 std::list<EntityWrapperPtr> aSubs;
437 // Create SolveSpace entity corresponding to the sketch origin
438 aNewEnt = createAttribute(anOrigin, theGroupID);
440 return EntityWrapperPtr();
441 aSubs.push_back(aNewEnt);
443 // Create SolveSpace entity corresponding the the sketch normal
444 aNewEnt = createNormal(aNorm, aDirX, theGroupID);
446 return EntityWrapperPtr();
447 aSubs.push_back(aNewEnt);
450 Slvs_Entity aWorkplane = Slvs_MakeWorkplane(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
451 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
453 aNewEnt = EntityWrapperPtr(
454 new SolveSpaceSolver_EntityWrapper(FeaturePtr(theSketch), aWorkplane));
455 aNewEnt->setSubEntities(aSubs);
459 EntityWrapperPtr SolveSpaceSolver_Builder::createNormal(
460 AttributePtr theNormal,
461 AttributePtr theDirX,
462 const GroupID& theGroupID) const
464 std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theNormal);
465 std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
466 if (!aDirX || !aNorm ||
467 (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance) ||
468 !aNorm->isInitialized())
469 return EntityWrapperPtr();
470 // calculate Y direction
471 std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aDirX->dir())));
473 // quaternion parameters of normal vector
474 double qw, qx, qy, qz;
475 Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), aDirY->x(), aDirY->y(), aDirY->z(), &qw,
477 double aNormCoord[4] = { qw, qx, qy, qz };
479 // Create parameters of the normal
480 std::list<ParameterWrapperPtr> aParameters;
481 for (int i = 0; i < 4; i++)
482 aParameters.push_back(createParameter(theGroupID, aNormCoord[i]));
484 // Create a normal with empty parameters
485 Slvs_Entity aNormalEnt = Slvs_MakeNormal3d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
486 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
487 EntityWrapperPtr aNormal(new SolveSpaceSolver_EntityWrapper(theNormal, aNormalEnt));
488 aNormal->setParameters(aParameters);
492 ParameterWrapperPtr SolveSpaceSolver_Builder::createParameter(
493 const GroupID& theGroup, const double theValue, const bool theExpr) const
495 Slvs_Param aParam = Slvs_MakeParam(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroup, theValue);
496 ParameterWrapperPtr aWrapper(new SolveSpaceSolver_ParameterWrapper(aParam));
497 aWrapper->setIsParametric(theExpr);
505 // ================ Auxiliary functions ==========================
506 EntityWrapperPtr createLine(FeaturePtr theFeature,
507 const std::list<EntityWrapperPtr>& theAttributes,
508 const GroupID& theGroupID,
509 const EntityID& theSketchID)
511 EntityWrapperPtr aNewEntity;
512 std::list<EntityWrapperPtr> aSubs;
514 AttributePtr aStart = theFeature->attribute(SketchPlugin_Line::START_ID());
515 AttributePtr aEnd = theFeature->attribute(SketchPlugin_Line::END_ID());
516 if (!aStart->isInitialized() || !aEnd->isInitialized())
519 EntityWrapperPtr aStartEnt, aEndEnt;
520 std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
521 for (; anIt != theAttributes.end(); ++anIt) {
522 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
523 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
524 if (aSlvsEntity->isBase(aStart))
525 aStartEnt = aSlvsEntity;
526 else if (aSlvsEntity->isBase(aEnd))
527 aEndEnt = aSlvsEntity;
529 if (!aStartEnt || !aEndEnt)
532 aSubs.push_back(aStartEnt);
533 aSubs.push_back(aEndEnt);
534 Slvs_Entity anEntity = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
535 (Slvs_hEntity)theSketchID, (Slvs_hEntity)aStartEnt->id(), (Slvs_hEntity)aEndEnt->id());
537 aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
538 aNewEntity->setSubEntities(aSubs);
542 EntityWrapperPtr createCircle(FeaturePtr theFeature,
543 const std::list<EntityWrapperPtr>& theAttributes,
544 const GroupID& theGroupID,
545 const EntityID& theSketchID)
547 EntityWrapperPtr aNewEntity;
548 std::list<EntityWrapperPtr> aSubs;
550 AttributePtr aCenter = theFeature->attribute(SketchPlugin_Circle::CENTER_ID());
551 AttributePtr aRadius = theFeature->attribute(SketchPlugin_Circle::RADIUS_ID());
552 if (!aCenter->isInitialized() || !aRadius->isInitialized())
555 EntityWrapperPtr aCenterEnt, aRadiusEnt, aNormalEnt;
556 std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
557 for (; anIt != theAttributes.end(); ++anIt) {
558 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
559 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
560 if (aSlvsEntity->isBase(aCenter))
561 aCenterEnt = aSlvsEntity;
562 else if (aSlvsEntity->isBase(aRadius))
563 aRadiusEnt = aSlvsEntity;
564 else if (aSlvsEntity->type() == ENTITY_NORMAL)
565 aNormalEnt = aSlvsEntity;
567 if (!aCenterEnt || !aRadiusEnt || !aNormalEnt)
570 aSubs.push_back(aCenterEnt);
571 aSubs.push_back(aRadiusEnt);
572 Slvs_Entity anEntity = Slvs_MakeCircle(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
573 (Slvs_hEntity)theSketchID, (Slvs_hEntity)aCenterEnt->id(),
574 (Slvs_hEntity)aNormalEnt->id(), (Slvs_hEntity)aRadiusEnt->id());
576 aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
577 aNewEntity->setSubEntities(aSubs);
581 EntityWrapperPtr createArc(FeaturePtr theFeature,
582 const std::list<EntityWrapperPtr>& theAttributes,
583 const GroupID& theGroupID,
584 const EntityID& theSketchID)
586 EntityWrapperPtr aNewEntity;
587 std::list<EntityWrapperPtr> aSubs;
589 AttributePtr aCenter = theFeature->attribute(SketchPlugin_Arc::CENTER_ID());
590 AttributePtr aStart = theFeature->attribute(SketchPlugin_Arc::START_ID());
591 AttributePtr aEnd = theFeature->attribute(SketchPlugin_Arc::END_ID());
592 if (!aCenter->isInitialized() || !aStart->isInitialized() || !aEnd->isInitialized())
595 EntityWrapperPtr aCenterEnt, aStartEnt, aEndEnt, aNormalEnt;
596 std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
597 for (; anIt != theAttributes.end(); ++anIt) {
598 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
599 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
600 if (aSlvsEntity->isBase(aCenter))
601 aCenterEnt = aSlvsEntity;
602 else if (aSlvsEntity->isBase(aStart))
603 aStartEnt = aSlvsEntity;
604 else if (aSlvsEntity->isBase(aEnd))
605 aEndEnt = aSlvsEntity;
606 else if (aSlvsEntity->type() == ENTITY_NORMAL)
607 aNormalEnt = aSlvsEntity;
609 if (!aCenterEnt || !aStartEnt || !aEndEnt || !aNormalEnt)
612 aSubs.push_back(aCenterEnt);
613 aSubs.push_back(aStartEnt);
614 aSubs.push_back(aEndEnt);
615 Slvs_Entity anEntity = Slvs_MakeArcOfCircle(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
616 (Slvs_hEntity)theSketchID, (Slvs_hEntity)aNormalEnt->id(),
617 (Slvs_hEntity)aCenterEnt->id(), (Slvs_hEntity)aStartEnt->id(), (Slvs_hEntity)aEndEnt->id());
619 aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
620 aNewEntity->setSubEntities(aSubs);
625 void adjustTangency(ConstraintWrapperPtr theConstraint)
627 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
629 std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
630 std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
632 // Collect start, end points of entities
633 std::shared_ptr<GeomAPI_Pnt2d> aStartEntPoints[2][2];
634 bool isCoinc[2][2] = {false};
635 const std::list<EntityWrapperPtr>& aSubs = aConstraint->entities();
636 std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
637 for (int i = 0; aSIt != aSubs.end(); ++aSIt, ++i) {
638 const std::list<EntityWrapperPtr>& aPoints = (*aSIt)->subEntities();
639 std::list<EntityWrapperPtr>::const_iterator aPIt = aPoints.begin();
640 if ((*aSIt)->type() == ENTITY_ARC)
642 for (int j = 0; aPIt != aPoints.end(); ++aPIt, ++j) {
643 aStartEntPoints[i][j] = aBuilder->point(*aPIt);
644 if (i > 0) { // check coincidence
645 for (int k = 0; k < 2; ++k)
646 if (aStartEntPoints[i][j]->distance(aStartEntPoints[0][k]) < tolerance)
647 isCoinc[0][k] = isCoinc[i][j] = true;
652 Slvs_Constraint& aSlvsConstraint = aConstraint->changeConstraint();
653 if (isCoinc[0][0] == false && isCoinc[0][1] == true)
654 aSlvsConstraint.other = 1;
655 else aSlvsConstraint.other = 0;
656 if (isCoinc[1][0] == false && isCoinc[1][1] == true)
657 aSlvsConstraint.other2 = 1;
658 else aSlvsConstraint.other2 = 0;
661 void adjustAngle(ConstraintWrapperPtr theConstraint)
663 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
665 std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
666 std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
669 std::shared_ptr<GeomAPI_Pnt2d> aPoints[2][2]; // start and end points of lines
670 const std::list<EntityWrapperPtr>& aConstrLines = aConstraint->entities();
671 std::list<EntityWrapperPtr>::const_iterator aCLIt = aConstrLines.begin();
672 for (int i = 0; aCLIt != aConstrLines.end(); ++i, ++aCLIt) {
673 const std::list<EntityWrapperPtr>& aLinePoints = (*aCLIt)->subEntities();
674 std::list<EntityWrapperPtr>::const_iterator aLPIt = aLinePoints.begin();
675 for (int j = 0; aLPIt != aLinePoints.end(); ++j, ++aLPIt) {
676 isFixed[i][j] = ((*aLPIt)->group() != theConstraint->group());
677 aPoints[i][j] = aBuilder->point(*aLPIt);
681 if (isFixed[0][0] && isFixed[0][1] && isFixed[1][0] && isFixed[1][1])
682 return; // both lines are fixed => no need to update them
684 std::shared_ptr<GeomAPI_Lin2d> aLine[2] = {
685 std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[0][0], aPoints[0][1])),
686 std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[1][0], aPoints[1][1]))
688 std::shared_ptr<GeomAPI_Pnt2d> anIntersection = aLine[0]->intersect(aLine[1]);
692 for (int i = 0; i < 2; i++) {
693 for (int j = 0; j < 2; j++) {
694 aDist[i][j] = anIntersection->distance(aPoints[i][j]);
695 if (fabs(aDist[i][j]) <= tolerance)
698 if (aDist[i][0] > tolerance && aDist[i][1] > tolerance &&
699 aDist[i][0] + aDist[i][1] < aPoints[i][0]->distance(aPoints[i][1]) + 2.0 * tolerance) {
700 // the intersection point is an inner point of the line,
701 // we change the sign of distance till start point to calculate correct coordinates
706 std::shared_ptr<GeomAPI_Dir2d> aDir[2];
707 for (int i = 0; i < 2; i++) {
708 if (aDist[i][1] > fabs(aDist[i][0]))
709 aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(
710 aPoints[i][1]->xy()->decreased(anIntersection->xy())));
712 aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(
713 aPoints[i][0]->xy()->decreased(anIntersection->xy())));
714 // main direction is opposite => change signs
715 if (aDist[i][0] < 0.0) {
722 Slvs_Constraint& aSlvsConstraint = aConstraint->changeConstraint();
723 aSlvsConstraint.other = false;
724 for (int i = 0; i < 2; i++)
725 if (aLine[i]->direction()->dot(aDir[i]) < 0.0)
726 aSlvsConstraint.other = !aSlvsConstraint.other;
728 // Recalculate positions of lines to avoid conflicting constraints
729 // while changing angle value several times
730 double cosA = cos(aConstraint->value() * PI / 180.0);
731 double sinA = sin(aConstraint->value() * PI / 180.0);
732 if (aDir[0]->cross(aDir[1]) < 0.0)
735 if (isFixed[1][0] && isFixed[1][1]) {
739 double x = aDir[1-aLineToUpd]->x() * cosA - aDir[1-aLineToUpd]->y() * sinA;
740 double y = aDir[1-aLineToUpd]->x() * sinA + aDir[1-aLineToUpd]->y() * cosA;
742 std::shared_ptr<GeomAPI_Pnt2d> aNewPoints[2];
743 for (int i = 0; i < 2; i++) {
744 aNewPoints[i] = std::shared_ptr<GeomAPI_Pnt2d>(
745 new GeomAPI_Pnt2d(anIntersection->x() + x * aDist[aLineToUpd][i],
746 anIntersection->y() + y * aDist[aLineToUpd][i]));
749 std::shared_ptr<GeomAPI_XY> aDelta;
750 if (isFixed[aLineToUpd][0] && !isFixed[aLineToUpd][1])
751 aDelta = aPoints[aLineToUpd][0]->xy()->decreased(aNewPoints[0]->xy());
752 else if (!isFixed[aLineToUpd][0] && isFixed[aLineToUpd][1])
753 aDelta = aPoints[aLineToUpd][1]->xy()->decreased(aNewPoints[1]->xy());
755 for (int i = 0; i < 2; i++) {
756 aNewPoints[i]->setX(aNewPoints[i]->x() + aDelta->x());
757 aNewPoints[i]->setY(aNewPoints[i]->y() + aDelta->y());
761 // Update positions of points
762 std::list<EntityWrapperPtr>::const_iterator anUpdLine = aConstrLines.begin();
763 if (aLineToUpd > 0) ++anUpdLine;
764 const std::list<EntityWrapperPtr>& anUpdPoints = (*anUpdLine)->subEntities();
765 std::list<EntityWrapperPtr>::const_iterator aPIt = anUpdPoints.begin();
766 for (int i = 0; aPIt != anUpdPoints.end(); ++aPIt, ++i) {
767 double aCoord[2] = {aNewPoints[i]->x(), aNewPoints[i]->y()};
768 const std::list<ParameterWrapperPtr>& aParams = (*aPIt)->parameters();
769 std::list<ParameterWrapperPtr>::const_iterator aParIt = aParams.begin();
770 for (int j = 0; aParIt != aParams.end(); ++j, ++aParIt)
771 (*aParIt)->setValue(aCoord[j]);
775 void adjustMirror(ConstraintWrapperPtr theConstraint)
777 std::vector<EntityWrapperPtr> aPoints;
778 EntityWrapperPtr aMirrorLine;
780 const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
781 std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
782 for (; anIt != aSubs.end(); ++anIt) {
783 if ((*anIt)->type() == ENTITY_POINT)
784 aPoints.push_back(*anIt);
785 else if ((*anIt)->type() == ENTITY_LINE)
789 makeMirrorPoints(aPoints[0], aPoints[1], aMirrorLine);
792 void makeMirrorPoints(EntityWrapperPtr theOriginal,
793 EntityWrapperPtr theMirrored,
794 EntityWrapperPtr theMirrorLine)
796 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
798 std::shared_ptr<GeomAPI_Lin2d> aMirrorLine = aBuilder->line(theMirrorLine);
799 std::shared_ptr<GeomAPI_Dir2d> aMLDir = aMirrorLine->direction();
800 // orthogonal direction
801 aMLDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aMLDir->y(), -aMLDir->x()));
803 std::shared_ptr<GeomAPI_Pnt2d> aPoint = aBuilder->point(theOriginal);
804 std::shared_ptr<GeomAPI_XY> aVec = aPoint->xy()->decreased(aMirrorLine->location()->xy());
805 double aDist = aVec->dot(aMLDir->xy());
806 aVec = aPoint->xy()->added(aMLDir->xy()->multiplied(-2.0 * aDist));
807 double aCoord[2] = {aVec->x(), aVec->y()};
808 std::list<ParameterWrapperPtr>::const_iterator aMIt = theMirrored->parameters().begin();
809 for (int i = 0; aMIt != theMirrored->parameters().end(); ++aMIt, ++i)
810 (*aMIt)->setValue(aCoord[i]);
812 // update corresponding attribute
813 AttributePtr anAttr = std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theMirrored)->baseAttribute();
815 std::shared_ptr<GeomDataAPI_Point2D> aMirroredPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
816 aMirroredPnt->setValue(aCoord[0], aCoord[1]);
820 void adjustPtLineDistance(ConstraintWrapperPtr theConstraint)
822 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
824 std::shared_ptr<GeomAPI_Pnt2d> aPoint;
825 std::shared_ptr<GeomAPI_Lin2d> aLine;
826 std::list<EntityWrapperPtr> aSubs = theConstraint->entities();
827 std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
828 for (; aSIt != aSubs.end(); ++aSIt) {
829 if ((*aSIt)->type() == ENTITY_POINT)
830 aPoint = aBuilder->point(*aSIt);
831 else if ((*aSIt)->type() == ENTITY_LINE)
832 aLine = aBuilder->line(*aSIt);
835 std::shared_ptr<GeomAPI_XY> aLineVec = aLine->direction()->xy();
836 std::shared_ptr<GeomAPI_XY> aPtLineVec = aPoint->xy()->decreased(aLine->location()->xy());
837 if (aPtLineVec->cross(aLineVec) * theConstraint->value() < 0.0)
838 theConstraint->setValue(theConstraint->value() * (-1.0));