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>
13 #include <PlaneGCSSolver_AttributeBuilder.h>
14 #include <PlaneGCSSolver_FeatureBuilder.h>
15 #include <PlaneGCSSolver_EntityDestroyer.h>
17 #include <GeomAPI_Dir2d.h>
18 #include <GeomAPI_Pnt2d.h>
19 #include <GeomAPI_XY.h>
20 #include <GeomDataAPI_Point2D.h>
21 #include <ModelAPI_AttributeRefAttr.h>
22 #include <SketchPlugin_Projection.h>
27 static void constraintsToSolver(const ConstraintWrapperPtr& theConstraint,
28 const SolverPtr& theSolver)
30 const std::list<GCSConstraintPtr>& aConstraints =
31 std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(theConstraint)->constraints();
32 std::list<GCSConstraintPtr>::const_iterator anIt = aConstraints.begin();
33 for (; anIt != aConstraints.end(); ++anIt)
34 theSolver->addConstraint(*anIt);
38 PlaneGCSSolver_Storage::PlaneGCSSolver_Storage(const SolverPtr& theSolver)
39 : SketchSolver_Storage(theSolver),
40 myConstraintLastID(CID_UNKNOWN)
44 void PlaneGCSSolver_Storage::addConstraint(
45 ConstraintPtr theConstraint,
46 ConstraintWrapperPtr theSolverConstraint)
48 SketchSolver_Storage::addConstraint(theConstraint, theSolverConstraint);
50 theSolverConstraint->setId(++myConstraintLastID);
51 constraintsToSolver(theSolverConstraint, mySketchSolver);
54 void PlaneGCSSolver_Storage::addTemporaryConstraint(
55 const ConstraintWrapperPtr& theSolverConstraint)
57 if (myConstraintMap.empty())
58 return; // no need to process temporary constraints if there is no active constraint
60 // before adding movement constraint to solver, re-check its DOF
61 if (mySketchSolver->dof() == 0)
62 mySketchSolver->diagnose();
64 theSolverConstraint->setId(CID_MOVEMENT);
65 constraintsToSolver(theSolverConstraint, mySketchSolver);
69 EntityWrapperPtr PlaneGCSSolver_Storage::createFeature(
70 const FeaturePtr& theFeature,
71 PlaneGCSSolver_EntityBuilder* theBuilder)
73 std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
74 std::list<AttributePtr>::const_iterator anIt = anAttributes.begin();
75 for (; anIt != anAttributes.end(); ++anIt)
76 createAttribute(*anIt, theBuilder);
78 EntityWrapperPtr aResult = theBuilder->createFeature(theFeature);
80 addEntity(theFeature, aResult);
84 EntityWrapperPtr PlaneGCSSolver_Storage::createAttribute(
85 const AttributePtr& theAttribute,
86 PlaneGCSSolver_EntityBuilder* theBuilder)
88 EntityWrapperPtr aResult = theBuilder->createAttribute(theAttribute);
90 addEntity(theAttribute, aResult);
94 /// \brief Update value
95 static bool updateValue(const double& theSource, double& theDest)
97 static const double aTol = 1000. * tolerance;
98 bool isUpdated = fabs(theSource - theDest) > aTol;
104 /// \brief Update coordinates of the point or scalar using its base attribute
105 static bool updateValues(AttributePtr& theAttribute, EntityWrapperPtr& theEntity)
107 bool isUpdated = false;
109 std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
110 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
112 const GCSPointPtr& aGCSPoint =
113 std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theEntity)->point();
114 isUpdated = updateValue(aPoint2D->x(), *(aGCSPoint->x)) || isUpdated;
115 isUpdated = updateValue(aPoint2D->y(), *(aGCSPoint->y)) || isUpdated;
117 AttributeDoublePtr aScalar =
118 std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
120 ScalarWrapperPtr aWrapper =
121 std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(theEntity);
122 // There is possible angular value, which is converted between degrees and radians.
123 // So, we use its value instead of using direct pointer to value.
124 double aValue = aWrapper->value();
125 isUpdated = updateValue(aScalar->value(), aValue);
127 aWrapper->setValue(aValue);
134 static bool isCopyInMulti(std::shared_ptr<SketchPlugin_Feature> theFeature)
139 bool aResult = theFeature->isCopy();
141 const std::set<AttributePtr>& aRefs = theFeature->data()->refsToMe();
142 for (std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin();
143 aRefIt != aRefs.end() && aResult; ++aRefIt) {
144 FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner());
145 if (anOwner->getKind() == SketchPlugin_Projection::ID())
152 bool PlaneGCSSolver_Storage::update(FeaturePtr theFeature, bool theForce)
154 bool sendNotify = false;
155 bool isUpdated = false;
156 EntityWrapperPtr aRelated = entity(theFeature);
157 if (aRelated) // send signal to subscribers
159 else { // Feature is not exist, create it
160 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
161 std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
162 bool isCopy = isCopyInMulti(aSketchFeature);
163 // the feature is a copy in "Multi" constraint and does not used in other constraints
164 if (!theForce && isCopy && myFeatureMap.find(theFeature) == myFeatureMap.end())
167 // external feature processing
168 bool isExternal = (aSketchFeature && (aSketchFeature->isExternal() || isCopy));
170 PlaneGCSSolver_FeatureBuilder aBuilder(isExternal ? 0 : this);
172 // Reserve the feature in the map of features
173 // (do not want to add several copies of it while adding attributes)
174 aRelated = createFeature(theFeature, &aBuilder);
175 myFeatureMap[theFeature] = aRelated;
177 const std::list<GCSConstraintPtr>& aConstraints = aBuilder.constraints();
178 if (!aConstraints.empty()) { // the feature is arc
179 /// TODO: avoid this workaround
180 ConstraintWrapperPtr aWrapper(
181 new PlaneGCSSolver_ConstraintWrapper(aConstraints, CONSTRAINT_UNKNOWN));
182 aWrapper->setId(++myConstraintLastID);
183 constraintsToSolver(aWrapper, mySketchSolver);
185 myArcConstraintMap[myFeatureMap[theFeature]] = aWrapper;
190 std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
191 std::list<AttributePtr>::iterator anAttrIt = anAttributes.begin();
192 for (; anAttrIt != anAttributes.end(); ++anAttrIt)
193 if ((*anAttrIt)->attributeType() == GeomDataAPI_Point2D::typeId() ||
194 (*anAttrIt)->attributeType() == ModelAPI_AttributeDouble::typeId())
195 isUpdated = update(*anAttrIt) || isUpdated;
197 // send notification to listeners due to at least one attribute is changed
198 if (sendNotify && isUpdated)
202 if (aRelated && aRelated->type() == ENTITY_ARC) {
203 /// TODO: this code should be shared with FeatureBuilder somehow
205 std::shared_ptr<PlaneGCSSolver_EdgeWrapper> anEntity =
206 std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(aRelated);
207 std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEntity->entity());
209 static std::shared_ptr<GeomAPI_Dir2d> OX(new GeomAPI_Dir2d(1.0, 0.0));
210 std::shared_ptr<GeomAPI_Pnt2d> aCenter(
211 new GeomAPI_Pnt2d(*anArc->center.x, *anArc->center.y));
212 std::shared_ptr<GeomAPI_Pnt2d> aStart(
213 new GeomAPI_Pnt2d(*anArc->start.x, *anArc->start.y));
215 *anArc->rad = aStart->distance(aCenter);
217 std::shared_ptr<GeomAPI_Dir2d> aDir(new GeomAPI_Dir2d(aStart->xy()->decreased(aCenter->xy())));
218 *anArc->startAngle = OX->angle(aDir);
220 aDir = std::shared_ptr<GeomAPI_Dir2d>(
221 new GeomAPI_Dir2d((*anArc->end.x) - aCenter->x(), (*anArc->end.y) - aCenter->y()));
222 *anArc->endAngle = OX->angle(aDir);
228 bool PlaneGCSSolver_Storage::update(AttributePtr theAttribute, bool theForce)
230 if (!theAttribute->isInitialized())
233 AttributePtr anAttribute = theAttribute;
234 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
236 if (aRefAttr->isObject()) {
238 /// TODO: Check resultToFeatureOrAttribute() precisely.
239 resultToFeatureOrAttribute(aRefAttr->object(), aFeature, anAttribute);
241 return update(aFeature, theForce);
243 anAttribute = aRefAttr->attr();
246 EntityWrapperPtr aRelated = entity(anAttribute);
247 if (!aRelated) { // Attribute does not exist, create it.
248 // First of all check if the parent feature exists. If not, add it.
249 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
250 if (aFeature && myFeatureMap.find(aFeature) == myFeatureMap.end())
251 return update(aFeature, theForce); // theAttribute has been processed while adding feature
253 //// PlaneGCSSolver_AttributeBuilder aBuilder(this);
254 //// aRelated = createAttribute(anAttribute, &aBuilder);
255 return aRelated.get() != 0;
258 bool isUpdated = updateValues(anAttribute, aRelated);
260 setNeedToResolve(true);
266 bool PlaneGCSSolver_Storage::removeConstraint(ConstraintPtr theConstraint)
268 std::map<ConstraintPtr, ConstraintWrapperPtr>::iterator
269 aFound = myConstraintMap.find(theConstraint);
270 if (aFound != myConstraintMap.end()) {
271 ConstraintWrapperPtr aCW = aFound->second;
272 ConstraintID anID = aCW->id();
274 // Remove solver's constraints
275 mySketchSolver->removeConstraint(anID);
277 // Remove value if exists
278 const ScalarWrapperPtr& aValue = aCW->valueParameter();
280 GCS::SET_pD aParToRemove;
281 aParToRemove.insert(aValue->scalar());
282 removeParameters(aParToRemove);
286 myConstraintMap.erase(aFound);
288 if (anID != CID_MOVEMENT)
289 myNeedToResolve = true;
292 notify(theConstraint);
297 void PlaneGCSSolver_Storage::removeInvalidEntities()
299 PlaneGCSSolver_EntityDestroyer aDestroyer;
301 // Remove invalid constraints
302 std::list<ConstraintPtr> anInvalidConstraints;
303 std::map<ConstraintPtr, ConstraintWrapperPtr>::const_iterator
304 aCIter = myConstraintMap.begin();
305 for (; aCIter != myConstraintMap.end(); ++aCIter)
306 if (!aCIter->first->data() || !aCIter->first->data()->isValid())
307 anInvalidConstraints.push_back(aCIter->first);
308 std::list<ConstraintPtr>::const_iterator anInvCIt = anInvalidConstraints.begin();
309 for (; anInvCIt != anInvalidConstraints.end(); ++anInvCIt)
310 removeConstraint(*anInvCIt);
312 // Remove invalid features
313 std::list<FeaturePtr> anInvalidFeatures;
314 std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
315 for (; aFIter != myFeatureMap.end(); aFIter++)
316 if (!aFIter->first->data() || !aFIter->first->data()->isValid()) {
317 anInvalidFeatures.push_back(aFIter->first);
319 aDestroyer.remove(aFIter->second);
321 // remove invalid arc
322 std::map<EntityWrapperPtr, ConstraintWrapperPtr>::iterator
323 aFound = myArcConstraintMap.find(aFIter->second);
324 if (aFound != myArcConstraintMap.end()) {
325 mySketchSolver->removeConstraint(aFound->second->id());
326 myArcConstraintMap.erase(aFound);
329 std::list<FeaturePtr>::const_iterator anInvFIt = anInvalidFeatures.begin();
330 for (; anInvFIt != anInvalidFeatures.end(); ++anInvFIt)
331 removeFeature(*anInvFIt);
333 // Remove invalid attributes
334 std::list<AttributePtr> anInvalidAttributes;
335 std::map<AttributePtr, EntityWrapperPtr>::const_iterator anAttrIt = myAttributeMap.begin();
336 for (; anAttrIt != myAttributeMap.end(); ++anAttrIt) {
337 FeaturePtr anOwner = ModelAPI_Feature::feature(anAttrIt->first->owner());
338 if (!anOwner || !anOwner->data() || !anOwner->data()->isValid()) {
339 anInvalidAttributes.push_back(anAttrIt->first);
340 aDestroyer.remove(anAttrIt->second);
343 std::list<AttributePtr>::const_iterator anInvAtIt = anInvalidAttributes.begin();
344 for (; anInvAtIt != anInvalidAttributes.end(); ++anInvAtIt)
345 removeAttribute(*anInvAtIt);
347 // free memory occupied by parameters
348 removeParameters(aDestroyer.parametersToRemove());
350 /// TODO: Think on optimization of checking invalid features and attributes
355 double* PlaneGCSSolver_Storage::createParameter()
357 return mySketchSolver->createParameter();
360 void PlaneGCSSolver_Storage::removeParameters(const GCS::SET_pD& theParams)
362 mySketchSolver->removeParameters(theParams);
365 // indicates attribute containing in the external feature
366 static bool isExternalAttribute(const AttributePtr& theAttribute)
370 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
371 std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
372 return aSketchFeature.get() && aSketchFeature->isExternal();
375 static void addOwnerToSet(const AttributePtr& theAttribute, std::set<FeaturePtr>& theFeatures)
377 FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
379 theFeatures.insert(anOwner);
382 void PlaneGCSSolver_Storage::refresh() const
384 const double aTol = 1000. * tolerance; // tolerance to prevent frequent updates
386 std::set<FeaturePtr> anUpdatedFeatures;
388 std::map<AttributePtr, EntityWrapperPtr>::const_iterator anIt = myAttributeMap.begin();
389 for (; anIt != myAttributeMap.end(); ++anIt) {
390 // the external feature always should keep the up to date values, so,
391 // refresh from the solver is never needed
392 if (isExternalAttribute(anIt->first))
395 std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
396 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anIt->first);
398 std::shared_ptr<PlaneGCSSolver_PointWrapper> aPointWrapper =
399 std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
400 GCSPointPtr aGCSPoint = aPointWrapper->point();
401 if (fabs(aPoint2D->x() - (*aGCSPoint->x)) > aTol ||
402 fabs(aPoint2D->y() - (*aGCSPoint->y)) > aTol) {
403 aPoint2D->setValue(*aGCSPoint->x, *aGCSPoint->y);
404 addOwnerToSet(anIt->first, anUpdatedFeatures);
408 AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anIt->first);
410 ScalarWrapperPtr aScalarWrapper =
411 std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(anIt->second);
412 if (fabs(aScalar->value() - aScalarWrapper->value()) > aTol) {
413 aScalar->setValue(aScalarWrapper->value());
414 addOwnerToSet(anIt->first, anUpdatedFeatures);
420 // notify listeners about features update
421 std::set<FeaturePtr>::const_iterator aFIt = anUpdatedFeatures.begin();
422 for (; aFIt != anUpdatedFeatures.end(); ++aFIt)