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 EntityWrapperPtr& thePoint1,
138 const EntityWrapperPtr& thePoint2,
139 const std::list<EntityWrapperPtr>& theTrsfEnt) const
141 if (theType != CONSTRAINT_MULTI_ROTATION && theType != CONSTRAINT_MULTI_TRANSLATION)
142 return std::list<ConstraintWrapperPtr>();
144 int aType = ConstraintType::toSolveSpace(theType);
145 if (aType == SLVS_C_UNKNOWN)
146 return std::list<ConstraintWrapperPtr>();
148 Slvs_Constraint aConstraint =
149 Slvs_MakeConstraint(SLVS_C_UNKNOWN, (Slvs_hGroup)theGroupID, aType, (Slvs_hEntity)theSketchID,
150 theValue, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
152 std::list<EntityWrapperPtr> aConstrAttrList = theTrsfEnt;
154 aConstrAttrList.push_front(thePoint2);
155 aConstrAttrList.push_front(thePoint1);
157 ConstraintWrapperPtr aResult(new SolveSpaceSolver_ConstraintWrapper(theConstraint, aConstraint));
158 aResult->setValue(theValue);
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 //// std::shared_ptr<SolveSpaceSolver_EntityWrapper> anEntity1 =
173 //// std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theEntity1);
174 //// std::shared_ptr<SolveSpaceSolver_EntityWrapper> anEntity2 =
175 //// std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theEntity2);
177 //// // Make aMirrorEnt parameters to be symmetric with aBaseEnt
178 //// makeMirrorEntity(theEntity1, theEntity2, theMirrorLine);
180 Slvs_Constraint aConstraint;
181 std::list<ConstraintWrapperPtr> aResult;
182 std::list<EntityWrapperPtr> aConstrAttrList;
183 if (theEntity1->type() == ENTITY_POINT) {
184 if (theEntity2->group() == theGroupID) // theEntity2 is not fixed
185 makeMirrorPoints(theEntity1, theEntity2, theMirrorLine);
187 aConstraint = Slvs_MakeConstraint(
188 SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID, SLVS_C_SYMMETRIC_LINE, (Slvs_hEntity)theSketchID,
189 0.0, (Slvs_hEntity)theEntity1->id(), (Slvs_hEntity)theEntity2->id(),
190 (Slvs_hEntity)theMirrorLine->id(), SLVS_E_UNKNOWN);
192 aConstrAttrList.push_back(theEntity1);
193 aConstrAttrList.push_back(theEntity2);
194 aConstrAttrList.push_back(theMirrorLine);
196 ConstraintWrapperPtr aWrapper(new SolveSpaceSolver_ConstraintWrapper(
197 theConstraint, aConstraint));
198 aWrapper->setEntities(aConstrAttrList);
199 aResult.push_back(aWrapper);
201 else if (theEntity1->type() == ENTITY_LINE) {
202 const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
203 const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
204 std::list<EntityWrapperPtr>::const_iterator anIt1 = aPoints1.begin();
205 std::list<EntityWrapperPtr>::const_iterator anIt2 = aPoints2.begin();
206 for (; anIt1 != aPoints1.end() && anIt2 != aPoints2.end(); ++anIt1, ++anIt2) {
207 std::list<ConstraintWrapperPtr> aMrrList =
208 createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
209 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
212 else if (theEntity1->type() == ENTITY_CIRCLE) {
213 const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
214 std::list<EntityWrapperPtr>::const_iterator anIt1 = aPoints1.begin();
215 for (; anIt1 != aPoints1.end(); ++anIt1)
216 if ((*anIt1)->type() == ENTITY_POINT)
218 const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
219 std::list<EntityWrapperPtr>::const_iterator anIt2 = aPoints2.begin();
220 for (; anIt2 != aPoints2.end(); ++anIt2)
221 if ((*anIt2)->type() == ENTITY_POINT)
224 std::list<ConstraintWrapperPtr> aMrrList =
225 createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
226 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
228 // Additional constraint for equal radii
229 aMrrList = createConstraint(theConstraint, theGroupID, theSketchID, CONSTRAINT_EQUAL_RADIUS,
230 0.0, EntityWrapperPtr(), EntityWrapperPtr(), theEntity1, theEntity2);
231 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
233 else if (theEntity1->type() == ENTITY_ARC) {
234 // Do not allow mirrored arc recalculate its position until coordinated of all points recalculated
235 FeaturePtr aMirrArc = theEntity2->baseFeature();
236 aMirrArc->data()->blockSendAttributeUpdated(true);
238 std::list<ConstraintWrapperPtr> aMrrList;
239 std::list<EntityWrapperPtr>::const_iterator anIt1 = theEntity1->subEntities().begin();
240 std::list<EntityWrapperPtr>::const_iterator anIt2 = theEntity2->subEntities().begin();
241 if ((*anIt2)->group() == theGroupID) // mirrored point is not fixed
242 makeMirrorPoints(theEntity1->subEntities().front(),
243 theEntity2->subEntities().front(), theMirrorLine);
245 // Workaround to avoid problems in SolveSpace.
246 // The symmetry of two arcs will be done using symmetry of three points on these arcs:
247 // start point, end point, and any other point on the arc
248 std::list<EntityWrapperPtr> aBaseArcPoints(++anIt1, theEntity1->subEntities().end());
249 std::list<EntityWrapperPtr> aMirrorArcPoints(++anIt2, theEntity2->subEntities().end());
250 // indices of points of arc, center corresponds center, first point corresponds last point
251 aMirrorArcPoints.reverse();
253 //// EntityWrapperPtr aBothArcs[2] = {theEntity1, theEntity2};
254 //// EntityWrapperPtr aBothMiddlePoints[2];
255 //// for (int i = 0; i < 2; i++) {
256 //// aBothMiddlePoints[i] = calculateMiddlePoint(aBothArcs[i], 0.5, theGroupID, theSketchID);
257 //// // additional constraint point-on-curve
258 //// aMrrList = createConstraint(theConstraint, theGroupID, theSketchID, CONSTRAINT_PT_ON_CIRCLE,
259 //// 0.0, aBothMiddlePoints[i], EntityWrapperPtr(), aBothArcs[i]);
260 //// aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
261 //////// if (i == 0) {
262 //////// // additional constraint for the point to be in the middle of a base arc
263 //////// Slvs_Entity aLine1 = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(),
264 //////// myGroup->getWorkplaneId(), aBothArcs[i].point[1], aBothMiddlePoints[i]);
265 //////// aLine1.h = myStorage->addEntity(aLine1);
266 //////// Slvs_Entity aLine2 = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(),
267 //////// myGroup->getWorkplaneId(), aBothArcs[i].point[2], aBothMiddlePoints[i]);
268 //////// aLine2.h = myStorage->addEntity(aLine2);
269 //////// Slvs_Constraint aMiddleConstr = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
270 //////// SLVS_C_EQUAL_LENGTH_LINES, myGroup->getWorkplaneId(),
271 //////// 0.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aLine1.h, aLine2.h);
272 //////// aMiddleConstr.h = myStorage->addConstraint(aMiddleConstr);
273 //////// mySlvsConstraints.push_back(aMiddleConstr.h);
277 //// aBaseArcPoints.push_back(aBothMiddlePoints[0]);
278 //// aMirrorArcPoints.push_back(aBothMiddlePoints[1]);
279 anIt1 = aBaseArcPoints.begin();
280 anIt2 = aMirrorArcPoints.begin();
281 for (; anIt1 != aBaseArcPoints.end(); ++anIt1, ++anIt2) {
282 aMrrList = createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
283 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
285 // Restore event sending
286 aMirrArc->data()->blockSendAttributeUpdated(false);
291 void SolveSpaceSolver_Builder::adjustConstraint(ConstraintWrapperPtr theConstraint) const
293 SketchSolver_ConstraintType aType = theConstraint->type();
294 // Update flags in constraints
295 if (aType == CONSTRAINT_TANGENT_ARC_ARC || aType == CONSTRAINT_TANGENT_ARC_LINE)
296 adjustTangency(theConstraint);
297 else if (aType == CONSTRAINT_ANGLE)
298 adjustAngle(theConstraint);
299 else if (aType == CONSTRAINT_SYMMETRIC)
300 adjustMirror(theConstraint);
301 else if (aType == CONSTRAINT_MULTI_ROTATION)
302 adjustMultiRotation(theConstraint);
303 else if (aType == CONSTRAINT_MULTI_TRANSLATION)
304 adjustMultiTranslation(theConstraint);
307 EntityWrapperPtr SolveSpaceSolver_Builder::createFeature(
308 FeaturePtr theFeature,
309 const std::list<EntityWrapperPtr>& theAttributes,
310 const GroupID& theGroupID,
311 const EntityID& theSketchID) const
313 static EntityWrapperPtr aDummy;
314 if (!theFeature->data()->isValid())
318 CompositeFeaturePtr aSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
320 return createSketchEntity(aSketch, theGroupID);
322 // SketchPlugin features
323 std::shared_ptr<SketchPlugin_Feature> aFeature =
324 std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
328 // Verify the feature by its kind
329 const std::string& aFeatureKind = aFeature->getKind();
331 if (aFeatureKind == SketchPlugin_Line::ID())
332 return createLine(theFeature, theAttributes, theGroupID, theSketchID);
334 else if (aFeatureKind == SketchPlugin_Circle::ID())
335 return createCircle(theFeature, theAttributes,theGroupID, theSketchID);
337 else if (aFeatureKind == SketchPlugin_Arc::ID())
338 return createArc(theFeature, theAttributes,theGroupID, theSketchID);
339 // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
340 else if (aFeatureKind == SketchPlugin_Point::ID()) {
341 AttributePtr aPoint = theFeature->attribute(SketchPlugin_Point::COORD_ID());
342 if (!aPoint->isInitialized())
344 EntityWrapperPtr aSub = createAttribute(aPoint, theGroupID, theSketchID);
348 const Slvs_Entity& aSubEnt =
349 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(aSub)->entity();
350 EntityWrapperPtr aNewEntity(new SolveSpaceSolver_EntityWrapper(theFeature, aSubEnt));
351 aNewEntity->setSubEntities(std::list<EntityWrapperPtr>(1, aSub));
359 EntityWrapperPtr SolveSpaceSolver_Builder::createAttribute(
360 AttributePtr theAttribute,
361 const GroupID& theGroupID,
362 const EntityID& theSketchID) const
364 AttributePtr anAttribute = theAttribute;
365 AttributeRefAttrPtr aRefAttr =
366 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
368 if (aRefAttr->isObject()) {
369 // do not create features here
370 return EntityWrapperPtr();
372 anAttribute = aRefAttr->attr();
375 std::list<ParameterWrapperPtr> aParameters;
376 Slvs_Entity anEntity;
380 std::shared_ptr<GeomDataAPI_Point> aPoint =
381 std::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
383 aParameters.push_back(createParameter(theGroupID, aPoint->x(), !aPoint->textX().empty()));
384 aParameters.push_back(createParameter(theGroupID, aPoint->y(), !aPoint->textY().empty()));
385 aParameters.push_back(createParameter(theGroupID, aPoint->z(), !aPoint->textZ().empty()));
386 // Create entity (parameters are not filled)
387 anEntity = Slvs_MakePoint3d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
388 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
391 std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
392 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
394 aParameters.push_back(createParameter(theGroupID, aPoint2D->x(), !aPoint2D->textX().empty()));
395 aParameters.push_back(createParameter(theGroupID, aPoint2D->y(), !aPoint2D->textY().empty()));
396 // Create entity (parameters are not filled)
397 anEntity = Slvs_MakePoint2d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
398 (Slvs_hEntity)theSketchID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
400 // Scalar value (used for the distance entities)
401 AttributeDoublePtr aScalar =
402 std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
404 aParameters.push_back(createParameter(theGroupID, aScalar->value(), !aScalar->text().empty()));
405 // Create entity (parameter is not filled)
406 anEntity = Slvs_MakeDistance(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
407 (Slvs_hEntity)theSketchID, SLVS_E_UNKNOWN);
412 if (anEntity.type == 0) {
413 // unknown attribute type
414 return EntityWrapperPtr();
417 EntityWrapperPtr aResult(new SolveSpaceSolver_EntityWrapper(theAttribute, anEntity));
418 aResult->setParameters(aParameters);
424 EntityWrapperPtr SolveSpaceSolver_Builder::createSketchEntity(
425 CompositeFeaturePtr theSketch,
426 const GroupID& theGroupID) const
428 DataPtr aSketchData = theSketch->data();
429 if (!aSketchData || !aSketchData->isValid())
430 return EntityWrapperPtr(); // the sketch is incorrect
432 // Get parameters of workplane
433 AttributePtr aDirX = aSketchData->attribute(SketchPlugin_Sketch::DIRX_ID());
434 AttributePtr aNorm = aSketchData->attribute(SketchPlugin_Sketch::NORM_ID());
435 AttributePtr anOrigin = aSketchData->attribute(SketchPlugin_Sketch::ORIGIN_ID());
436 if (!anOrigin->isInitialized() || !aNorm->isInitialized() || !aDirX->isInitialized())
437 return EntityWrapperPtr();
439 EntityWrapperPtr aNewEnt;
440 std::list<EntityWrapperPtr> aSubs;
442 // Create SolveSpace entity corresponding to the sketch origin
443 aNewEnt = createAttribute(anOrigin, theGroupID);
445 return EntityWrapperPtr();
446 aSubs.push_back(aNewEnt);
448 // Create SolveSpace entity corresponding the the sketch normal
449 aNewEnt = createNormal(aNorm, aDirX, theGroupID);
451 return EntityWrapperPtr();
452 aSubs.push_back(aNewEnt);
455 Slvs_Entity aWorkplane = Slvs_MakeWorkplane(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
456 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
458 aNewEnt = EntityWrapperPtr(
459 new SolveSpaceSolver_EntityWrapper(FeaturePtr(theSketch), aWorkplane));
460 aNewEnt->setSubEntities(aSubs);
464 EntityWrapperPtr SolveSpaceSolver_Builder::createNormal(
465 AttributePtr theNormal,
466 AttributePtr theDirX,
467 const GroupID& theGroupID) const
469 std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theNormal);
470 std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
471 if (!aDirX || !aNorm ||
472 (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance) ||
473 !aNorm->isInitialized())
474 return EntityWrapperPtr();
475 // calculate Y direction
476 std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aDirX->dir())));
478 // quaternion parameters of normal vector
479 double qw, qx, qy, qz;
480 Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), aDirY->x(), aDirY->y(), aDirY->z(), &qw,
482 double aNormCoord[4] = { qw, qx, qy, qz };
484 // Create parameters of the normal
485 std::list<ParameterWrapperPtr> aParameters;
486 for (int i = 0; i < 4; i++)
487 aParameters.push_back(createParameter(theGroupID, aNormCoord[i]));
489 // Create a normal with empty parameters
490 Slvs_Entity aNormalEnt = Slvs_MakeNormal3d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
491 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
492 EntityWrapperPtr aNormal(new SolveSpaceSolver_EntityWrapper(theNormal, aNormalEnt));
493 aNormal->setParameters(aParameters);
497 ParameterWrapperPtr SolveSpaceSolver_Builder::createParameter(
498 const GroupID& theGroup, const double theValue, const bool theExpr) const
500 Slvs_Param aParam = Slvs_MakeParam(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroup, theValue);
501 ParameterWrapperPtr aWrapper(new SolveSpaceSolver_ParameterWrapper(aParam));
502 aWrapper->setIsParametric(theExpr);
510 // ================ Auxiliary functions ==========================
511 EntityWrapperPtr createLine(FeaturePtr theFeature,
512 const std::list<EntityWrapperPtr>& theAttributes,
513 const GroupID& theGroupID,
514 const EntityID& theSketchID)
516 EntityWrapperPtr aNewEntity;
517 std::list<EntityWrapperPtr> aSubs;
519 AttributePtr aStart = theFeature->attribute(SketchPlugin_Line::START_ID());
520 AttributePtr aEnd = theFeature->attribute(SketchPlugin_Line::END_ID());
521 if (!aStart->isInitialized() || !aEnd->isInitialized())
524 EntityWrapperPtr aStartEnt, aEndEnt;
525 std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
526 for (; anIt != theAttributes.end(); ++anIt) {
527 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
528 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
529 if (aSlvsEntity->isBase(aStart))
530 aStartEnt = aSlvsEntity;
531 else if (aSlvsEntity->isBase(aEnd))
532 aEndEnt = aSlvsEntity;
534 if (!aStartEnt || !aEndEnt)
537 aSubs.push_back(aStartEnt);
538 aSubs.push_back(aEndEnt);
539 Slvs_Entity anEntity = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
540 (Slvs_hEntity)theSketchID, (Slvs_hEntity)aStartEnt->id(), (Slvs_hEntity)aEndEnt->id());
542 aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
543 aNewEntity->setSubEntities(aSubs);
547 EntityWrapperPtr createCircle(FeaturePtr theFeature,
548 const std::list<EntityWrapperPtr>& theAttributes,
549 const GroupID& theGroupID,
550 const EntityID& theSketchID)
552 EntityWrapperPtr aNewEntity;
553 std::list<EntityWrapperPtr> aSubs;
555 AttributePtr aCenter = theFeature->attribute(SketchPlugin_Circle::CENTER_ID());
556 AttributePtr aRadius = theFeature->attribute(SketchPlugin_Circle::RADIUS_ID());
557 if (!aCenter->isInitialized() || !aRadius->isInitialized())
560 EntityWrapperPtr aCenterEnt, aRadiusEnt, aNormalEnt;
561 std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
562 for (; anIt != theAttributes.end(); ++anIt) {
563 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
564 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
565 if (aSlvsEntity->isBase(aCenter))
566 aCenterEnt = aSlvsEntity;
567 else if (aSlvsEntity->isBase(aRadius))
568 aRadiusEnt = aSlvsEntity;
569 else if (aSlvsEntity->type() == ENTITY_NORMAL)
570 aNormalEnt = aSlvsEntity;
572 if (!aCenterEnt || !aRadiusEnt || !aNormalEnt)
575 aSubs.push_back(aCenterEnt);
576 aSubs.push_back(aRadiusEnt);
577 Slvs_Entity anEntity = Slvs_MakeCircle(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
578 (Slvs_hEntity)theSketchID, (Slvs_hEntity)aCenterEnt->id(),
579 (Slvs_hEntity)aNormalEnt->id(), (Slvs_hEntity)aRadiusEnt->id());
581 aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
582 aNewEntity->setSubEntities(aSubs);
586 EntityWrapperPtr createArc(FeaturePtr theFeature,
587 const std::list<EntityWrapperPtr>& theAttributes,
588 const GroupID& theGroupID,
589 const EntityID& theSketchID)
591 EntityWrapperPtr aNewEntity;
592 std::list<EntityWrapperPtr> aSubs;
594 AttributePtr aCenter = theFeature->attribute(SketchPlugin_Arc::CENTER_ID());
595 AttributePtr aStart = theFeature->attribute(SketchPlugin_Arc::START_ID());
596 AttributePtr aEnd = theFeature->attribute(SketchPlugin_Arc::END_ID());
597 if (!aCenter->isInitialized() || !aStart->isInitialized() || !aEnd->isInitialized())
600 EntityWrapperPtr aCenterEnt, aStartEnt, aEndEnt, aNormalEnt;
601 std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
602 for (; anIt != theAttributes.end(); ++anIt) {
603 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
604 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
605 if (aSlvsEntity->isBase(aCenter))
606 aCenterEnt = aSlvsEntity;
607 else if (aSlvsEntity->isBase(aStart))
608 aStartEnt = aSlvsEntity;
609 else if (aSlvsEntity->isBase(aEnd))
610 aEndEnt = aSlvsEntity;
611 else if (aSlvsEntity->type() == ENTITY_NORMAL)
612 aNormalEnt = aSlvsEntity;
614 if (!aCenterEnt || !aStartEnt || !aEndEnt || !aNormalEnt)
617 aSubs.push_back(aCenterEnt);
618 aSubs.push_back(aStartEnt);
619 aSubs.push_back(aEndEnt);
620 Slvs_Entity anEntity = Slvs_MakeArcOfCircle(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
621 (Slvs_hEntity)theSketchID, (Slvs_hEntity)aNormalEnt->id(),
622 (Slvs_hEntity)aCenterEnt->id(), (Slvs_hEntity)aStartEnt->id(), (Slvs_hEntity)aEndEnt->id());
624 aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
625 aNewEntity->setSubEntities(aSubs);
630 void adjustTangency(ConstraintWrapperPtr theConstraint)
632 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
634 std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
635 std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
637 // Collect start, end points of entities
638 std::shared_ptr<GeomAPI_Pnt2d> aStartEntPoints[2][2];
639 bool isCoinc[2][2] = {false};
640 const std::list<EntityWrapperPtr>& aSubs = aConstraint->entities();
641 std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
642 for (int i = 0; aSIt != aSubs.end(); ++aSIt, ++i) {
643 const std::list<EntityWrapperPtr>& aPoints = (*aSIt)->subEntities();
644 std::list<EntityWrapperPtr>::const_iterator aPIt = aPoints.begin();
645 if ((*aSIt)->type() == ENTITY_ARC)
647 for (int j = 0; aPIt != aPoints.end(); ++aPIt, ++j) {
648 aStartEntPoints[i][j] = aBuilder->point(*aPIt);
649 if (i > 0) { // check coincidence
650 for (int k = 0; k < 2; ++k)
651 if (aStartEntPoints[i][j]->distance(aStartEntPoints[0][k]) < tolerance)
652 isCoinc[0][k] = isCoinc[i][j] = true;
657 Slvs_Constraint& aSlvsConstraint = aConstraint->changeConstraint();
658 if (isCoinc[0][0] == false && isCoinc[0][1] == true)
659 aSlvsConstraint.other = 1;
660 else aSlvsConstraint.other = 0;
661 if (isCoinc[1][0] == false && isCoinc[1][1] == true)
662 aSlvsConstraint.other2 = 1;
663 else aSlvsConstraint.other2 = 0;
666 void adjustAngle(ConstraintWrapperPtr theConstraint)
668 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
670 std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
671 std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
673 std::shared_ptr<GeomAPI_Pnt2d> aPoints[2][2]; // start and end points of lines
674 const std::list<EntityWrapperPtr>& aConstrLines = aConstraint->entities();
675 std::list<EntityWrapperPtr>::const_iterator aCLIt = aConstrLines.begin();
676 for (int i = 0; aCLIt != aConstrLines.end(); ++i, ++aCLIt) {
677 const std::list<EntityWrapperPtr>& aLinePoints = (*aCLIt)->subEntities();
678 std::list<EntityWrapperPtr>::const_iterator aLPIt = aLinePoints.begin();
679 for (int j = 0; aLPIt != aLinePoints.end(); ++j, ++aLPIt)
680 aPoints[i][j] = aBuilder->point(*aLPIt);
683 std::shared_ptr<GeomAPI_Lin2d> aLine[2] = {
684 std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[0][0], aPoints[0][1])),
685 std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[1][0], aPoints[1][1]))
687 std::shared_ptr<GeomAPI_Pnt2d> anIntersection = aLine[0]->intersect(aLine[1]);
691 for (int i = 0; i < 2; i++) {
692 for (int j = 0; j < 2; j++) {
693 aDist[i][j] = anIntersection->distance(aPoints[i][j]);
694 if (fabs(aDist[i][j]) <= tolerance)
697 if (aDist[i][0] > tolerance && aDist[i][1] > tolerance &&
698 aDist[i][0] + aDist[i][1] < aPoints[i][0]->distance(aPoints[i][1]) + 2.0 * tolerance) {
699 // the intersection point is an inner point of the line,
700 // we change the sign of distance till start point to calculate correct coordinates
705 std::shared_ptr<GeomAPI_Dir2d> aDir[2];
706 for (int i = 0; i < 2; i++) {
707 if (aDist[i][1] > fabs(aDist[i][0]))
708 aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(
709 aPoints[i][1]->xy()->decreased(anIntersection->xy())));
711 aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(
712 aPoints[i][0]->xy()->decreased(anIntersection->xy())));
713 // main direction is opposite => change signs
714 if (aDist[i][0] < 0.0) {
721 Slvs_Constraint& aSlvsConstraint = aConstraint->changeConstraint();
722 aSlvsConstraint.other = false;
723 for (int i = 0; i < 2; i++)
724 if (aLine[i]->direction()->dot(aDir[i]) < 0.0)
725 aSlvsConstraint.other = !aSlvsConstraint.other;
728 void adjustMirror(ConstraintWrapperPtr theConstraint)
730 std::vector<EntityWrapperPtr> aPoints;
731 EntityWrapperPtr aMirrorLine;
733 const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
734 std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
735 for (; anIt != aSubs.end(); ++anIt) {
736 if ((*anIt)->type() == ENTITY_POINT)
737 aPoints.push_back(*anIt);
738 else if ((*anIt)->type() == ENTITY_LINE)
742 makeMirrorPoints(aPoints[0], aPoints[1], aMirrorLine);
745 void makeMirrorPoints(EntityWrapperPtr theOriginal,
746 EntityWrapperPtr theMirrored,
747 EntityWrapperPtr theMirrorLine)
749 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
751 std::shared_ptr<GeomAPI_Lin2d> aMirrorLine = aBuilder->line(theMirrorLine);
752 std::shared_ptr<GeomAPI_Dir2d> aMLDir = aMirrorLine->direction();
753 // orthogonal direction
754 aMLDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aMLDir->y(), -aMLDir->x()));
756 std::shared_ptr<GeomAPI_Pnt2d> aPoint = aBuilder->point(theOriginal);
757 std::shared_ptr<GeomAPI_XY> aVec = aPoint->xy()->decreased(aMirrorLine->location()->xy());
758 double aDist = aVec->dot(aMLDir->xy());
759 aVec = aPoint->xy()->added(aMLDir->xy()->multiplied(-2.0 * aDist));
760 double aCoord[2] = {aVec->x(), aVec->y()};
761 std::list<ParameterWrapperPtr>::const_iterator aMIt = theMirrored->parameters().begin();
762 for (int i = 0; aMIt != theMirrored->parameters().end(); ++aMIt, ++i)
763 (*aMIt)->setValue(aCoord[i]);
765 // update corresponding attribute
766 AttributePtr anAttr = std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theMirrored)->baseAttribute();
768 std::shared_ptr<GeomDataAPI_Point2D> aMirroredPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
769 aMirroredPnt->setValue(aCoord[0], aCoord[1]);
773 static void rotate(EntityWrapperPtr theSource, EntityWrapperPtr theDest,
774 std::shared_ptr<GeomAPI_Pnt2d> theCenter,
775 double theSin, double theCos)
777 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSource =
778 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theSource);
779 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aDest =
780 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theDest);
782 if (theSource->type() == ENTITY_POINT) {
783 // Rotate single point
784 std::shared_ptr<GeomDataAPI_Point2D> aSrcAttr =
785 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aSource->baseAttribute());
786 std::shared_ptr<GeomDataAPI_Point2D> aDstAttr =
787 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aDest->baseAttribute());
788 if (aSrcAttr && aDstAttr) {
789 std::shared_ptr<GeomAPI_XY> aVec = aSrcAttr->pnt()->xy()->decreased(theCenter->xy());
790 double aNewX = aVec->x() * theCos - aVec->y() * theSin;
791 double aNewY = aVec->x() * theSin + aVec->y() * theCos;
792 aDstAttr->setValue(theCenter->x() + aNewX, theCenter->y() + aNewY);
797 FeaturePtr aDestFeature = aDest->baseFeature();
799 aDestFeature->data()->blockSendAttributeUpdated(true);
801 // Rotate points of the feature
802 const std::list<EntityWrapperPtr>& aSrcSubs = theSource->subEntities();
803 const std::list<EntityWrapperPtr>& aDstSubs = theDest->subEntities();
804 std::list<EntityWrapperPtr>::const_iterator aSrcIt, aDstIt;
805 for (aSrcIt = aSrcSubs.begin(), aDstIt = aDstSubs.begin();
806 aSrcIt != aSrcSubs.end() && aDstIt != aDstSubs.end(); ++aSrcIt, ++aDstIt)
807 rotate(*aSrcIt, *aDstIt, theCenter, theSin, theCos);
810 aDestFeature->data()->blockSendAttributeUpdated(false);
813 static void translate(EntityWrapperPtr theSource, EntityWrapperPtr theDest,
814 std::shared_ptr<GeomAPI_XY> theDelta)
816 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSource =
817 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theSource);
818 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aDest =
819 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theDest);
821 if (theSource->type() == ENTITY_POINT) {
822 // Translate single point
823 std::shared_ptr<GeomDataAPI_Point2D> aSrcAttr =
824 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aSource->baseAttribute());
825 std::shared_ptr<GeomDataAPI_Point2D> aDstAttr =
826 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aDest->baseAttribute());
827 if (aSrcAttr && aDstAttr)
828 aDstAttr->setValue(aSrcAttr->x() + theDelta->x(), aSrcAttr->y() + theDelta->y());
832 FeaturePtr aDestFeature = aDest->baseFeature();
834 aDestFeature->data()->blockSendAttributeUpdated(true);
836 // Translate points of the feature
837 const std::list<EntityWrapperPtr>& aSrcSubs = theSource->subEntities();
838 const std::list<EntityWrapperPtr>& aDstSubs = theDest->subEntities();
839 std::list<EntityWrapperPtr>::const_iterator aSrcIt, aDstIt;
840 for (aSrcIt = aSrcSubs.begin(), aDstIt = aDstSubs.begin();
841 aSrcIt != aSrcSubs.end() && aDstIt != aDstSubs.end(); ++aSrcIt, ++aDstIt)
842 translate(*aSrcIt, *aDstIt, theDelta);
845 aDestFeature->data()->blockSendAttributeUpdated(false);
848 void adjustMultiRotation(ConstraintWrapperPtr theConstraint)
850 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
852 double anAngleRad = theConstraint->value() * PI / 180.0;
853 double aSin = sin(anAngleRad);
854 double aCos = cos(anAngleRad);
856 const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
857 std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
859 std::shared_ptr<GeomAPI_Pnt2d> aCenter = aBuilder->point(*aSIt++);
860 std::list<EntityWrapperPtr>::const_iterator aPrevIt = aSIt++;
861 for (; aSIt != aSubs.end(); ++aPrevIt, ++aSIt)
862 rotate(*aPrevIt, *aSIt, aCenter, aSin, aCos);
865 void adjustMultiTranslation(ConstraintWrapperPtr theConstraint)
867 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
869 const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
870 std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
872 std::shared_ptr<GeomAPI_Pnt2d> aStartPnt = aBuilder->point(*aSIt++);
873 std::shared_ptr<GeomAPI_Pnt2d> aEndPnt = aBuilder->point(*aSIt++);
874 std::shared_ptr<GeomAPI_XY> aDelta = aEndPnt->xy()->decreased(aStartPnt->xy());
876 std::list<EntityWrapperPtr>::const_iterator aPrevIt = aSIt++;
877 for (; aSIt != aSubs.end(); ++aPrevIt, ++aSIt)
878 translate(*aPrevIt, *aSIt, aDelta);