1 // Copyright (C) 2014-2019 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 email : webmaster.salome@opencascade.com
20 #include <PlaneGCSSolver_Storage.h>
21 #include <PlaneGCSSolver_Solver.h>
22 #include <PlaneGCSSolver_BooleanWrapper.h>
23 #include <PlaneGCSSolver_ConstraintWrapper.h>
24 #include <PlaneGCSSolver_EdgeWrapper.h>
25 #include <PlaneGCSSolver_PointWrapper.h>
26 #include <PlaneGCSSolver_PointArrayWrapper.h>
27 #include <PlaneGCSSolver_ScalarArrayWrapper.h>
28 #include <PlaneGCSSolver_Tools.h>
30 #include <PlaneGCSSolver_AttributeBuilder.h>
31 #include <PlaneGCSSolver_FeatureBuilder.h>
32 #include <PlaneGCSSolver_EntityDestroyer.h>
34 #include <GeomAPI_Dir2d.h>
35 #include <GeomAPI_Pnt2d.h>
36 #include <GeomAPI_XY.h>
37 #include <GeomDataAPI_Point2D.h>
38 #include <GeomDataAPI_Point2DArray.h>
39 #include <ModelAPI_AttributeDoubleArray.h>
40 #include <ModelAPI_AttributeRefAttr.h>
41 #include <SketchPlugin_Ellipse.h>
42 #include <SketchPlugin_Projection.h>
47 static void constraintsToSolver(const ConstraintWrapperPtr& theConstraint,
48 const SolverPtr& theSolver)
50 const std::list<GCSConstraintPtr>& aConstraints =
51 std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(theConstraint)->constraints();
52 theSolver->addConstraint(theConstraint->id(), aConstraints);
56 PlaneGCSSolver_Storage::PlaneGCSSolver_Storage(const SolverPtr& theSolver)
57 : SketchSolver_Storage(theSolver),
58 myConstraintLastID(CID_UNKNOWN)
62 void PlaneGCSSolver_Storage::addConstraint(
63 ConstraintPtr theConstraint,
64 ConstraintWrapperPtr theSolverConstraint)
66 SketchSolver_Storage::addConstraint(theConstraint, theSolverConstraint);
68 theSolverConstraint->setId(++myConstraintLastID);
69 constraintsToSolver(theSolverConstraint, mySketchSolver);
72 void PlaneGCSSolver_Storage::addMovementConstraint(
73 const ConstraintWrapperPtr& theSolverConstraint)
75 // before adding movement constraint to solver, re-check its DOF
76 if (mySketchSolver->dof() == 0)
77 mySketchSolver->diagnose();
79 theSolverConstraint->setId(CID_MOVEMENT);
80 constraintsToSolver(theSolverConstraint, mySketchSolver);
84 EntityWrapperPtr PlaneGCSSolver_Storage::createFeature(
85 const FeaturePtr& theFeature,
86 PlaneGCSSolver_EntityBuilder* theBuilder)
88 std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
89 std::list<AttributePtr>::const_iterator anIt = anAttributes.begin();
90 for (; anIt != anAttributes.end(); ++anIt)
91 createAttribute(*anIt, theBuilder);
93 EntityWrapperPtr aResult = theBuilder->createFeature(theFeature);
95 addEntity(theFeature, aResult);
99 EntityWrapperPtr PlaneGCSSolver_Storage::createAttribute(
100 const AttributePtr& theAttribute,
101 PlaneGCSSolver_EntityBuilder* theBuilder)
103 EntityWrapperPtr aResult = theBuilder->createAttribute(theAttribute);
105 addEntity(theAttribute, aResult);
109 /// \brief Update value
110 static bool updateValue(const double& theSource, double& theDest)
112 static const double aTol = 1.e4 * tolerance;
113 bool isUpdated = fabs(theSource - theDest) > aTol;
119 /// \brief Update coordinates of the point or scalar using its base attribute
120 static bool updateValues(AttributePtr& theAttribute, EntityWrapperPtr& theEntity)
122 bool isUpdated = false;
124 std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
125 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
127 const GCSPointPtr& aGCSPoint =
128 std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theEntity)->point();
129 isUpdated = updateValue(aPoint2D->x(), *(aGCSPoint->x)) || isUpdated;
130 isUpdated = updateValue(aPoint2D->y(), *(aGCSPoint->y)) || isUpdated;
132 AttributeDoublePtr aScalar =
133 std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
135 ScalarWrapperPtr aWrapper =
136 std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(theEntity);
137 // There is possible angular value, which is converted between degrees and radians.
138 // So, we use its value instead of using direct pointer to value.
139 double aValue = aWrapper->value();
140 isUpdated = updateValue(aScalar->value(), aValue);
142 aWrapper->setValue(aValue);
144 AttributeBooleanPtr aBoolean =
145 std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(theAttribute);
147 BooleanWrapperPtr aWrapper =
148 std::dynamic_pointer_cast<PlaneGCSSolver_BooleanWrapper>(theEntity);
149 isUpdated = aWrapper->value() != aBoolean->value();
150 aWrapper->setValue(aBoolean->value());
158 static bool hasReference(std::shared_ptr<SketchPlugin_Feature> theFeature,
159 const std::string& theFeatureKind)
161 const std::set<AttributePtr>& aRefs = theFeature->data()->refsToMe();
162 for (std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin();
163 aRefIt != aRefs.end(); ++aRefIt) {
164 FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner());
165 if (anOwner && anOwner->getKind() == theFeatureKind)
171 static bool isCopyFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
173 return theFeature && theFeature->isCopy();
176 bool PlaneGCSSolver_Storage::update(FeaturePtr theFeature, bool theForce)
178 bool sendNotify = false;
179 bool isUpdated = false;
180 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
181 std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
182 EntityWrapperPtr aRelated = entity(theFeature);
183 if (aRelated) // send signal to subscribers
185 else { // Feature is not exist, create it
186 bool isCopy = isCopyFeature(aSketchFeature);
187 bool isProjReferred = hasReference(aSketchFeature, SketchPlugin_Projection::ID());
188 // the feature is a copy in "Multi" constraint and does not used in other constraints
189 if (!theForce && (isCopy && !isProjReferred) &&
190 myFeatureMap.find(theFeature) == myFeatureMap.end())
193 // external feature processing
195 (aSketchFeature && (aSketchFeature->isExternal() || isCopy || isProjReferred));
197 PlaneGCSSolver_FeatureBuilder aBuilder(isExternal ? 0 : this);
199 // Reserve the feature in the map of features
200 // (do not want to add several copies of it while adding attributes)
201 aRelated = createFeature(theFeature, &aBuilder);
202 myFeatureMap[theFeature] = aRelated;
203 createAuxiliaryConstraints(aRelated);
207 std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
208 std::list<AttributePtr>::iterator anAttrIt = anAttributes.begin();
209 for (; anAttrIt != anAttributes.end(); ++anAttrIt)
210 if ((*anAttrIt)->attributeType() == GeomDataAPI_Point2D::typeId() ||
211 (*anAttrIt)->attributeType() == ModelAPI_AttributeDouble::typeId() ||
212 (*anAttrIt)->attributeType() == ModelAPI_AttributeBoolean::typeId())
213 isUpdated = update(*anAttrIt) || isUpdated;
215 // check external attribute is changed
216 bool isExternal = aSketchFeature &&
217 (aSketchFeature->isExternal() || isCopyFeature(aSketchFeature));
218 if (aRelated && isExternal != aRelated->isExternal()) {
220 makeExternal(aRelated);
222 makeNonExternal(aRelated);
226 // send notification to listeners due to at least one attribute is changed
227 if (sendNotify && isUpdated)
232 PlaneGCSSolver_Tools::recalculateArcParameters(aRelated);
237 bool PlaneGCSSolver_Storage::update(AttributePtr theAttribute, bool theForce)
239 if (!theAttribute->isInitialized())
242 AttributePtr anAttribute = theAttribute;
243 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
245 if (aRefAttr->isObject()) {
247 /// TODO: Check resultToFeatureOrAttribute() precisely.
248 resultToFeatureOrAttribute(aRefAttr->object(), aFeature, anAttribute);
250 return update(aFeature, theForce);
252 anAttribute = aRefAttr->attr();
255 EntityWrapperPtr aRelated = entity(anAttribute);
256 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
257 if (!aRelated) { // Attribute does not exist, create it.
258 // First of all check if the parent feature exists. If not, add it.
259 if (aFeature && myFeatureMap.find(aFeature) == myFeatureMap.end())
260 return update(aFeature, theForce); // theAttribute has been processed while adding feature
261 return aRelated.get() != 0;
264 bool isUpdated = updateValues(anAttribute, aRelated);
266 setNeedToResolve(true);
272 void PlaneGCSSolver_Storage::makeExternal(const EntityWrapperPtr& theEntity)
274 if (theEntity->isExternal())
277 removeAuxiliaryConstraints(theEntity);
279 GCS::SET_pD aParameters = PlaneGCSSolver_Tools::parameters(theEntity);
280 mySketchSolver->removeParameters(aParameters);
281 theEntity->setExternal(true);
282 myNeedToResolve = true;
285 void PlaneGCSSolver_Storage::makeNonExternal(const EntityWrapperPtr& theEntity)
287 if (!theEntity->isExternal())
290 GCS::SET_pD aParameters = PlaneGCSSolver_Tools::parameters(theEntity);
291 mySketchSolver->addParameters(aParameters);
292 theEntity->setExternal(false);
294 createAuxiliaryConstraints(theEntity);
296 myNeedToResolve = true;
300 static void createArcConstraints(const EntityWrapperPtr& theArc,
301 const SolverPtr& theSolver,
302 const ConstraintID theConstraintID,
303 std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
305 EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theArc);
306 std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEdge->entity());
308 // Additional constaints to fix arc's extra DoF (if the arc is not external):
309 std::list<GCSConstraintPtr> anArcConstraints;
310 // 1. distances from center till start and end points are equal to radius
311 anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
312 anArc->center, anArc->start, anArc->rad)));
313 anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
314 anArc->center, anArc->end, anArc->rad)));
315 // 2. angles of start and end points should be equal to the arc angles
316 anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle(
317 anArc->center, anArc->start, anArc->startAngle)));
318 anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle(
319 anArc->center, anArc->end, anArc->endAngle)));
321 ConstraintWrapperPtr aWrapper(
322 new PlaneGCSSolver_ConstraintWrapper(anArcConstraints, CONSTRAINT_UNKNOWN));
323 aWrapper->setId(theConstraintID);
324 constraintsToSolver(aWrapper, theSolver);
326 theConstraints[theArc] = aWrapper;
329 static void createEllipseConstraints(
330 const EntityWrapperPtr& theEllipse,
331 const SolverPtr& theSolver,
332 const ConstraintID theConstraintID,
333 std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
335 EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theEllipse);
336 std::shared_ptr<GCS::Ellipse> anEllipse =
337 std::dynamic_pointer_cast<GCS::Ellipse>(anEdge->entity());
339 // Additional constaints to fix ellipse's extra points
340 std::list<GCSConstraintPtr> anEllipseConstraints;
342 const std::map<std::string, EntityWrapperPtr>& anAttributes = theEllipse->additionalAttributes();
343 for (std::map<std::string, EntityWrapperPtr>::const_iterator anIt = anAttributes.begin();
344 anIt != anAttributes.end(); ++anIt) {
345 std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint =
346 std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
350 GCS::InternalAlignmentType anAlignmentX, anAlignmentY;
351 if (anIt->first == SketchPlugin_Ellipse::SECOND_FOCUS_ID())
352 anAlignmentX = GCS::EllipseFocus2X;
353 else if (anIt->first == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID())
354 anAlignmentX = GCS::EllipseNegativeMajorX;
355 else if (anIt->first == SketchPlugin_Ellipse::MAJOR_AXIS_END_ID())
356 anAlignmentX = GCS::EllipsePositiveMajorX;
357 else if (anIt->first == SketchPlugin_Ellipse::MINOR_AXIS_START_ID())
358 anAlignmentX = GCS::EllipseNegativeMinorX;
359 else if (anIt->first == SketchPlugin_Ellipse::MINOR_AXIS_END_ID())
360 anAlignmentX = GCS::EllipsePositiveMinorX;
362 anEllipseConstraints.push_back(GCSConstraintPtr(
363 new GCS::ConstraintInternalAlignmentPoint2Ellipse(
364 *anEllipse, *(aPoint->point()), anAlignmentX)));
365 anAlignmentY = (GCS::InternalAlignmentType)((int)anAlignmentX + 1);
366 anEllipseConstraints.push_back(GCSConstraintPtr(
367 new GCS::ConstraintInternalAlignmentPoint2Ellipse(
368 *anEllipse, *(aPoint->point()), anAlignmentY)));
371 // constraint to bind the major radius value
372 std::shared_ptr<PlaneGCSSolver_PointWrapper> aMajorAxisStart =
373 std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
374 anAttributes.at(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID()));
375 ScalarWrapperPtr aMajorRadius =
376 std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(
377 anAttributes.at(SketchPlugin_Ellipse::MAJOR_RADIUS_ID()));
378 anEllipseConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
379 anEllipse->center, *(aMajorAxisStart->point()), aMajorRadius->scalar())));
381 ConstraintWrapperPtr aWrapper(
382 new PlaneGCSSolver_ConstraintWrapper(anEllipseConstraints, CONSTRAINT_UNKNOWN));
383 aWrapper->setId(theConstraintID);
385 constraintsToSolver(aWrapper, theSolver);
387 theConstraints[theEllipse] = aWrapper;
390 static void createEllipticArcConstraints(
391 const EntityWrapperPtr& theEllipticArc,
392 const SolverPtr& theSolver,
393 const ConstraintID theConstraintID,
394 std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
396 // create base constraints for the ellipse without adding them to solver
397 createEllipseConstraints(theEllipticArc, SolverPtr(), theConstraintID, theConstraints);
399 ConstraintWrapperPtr& aConstraint = theConstraints[theEllipticArc];
400 std::list<GCSConstraintPtr> anEllArcConstraints = aConstraint->constraints();
402 // constrain extremities of the elliptic arc
403 EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theEllipticArc);
404 std::shared_ptr<GCS::ArcOfEllipse> anArc =
405 std::dynamic_pointer_cast<GCS::ArcOfEllipse>(anEdge->entity());
407 anEllArcConstraints.push_back(GCSConstraintPtr(
408 new GCS::ConstraintCurveValue(anArc->start, anArc->start.x, *anArc, anArc->startAngle)));
409 anEllArcConstraints.push_back(GCSConstraintPtr(
410 new GCS::ConstraintCurveValue(anArc->start, anArc->start.y, *anArc, anArc->startAngle)));
411 anEllArcConstraints.push_back(GCSConstraintPtr(
412 new GCS::ConstraintCurveValue(anArc->end, anArc->end.x, *anArc, anArc->endAngle)));
413 anEllArcConstraints.push_back(GCSConstraintPtr(
414 new GCS::ConstraintCurveValue(anArc->end, anArc->end.y, *anArc, anArc->endAngle)));
416 aConstraint->setConstraints(anEllArcConstraints);
417 constraintsToSolver(aConstraint, theSolver);
420 void PlaneGCSSolver_Storage::createAuxiliaryConstraints(const EntityWrapperPtr& theEntity)
422 if (!theEntity || theEntity->isExternal())
425 if (theEntity->type() == ENTITY_ARC)
426 createArcConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap);
427 else if (theEntity->type() == ENTITY_ELLIPSE)
428 createEllipseConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap);
429 else if (theEntity->type() == ENTITY_ELLIPTIC_ARC) {
430 createEllipticArcConstraints(theEntity, mySketchSolver,
431 ++myConstraintLastID, myAuxConstraintMap);
435 void PlaneGCSSolver_Storage::removeAuxiliaryConstraints(const EntityWrapperPtr& theEntity)
437 std::map<EntityWrapperPtr, ConstraintWrapperPtr>::iterator
438 aFound = myAuxConstraintMap.find(theEntity);
439 if (aFound != myAuxConstraintMap.end()) {
440 mySketchSolver->removeConstraint(aFound->second->id());
441 myAuxConstraintMap.erase(aFound);
445 template <typename ARCTYPE>
446 void adjustArcParametrization(ARCTYPE& theArc, bool theReversed)
448 // tune start angle of the arc to be in [0, 2PI]
449 while (*theArc.startAngle < -PI)
450 *theArc.startAngle += 2.0 * PI;
451 while (*theArc.startAngle >= PI)
452 *theArc.startAngle -= 2.0 * PI;
453 // adjust end angle of the arc
455 while (*theArc.endAngle > *theArc.startAngle)
456 *theArc.endAngle -= 2.0 * PI;
457 while (*theArc.endAngle + 2 * PI < *theArc.startAngle)
458 *theArc.endAngle += 2.0 * PI;
461 while (*theArc.endAngle < *theArc.startAngle)
462 *theArc.endAngle += 2.0 * PI;
463 while (*theArc.endAngle > *theArc.startAngle + 2 * PI)
464 *theArc.endAngle -= 2.0 * PI;
468 void PlaneGCSSolver_Storage::adjustParametrizationOfArcs()
470 std::map<EntityWrapperPtr, ConstraintWrapperPtr>::iterator anIt = myAuxConstraintMap.begin();
471 for (; anIt != myAuxConstraintMap.end(); ++anIt) {
472 EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(anIt->first);
473 std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEdge->entity());
475 adjustArcParametrization(*anArc, anEdge->isReversed());
477 std::shared_ptr<GCS::ArcOfEllipse> aEllArc =
478 std::dynamic_pointer_cast<GCS::ArcOfEllipse>(anEdge->entity());
480 adjustArcParametrization(*aEllArc, anEdge->isReversed());
484 // update parameters of Middle point constraint for point on arc
485 std::map<ConstraintPtr, ConstraintWrapperPtr>::iterator aCIt = myConstraintMap.begin();
486 for (; aCIt != myConstraintMap.end(); ++aCIt)
487 if (aCIt->second->type() == CONSTRAINT_MIDDLE_POINT) {
493 bool PlaneGCSSolver_Storage::removeConstraint(ConstraintPtr theConstraint)
495 std::map<ConstraintPtr, ConstraintWrapperPtr>::iterator
496 aFound = myConstraintMap.find(theConstraint);
497 if (aFound != myConstraintMap.end()) {
498 ConstraintWrapperPtr aCW = aFound->second;
499 ConstraintID anID = aCW->id();
501 // Remove solver's constraints
502 mySketchSolver->removeConstraint(anID);
504 // Remove value if exists
505 const ScalarWrapperPtr& aValue = aCW->valueParameter();
507 GCS::SET_pD aParToRemove;
508 aParToRemove.insert(aValue->scalar());
509 removeParameters(aParToRemove);
513 myConstraintMap.erase(aFound);
515 if (anID != CID_MOVEMENT)
516 myNeedToResolve = true;
519 notify(theConstraint);
524 void PlaneGCSSolver_Storage::removeInvalidEntities()
526 PlaneGCSSolver_EntityDestroyer aDestroyer;
528 // Remove invalid constraints
529 std::list<ConstraintPtr> anInvalidConstraints;
530 std::map<ConstraintPtr, ConstraintWrapperPtr>::const_iterator
531 aCIter = myConstraintMap.begin();
532 for (; aCIter != myConstraintMap.end(); ++aCIter)
533 if (!aCIter->first->data() || !aCIter->first->data()->isValid())
534 anInvalidConstraints.push_back(aCIter->first);
535 std::list<ConstraintPtr>::const_iterator anInvCIt = anInvalidConstraints.begin();
536 for (; anInvCIt != anInvalidConstraints.end(); ++anInvCIt)
537 removeConstraint(*anInvCIt);
539 // Remove invalid features
540 std::list<FeaturePtr> anInvalidFeatures;
541 std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
542 for (; aFIter != myFeatureMap.end(); aFIter++)
543 if (!aFIter->first->data() || !aFIter->first->data()->isValid()) {
544 anInvalidFeatures.push_back(aFIter->first);
546 aDestroyer.remove(aFIter->second);
548 // remove invalid arc
549 removeAuxiliaryConstraints(aFIter->second);
551 std::list<FeaturePtr>::const_iterator anInvFIt = anInvalidFeatures.begin();
552 for (; anInvFIt != anInvalidFeatures.end(); ++anInvFIt)
553 removeFeature(*anInvFIt);
555 // Remove invalid attributes
556 std::list<AttributePtr> anInvalidAttributes;
557 std::map<AttributePtr, EntityWrapperPtr>::const_iterator anAttrIt = myAttributeMap.begin();
558 for (; anAttrIt != myAttributeMap.end(); ++anAttrIt) {
559 FeaturePtr anOwner = ModelAPI_Feature::feature(anAttrIt->first->owner());
560 if (!anOwner || !anOwner->data() || !anOwner->data()->isValid()) {
561 anInvalidAttributes.push_back(anAttrIt->first);
562 aDestroyer.remove(anAttrIt->second);
565 std::list<AttributePtr>::const_iterator anInvAtIt = anInvalidAttributes.begin();
566 for (; anInvAtIt != anInvalidAttributes.end(); ++anInvAtIt)
567 removeAttribute(*anInvAtIt);
569 // free memory occupied by parameters
570 removeParameters(aDestroyer.parametersToRemove());
572 /// TODO: Think on optimization of checking invalid features and attributes
577 double* PlaneGCSSolver_Storage::createParameter()
579 return mySketchSolver->createParameter();
582 void PlaneGCSSolver_Storage::removeParameters(const GCS::SET_pD& theParams)
584 mySketchSolver->removeParameters(theParams);
587 // indicates attribute containing in the external feature
588 static bool isExternalAttribute(const AttributePtr& theAttribute)
592 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
593 std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
594 return aSketchFeature.get() && aSketchFeature->isExternal();
597 static void addOwnerToSet(const AttributePtr& theAttribute, std::set<FeaturePtr>& theFeatures)
599 FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
601 theFeatures.insert(anOwner);
604 void PlaneGCSSolver_Storage::refresh() const
606 const double aTol = 1000. * tolerance; // tolerance to prevent frequent updates
608 std::set<FeaturePtr> anUpdatedFeatures;
610 std::map<AttributePtr, EntityWrapperPtr>::const_iterator anIt = myAttributeMap.begin();
611 for (; anIt != myAttributeMap.end(); ++anIt) {
612 if (!anIt->first->isInitialized())
615 // the external feature always should keep the up to date values, so,
616 // refresh from the solver is never needed
617 if (isExternalAttribute(anIt->first))
620 std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
621 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anIt->first);
623 std::shared_ptr<PlaneGCSSolver_PointWrapper> aPointWrapper =
624 std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
625 GCSPointPtr aGCSPoint = aPointWrapper->point();
626 if (fabs(aPoint2D->x() - (*aGCSPoint->x)) > aTol ||
627 fabs(aPoint2D->y() - (*aGCSPoint->y)) > aTol) {
628 aPoint2D->setValue(*aGCSPoint->x, *aGCSPoint->y);
629 addOwnerToSet(anIt->first, anUpdatedFeatures);
633 std::shared_ptr<GeomDataAPI_Point2DArray> aPointArray =
634 std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(anIt->first);
636 std::shared_ptr<PlaneGCSSolver_PointArrayWrapper> anArrayWrapper =
637 std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(anIt->second);
638 int aSize = aPointArray->size();
639 for (int anIndex = 0; anIndex < aSize; ++anIndex) {
640 GeomPnt2dPtr anOriginal = aPointArray->pnt(anIndex);
641 GCSPointPtr aGCSPoint = anArrayWrapper->value(anIndex)->point();
642 if (fabs(anOriginal->x() - (*aGCSPoint->x)) > aTol ||
643 fabs(anOriginal->y() - (*aGCSPoint->y)) > aTol) {
644 aPointArray->setPnt(anIndex, *aGCSPoint->x, *aGCSPoint->y);
645 addOwnerToSet(anIt->first, anUpdatedFeatures);
650 AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anIt->first);
652 ScalarWrapperPtr aScalarWrapper =
653 std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(anIt->second);
654 if (fabs(aScalar->value() - aScalarWrapper->value()) > aTol) {
655 aScalar->setValue(aScalarWrapper->value());
656 addOwnerToSet(anIt->first, anUpdatedFeatures);
660 AttributeDoubleArrayPtr aRealArray =
661 std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(anIt->first);
663 std::shared_ptr<PlaneGCSSolver_ScalarArrayWrapper> anArrayWrapper =
664 std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(anIt->second);
665 int aSize = aRealArray->size();
666 for (int anIndex = 0; anIndex < aSize; ++anIndex) {
667 if (fabs(aRealArray->value(anIndex) - *anArrayWrapper->array()[anIndex]) > aTol) {
668 aRealArray->setValue(anIndex, *anArrayWrapper->array()[anIndex]);
669 addOwnerToSet(anIt->first, anUpdatedFeatures);
676 // notify listeners about features update
677 std::set<FeaturePtr>::const_iterator aFIt = anUpdatedFeatures.begin();
678 for (; aFIt != anUpdatedFeatures.end(); ++aFIt)
682 PlaneGCSSolver_Solver::SolveStatus PlaneGCSSolver_Storage::checkDegeneratedGeometry() const
684 std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
685 for (; aFIt != myFeatureMap.end(); ++aFIt) {
686 EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(aFIt->second);
687 if (anEdge && anEdge->isDegenerated())
688 return PlaneGCSSolver_Solver::STATUS_DEGENERATED;
690 return PlaneGCSSolver_Solver::STATUS_OK;
694 void PlaneGCSSolver_Storage::getUnderconstrainedGeometry(std::set<ObjectPtr>& theFeatures) const
696 std::set<double*> aFreeParams;
697 mySketchSolver->getFreeParameters(aFreeParams);
698 if (aFreeParams.empty())
701 for (std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
702 aFIt != myFeatureMap.end(); ++aFIt) {
705 GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(aFIt->second);
706 for (GCS::SET_pD::iterator aPIt = aParams.begin(); aPIt != aParams.end(); ++aPIt)
707 if (aFreeParams.find(*aPIt) != aFreeParams.end()) {
708 theFeatures.insert(aFIt->first);