1 // Copyright (C) 2014-2017 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
21 #include <SolveSpaceSolver_Builder.h>
22 #include <SolveSpaceSolver_Solver.h>
23 #include <SolveSpaceSolver_Storage.h>
24 #include <SolveSpaceSolver_ParameterWrapper.h>
25 #include <SolveSpaceSolver_EntityWrapper.h>
26 #include <SolveSpaceSolver_ConstraintWrapper.h>
27 #include <SolveSpaceSolver_ConstraintType.h>
29 #include <SketchSolver_Manager.h>
31 #include <GeomAPI_Angle2d.h>
32 #include <GeomAPI_Dir2d.h>
33 #include <GeomAPI_Pnt2d.h>
34 #include <GeomAPI_XY.h>
35 #include <GeomDataAPI_Dir.h>
36 #include <GeomDataAPI_Point.h>
37 #include <GeomDataAPI_Point2D.h>
38 #include <ModelAPI_Attribute.h>
39 #include <ModelAPI_AttributeRefAttr.h>
41 #include <SketchPlugin_Arc.h>
42 #include <SketchPlugin_Circle.h>
43 #include <SketchPlugin_Line.h>
44 #include <SketchPlugin_Point.h>
45 #include <SketchPlugin_IntersectionPoint.h>
46 #include <SketchPlugin_ConstraintAngle.h>
51 static EntityWrapperPtr createLine(FeaturePtr theFeature,
52 const std::list<EntityWrapperPtr>& theAttributes,
53 const GroupID& theGroupID,
54 const EntityID& theSketchID);
55 static EntityWrapperPtr createCircle(FeaturePtr theFeature,
56 const std::list<EntityWrapperPtr>& theAttributes,
57 const GroupID& theGroupID,
58 const EntityID& theSketchID);
59 static EntityWrapperPtr createArc(FeaturePtr theFeature,
60 const std::list<EntityWrapperPtr>& theAttributes,
61 const GroupID& theGroupID,
62 const EntityID& theSketchID);
64 /// \brief Set flags of constraint to identify which points are coincident in the Tangency
65 /// (for more information, see SolveSpace documentation)
66 static void adjustTangency(ConstraintWrapperPtr theConstraint);
67 /// \brief Set flags for angle constraint
68 static void adjustAngle(ConstraintWrapperPtr theConstraint);
69 /// \brief Update mirror points
70 static void adjustMirror(ConstraintWrapperPtr theConstraint);
71 /// \brief Update a sign of the point-line distance constraint
72 static void adjustPtLineDistance(ConstraintWrapperPtr theConstraint);
74 /// \brief Transform points to be symmetric regarding to the mirror line
75 static void makeMirrorPoints(EntityWrapperPtr theOriginal,
76 EntityWrapperPtr theMirrored,
77 EntityWrapperPtr theMirrorLine);
81 // Initialization of constraint builder self pointer
82 BuilderPtr SolveSpaceSolver_Builder::mySelf = SolveSpaceSolver_Builder::getInstance();
84 BuilderPtr SolveSpaceSolver_Builder::getInstance()
87 mySelf = BuilderPtr(new SolveSpaceSolver_Builder);
88 SketchSolver_Manager::instance()->setBuilder(mySelf);
93 StoragePtr SolveSpaceSolver_Builder::createStorage(const GroupID& theGroup) const
95 return StoragePtr(new SolveSpaceSolver_Storage(theGroup));
98 SolverPtr SolveSpaceSolver_Builder::createSolver() const
100 return SolverPtr(new SolveSpaceSolver_Solver);
104 std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createConstraint(
105 ConstraintPtr theConstraint,
106 const GroupID& theGroupID,
107 const EntityID& theSketchID,
108 const SketchSolver_ConstraintType& theType,
109 const double& theValue,
110 const EntityWrapperPtr& thePoint1,
111 const EntityWrapperPtr& thePoint2,
112 const EntityWrapperPtr& theEntity1,
113 const EntityWrapperPtr& theEntity2) const
115 if (theType == CONSTRAINT_SYMMETRIC)
116 return createMirror(theConstraint, theGroupID, theSketchID,
117 thePoint1, thePoint2, theEntity1);
118 else if (theType == CONSTRAINT_TANGENT_CIRCLE_LINE) {
119 // replace by distance from center of circle to the line
120 const std::list<EntityWrapperPtr>& aSubs = theEntity1->subEntities();
121 EntityWrapperPtr aCenter = aSubs.front();
122 AttributeDoublePtr aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
123 aSubs.back()->baseAttribute());
124 return createConstraint(theConstraint, theGroupID, theSketchID,
125 CONSTRAINT_PT_LINE_DISTANCE, aRadius->value(), aCenter, EntityWrapperPtr(), theEntity2);
127 else if (theType == CONSTRAINT_COLLINEAR) {
128 // replace by two constraints point-on-line
129 std::list<ConstraintWrapperPtr> aConstraints;
130 const std::list<EntityWrapperPtr>& aSubs1 = theEntity1->subEntities();
131 const std::list<EntityWrapperPtr>& aSubs2 = theEntity2->subEntities();
132 std::list<EntityWrapperPtr>::const_iterator anIt1, anIt2;
133 for (anIt2 = aSubs2.begin(); anIt2 != aSubs2.end(); ++anIt2) {
134 for (anIt1 = aSubs1.begin(); anIt1 != aSubs1.end(); ++anIt1)
135 if ((*anIt1)->id() == (*anIt2)->id())
137 if (anIt1 != aSubs1.end())
138 continue; // the lines have coincident point
140 std::list<ConstraintWrapperPtr> aC = createConstraint(theConstraint, theGroupID,
141 theSketchID, CONSTRAINT_PT_ON_LINE, theValue, *anIt2, EntityWrapperPtr(), theEntity1);
142 aConstraints.insert(aConstraints.end(), aC.begin(), aC.end());
147 int aType = ConstraintType::toSolveSpace(theType);
148 if (aType == SLVS_C_UNKNOWN)
149 return std::list<ConstraintWrapperPtr>();
151 Slvs_hEntity aSlvsEntities[4] = {SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN};
152 EntityWrapperPtr anOriginal[4] = {thePoint1, thePoint2, theEntity1, theEntity2};
153 std::list<EntityWrapperPtr> aConstrAttrList; // to be filled
154 for (int i = 0; i < 4; ++i) {
157 aSlvsEntities[i] = (Slvs_hEntity)anOriginal[i]->id();
158 // entity is not added into a storage, constraint can not be created
159 if (aSlvsEntities[i] == SLVS_E_UNKNOWN)
160 return std::list<ConstraintWrapperPtr>();
161 aConstrAttrList.push_back(anOriginal[i]);
164 Slvs_Constraint aConstraint = Slvs_MakeConstraint(
165 SLVS_C_UNKNOWN, (Slvs_hGroup)theGroupID, aType, (Slvs_hEntity)theSketchID,
166 theValue, aSlvsEntities[0], aSlvsEntities[1], aSlvsEntities[2], aSlvsEntities[3]);
167 ConstraintWrapperPtr aResult(new SolveSpaceSolver_ConstraintWrapper(theConstraint, aConstraint));
168 aResult->setGroup(theGroupID);
169 aResult->setValue(theValue);
170 aResult->setEntities(aConstrAttrList);
171 adjustConstraint(aResult);
173 return std::list<ConstraintWrapperPtr>(1, aResult);
176 std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createConstraint(
177 ConstraintPtr theConstraint,
178 const GroupID& theGroupID,
179 const EntityID& theSketchID,
180 const SketchSolver_ConstraintType& theType,
181 const double& theValue,
182 const bool theFullValue,
183 const EntityWrapperPtr& thePoint1,
184 const EntityWrapperPtr& thePoint2,
185 const std::list<EntityWrapperPtr>& theTrsfEnt) const
187 if (theType != CONSTRAINT_MULTI_ROTATION && theType != CONSTRAINT_MULTI_TRANSLATION)
188 return std::list<ConstraintWrapperPtr>();
190 int aType = ConstraintType::toSolveSpace(theType);
191 if (aType == SLVS_C_UNKNOWN)
192 return std::list<ConstraintWrapperPtr>();
194 Slvs_Constraint aConstraint =
195 Slvs_MakeConstraint(SLVS_C_UNKNOWN, (Slvs_hGroup)theGroupID, aType, (Slvs_hEntity)theSketchID,
196 theValue, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
198 std::list<EntityWrapperPtr> aConstrAttrList = theTrsfEnt;
200 aConstrAttrList.push_front(thePoint2);
201 aConstrAttrList.push_front(thePoint1);
203 ConstraintWrapperPtr aResult(new SolveSpaceSolver_ConstraintWrapper(theConstraint, aConstraint));
204 aResult->setGroup(theGroupID);
205 aResult->setValue(theValue);
206 aResult->setIsFullValue(theFullValue);
207 aResult->setEntities(aConstrAttrList);
208 return std::list<ConstraintWrapperPtr>(1, aResult);
212 std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createMirror(
213 ConstraintPtr theConstraint,
214 const GroupID& theGroupID,
215 const EntityID& theSketchID,
216 const EntityWrapperPtr& theEntity1,
217 const EntityWrapperPtr& theEntity2,
218 const EntityWrapperPtr& theMirrorLine) const
220 Slvs_Constraint aConstraint;
221 std::list<ConstraintWrapperPtr> aResult;
222 std::list<EntityWrapperPtr> aConstrAttrList;
223 if (theEntity1->type() == ENTITY_POINT) {
224 makeMirrorPoints(theEntity1, theEntity2, theMirrorLine);
226 aConstraint = Slvs_MakeConstraint(
227 SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID, SLVS_C_SYMMETRIC_LINE, (Slvs_hEntity)theSketchID,
228 0.0, (Slvs_hEntity)theEntity1->id(), (Slvs_hEntity)theEntity2->id(),
229 (Slvs_hEntity)theMirrorLine->id(), SLVS_E_UNKNOWN);
231 aConstrAttrList.push_back(theEntity1);
232 aConstrAttrList.push_back(theEntity2);
233 aConstrAttrList.push_back(theMirrorLine);
235 ConstraintWrapperPtr aWrapper(new SolveSpaceSolver_ConstraintWrapper(
236 theConstraint, aConstraint));
237 aWrapper->setGroup(theGroupID);
238 aWrapper->setEntities(aConstrAttrList);
239 aResult.push_back(aWrapper);
241 else if (theEntity1->type() == ENTITY_LINE) {
242 const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
243 const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
244 std::list<EntityWrapperPtr>::const_iterator anIt1 = aPoints1.begin();
245 std::list<EntityWrapperPtr>::const_iterator anIt2 = aPoints2.begin();
246 for (; anIt1 != aPoints1.end() && anIt2 != aPoints2.end(); ++anIt1, ++anIt2) {
247 std::list<ConstraintWrapperPtr> aMrrList =
248 createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
249 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
252 else if (theEntity1->type() == ENTITY_CIRCLE) {
253 const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
254 std::list<EntityWrapperPtr>::const_iterator anIt1 = aPoints1.begin();
255 for (; anIt1 != aPoints1.end(); ++anIt1)
256 if ((*anIt1)->type() == ENTITY_POINT)
258 const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
259 std::list<EntityWrapperPtr>::const_iterator anIt2 = aPoints2.begin();
260 for (; anIt2 != aPoints2.end(); ++anIt2)
261 if ((*anIt2)->type() == ENTITY_POINT)
264 std::list<ConstraintWrapperPtr> aMrrList =
265 createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
266 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
268 // Additional constraint for equal radii
269 aMrrList = createConstraint(theConstraint, theGroupID, theSketchID, CONSTRAINT_EQUAL_RADIUS,
270 0.0, EntityWrapperPtr(), EntityWrapperPtr(), theEntity1, theEntity2);
271 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
273 else if (theEntity1->type() == ENTITY_ARC) {
274 // Do not allow mirrored arc recalculate its position until
275 // coordinated of all points recalculated
276 FeaturePtr aMirrArc = theEntity2->baseFeature();
277 bool aWasBlocked = aMirrArc->data()->blockSendAttributeUpdated(true);
279 std::list<ConstraintWrapperPtr> aMrrList;
280 std::list<EntityWrapperPtr>::const_iterator anIt1 = theEntity1->subEntities().begin();
281 std::list<EntityWrapperPtr>::const_iterator anIt2 = theEntity2->subEntities().begin();
282 makeMirrorPoints(*anIt1, *anIt2, theMirrorLine);
284 // Workaround to avoid problems in SolveSpace.
285 // The symmetry of two arcs will be done using symmetry of three points on these arcs:
286 // start point, end point, and any other point on the arc
287 std::list<EntityWrapperPtr> aBaseArcPoints(++anIt1, theEntity1->subEntities().end());
288 std::list<EntityWrapperPtr> aMirrorArcPoints(++anIt2, theEntity2->subEntities().end());
289 // indices of points of arc, center corresponds center, first point corresponds last point
290 aMirrorArcPoints.reverse();
292 anIt1 = aBaseArcPoints.begin();
293 anIt2 = aMirrorArcPoints.begin();
294 for (; anIt1 != aBaseArcPoints.end(); ++anIt1, ++anIt2) {
296 createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
297 aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
299 // Restore event sending
300 aMirrArc->data()->blockSendAttributeUpdated(aWasBlocked);
305 void SolveSpaceSolver_Builder::adjustConstraint(ConstraintWrapperPtr theConstraint) const
307 SketchSolver_ConstraintType aType = theConstraint->type();
308 // Update flags in constraints
309 if (aType == CONSTRAINT_TANGENT_ARC_ARC || aType == CONSTRAINT_TANGENT_ARC_LINE)
310 adjustTangency(theConstraint);
311 else if (aType == CONSTRAINT_ANGLE)
312 adjustAngle(theConstraint);
313 else if (aType == CONSTRAINT_SYMMETRIC)
314 adjustMirror(theConstraint);
315 else if (aType == CONSTRAINT_PT_LINE_DISTANCE)
316 adjustPtLineDistance(theConstraint);
319 EntityWrapperPtr SolveSpaceSolver_Builder::createFeature(
320 FeaturePtr theFeature,
321 const std::list<EntityWrapperPtr>& theAttributes,
322 const GroupID& theGroupID,
323 const EntityID& theSketchID) const
325 static EntityWrapperPtr aDummy;
326 if (!theFeature->data()->isValid())
330 CompositeFeaturePtr aSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
332 return createSketchEntity(aSketch, theGroupID);
334 // SketchPlugin features
335 std::shared_ptr<SketchPlugin_Feature> aFeature =
336 std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
340 // Verify the feature by its kind
341 const std::string& aFeatureKind = aFeature->getKind();
343 if (aFeatureKind == SketchPlugin_Line::ID())
344 return createLine(theFeature, theAttributes, theGroupID, theSketchID);
346 else if (aFeatureKind == SketchPlugin_Circle::ID())
347 return createCircle(theFeature, theAttributes, theGroupID, theSketchID);
349 else if (aFeatureKind == SketchPlugin_Arc::ID())
350 return createArc(theFeature, theAttributes, theGroupID, theSketchID);
351 // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
352 else if (aFeatureKind == SketchPlugin_Point::ID() ||
353 aFeatureKind == SketchPlugin_IntersectionPoint::ID()) {
354 AttributePtr aPoint = theFeature->attribute(SketchPlugin_Point::COORD_ID());
355 if (!aPoint->isInitialized())
357 EntityWrapperPtr aSub = theAttributes.empty() ?
358 createAttribute(aPoint, theGroupID, theSketchID) :
359 theAttributes.front();
363 const Slvs_Entity& aSubEnt =
364 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(aSub)->entity();
365 EntityWrapperPtr aResult(new SolveSpaceSolver_EntityWrapper(theFeature, aPoint, aSubEnt));
366 aResult->setSubEntities(theAttributes);
374 EntityWrapperPtr SolveSpaceSolver_Builder::createAttribute(
375 AttributePtr theAttribute,
376 const GroupID& theGroupID,
377 const EntityID& theSketchID) const
379 AttributePtr anAttribute = theAttribute;
380 AttributeRefAttrPtr aRefAttr =
381 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
383 if (aRefAttr->isObject()) {
384 // do not create features here
385 return EntityWrapperPtr();
387 anAttribute = aRefAttr->attr();
390 std::list<ParameterWrapperPtr> aParameters;
391 Slvs_Entity anEntity;
395 std::shared_ptr<GeomDataAPI_Point> aPoint =
396 std::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
398 aParameters.push_back(createParameter(theGroupID, aPoint->x(), !aPoint->textX().empty()));
399 aParameters.push_back(createParameter(theGroupID, aPoint->y(), !aPoint->textY().empty()));
400 aParameters.push_back(createParameter(theGroupID, aPoint->z(), !aPoint->textZ().empty()));
401 // Create entity (parameters are not filled)
402 anEntity = Slvs_MakePoint3d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
403 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
406 std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
407 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
409 aParameters.push_back(createParameter(theGroupID, aPoint2D->x(),
410 !aPoint2D->textX().empty()));
411 aParameters.push_back(createParameter(theGroupID, aPoint2D->y(),
412 !aPoint2D->textY().empty()));
413 // Create entity (parameters are not filled)
414 anEntity = Slvs_MakePoint2d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
415 (Slvs_hEntity)theSketchID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
417 // Scalar value (used for the distance entities)
418 AttributeDoublePtr aScalar =
419 std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
421 aParameters.push_back(createParameter(theGroupID, aScalar->value(),
422 !aScalar->text().empty()));
423 // Create entity (parameter is not filled)
424 anEntity = Slvs_MakeDistance(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
425 (Slvs_hEntity)theSketchID, SLVS_E_UNKNOWN);
430 if (anEntity.type == 0) {
431 // unknown attribute type
432 return EntityWrapperPtr();
435 EntityWrapperPtr aResult(new SolveSpaceSolver_EntityWrapper(theAttribute, anEntity));
436 aResult->setParameters(aParameters);
442 EntityWrapperPtr SolveSpaceSolver_Builder::createSketchEntity(
443 CompositeFeaturePtr theSketch,
444 const GroupID& theGroupID) const
446 DataPtr aSketchData = theSketch->data();
447 if (!aSketchData || !aSketchData->isValid())
448 return EntityWrapperPtr(); // the sketch is incorrect
450 // Get parameters of workplane
451 AttributePtr aDirX = aSketchData->attribute(SketchPlugin_Sketch::DIRX_ID());
452 AttributePtr aNorm = aSketchData->attribute(SketchPlugin_Sketch::NORM_ID());
453 AttributePtr anOrigin = aSketchData->attribute(SketchPlugin_Sketch::ORIGIN_ID());
454 if (!anOrigin->isInitialized() || !aNorm->isInitialized() || !aDirX->isInitialized())
455 return EntityWrapperPtr();
457 EntityWrapperPtr aNewEnt;
458 std::list<EntityWrapperPtr> aSubs;
460 // Create SolveSpace entity corresponding to the sketch origin
461 aNewEnt = createAttribute(anOrigin, theGroupID);
463 return EntityWrapperPtr();
464 aSubs.push_back(aNewEnt);
466 // Create SolveSpace entity corresponding the the sketch normal
467 aNewEnt = createNormal(aNorm, aDirX, theGroupID);
469 return EntityWrapperPtr();
470 aSubs.push_back(aNewEnt);
473 Slvs_Entity aWorkplane = Slvs_MakeWorkplane(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
474 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
476 aNewEnt = EntityWrapperPtr(
477 new SolveSpaceSolver_EntityWrapper(FeaturePtr(theSketch), aWorkplane));
478 aNewEnt->setSubEntities(aSubs);
482 EntityWrapperPtr SolveSpaceSolver_Builder::createNormal(
483 AttributePtr theNormal,
484 AttributePtr theDirX,
485 const GroupID& theGroupID) const
487 std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theNormal);
488 std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
489 if (!aDirX || !aNorm ||
490 (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance) ||
491 !aNorm->isInitialized())
492 return EntityWrapperPtr();
493 // calculate Y direction
494 std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aDirX->dir())));
496 // quaternion parameters of normal vector
497 double qw, qx, qy, qz;
498 Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), aDirY->x(), aDirY->y(), aDirY->z(), &qw,
500 double aNormCoord[4] = { qw, qx, qy, qz };
502 // Create parameters of the normal
503 std::list<ParameterWrapperPtr> aParameters;
504 for (int i = 0; i < 4; i++)
505 aParameters.push_back(createParameter(theGroupID, aNormCoord[i]));
507 // Create a normal with empty parameters
508 Slvs_Entity aNormalEnt = Slvs_MakeNormal3d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
509 SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
510 EntityWrapperPtr aNormal(new SolveSpaceSolver_EntityWrapper(theNormal, aNormalEnt));
511 aNormal->setParameters(aParameters);
515 ParameterWrapperPtr SolveSpaceSolver_Builder::createParameter(
516 const GroupID& theGroup, const double theValue, const bool theExpr) const
518 Slvs_Param aParam = Slvs_MakeParam(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroup, theValue);
519 ParameterWrapperPtr aWrapper(new SolveSpaceSolver_ParameterWrapper(aParam));
520 aWrapper->setIsParametric(theExpr);
528 // ================ Auxiliary functions ==========================
529 EntityWrapperPtr createLine(FeaturePtr theFeature,
530 const std::list<EntityWrapperPtr>& theAttributes,
531 const GroupID& theGroupID,
532 const EntityID& theSketchID)
534 EntityWrapperPtr aNewEntity;
535 std::list<EntityWrapperPtr> aSubs;
537 AttributePtr aStart = theFeature->attribute(SketchPlugin_Line::START_ID());
538 AttributePtr aEnd = theFeature->attribute(SketchPlugin_Line::END_ID());
539 if (!aStart->isInitialized() || !aEnd->isInitialized())
542 EntityWrapperPtr aStartEnt, aEndEnt;
543 std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
544 for (; anIt != theAttributes.end(); ++anIt) {
545 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
546 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
547 if (aSlvsEntity->isBase(aStart))
548 aStartEnt = aSlvsEntity;
549 else if (aSlvsEntity->isBase(aEnd))
550 aEndEnt = aSlvsEntity;
552 if (!aStartEnt || !aEndEnt)
555 aSubs.push_back(aStartEnt);
556 aSubs.push_back(aEndEnt);
557 Slvs_Entity anEntity = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
558 (Slvs_hEntity)theSketchID, (Slvs_hEntity)aStartEnt->id(), (Slvs_hEntity)aEndEnt->id());
560 aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
561 aNewEntity->setSubEntities(aSubs);
565 EntityWrapperPtr createCircle(FeaturePtr theFeature,
566 const std::list<EntityWrapperPtr>& theAttributes,
567 const GroupID& theGroupID,
568 const EntityID& theSketchID)
570 EntityWrapperPtr aNewEntity;
571 std::list<EntityWrapperPtr> aSubs;
573 AttributePtr aCenter = theFeature->attribute(SketchPlugin_Circle::CENTER_ID());
574 AttributePtr aRadius = theFeature->attribute(SketchPlugin_Circle::RADIUS_ID());
575 if (!aCenter->isInitialized() || !aRadius->isInitialized())
578 EntityWrapperPtr aCenterEnt, aRadiusEnt, aNormalEnt;
579 std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
580 for (; anIt != theAttributes.end(); ++anIt) {
581 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
582 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
583 if (aSlvsEntity->isBase(aCenter))
584 aCenterEnt = aSlvsEntity;
585 else if (aSlvsEntity->isBase(aRadius))
586 aRadiusEnt = aSlvsEntity;
587 else if (aSlvsEntity->type() == ENTITY_NORMAL)
588 aNormalEnt = aSlvsEntity;
590 if (!aCenterEnt || !aRadiusEnt || !aNormalEnt)
593 aSubs.push_back(aCenterEnt);
594 aSubs.push_back(aRadiusEnt);
595 Slvs_Entity anEntity = Slvs_MakeCircle(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
596 (Slvs_hEntity)theSketchID, (Slvs_hEntity)aCenterEnt->id(),
597 (Slvs_hEntity)aNormalEnt->id(), (Slvs_hEntity)aRadiusEnt->id());
599 aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
600 aNewEntity->setSubEntities(aSubs);
604 EntityWrapperPtr createArc(FeaturePtr theFeature,
605 const std::list<EntityWrapperPtr>& theAttributes,
606 const GroupID& theGroupID,
607 const EntityID& theSketchID)
609 EntityWrapperPtr aNewEntity;
610 std::list<EntityWrapperPtr> aSubs;
612 AttributePtr aCenter = theFeature->attribute(SketchPlugin_Arc::CENTER_ID());
613 AttributePtr aStart = theFeature->attribute(SketchPlugin_Arc::START_ID());
614 AttributePtr aEnd = theFeature->attribute(SketchPlugin_Arc::END_ID());
615 if (!aCenter->isInitialized() || !aStart->isInitialized() || !aEnd->isInitialized())
618 EntityWrapperPtr aCenterEnt, aStartEnt, aEndEnt, aNormalEnt;
619 std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
620 for (; anIt != theAttributes.end(); ++anIt) {
621 std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
622 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
623 if (aSlvsEntity->isBase(aCenter))
624 aCenterEnt = aSlvsEntity;
625 else if (aSlvsEntity->isBase(aStart))
626 aStartEnt = aSlvsEntity;
627 else if (aSlvsEntity->isBase(aEnd))
628 aEndEnt = aSlvsEntity;
629 else if (aSlvsEntity->type() == ENTITY_NORMAL)
630 aNormalEnt = aSlvsEntity;
632 if (!aCenterEnt || !aStartEnt || !aEndEnt || !aNormalEnt)
635 aSubs.push_back(aCenterEnt);
636 aSubs.push_back(aStartEnt);
637 aSubs.push_back(aEndEnt);
638 Slvs_Entity anEntity = Slvs_MakeArcOfCircle(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
639 (Slvs_hEntity)theSketchID, (Slvs_hEntity)aNormalEnt->id(),
640 (Slvs_hEntity)aCenterEnt->id(), (Slvs_hEntity)aStartEnt->id(), (Slvs_hEntity)aEndEnt->id());
642 aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
643 aNewEntity->setSubEntities(aSubs);
648 void adjustTangency(ConstraintWrapperPtr theConstraint)
650 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
652 std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
653 std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
655 // Collect start, end points of entities
656 std::shared_ptr<GeomAPI_Pnt2d> aStartEntPoints[2][2];
657 bool isCoinc[2][2] = {false};
658 const std::list<EntityWrapperPtr>& aSubs = aConstraint->entities();
659 std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
660 for (int i = 0; aSIt != aSubs.end(); ++aSIt, ++i) {
661 const std::list<EntityWrapperPtr>& aPoints = (*aSIt)->subEntities();
662 std::list<EntityWrapperPtr>::const_iterator aPIt = aPoints.begin();
663 if ((*aSIt)->type() == ENTITY_ARC)
665 for (int j = 0; aPIt != aPoints.end(); ++aPIt, ++j) {
666 aStartEntPoints[i][j] = aBuilder->point(*aPIt);
667 if (i > 0) { // check coincidence
668 for (int k = 0; k < 2; ++k)
669 if (aStartEntPoints[i][j]->distance(aStartEntPoints[0][k]) < tolerance)
670 isCoinc[0][k] = isCoinc[i][j] = true;
675 Slvs_Constraint& aSlvsConstraint = aConstraint->changeConstraint();
676 if (isCoinc[0][0] == false && isCoinc[0][1] == true)
677 aSlvsConstraint.other = 1;
678 else aSlvsConstraint.other = 0;
679 if (isCoinc[1][0] == false && isCoinc[1][1] == true)
680 aSlvsConstraint.other2 = 1;
681 else aSlvsConstraint.other2 = 0;
684 void adjustAngle(ConstraintWrapperPtr theConstraint)
686 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
688 std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
689 std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
692 std::shared_ptr<GeomAPI_Pnt2d> aPoints[2][2]; // start and end points of lines
693 const std::list<EntityWrapperPtr>& aConstrLines = aConstraint->entities();
694 std::list<EntityWrapperPtr>::const_iterator aCLIt = aConstrLines.begin();
695 for (int i = 0; aCLIt != aConstrLines.end(); ++i, ++aCLIt) {
696 const std::list<EntityWrapperPtr>& aLinePoints = (*aCLIt)->subEntities();
697 std::list<EntityWrapperPtr>::const_iterator aLPIt = aLinePoints.begin();
698 for (int j = 0; aLPIt != aLinePoints.end(); ++j, ++aLPIt) {
699 isFixed[i][j] = ((*aLPIt)->group() != theConstraint->group());
700 aPoints[i][j] = aBuilder->point(*aLPIt);
704 if (isFixed[0][0] && isFixed[0][1] && isFixed[1][0] && isFixed[1][1])
705 return; // both lines are fixed => no need to update them
707 std::shared_ptr<GeomAPI_Lin2d> aLine[2] = {
708 std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[0][0], aPoints[0][1])),
709 std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[1][0], aPoints[1][1]))
711 bool isReversed[2] = {
712 aConstraint->baseConstraint()->boolean(
713 SketchPlugin_ConstraintAngle::ANGLE_REVERSED_FIRST_LINE_ID())->value(),
714 aConstraint->baseConstraint()->boolean(
715 SketchPlugin_ConstraintAngle::ANGLE_REVERSED_SECOND_LINE_ID())->value()
717 std::shared_ptr<GeomAPI_Angle2d>
718 anAngle(new GeomAPI_Angle2d(aLine[0], isReversed[0], aLine[1], isReversed[1]));
719 std::shared_ptr<GeomAPI_Pnt2d> aCenter = anAngle->center();
721 Slvs_Constraint& aSlvsConstraint = aConstraint->changeConstraint();
722 aSlvsConstraint.other = isReversed[0] != isReversed[1];
725 void adjustMirror(ConstraintWrapperPtr theConstraint)
727 std::vector<EntityWrapperPtr> aPoints;
728 EntityWrapperPtr aMirrorLine;
730 const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
731 std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
732 for (; anIt != aSubs.end(); ++anIt) {
733 if ((*anIt)->type() == ENTITY_POINT)
734 aPoints.push_back(*anIt);
735 else if ((*anIt)->type() == ENTITY_LINE)
739 makeMirrorPoints(aPoints[0], aPoints[1], aMirrorLine);
742 void makeMirrorPoints(EntityWrapperPtr theOriginal,
743 EntityWrapperPtr theMirrored,
744 EntityWrapperPtr theMirrorLine)
746 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
748 std::shared_ptr<GeomAPI_Lin2d> aMirrorLine = aBuilder->line(theMirrorLine);
749 std::shared_ptr<GeomAPI_Dir2d> aMLDir = aMirrorLine->direction();
750 // orthogonal direction
751 aMLDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aMLDir->y(), -aMLDir->x()));
753 std::shared_ptr<GeomAPI_Pnt2d> aPoint = aBuilder->point(theOriginal);
754 std::shared_ptr<GeomAPI_XY> aVec = aPoint->xy()->decreased(aMirrorLine->location()->xy());
755 double aDist = aVec->dot(aMLDir->xy());
756 aVec = aPoint->xy()->added(aMLDir->xy()->multiplied(-2.0 * aDist));
757 double aCoord[2] = {aVec->x(), aVec->y()};
758 std::list<ParameterWrapperPtr>::const_iterator aMIt = theMirrored->parameters().begin();
759 for (int i = 0; aMIt != theMirrored->parameters().end(); ++aMIt, ++i)
760 (*aMIt)->setValue(aCoord[i]);
762 // update corresponding attribute
763 AttributePtr anAttr =
764 std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theMirrored)->baseAttribute();
766 std::shared_ptr<GeomDataAPI_Point2D> aMirroredPnt =
767 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
768 aMirroredPnt->setValue(aCoord[0], aCoord[1]);
772 void adjustPtLineDistance(ConstraintWrapperPtr theConstraint)
774 BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
776 std::shared_ptr<GeomAPI_Pnt2d> aPoint;
777 std::shared_ptr<GeomAPI_Lin2d> aLine;
778 std::list<EntityWrapperPtr> aSubs = theConstraint->entities();
779 std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
780 for (; aSIt != aSubs.end(); ++aSIt) {
781 if ((*aSIt)->type() == ENTITY_POINT)
782 aPoint = aBuilder->point(*aSIt);
783 else if ((*aSIt)->type() == ENTITY_LINE)
784 aLine = aBuilder->line(*aSIt);
787 std::shared_ptr<GeomAPI_XY> aLineVec = aLine->direction()->xy();
788 std::shared_ptr<GeomAPI_XY> aPtLineVec = aPoint->xy()->decreased(aLine->location()->xy());
789 if (aPtLineVec->cross(aLineVec) * theConstraint->value() < 0.0)
790 theConstraint->setValue(theConstraint->value() * (-1.0));