1 // Copyright (C) 2014-2023 CEA, EDF
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_BSpline.h>
42 #include <SketchPlugin_Ellipse.h>
43 #include <SketchPlugin_Projection.h>
48 static void constraintsToSolver(const ConstraintWrapperPtr& theConstraint,
49 const SolverPtr& theSolver)
51 const std::list<GCSConstraintPtr>& aConstraints =
52 std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(theConstraint)->constraints();
53 theSolver->addConstraint(theConstraint->id(), aConstraints);
57 PlaneGCSSolver_Storage::PlaneGCSSolver_Storage(const SolverPtr& theSolver)
58 : SketchSolver_Storage(theSolver),
59 myConstraintLastID(CID_UNKNOWN)
63 void PlaneGCSSolver_Storage::addConstraint(
64 ConstraintPtr theConstraint,
65 ConstraintWrapperPtr theSolverConstraint)
67 SketchSolver_Storage::addConstraint(theConstraint, theSolverConstraint);
69 theSolverConstraint->setId(++myConstraintLastID);
70 constraintsToSolver(theSolverConstraint, mySketchSolver);
73 void PlaneGCSSolver_Storage::addMovementConstraint(
74 const ConstraintWrapperPtr& theSolverConstraint)
76 // before adding movement constraint to solver, re-check its DOF
77 if (mySketchSolver->dof() == 0)
78 mySketchSolver->diagnose();
80 theSolverConstraint->setId(CID_MOVEMENT);
81 constraintsToSolver(theSolverConstraint, mySketchSolver);
85 EntityWrapperPtr PlaneGCSSolver_Storage::createFeature(
86 const FeaturePtr& theFeature,
87 PlaneGCSSolver_EntityBuilder* theBuilder)
89 std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
90 std::list<AttributePtr>::const_iterator anIt = anAttributes.begin();
91 for (; anIt != anAttributes.end(); ++anIt)
92 createAttribute(*anIt, theBuilder);
94 EntityWrapperPtr aResult = theBuilder->createFeature(theFeature);
96 addEntity(theFeature, aResult);
100 EntityWrapperPtr PlaneGCSSolver_Storage::createAttribute(
101 const AttributePtr& theAttribute,
102 PlaneGCSSolver_EntityBuilder* theBuilder)
104 EntityWrapperPtr aResult = theBuilder->createAttribute(theAttribute);
106 addEntity(theAttribute, aResult);
110 static bool hasReference(std::shared_ptr<SketchPlugin_Feature> theFeature,
111 const std::string& theFeatureKind)
113 const std::set<AttributePtr>& aRefs = theFeature->data()->refsToMe();
114 for (std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin();
115 aRefIt != aRefs.end(); ++aRefIt) {
116 FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner());
117 if (anOwner && !anOwner->isMacro() && anOwner->getKind() == theFeatureKind)
123 static bool isCopyFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
125 return theFeature && theFeature->isCopy();
128 bool PlaneGCSSolver_Storage::update(FeaturePtr theFeature, bool theForce)
130 bool sendNotify = false;
131 bool isUpdated = false;
132 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
133 std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
134 EntityWrapperPtr aRelated = entity(theFeature);
135 if (aRelated) // send signal to subscribers
137 else { // Feature is not exist, create it
138 bool isCopy = isCopyFeature(aSketchFeature);
139 bool isProjReferred = hasReference(aSketchFeature, SketchPlugin_Projection::ID());
140 // the feature is a copy in "Multi" constraint and does not used in other constraints
141 if (!theForce && (isCopy && !isProjReferred) &&
142 myFeatureMap.find(theFeature) == myFeatureMap.end())
145 // external feature processing
147 (aSketchFeature && (aSketchFeature->isExternal() || isCopy || isProjReferred));
149 PlaneGCSSolver_FeatureBuilder aBuilder(isExternal ? 0 : this);
151 // Reserve the feature in the map of features
152 // (do not want to add several copies of it while adding attributes)
153 aRelated = createFeature(theFeature, &aBuilder);
154 myFeatureMap[theFeature] = aRelated;
155 createAuxiliaryConstraints(aRelated);
159 std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
160 std::list<AttributePtr>::iterator anAttrIt = anAttributes.begin();
161 for (; anAttrIt != anAttributes.end(); ++anAttrIt)
162 if (PlaneGCSSolver_Tools::isAttributeApplicable((*anAttrIt)->id(), theFeature->getKind()))
163 isUpdated = update(*anAttrIt) || isUpdated;
165 // check external attribute is changed
166 bool isExternal = aSketchFeature &&
167 (aSketchFeature->isExternal() || isCopyFeature(aSketchFeature));
168 if (aRelated && isExternal != aRelated->isExternal()) {
170 makeExternal(aRelated);
172 makeNonExternal(aRelated);
176 // send notification to listeners due to at least one attribute is changed
177 if (sendNotify && isUpdated)
182 PlaneGCSSolver_Tools::recalculateArcParameters(aRelated);
187 bool PlaneGCSSolver_Storage::update(AttributePtr theAttribute, bool theForce)
189 if (!theAttribute->isInitialized())
192 AttributePtr anAttribute = theAttribute;
193 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
195 if (aRefAttr->isObject()) {
197 /// TODO: Check resultToFeatureOrAttribute() precisely.
198 resultToFeatureOrAttribute(aRefAttr->object(), aFeature, anAttribute);
200 return update(aFeature, theForce);
202 anAttribute = aRefAttr->attr();
205 EntityWrapperPtr aRelated = entity(anAttribute);
206 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
207 if (!aRelated) { // Attribute does not exist, create it.
208 // First of all check if the parent feature exists. If not, add it.
209 if (aFeature && myFeatureMap.find(aFeature) == myFeatureMap.end())
210 return update(aFeature, theForce); // theAttribute has been processed while adding feature
211 return aRelated.get() != 0;
214 PlaneGCSSolver_AttributeBuilder aBuilder(aRelated->isExternal() ? 0 : this);
215 bool isUpdated = aBuilder.updateAttribute(anAttribute, aRelated);
217 setNeedToResolve(true);
223 void PlaneGCSSolver_Storage::makeExternal(const EntityWrapperPtr& theEntity)
225 if (theEntity->isExternal())
228 removeAuxiliaryConstraints(theEntity);
230 GCS::SET_pD aParameters = PlaneGCSSolver_Tools::parameters(theEntity);
231 mySketchSolver->removeParameters(aParameters);
232 theEntity->setExternal(true);
233 myNeedToResolve = true;
236 void PlaneGCSSolver_Storage::makeNonExternal(const EntityWrapperPtr& theEntity)
238 if (!theEntity->isExternal())
241 GCS::SET_pD aParameters = PlaneGCSSolver_Tools::parameters(theEntity);
242 mySketchSolver->addParameters(aParameters);
243 theEntity->setExternal(false);
245 createAuxiliaryConstraints(theEntity);
247 myNeedToResolve = true;
251 static void createArcConstraints(const EntityWrapperPtr& theArc,
252 const SolverPtr& theSolver,
253 const ConstraintID theConstraintID,
254 std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
256 EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theArc);
257 std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEdge->entity());
259 // Additional constaints to fix arc's extra DoF (if the arc is not external):
260 std::list<GCSConstraintPtr> anArcConstraints;
261 // 1. distances from center till start and end points are equal to radius
262 anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
263 anArc->center, anArc->start, anArc->rad)));
264 anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
265 anArc->center, anArc->end, anArc->rad)));
266 // 2. angles of start and end points should be equal to the arc angles
267 anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle(
268 anArc->center, anArc->start, anArc->startAngle)));
269 anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle(
270 anArc->center, anArc->end, anArc->endAngle)));
272 ConstraintWrapperPtr aWrapper(
273 new PlaneGCSSolver_ConstraintWrapper(anArcConstraints, CONSTRAINT_UNKNOWN));
274 aWrapper->setId(theConstraintID);
275 constraintsToSolver(aWrapper, theSolver);
277 theConstraints[theArc] = aWrapper;
280 static void createEllipseConstraints(
281 const EntityWrapperPtr& theEllipse,
282 const SolverPtr& theSolver,
283 const ConstraintID theConstraintID,
284 std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
286 EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theEllipse);
287 std::shared_ptr<GCS::Ellipse> anEllipse =
288 std::dynamic_pointer_cast<GCS::Ellipse>(anEdge->entity());
290 // Additional constaints to fix ellipse's extra points
291 std::list<GCSConstraintPtr> anEllipseConstraints;
293 const std::map<std::string, EntityWrapperPtr>& anAttributes = theEllipse->additionalAttributes();
294 for (std::map<std::string, EntityWrapperPtr>::const_iterator anIt = anAttributes.begin();
295 anIt != anAttributes.end(); ++anIt) {
296 std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint =
297 std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
301 GCS::InternalAlignmentType anAlignmentX, anAlignmentY;
302 if (anIt->first == SketchPlugin_Ellipse::SECOND_FOCUS_ID())
303 anAlignmentX = GCS::EllipseFocus2X;
304 else if (anIt->first == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID())
305 anAlignmentX = GCS::EllipseNegativeMajorX;
306 else if (anIt->first == SketchPlugin_Ellipse::MAJOR_AXIS_END_ID())
307 anAlignmentX = GCS::EllipsePositiveMajorX;
308 else if (anIt->first == SketchPlugin_Ellipse::MINOR_AXIS_START_ID())
309 anAlignmentX = GCS::EllipseNegativeMinorX;
310 else if (anIt->first == SketchPlugin_Ellipse::MINOR_AXIS_END_ID())
311 anAlignmentX = GCS::EllipsePositiveMinorX;
313 anEllipseConstraints.push_back(GCSConstraintPtr(
314 new GCS::ConstraintInternalAlignmentPoint2Ellipse(
315 *anEllipse, *(aPoint->point()), anAlignmentX)));
316 anAlignmentY = (GCS::InternalAlignmentType)((int)anAlignmentX + 1);
317 anEllipseConstraints.push_back(GCSConstraintPtr(
318 new GCS::ConstraintInternalAlignmentPoint2Ellipse(
319 *anEllipse, *(aPoint->point()), anAlignmentY)));
322 // constraint to bind the major radius value
323 std::shared_ptr<PlaneGCSSolver_PointWrapper> aMajorAxisStart =
324 std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
325 anAttributes.at(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID()));
326 ScalarWrapperPtr aMajorRadius =
327 std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(
328 anAttributes.at(SketchPlugin_Ellipse::MAJOR_RADIUS_ID()));
329 anEllipseConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
330 anEllipse->center, *(aMajorAxisStart->point()), aMajorRadius->scalar())));
332 ConstraintWrapperPtr aWrapper(
333 new PlaneGCSSolver_ConstraintWrapper(anEllipseConstraints, CONSTRAINT_UNKNOWN));
334 aWrapper->setId(theConstraintID);
336 constraintsToSolver(aWrapper, theSolver);
338 theConstraints[theEllipse] = aWrapper;
341 static void createEllipticArcConstraints(
342 const EntityWrapperPtr& theEllipticArc,
343 const SolverPtr& theSolver,
344 const ConstraintID theConstraintID,
345 std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
347 // create base constraints for the ellipse without adding them to solver
348 createEllipseConstraints(theEllipticArc, SolverPtr(), theConstraintID, theConstraints);
350 ConstraintWrapperPtr& aConstraint = theConstraints[theEllipticArc];
351 std::list<GCSConstraintPtr> anEllArcConstraints = aConstraint->constraints();
353 // constrain extremities of the elliptic arc
354 EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theEllipticArc);
355 std::shared_ptr<GCS::ArcOfEllipse> anArc =
356 std::dynamic_pointer_cast<GCS::ArcOfEllipse>(anEdge->entity());
358 anEllArcConstraints.push_back(GCSConstraintPtr(
359 new GCS::ConstraintCurveValue(anArc->start, anArc->start.x, *anArc, anArc->startAngle)));
360 anEllArcConstraints.push_back(GCSConstraintPtr(
361 new GCS::ConstraintCurveValue(anArc->start, anArc->start.y, *anArc, anArc->startAngle)));
362 anEllArcConstraints.push_back(GCSConstraintPtr(
363 new GCS::ConstraintCurveValue(anArc->end, anArc->end.x, *anArc, anArc->endAngle)));
364 anEllArcConstraints.push_back(GCSConstraintPtr(
365 new GCS::ConstraintCurveValue(anArc->end, anArc->end.y, *anArc, anArc->endAngle)));
367 aConstraint->setConstraints(anEllArcConstraints);
368 constraintsToSolver(aConstraint, theSolver);
371 static void createBSplineConstraints(
372 const EntityWrapperPtr& theCurve,
373 const SolverPtr& theSolver,
374 const ConstraintID theConstraintID,
375 std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
377 // set start and end point of B-spline equal to first and last pole correspondingly
378 EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theCurve);
379 std::shared_ptr<GCS::BSpline> aBSpline =
380 std::dynamic_pointer_cast<GCS::BSpline>(anEdge->entity());
381 if (aBSpline->periodic)
382 return; // additional constraints are not necessary
384 std::list<GCSConstraintPtr> aBSplineConstraints;
386 const std::map<std::string, EntityWrapperPtr>& anAdditional = anEdge->additionalAttributes();
387 PointWrapperPtr aStartPoint = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
388 anAdditional.at(SketchPlugin_BSpline::START_ID()));
390 const GCS::Point& sp = *aStartPoint->point();
391 const GCS::Point& p0 = aBSpline->poles.front();
392 aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(p0.x, sp.x)));
393 aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(p0.y, sp.y)));
395 PointWrapperPtr aEndPoint = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
396 anAdditional.at(SketchPlugin_BSpline::END_ID()));
398 const GCS::Point& ep = *aEndPoint->point();
399 const GCS::Point& pN = aBSpline->poles.back();
400 aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(pN.x, ep.x)));
401 aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(pN.y, ep.y)));
403 ConstraintWrapperPtr aWrapper(
404 new PlaneGCSSolver_ConstraintWrapper(aBSplineConstraints, CONSTRAINT_UNKNOWN));
405 aWrapper->setId(theConstraintID);
407 constraintsToSolver(aWrapper, theSolver);
409 theConstraints[theCurve] = aWrapper;
412 void PlaneGCSSolver_Storage::createAuxiliaryConstraints(const EntityWrapperPtr& theEntity)
414 if (!theEntity || theEntity->isExternal())
417 if (theEntity->type() == ENTITY_ARC)
418 createArcConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap);
419 else if (theEntity->type() == ENTITY_ELLIPSE)
420 createEllipseConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap);
421 else if (theEntity->type() == ENTITY_ELLIPTIC_ARC) {
422 createEllipticArcConstraints(theEntity, mySketchSolver,
423 ++myConstraintLastID, myAuxConstraintMap);
425 else if (theEntity->type() == ENTITY_BSPLINE)
426 createBSplineConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap);
429 void PlaneGCSSolver_Storage::removeAuxiliaryConstraints(const EntityWrapperPtr& theEntity)
431 std::map<EntityWrapperPtr, ConstraintWrapperPtr>::iterator
432 aFound = myAuxConstraintMap.find(theEntity);
433 if (aFound != myAuxConstraintMap.end()) {
434 mySketchSolver->removeConstraint(aFound->second->id());
435 myAuxConstraintMap.erase(aFound);
439 template <typename ARCTYPE>
440 void adjustArcParametrization(ARCTYPE& theArc, bool theReversed)
442 // tune start angle of the arc to be in [0, 2PI]
443 while (*theArc.startAngle < -PI)
444 *theArc.startAngle += 2.0 * PI;
445 while (*theArc.startAngle >= PI)
446 *theArc.startAngle -= 2.0 * PI;
447 // adjust end angle of the arc
449 while (*theArc.endAngle > *theArc.startAngle)
450 *theArc.endAngle -= 2.0 * PI;
451 while (*theArc.endAngle + 2 * PI < *theArc.startAngle)
452 *theArc.endAngle += 2.0 * PI;
455 while (*theArc.endAngle < *theArc.startAngle)
456 *theArc.endAngle += 2.0 * PI;
457 while (*theArc.endAngle > *theArc.startAngle + 2 * PI)
458 *theArc.endAngle -= 2.0 * PI;
462 void PlaneGCSSolver_Storage::adjustParametrizationOfArcs()
464 std::map<EntityWrapperPtr, ConstraintWrapperPtr>::iterator anIt = myAuxConstraintMap.begin();
465 for (; anIt != myAuxConstraintMap.end(); ++anIt) {
466 EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(anIt->first);
467 std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEdge->entity());
469 adjustArcParametrization(*anArc, anEdge->isReversed());
471 std::shared_ptr<GCS::ArcOfEllipse> aEllArc =
472 std::dynamic_pointer_cast<GCS::ArcOfEllipse>(anEdge->entity());
474 adjustArcParametrization(*aEllArc, anEdge->isReversed());
478 // update parameters of Middle point constraint for point on arc
479 std::map<ConstraintPtr, ConstraintWrapperPtr>::iterator aCIt = myConstraintMap.begin();
480 for (; aCIt != myConstraintMap.end(); ++aCIt)
481 if (aCIt->second->type() == CONSTRAINT_MIDDLE_POINT) {
487 bool PlaneGCSSolver_Storage::removeConstraint(ConstraintPtr theConstraint)
489 std::map<ConstraintPtr, ConstraintWrapperPtr>::iterator
490 aFound = myConstraintMap.find(theConstraint);
491 if (aFound != myConstraintMap.end()) {
492 ConstraintWrapperPtr aCW = aFound->second;
493 ConstraintID anID = aCW->id();
495 // Remove solver's constraints
496 mySketchSolver->removeConstraint(anID);
498 // Remove value if exists
499 const ScalarWrapperPtr& aValue = aCW->valueParameter();
501 GCS::SET_pD aParToRemove;
502 aParToRemove.insert(aValue->scalar());
503 removeParameters(aParToRemove);
507 myConstraintMap.erase(aFound);
509 if (anID != CID_MOVEMENT)
510 myNeedToResolve = true;
513 notify(theConstraint);
518 void PlaneGCSSolver_Storage::removeInvalidEntities()
520 PlaneGCSSolver_EntityDestroyer aDestroyer;
522 // Remove invalid constraints
523 std::list<ConstraintPtr> anInvalidConstraints;
524 std::map<ConstraintPtr, ConstraintWrapperPtr>::const_iterator
525 aCIter = myConstraintMap.begin();
526 for (; aCIter != myConstraintMap.end(); ++aCIter)
527 if (!aCIter->first->data() || !aCIter->first->data()->isValid())
528 anInvalidConstraints.push_back(aCIter->first);
529 std::list<ConstraintPtr>::const_iterator anInvCIt = anInvalidConstraints.begin();
530 for (; anInvCIt != anInvalidConstraints.end(); ++anInvCIt)
531 removeConstraint(*anInvCIt);
533 // Remove invalid features
534 std::list<FeaturePtr> anInvalidFeatures;
535 std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
536 for (; aFIter != myFeatureMap.end(); aFIter++)
537 if (!aFIter->first->data() || !aFIter->first->data()->isValid()) {
538 anInvalidFeatures.push_back(aFIter->first);
540 aDestroyer.remove(aFIter->second);
542 // remove invalid arc
543 removeAuxiliaryConstraints(aFIter->second);
545 std::list<FeaturePtr>::const_iterator anInvFIt = anInvalidFeatures.begin();
546 for (; anInvFIt != anInvalidFeatures.end(); ++anInvFIt)
547 removeFeature(*anInvFIt);
549 // Remove invalid attributes
550 std::list<AttributePtr> anInvalidAttributes;
551 std::map<AttributePtr, EntityWrapperPtr>::const_iterator anAttrIt = myAttributeMap.begin();
552 for (; anAttrIt != myAttributeMap.end(); ++anAttrIt) {
553 FeaturePtr anOwner = ModelAPI_Feature::feature(anAttrIt->first->owner());
554 if (!anOwner || !anOwner->data() || !anOwner->data()->isValid()) {
555 anInvalidAttributes.push_back(anAttrIt->first);
556 aDestroyer.remove(anAttrIt->second);
559 std::list<AttributePtr>::const_iterator anInvAtIt = anInvalidAttributes.begin();
560 for (; anInvAtIt != anInvalidAttributes.end(); ++anInvAtIt)
561 removeAttribute(*anInvAtIt);
563 // free memory occupied by parameters
564 removeParameters(aDestroyer.parametersToRemove());
566 /// TODO: Think on optimization of checking invalid features and attributes
571 double* PlaneGCSSolver_Storage::createParameter()
573 return mySketchSolver->createParameter();
576 void PlaneGCSSolver_Storage::removeParameters(const GCS::SET_pD& theParams)
578 mySketchSolver->removeParameters(theParams);
579 //for (GCS::SET_pD::iterator it = theParams.begin(); it != theParams.end(); ++it)
583 // indicates attribute containing in the external feature
584 static bool isExternalAttribute(const AttributePtr& theAttribute)
588 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
589 std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
590 return aSketchFeature.get() && aSketchFeature->isExternal();
593 static void addOwnerToSet(const AttributePtr& theAttribute, std::set<FeaturePtr>& theFeatures)
595 FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
597 theFeatures.insert(anOwner);
600 void PlaneGCSSolver_Storage::refresh() const
602 const double aTol = 1000. * tolerance; // tolerance to prevent frequent updates
604 std::set<FeaturePtr> anUpdatedFeatures;
606 std::map<AttributePtr, EntityWrapperPtr>::const_iterator anIt = myAttributeMap.begin();
607 for (; anIt != myAttributeMap.end(); ++anIt) {
608 if (!anIt->first->isInitialized())
611 // the external feature always should keep the up to date values, so,
612 // refresh from the solver is never needed
613 if (isExternalAttribute(anIt->first))
616 std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
617 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anIt->first);
619 std::shared_ptr<PlaneGCSSolver_PointWrapper> aPointWrapper =
620 std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
621 GCSPointPtr aGCSPoint = aPointWrapper->point();
622 if (fabs(aPoint2D->x() - (*aGCSPoint->x)) > aTol ||
623 fabs(aPoint2D->y() - (*aGCSPoint->y)) > aTol) {
624 aPoint2D->setValue(*aGCSPoint->x, *aGCSPoint->y);
625 addOwnerToSet(anIt->first, anUpdatedFeatures);
629 std::shared_ptr<GeomDataAPI_Point2DArray> aPointArray =
630 std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(anIt->first);
632 std::shared_ptr<PlaneGCSSolver_PointArrayWrapper> anArrayWrapper =
633 std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(anIt->second);
634 int aSize = aPointArray->size();
635 for (int anIndex = 0; anIndex < aSize; ++anIndex) {
636 GeomPnt2dPtr anOriginal = aPointArray->pnt(anIndex);
637 GCSPointPtr aGCSPoint = anArrayWrapper->value(anIndex)->point();
638 if (fabs(anOriginal->x() - (*aGCSPoint->x)) > aTol ||
639 fabs(anOriginal->y() - (*aGCSPoint->y)) > aTol) {
640 aPointArray->setPnt(anIndex, *aGCSPoint->x, *aGCSPoint->y);
641 addOwnerToSet(anIt->first, anUpdatedFeatures);
646 AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anIt->first);
648 ScalarWrapperPtr aScalarWrapper =
649 std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(anIt->second);
650 if (fabs(aScalar->value() - aScalarWrapper->value()) > aTol) {
651 aScalar->setValue(aScalarWrapper->value());
652 addOwnerToSet(anIt->first, anUpdatedFeatures);
656 AttributeDoubleArrayPtr aRealArray =
657 std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(anIt->first);
659 std::shared_ptr<PlaneGCSSolver_ScalarArrayWrapper> anArrayWrapper =
660 std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(anIt->second);
661 int aSize = aRealArray->size();
662 for (int anIndex = 0; anIndex < aSize; ++anIndex) {
663 if (fabs(aRealArray->value(anIndex) - *anArrayWrapper->array()[anIndex]) > aTol) {
664 aRealArray->setValue(anIndex, *anArrayWrapper->array()[anIndex]);
665 addOwnerToSet(anIt->first, anUpdatedFeatures);
672 // notify listeners about features update
673 std::set<FeaturePtr>::const_iterator aFIt = anUpdatedFeatures.begin();
674 for (; aFIt != anUpdatedFeatures.end(); ++aFIt)
678 PlaneGCSSolver_Solver::SolveStatus PlaneGCSSolver_Storage::checkDegeneratedGeometry() const
680 std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
681 for (; aFIt != myFeatureMap.end(); ++aFIt) {
682 EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(aFIt->second);
683 if (anEdge && anEdge->isDegenerated())
684 return PlaneGCSSolver_Solver::STATUS_DEGENERATED;
686 return PlaneGCSSolver_Solver::STATUS_OK;
690 void PlaneGCSSolver_Storage::getUnderconstrainedGeometry(std::set<ObjectPtr>& theFeatures) const
692 std::set<double*> aFreeParams;
693 mySketchSolver->getFreeParameters(aFreeParams);
694 if (aFreeParams.empty())
697 for (std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
698 aFIt != myFeatureMap.end(); ++aFIt) {
701 GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(aFIt->second);
702 for (GCS::SET_pD::iterator aPIt = aParams.begin(); aPIt != aParams.end(); ++aPIt)
703 if (aFreeParams.find(*aPIt) != aFreeParams.end()) {
704 theFeatures.insert(aFIt->first);