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 = createAttribute(aPoint, theGroupID, theSketchID);
315 const Slvs_Entity& aSubEnt =
316 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(aSub)->entity();
317 return EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, aPoint, aSubEnt));
324 EntityWrapperPtr SolveSpaceSolver_Builder::createAttribute(
325 AttributePtr theAttribute,
326 const GroupID& theGroupID,
327 const EntityID& theSketchID) const
329 AttributePtr anAttribute = theAttribute;
330 AttributeRefAttrPtr aRefAttr =
331 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
333 if (aRefAttr->isObject()) {
334 // do not create features here
335 return EntityWrapperPtr();
337 anAttribute = aRefAttr->attr();
340 std::list<ParameterWrapperPtr> aParameters;
341 Slvs_Entity anEntity;
345 std::shared_ptr<GeomDataAPI_Point> aPoint =
346 std::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
348 aParameters.push_back(createParameter(theGroupID, aPoint->x(), !aPoint->textX().empty()));
349 aParameters.push_back(createParameter(theGroupID, aPoint->y(), !aPoint->textY().empty()));
350 aParameters.push_back(createParameter(theGroupID, aPoint->z(), !aPoint->textZ().empty()));
351 // Create entity (parameters are not filled)
352 anEntity = Slvs_MakePoint3d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
353 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
356 std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
357 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
359 aParameters.push_back(createParameter(theGroupID, aPoint2D->x(), !aPoint2D->textX().empty()));
360 aParameters.push_back(createParameter(theGroupID, aPoint2D->y(), !aPoint2D->textY().empty()));
361 // Create entity (parameters are not filled)
362 anEntity = Slvs_MakePoint2d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
363 (Slvs_hEntity)theSketchID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
365 // Scalar value (used for the distance entities)
366 AttributeDoublePtr aScalar =
367 std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
369 aParameters.push_back(createParameter(theGroupID, aScalar->value(), !aScalar->text().empty()));
370 // Create entity (parameter is not filled)
371 anEntity = Slvs_MakeDistance(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
372 (Slvs_hEntity)theSketchID, SLVS_E_UNKNOWN);
377 if (anEntity.type == 0) {
378 // unknown attribute type
379 return EntityWrapperPtr();
382 EntityWrapperPtr aResult(new SolveSpaceSolver_EntityWrapper(theAttribute, anEntity));
383 aResult->setParameters(aParameters);
389 EntityWrapperPtr SolveSpaceSolver_Builder::createSketchEntity(
390 CompositeFeaturePtr theSketch,
391 const GroupID& theGroupID) const
393 DataPtr aSketchData = theSketch->data();
394 if (!aSketchData || !aSketchData->isValid())
395 return EntityWrapperPtr(); // the sketch is incorrect
397 // Get parameters of workplane
398 AttributePtr aDirX = aSketchData->attribute(SketchPlugin_Sketch::DIRX_ID());
399 AttributePtr aNorm = aSketchData->attribute(SketchPlugin_Sketch::NORM_ID());
400 AttributePtr anOrigin = aSketchData->attribute(SketchPlugin_Sketch::ORIGIN_ID());
401 if (!anOrigin->isInitialized() || !aNorm->isInitialized() || !aDirX->isInitialized())
402 return EntityWrapperPtr();
404 EntityWrapperPtr aNewEnt;
405 std::list<EntityWrapperPtr> aSubs;
407 // Create SolveSpace entity corresponding to the sketch origin
408 aNewEnt = createAttribute(anOrigin, theGroupID);
410 return EntityWrapperPtr();
411 aSubs.push_back(aNewEnt);
413 // Create SolveSpace entity corresponding the the sketch normal
414 aNewEnt = createNormal(aNorm, aDirX, theGroupID);
416 return EntityWrapperPtr();
417 aSubs.push_back(aNewEnt);
420 Slvs_Entity aWorkplane = Slvs_MakeWorkplane(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
421 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
423 aNewEnt = EntityWrapperPtr(
424 new SolveSpaceSolver_EntityWrapper(FeaturePtr(theSketch), aWorkplane));
425 aNewEnt->setSubEntities(aSubs);
429 EntityWrapperPtr SolveSpaceSolver_Builder::createNormal(
430 AttributePtr theNormal,
431 AttributePtr theDirX,
432 const GroupID& theGroupID) const
434 std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theNormal);
435 std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
436 if (!aDirX || !aNorm ||
437 (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance) ||
438 !aNorm->isInitialized())
439 return EntityWrapperPtr();
440 // calculate Y direction
441 std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aDirX->dir())));
443 // quaternion parameters of normal vector
444 double qw, qx, qy, qz;
445 Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), aDirY->x(), aDirY->y(), aDirY->z(), &qw,
447 double aNormCoord[4] = { qw, qx, qy, qz };
449 // Create parameters of the normal
450 std::list<ParameterWrapperPtr> aParameters;
451 for (int i = 0; i < 4; i++)
452 aParameters.push_back(createParameter(theGroupID, aNormCoord[i]));
454 // Create a normal with empty parameters
455 Slvs_Entity aNormalEnt = Slvs_MakeNormal3d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
456 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
457 EntityWrapperPtr aNormal(new SolveSpaceSolver_EntityWrapper(theNormal, aNormalEnt));
458 aNormal->setParameters(aParameters);
462 ParameterWrapperPtr SolveSpaceSolver_Builder::createParameter(
463 const GroupID& theGroup, const double theValue, const bool theExpr) const
465 Slvs_Param aParam = Slvs_MakeParam(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroup, theValue);
466 ParameterWrapperPtr aWrapper(new SolveSpaceSolver_ParameterWrapper(aParam));
467 aWrapper->setIsParametric(theExpr);
475 // ================ Auxiliary functions ==========================
476 EntityWrapperPtr createLine(FeaturePtr theFeature,
477 const std::list<EntityWrapperPtr>& theAttributes,
478 const GroupID& theGroupID,
479 const EntityID& theSketchID)
481 EntityWrapperPtr aNewEntity;
482 std::list<EntityWrapperPtr> aSubs;
484 AttributePtr aStart = theFeature->attribute(SketchPlugin_Line::START_ID());
485 AttributePtr aEnd = theFeature->attribute(SketchPlugin_Line::END_ID());
486 if (!aStart->isInitialized() || !aEnd->isInitialized())
489 EntityWrapperPtr aStartEnt, aEndEnt;
490 std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
491 for (; anIt != theAttributes.end(); ++anIt) {
492 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
493 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
494 if (aSlvsEntity->isBase(aStart))
495 aStartEnt = aSlvsEntity;
496 else if (aSlvsEntity->isBase(aEnd))
497 aEndEnt = aSlvsEntity;
499 if (!aStartEnt || !aEndEnt)
502 aSubs.push_back(aStartEnt);
503 aSubs.push_back(aEndEnt);
504 Slvs_Entity anEntity = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
505 (Slvs_hEntity)theSketchID, (Slvs_hEntity)aStartEnt->id(), (Slvs_hEntity)aEndEnt->id());
507 aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
508 aNewEntity->setSubEntities(aSubs);
512 EntityWrapperPtr createCircle(FeaturePtr theFeature,
513 const std::list<EntityWrapperPtr>& theAttributes,
514 const GroupID& theGroupID,
515 const EntityID& theSketchID)
517 EntityWrapperPtr aNewEntity;
518 std::list<EntityWrapperPtr> aSubs;
520 AttributePtr aCenter = theFeature->attribute(SketchPlugin_Circle::CENTER_ID());
521 AttributePtr aRadius = theFeature->attribute(SketchPlugin_Circle::RADIUS_ID());
522 if (!aCenter->isInitialized() || !aRadius->isInitialized())
525 EntityWrapperPtr aCenterEnt, aRadiusEnt, aNormalEnt;
526 std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
527 for (; anIt != theAttributes.end(); ++anIt) {
528 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
529 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
530 if (aSlvsEntity->isBase(aCenter))
531 aCenterEnt = aSlvsEntity;
532 else if (aSlvsEntity->isBase(aRadius))
533 aRadiusEnt = aSlvsEntity;
534 else if (aSlvsEntity->type() == ENTITY_NORMAL)
535 aNormalEnt = aSlvsEntity;
537 if (!aCenterEnt || !aRadiusEnt || !aNormalEnt)
540 aSubs.push_back(aCenterEnt);
541 aSubs.push_back(aRadiusEnt);
542 Slvs_Entity anEntity = Slvs_MakeCircle(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
543 (Slvs_hEntity)theSketchID, (Slvs_hEntity)aCenterEnt->id(),
544 (Slvs_hEntity)aNormalEnt->id(), (Slvs_hEntity)aRadiusEnt->id());
546 aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
547 aNewEntity->setSubEntities(aSubs);
551 EntityWrapperPtr createArc(FeaturePtr theFeature,
552 const std::list<EntityWrapperPtr>& theAttributes,
553 const GroupID& theGroupID,
554 const EntityID& theSketchID)
556 EntityWrapperPtr aNewEntity;
557 std::list<EntityWrapperPtr> aSubs;
559 AttributePtr aCenter = theFeature->attribute(SketchPlugin_Arc::CENTER_ID());
560 AttributePtr aStart = theFeature->attribute(SketchPlugin_Arc::START_ID());
561 AttributePtr aEnd = theFeature->attribute(SketchPlugin_Arc::END_ID());
562 if (!aCenter->isInitialized() || !aStart->isInitialized() || !aEnd->isInitialized())
565 EntityWrapperPtr aCenterEnt, aStartEnt, aEndEnt, aNormalEnt;
566 std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
567 for (; anIt != theAttributes.end(); ++anIt) {
568 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
569 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
570 if (aSlvsEntity->isBase(aCenter))
571 aCenterEnt = aSlvsEntity;
572 else if (aSlvsEntity->isBase(aStart))
573 aStartEnt = aSlvsEntity;
574 else if (aSlvsEntity->isBase(aEnd))
575 aEndEnt = aSlvsEntity;
576 else if (aSlvsEntity->type() == ENTITY_NORMAL)
577 aNormalEnt = aSlvsEntity;
579 if (!aCenterEnt || !aStartEnt || !aEndEnt || !aNormalEnt)
582 aSubs.push_back(aCenterEnt);
583 aSubs.push_back(aStartEnt);
584 aSubs.push_back(aEndEnt);
585 Slvs_Entity anEntity = Slvs_MakeArcOfCircle(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
586 (Slvs_hEntity)theSketchID, (Slvs_hEntity)aNormalEnt->id(),
587 (Slvs_hEntity)aCenterEnt->id(), (Slvs_hEntity)aStartEnt->id(), (Slvs_hEntity)aEndEnt->id());
589 aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
590 aNewEntity->setSubEntities(aSubs);
595 void adjustTangency(ConstraintWrapperPtr theConstraint)
597 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
599 std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
600 std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
602 // Collect start, end points of entities
603 std::shared_ptr<GeomAPI_Pnt2d> aStartEntPoints[2][2];
604 bool isCoinc[2][2] = {false};
605 const std::list<EntityWrapperPtr>& aSubs = aConstraint->entities();
606 std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
607 for (int i = 0; aSIt != aSubs.end(); ++aSIt, ++i) {
608 const std::list<EntityWrapperPtr>& aPoints = (*aSIt)->subEntities();
609 std::list<EntityWrapperPtr>::const_iterator aPIt = aPoints.begin();
610 if ((*aSIt)->type() == ENTITY_ARC)
612 for (int j = 0; aPIt != aPoints.end(); ++aPIt, ++j) {
613 aStartEntPoints[i][j] = aBuilder->point(*aPIt);
614 if (i > 0) { // check coincidence
615 for (int k = 0; k < 2; ++k)
616 if (aStartEntPoints[i][j]->distance(aStartEntPoints[0][k]) < tolerance)
617 isCoinc[0][k] = isCoinc[i][j] = true;
622 Slvs_Constraint& aSlvsConstraint = aConstraint->changeConstraint();
623 if (isCoinc[0][0] == false && isCoinc[0][1] == true)
624 aSlvsConstraint.other = 1;
625 else aSlvsConstraint.other = 0;
626 if (isCoinc[1][0] == false && isCoinc[1][1] == true)
627 aSlvsConstraint.other2 = 1;
628 else aSlvsConstraint.other2 = 0;
631 void adjustAngle(ConstraintWrapperPtr theConstraint)
633 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
635 std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
636 std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
638 std::shared_ptr<GeomAPI_Pnt2d> aPoints[2][2]; // start and end points of lines
639 const std::list<EntityWrapperPtr>& aConstrLines = aConstraint->entities();
640 std::list<EntityWrapperPtr>::const_iterator aCLIt = aConstrLines.begin();
641 for (int i = 0; aCLIt != aConstrLines.end(); ++i, ++aCLIt) {
642 const std::list<EntityWrapperPtr>& aLinePoints = (*aCLIt)->subEntities();
643 std::list<EntityWrapperPtr>::const_iterator aLPIt = aLinePoints.begin();
644 for (int j = 0; aLPIt != aLinePoints.end(); ++j, ++aLPIt)
645 aPoints[i][j] = aBuilder->point(*aLPIt);
648 std::shared_ptr<GeomAPI_Lin2d> aLine[2] = {
649 std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[0][0], aPoints[0][1])),
650 std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[1][0], aPoints[1][1]))
652 std::shared_ptr<GeomAPI_Pnt2d> anIntersection = aLine[0]->intersect(aLine[1]);
656 for (int i = 0; i < 2; i++) {
657 for (int j = 0; j < 2; j++) {
658 aDist[i][j] = anIntersection->distance(aPoints[i][j]);
659 if (fabs(aDist[i][j]) <= tolerance)
662 if (aDist[i][0] > tolerance && aDist[i][1] > tolerance &&
663 aDist[i][0] + aDist[i][1] < aPoints[i][0]->distance(aPoints[i][1]) + 2.0 * tolerance) {
664 // the intersection point is an inner point of the line,
665 // we change the sign of distance till start point to calculate correct coordinates
670 std::shared_ptr<GeomAPI_Dir2d> aDir[2];
671 for (int i = 0; i < 2; i++) {
672 if (aDist[i][1] > fabs(aDist[i][0]))
673 aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(
674 aPoints[i][1]->xy()->decreased(anIntersection->xy())));
676 aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(
677 aPoints[i][0]->xy()->decreased(anIntersection->xy())));
678 // main direction is opposite => change signs
679 if (aDist[i][0] < 0.0) {
686 Slvs_Constraint& aSlvsConstraint = aConstraint->changeConstraint();
687 aSlvsConstraint.other = false;
688 for (int i = 0; i < 2; i++)
689 if (aLine[i]->direction()->dot(aDir[i]) < 0.0)
690 aSlvsConstraint.other = !aSlvsConstraint.other;
693 void adjustMirror(ConstraintWrapperPtr theConstraint)
695 std::vector<EntityWrapperPtr> aPoints;
696 EntityWrapperPtr aMirrorLine;
698 const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
699 std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
700 for (; anIt != aSubs.end(); ++anIt) {
701 if ((*anIt)->type() == ENTITY_POINT)
702 aPoints.push_back(*anIt);
703 else if ((*anIt)->type() == ENTITY_LINE)
707 makeMirrorPoints(aPoints[0], aPoints[1], aMirrorLine);
710 void makeMirrorPoints(EntityWrapperPtr theOriginal,
711 EntityWrapperPtr theMirrored,
712 EntityWrapperPtr theMirrorLine)
714 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
716 std::shared_ptr<GeomAPI_Lin2d> aMirrorLine = aBuilder->line(theMirrorLine);
717 std::shared_ptr<GeomAPI_Dir2d> aMLDir = aMirrorLine->direction();
718 // orthogonal direction
719 aMLDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aMLDir->y(), -aMLDir->x()));
721 std::shared_ptr<GeomAPI_Pnt2d> aPoint = aBuilder->point(theOriginal);
722 std::shared_ptr<GeomAPI_XY> aVec = aPoint->xy()->decreased(aMirrorLine->location()->xy());
723 double aDist = aVec->dot(aMLDir->xy());
724 aVec = aPoint->xy()->added(aMLDir->xy()->multiplied(-2.0 * aDist));
725 double aCoord[2] = {aVec->x(), aVec->y()};
726 std::list<ParameterWrapperPtr>::const_iterator aMIt = theMirrored->parameters().begin();
727 for (int i = 0; aMIt != theMirrored->parameters().end(); ++aMIt, ++i)
728 (*aMIt)->setValue(aCoord[i]);
730 // update corresponding attribute
731 AttributePtr anAttr = std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theMirrored)->baseAttribute();
733 std::shared_ptr<GeomDataAPI_Point2D> aMirroredPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
734 aMirroredPnt->setValue(aCoord[0], aCoord[1]);
738 static void rotate(EntityWrapperPtr theSource, EntityWrapperPtr theDest,
739 std::shared_ptr<GeomAPI_Pnt2d> theCenter,
740 double theSin, double theCos)
742 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSource =
743 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theSource);
744 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aDest =
745 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theDest);
747 if (theSource->type() == ENTITY_POINT) {
748 // Rotate single point
749 std::shared_ptr<GeomDataAPI_Point2D> aSrcAttr =
750 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aSource->baseAttribute());
751 std::shared_ptr<GeomDataAPI_Point2D> aDstAttr =
752 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aDest->baseAttribute());
753 if (aSrcAttr && aDstAttr) {
754 std::shared_ptr<GeomAPI_XY> aVec = aSrcAttr->pnt()->xy()->decreased(theCenter->xy());
755 double aNewX = aVec->x() * theCos - aVec->y() * theSin;
756 double aNewY = aVec->x() * theSin + aVec->y() * theCos;
757 aDstAttr->setValue(theCenter->x() + aNewX, theCenter->y() + aNewY);
762 FeaturePtr aDestFeature = aDest->baseFeature();
764 aDestFeature->data()->blockSendAttributeUpdated(true);
766 // Rotate points of the feature
767 const std::list<EntityWrapperPtr>& aSrcSubs = theSource->subEntities();
768 const std::list<EntityWrapperPtr>& aDstSubs = theDest->subEntities();
769 std::list<EntityWrapperPtr>::const_iterator aSrcIt, aDstIt;
770 for (aSrcIt = aSrcSubs.begin(), aDstIt = aDstSubs.begin();
771 aSrcIt != aSrcSubs.end() && aDstIt != aDstSubs.end(); ++aSrcIt, ++aDstIt)
772 rotate(*aSrcIt, *aDstIt, theCenter, theSin, theCos);
775 aDestFeature->data()->blockSendAttributeUpdated(false);
778 static void translate(EntityWrapperPtr theSource, EntityWrapperPtr theDest,
779 std::shared_ptr<GeomAPI_XY> theDelta)
781 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSource =
782 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theSource);
783 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aDest =
784 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theDest);
786 if (theSource->type() == ENTITY_POINT) {
787 // Translate single point
788 std::shared_ptr<GeomDataAPI_Point2D> aSrcAttr =
789 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aSource->baseAttribute());
790 std::shared_ptr<GeomDataAPI_Point2D> aDstAttr =
791 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aDest->baseAttribute());
792 if (aSrcAttr && aDstAttr)
793 aDstAttr->setValue(aSrcAttr->x() + theDelta->x(), aSrcAttr->y() + theDelta->y());
797 FeaturePtr aDestFeature = aDest->baseFeature();
799 aDestFeature->data()->blockSendAttributeUpdated(true);
801 // Translate 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 translate(*aSrcIt, *aDstIt, theDelta);
810 aDestFeature->data()->blockSendAttributeUpdated(false);
813 void adjustMultiRotation(ConstraintWrapperPtr theConstraint)
815 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
817 double anAngleValue = theConstraint->value();
818 const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
820 bool isFullValue = theConstraint->isFullValue();
821 int aNbObjects = aSubs.size()-2;
822 if (isFullValue && aNbObjects > 0) {
823 anAngleValue /= aNbObjects;
826 double anAngleRad = anAngleValue * PI / 180.0;
827 double aSin = sin(anAngleRad);
828 double aCos = cos(anAngleRad);
830 std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
832 std::shared_ptr<GeomAPI_Pnt2d> aCenter = aBuilder->point(*aSIt++);
833 std::list<EntityWrapperPtr>::const_iterator aPrevIt = aSIt++;
834 for (; aSIt != aSubs.end(); ++aPrevIt, ++aSIt)
835 rotate(*aPrevIt, *aSIt, aCenter, aSin, aCos);
838 void adjustMultiTranslation(ConstraintWrapperPtr theConstraint)
840 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
842 const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
843 std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
845 std::shared_ptr<GeomAPI_Pnt2d> aStartPnt = aBuilder->point(*aSIt++);
846 std::shared_ptr<GeomAPI_Pnt2d> aEndPnt = aBuilder->point(*aSIt++);
847 std::shared_ptr<GeomAPI_XY> aDelta = aEndPnt->xy()->decreased(aStartPnt->xy());
849 bool isFullValue = theConstraint->isFullValue();
850 int aNbObjects = aSubs.size()-3;
851 if (isFullValue && aNbObjects > 0) {
852 aDelta->setX(aDelta->x()/aNbObjects);
853 aDelta->setY(aDelta->y()/aNbObjects);
856 std::list<EntityWrapperPtr>::const_iterator aPrevIt = aSIt++;
857 for (; aSIt != aSubs.end(); ++aPrevIt, ++aSIt)
858 translate(*aPrevIt, *aSIt, aDelta);