1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
3 // File: PlaneGCSSolver_Storage.cpp
4 // Created: 14 Dec 2015
5 // Author: Artem ZHIDKOV
7 #include <PlaneGCSSolver_Storage.h>
8 #include <PlaneGCSSolver_Solver.h>
9 #include <PlaneGCSSolver_ConstraintWrapper.h>
10 #include <PlaneGCSSolver_EdgeWrapper.h>
11 #include <PlaneGCSSolver_PointWrapper.h>
12 #include <PlaneGCSSolver_Tools.h>
14 #include <PlaneGCSSolver_AttributeBuilder.h>
15 #include <PlaneGCSSolver_FeatureBuilder.h>
16 #include <PlaneGCSSolver_EntityDestroyer.h>
18 #include <GeomAPI_Dir2d.h>
19 #include <GeomAPI_Pnt2d.h>
20 #include <GeomAPI_XY.h>
21 #include <GeomDataAPI_Point2D.h>
22 #include <ModelAPI_AttributeRefAttr.h>
23 #include <SketchPlugin_Projection.h>
28 static void constraintsToSolver(const ConstraintWrapperPtr& theConstraint,
29 const SolverPtr& theSolver)
31 const std::list<GCSConstraintPtr>& aConstraints =
32 std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(theConstraint)->constraints();
33 std::list<GCSConstraintPtr>::const_iterator anIt = aConstraints.begin();
34 for (; anIt != aConstraints.end(); ++anIt)
35 theSolver->addConstraint(*anIt);
39 PlaneGCSSolver_Storage::PlaneGCSSolver_Storage(const SolverPtr& theSolver)
40 : SketchSolver_Storage(theSolver),
41 myConstraintLastID(CID_UNKNOWN)
45 void PlaneGCSSolver_Storage::addConstraint(
46 ConstraintPtr theConstraint,
47 ConstraintWrapperPtr theSolverConstraint)
49 SketchSolver_Storage::addConstraint(theConstraint, theSolverConstraint);
51 theSolverConstraint->setId(++myConstraintLastID);
52 constraintsToSolver(theSolverConstraint, mySketchSolver);
55 void PlaneGCSSolver_Storage::addTemporaryConstraint(
56 const ConstraintWrapperPtr& theSolverConstraint)
58 if (myConstraintMap.empty())
59 return; // no need to process temporary constraints if there is no active constraint
61 // before adding movement constraint to solver, re-check its DOF
62 if (mySketchSolver->dof() == 0)
63 mySketchSolver->diagnose();
65 theSolverConstraint->setId(CID_MOVEMENT);
66 constraintsToSolver(theSolverConstraint, mySketchSolver);
70 EntityWrapperPtr PlaneGCSSolver_Storage::createFeature(
71 const FeaturePtr& theFeature,
72 PlaneGCSSolver_EntityBuilder* theBuilder)
74 std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
75 std::list<AttributePtr>::const_iterator anIt = anAttributes.begin();
76 for (; anIt != anAttributes.end(); ++anIt)
77 createAttribute(*anIt, theBuilder);
79 EntityWrapperPtr aResult = theBuilder->createFeature(theFeature);
81 addEntity(theFeature, aResult);
85 EntityWrapperPtr PlaneGCSSolver_Storage::createAttribute(
86 const AttributePtr& theAttribute,
87 PlaneGCSSolver_EntityBuilder* theBuilder)
89 EntityWrapperPtr aResult = theBuilder->createAttribute(theAttribute);
91 addEntity(theAttribute, aResult);
95 /// \brief Update value
96 static bool updateValue(const double& theSource, double& theDest)
98 static const double aTol = 1000. * tolerance;
99 bool isUpdated = fabs(theSource - theDest) > aTol;
105 /// \brief Update coordinates of the point or scalar using its base attribute
106 static bool updateValues(AttributePtr& theAttribute, EntityWrapperPtr& theEntity)
108 bool isUpdated = false;
110 std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
111 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
113 const GCSPointPtr& aGCSPoint =
114 std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theEntity)->point();
115 isUpdated = updateValue(aPoint2D->x(), *(aGCSPoint->x)) || isUpdated;
116 isUpdated = updateValue(aPoint2D->y(), *(aGCSPoint->y)) || isUpdated;
118 AttributeDoublePtr aScalar =
119 std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
121 ScalarWrapperPtr aWrapper =
122 std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(theEntity);
123 // There is possible angular value, which is converted between degrees and radians.
124 // So, we use its value instead of using direct pointer to value.
125 double aValue = aWrapper->value();
126 isUpdated = updateValue(aScalar->value(), aValue);
128 aWrapper->setValue(aValue);
135 static bool hasReference(std::shared_ptr<SketchPlugin_Feature> theFeature,
136 const std::string& theFeatureKind)
138 const std::set<AttributePtr>& aRefs = theFeature->data()->refsToMe();
139 for (std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin();
140 aRefIt != aRefs.end(); ++aRefIt) {
141 FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner());
142 if (anOwner->getKind() == theFeatureKind)
148 static bool isCopyFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
150 return theFeature && theFeature->isCopy();
153 bool PlaneGCSSolver_Storage::update(FeaturePtr theFeature, bool theForce)
155 bool sendNotify = false;
156 bool isUpdated = false;
157 EntityWrapperPtr aRelated = entity(theFeature);
158 if (aRelated) // send signal to subscribers
160 else { // Feature is not exist, create it
161 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
162 std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
163 bool isCopy = isCopyFeature(aSketchFeature);
164 bool isProjReferred = hasReference(aSketchFeature, SketchPlugin_Projection::ID());
165 // the feature is a copy in "Multi" constraint and does not used in other constraints
166 if (!theForce && (isCopy && !isProjReferred) &&
167 myFeatureMap.find(theFeature) == myFeatureMap.end())
170 // external feature processing
172 (aSketchFeature && (aSketchFeature->isExternal() || isCopy || isProjReferred));
174 PlaneGCSSolver_FeatureBuilder aBuilder(isExternal ? 0 : this);
176 // Reserve the feature in the map of features
177 // (do not want to add several copies of it while adding attributes)
178 aRelated = createFeature(theFeature, &aBuilder);
179 myFeatureMap[theFeature] = aRelated;
180 createArcConstraints(aRelated);
184 std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
185 std::list<AttributePtr>::iterator anAttrIt = anAttributes.begin();
186 for (; anAttrIt != anAttributes.end(); ++anAttrIt)
187 if ((*anAttrIt)->attributeType() == GeomDataAPI_Point2D::typeId() ||
188 (*anAttrIt)->attributeType() == ModelAPI_AttributeDouble::typeId())
189 isUpdated = update(*anAttrIt) || isUpdated;
191 // send notification to listeners due to at least one attribute is changed
192 if (sendNotify && isUpdated)
196 if (aRelated && aRelated->type() == ENTITY_ARC) {
197 /// TODO: this code should be shared with FeatureBuilder somehow
199 std::shared_ptr<PlaneGCSSolver_EdgeWrapper> anEntity =
200 std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(aRelated);
201 std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEntity->entity());
203 static std::shared_ptr<GeomAPI_Dir2d> OX(new GeomAPI_Dir2d(1.0, 0.0));
204 std::shared_ptr<GeomAPI_Pnt2d> aCenter(
205 new GeomAPI_Pnt2d(*anArc->center.x, *anArc->center.y));
206 std::shared_ptr<GeomAPI_Pnt2d> aStart(
207 new GeomAPI_Pnt2d(*anArc->start.x, *anArc->start.y));
209 *anArc->rad = aStart->distance(aCenter);
211 std::shared_ptr<GeomAPI_Dir2d> aDir(new GeomAPI_Dir2d(aStart->xy()->decreased(aCenter->xy())));
212 *anArc->startAngle = OX->angle(aDir);
214 aDir = std::shared_ptr<GeomAPI_Dir2d>(
215 new GeomAPI_Dir2d((*anArc->end.x) - aCenter->x(), (*anArc->end.y) - aCenter->y()));
216 *anArc->endAngle = OX->angle(aDir);
222 bool PlaneGCSSolver_Storage::update(AttributePtr theAttribute, bool theForce)
224 if (!theAttribute->isInitialized())
227 AttributePtr anAttribute = theAttribute;
228 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
230 if (aRefAttr->isObject()) {
232 /// TODO: Check resultToFeatureOrAttribute() precisely.
233 resultToFeatureOrAttribute(aRefAttr->object(), aFeature, anAttribute);
235 return update(aFeature, theForce);
237 anAttribute = aRefAttr->attr();
240 EntityWrapperPtr aRelated = entity(anAttribute);
241 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
242 if (!aRelated) { // Attribute does not exist, create it.
243 // First of all check if the parent feature exists. If not, add it.
244 if (aFeature && myFeatureMap.find(aFeature) == myFeatureMap.end())
245 return update(aFeature, theForce); // theAttribute has been processed while adding feature
246 return aRelated.get() != 0;
249 bool isUpdated = updateValues(anAttribute, aRelated);
251 setNeedToResolve(true);
257 void PlaneGCSSolver_Storage::makeExternal(const EntityWrapperPtr& theEntity)
259 if (theEntity->isExternal())
262 removeArcConstraints(theEntity);
264 GCS::SET_pD aParameters = PlaneGCSSolver_Tools::parameters(theEntity);
265 mySketchSolver->removeParameters(aParameters);
266 theEntity->setExternal(true);
267 myNeedToResolve = true;
270 void PlaneGCSSolver_Storage::makeNonExternal(const EntityWrapperPtr& theEntity)
272 if (!theEntity->isExternal())
275 GCS::SET_pD aParameters = PlaneGCSSolver_Tools::parameters(theEntity);
276 mySketchSolver->addParameters(aParameters);
277 theEntity->setExternal(false);
279 createArcConstraints(theEntity);
281 myNeedToResolve = true;
285 void PlaneGCSSolver_Storage::createArcConstraints(const EntityWrapperPtr& theArc)
287 if (!theArc || theArc->type() != ENTITY_ARC || theArc->isExternal())
290 EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theArc);
291 std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEdge->entity());
293 // Additional constaints to fix arc's extra DoF (if the arc is not external):
294 std::list<GCSConstraintPtr> anArcConstraints;
295 // 1. distances from center till start and end points are equal to radius
296 anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
297 anArc->center, anArc->start, anArc->rad)));
298 anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
299 anArc->center, anArc->end, anArc->rad)));
300 // 2. angles of start and end points should be equal to the arc angles
301 anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle(
302 anArc->center, anArc->start, anArc->startAngle)));
303 anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle(
304 anArc->center, anArc->end, anArc->endAngle)));
306 ConstraintWrapperPtr aWrapper(
307 new PlaneGCSSolver_ConstraintWrapper(anArcConstraints, CONSTRAINT_UNKNOWN));
308 aWrapper->setId(++myConstraintLastID);
309 constraintsToSolver(aWrapper, mySketchSolver);
311 myArcConstraintMap[theArc] = aWrapper;
314 void PlaneGCSSolver_Storage::removeArcConstraints(const EntityWrapperPtr& theArc)
316 std::map<EntityWrapperPtr, ConstraintWrapperPtr>::iterator
317 aFound = myArcConstraintMap.find(theArc);
318 if (aFound != myArcConstraintMap.end()) {
319 mySketchSolver->removeConstraint(aFound->second->id());
320 myArcConstraintMap.erase(aFound);
325 bool PlaneGCSSolver_Storage::removeConstraint(ConstraintPtr theConstraint)
327 std::map<ConstraintPtr, ConstraintWrapperPtr>::iterator
328 aFound = myConstraintMap.find(theConstraint);
329 if (aFound != myConstraintMap.end()) {
330 ConstraintWrapperPtr aCW = aFound->second;
331 ConstraintID anID = aCW->id();
333 // Remove solver's constraints
334 mySketchSolver->removeConstraint(anID);
336 // Remove value if exists
337 const ScalarWrapperPtr& aValue = aCW->valueParameter();
339 GCS::SET_pD aParToRemove;
340 aParToRemove.insert(aValue->scalar());
341 removeParameters(aParToRemove);
345 myConstraintMap.erase(aFound);
347 if (anID != CID_MOVEMENT)
348 myNeedToResolve = true;
351 notify(theConstraint);
356 void PlaneGCSSolver_Storage::removeInvalidEntities()
358 PlaneGCSSolver_EntityDestroyer aDestroyer;
360 // Remove invalid constraints
361 std::list<ConstraintPtr> anInvalidConstraints;
362 std::map<ConstraintPtr, ConstraintWrapperPtr>::const_iterator
363 aCIter = myConstraintMap.begin();
364 for (; aCIter != myConstraintMap.end(); ++aCIter)
365 if (!aCIter->first->data() || !aCIter->first->data()->isValid())
366 anInvalidConstraints.push_back(aCIter->first);
367 std::list<ConstraintPtr>::const_iterator anInvCIt = anInvalidConstraints.begin();
368 for (; anInvCIt != anInvalidConstraints.end(); ++anInvCIt)
369 removeConstraint(*anInvCIt);
371 // Remove invalid features
372 std::list<FeaturePtr> anInvalidFeatures;
373 std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
374 for (; aFIter != myFeatureMap.end(); aFIter++)
375 if (!aFIter->first->data() || !aFIter->first->data()->isValid()) {
376 anInvalidFeatures.push_back(aFIter->first);
378 aDestroyer.remove(aFIter->second);
380 // remove invalid arc
381 removeArcConstraints(aFIter->second);
383 std::list<FeaturePtr>::const_iterator anInvFIt = anInvalidFeatures.begin();
384 for (; anInvFIt != anInvalidFeatures.end(); ++anInvFIt)
385 removeFeature(*anInvFIt);
387 // Remove invalid attributes
388 std::list<AttributePtr> anInvalidAttributes;
389 std::map<AttributePtr, EntityWrapperPtr>::const_iterator anAttrIt = myAttributeMap.begin();
390 for (; anAttrIt != myAttributeMap.end(); ++anAttrIt) {
391 FeaturePtr anOwner = ModelAPI_Feature::feature(anAttrIt->first->owner());
392 if (!anOwner || !anOwner->data() || !anOwner->data()->isValid()) {
393 anInvalidAttributes.push_back(anAttrIt->first);
394 aDestroyer.remove(anAttrIt->second);
397 std::list<AttributePtr>::const_iterator anInvAtIt = anInvalidAttributes.begin();
398 for (; anInvAtIt != anInvalidAttributes.end(); ++anInvAtIt)
399 removeAttribute(*anInvAtIt);
401 // free memory occupied by parameters
402 removeParameters(aDestroyer.parametersToRemove());
404 /// TODO: Think on optimization of checking invalid features and attributes
409 double* PlaneGCSSolver_Storage::createParameter()
411 return mySketchSolver->createParameter();
414 void PlaneGCSSolver_Storage::removeParameters(const GCS::SET_pD& theParams)
416 mySketchSolver->removeParameters(theParams);
419 // indicates attribute containing in the external feature
420 static bool isExternalAttribute(const AttributePtr& theAttribute)
424 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
425 std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
426 return aSketchFeature.get() && aSketchFeature->isExternal();
429 static void addOwnerToSet(const AttributePtr& theAttribute, std::set<FeaturePtr>& theFeatures)
431 FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
433 theFeatures.insert(anOwner);
436 void PlaneGCSSolver_Storage::refresh() const
438 const double aTol = 1000. * tolerance; // tolerance to prevent frequent updates
440 std::set<FeaturePtr> anUpdatedFeatures;
442 std::map<AttributePtr, EntityWrapperPtr>::const_iterator anIt = myAttributeMap.begin();
443 for (; anIt != myAttributeMap.end(); ++anIt) {
444 // the external feature always should keep the up to date values, so,
445 // refresh from the solver is never needed
446 if (isExternalAttribute(anIt->first))
449 std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
450 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anIt->first);
452 std::shared_ptr<PlaneGCSSolver_PointWrapper> aPointWrapper =
453 std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
454 GCSPointPtr aGCSPoint = aPointWrapper->point();
455 if (fabs(aPoint2D->x() - (*aGCSPoint->x)) > aTol ||
456 fabs(aPoint2D->y() - (*aGCSPoint->y)) > aTol) {
457 aPoint2D->setValue(*aGCSPoint->x, *aGCSPoint->y);
458 addOwnerToSet(anIt->first, anUpdatedFeatures);
462 AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anIt->first);
464 ScalarWrapperPtr aScalarWrapper =
465 std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(anIt->second);
466 if (fabs(aScalar->value() - aScalarWrapper->value()) > aTol) {
467 aScalar->setValue(aScalarWrapper->value());
468 addOwnerToSet(anIt->first, anUpdatedFeatures);
474 // notify listeners about features update
475 std::set<FeaturePtr>::const_iterator aFIt = anUpdatedFeatures.begin();
476 for (; aFIt != anUpdatedFeatures.end(); ++aFIt)