]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp
Salome HOME
Remove external links and features which produce such entities.
[modules/shaper.git] / src / SketchSolver / PlaneGCSSolver / PlaneGCSSolver_Storage.cpp
1 // Copyright (C) 2014-2019  CEA/DEN, EDF R&D
2 //
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.
7 //
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.
12 //
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
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include <PlaneGCSSolver_Storage.h>
21 #include <PlaneGCSSolver_Solver.h>
22 #include <PlaneGCSSolver_ConstraintWrapper.h>
23 #include <PlaneGCSSolver_EdgeWrapper.h>
24 #include <PlaneGCSSolver_PointWrapper.h>
25 #include <PlaneGCSSolver_Tools.h>
26
27 #include <PlaneGCSSolver_AttributeBuilder.h>
28 #include <PlaneGCSSolver_FeatureBuilder.h>
29 #include <PlaneGCSSolver_EntityDestroyer.h>
30
31 #include <GeomAPI_Dir2d.h>
32 #include <GeomAPI_Pnt2d.h>
33 #include <GeomAPI_XY.h>
34 #include <GeomDataAPI_Point2D.h>
35 #include <ModelAPI_AttributeRefAttr.h>
36 #include <SketchPlugin_Projection.h>
37
38 #include <cmath>
39
40
41 static void constraintsToSolver(const ConstraintWrapperPtr& theConstraint,
42                                 const SolverPtr& theSolver)
43 {
44   const std::list<GCSConstraintPtr>& aConstraints =
45       std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(theConstraint)->constraints();
46   theSolver->addConstraint(theConstraint->id(), aConstraints);
47 }
48
49
50 PlaneGCSSolver_Storage::PlaneGCSSolver_Storage(const SolverPtr& theSolver)
51   : SketchSolver_Storage(theSolver),
52     myConstraintLastID(CID_UNKNOWN)
53 {
54 }
55
56 void PlaneGCSSolver_Storage::addConstraint(
57     ConstraintPtr        theConstraint,
58     ConstraintWrapperPtr theSolverConstraint)
59 {
60   SketchSolver_Storage::addConstraint(theConstraint, theSolverConstraint);
61
62   theSolverConstraint->setId(++myConstraintLastID);
63   constraintsToSolver(theSolverConstraint, mySketchSolver);
64 }
65
66 void PlaneGCSSolver_Storage::addMovementConstraint(
67     const ConstraintWrapperPtr& theSolverConstraint)
68 {
69   // before adding movement constraint to solver, re-check its DOF
70   if (mySketchSolver->dof() == 0)
71     mySketchSolver->diagnose();
72
73   theSolverConstraint->setId(CID_MOVEMENT);
74   constraintsToSolver(theSolverConstraint, mySketchSolver);
75 }
76
77
78 EntityWrapperPtr PlaneGCSSolver_Storage::createFeature(
79     const FeaturePtr&             theFeature,
80     PlaneGCSSolver_EntityBuilder* theBuilder)
81 {
82   std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
83   std::list<AttributePtr>::const_iterator anIt = anAttributes.begin();
84   for (; anIt != anAttributes.end(); ++anIt)
85     createAttribute(*anIt, theBuilder);
86
87   EntityWrapperPtr aResult = theBuilder->createFeature(theFeature);
88   if (aResult)
89     addEntity(theFeature, aResult);
90   return aResult;
91 }
92
93 EntityWrapperPtr PlaneGCSSolver_Storage::createAttribute(
94     const AttributePtr&           theAttribute,
95     PlaneGCSSolver_EntityBuilder* theBuilder)
96 {
97   EntityWrapperPtr aResult = theBuilder->createAttribute(theAttribute);
98   if (aResult)
99     addEntity(theAttribute, aResult);
100   return aResult;
101 }
102
103 /// \brief Update value
104 static bool updateValue(const double& theSource, double& theDest)
105 {
106   static const double aTol = 1000. * tolerance;
107   bool isUpdated = fabs(theSource - theDest) > aTol;
108   if (isUpdated)
109     theDest = theSource;
110   return isUpdated;
111 }
112
113 /// \brief Update coordinates of the point or scalar using its base attribute
114 static bool updateValues(AttributePtr& theAttribute, EntityWrapperPtr& theEntity)
115 {
116   bool isUpdated = false;
117
118   std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
119       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
120   if (aPoint2D) {
121     const GCSPointPtr& aGCSPoint =
122         std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theEntity)->point();
123     isUpdated = updateValue(aPoint2D->x(), *(aGCSPoint->x)) || isUpdated;
124     isUpdated = updateValue(aPoint2D->y(), *(aGCSPoint->y)) || isUpdated;
125   } else {
126     AttributeDoublePtr aScalar =
127         std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
128     if (aScalar) {
129       ScalarWrapperPtr aWrapper =
130           std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(theEntity);
131       // There is possible angular value, which is converted between degrees and radians.
132       // So, we use its value instead of using direct pointer to value.
133       double aValue = aWrapper->value();
134       isUpdated = updateValue(aScalar->value(), aValue);
135       if (isUpdated)
136         aWrapper->setValue(aValue);
137     }
138   }
139
140   return isUpdated;
141 }
142
143 static bool hasReference(std::shared_ptr<SketchPlugin_Feature> theFeature,
144                          const std::string& theFeatureKind)
145 {
146   const std::set<AttributePtr>& aRefs = theFeature->data()->refsToMe();
147   for (std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin();
148        aRefIt != aRefs.end(); ++aRefIt) {
149      FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner());
150      if (anOwner && anOwner->getKind() == theFeatureKind)
151        return true;
152   }
153   return false;
154 }
155
156 static bool isCopyFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
157 {
158   return theFeature && theFeature->isCopy();
159 }
160
161 bool PlaneGCSSolver_Storage::update(FeaturePtr theFeature, bool theForce)
162 {
163   bool sendNotify = false;
164   bool isUpdated = false;
165   std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
166       std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
167   EntityWrapperPtr aRelated = entity(theFeature);
168   if (aRelated) // send signal to subscribers
169     sendNotify = true;
170   else { // Feature is not exist, create it
171     bool isCopy = isCopyFeature(aSketchFeature);
172     bool isProjReferred = hasReference(aSketchFeature, SketchPlugin_Projection::ID());
173     // the feature is a copy in "Multi" constraint and does not used in other constraints
174     if (!theForce && (isCopy && !isProjReferred) &&
175         myFeatureMap.find(theFeature) == myFeatureMap.end())
176       return false;
177
178     // external feature processing
179     bool isExternal =
180         (aSketchFeature && (aSketchFeature->isExternal() || isCopy || isProjReferred));
181
182     PlaneGCSSolver_FeatureBuilder aBuilder(isExternal ? 0 : this);
183
184     // Reserve the feature in the map of features
185     // (do not want to add several copies of it while adding attributes)
186     aRelated = createFeature(theFeature, &aBuilder);
187     myFeatureMap[theFeature] = aRelated;
188     createArcConstraints(aRelated);
189     isUpdated = true;
190   }
191
192   std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
193   std::list<AttributePtr>::iterator anAttrIt = anAttributes.begin();
194   for (; anAttrIt != anAttributes.end(); ++anAttrIt)
195     if ((*anAttrIt)->attributeType() == GeomDataAPI_Point2D::typeId() ||
196         (*anAttrIt)->attributeType() == ModelAPI_AttributeDouble::typeId())
197       isUpdated = update(*anAttrIt) || isUpdated;
198
199   // check external attribute is changed
200   bool isExternal = aSketchFeature && aSketchFeature->isExternal();
201   if (aRelated && isExternal != aRelated->isExternal()) {
202     if (isExternal)
203       makeExternal(aRelated);
204     else
205       makeNonExternal(aRelated);
206     isUpdated = true;
207   }
208
209   // send notification to listeners due to at least one attribute is changed
210   if (sendNotify && isUpdated)
211     notify(theFeature);
212
213   // update arc
214   if (aRelated && aRelated->type() == ENTITY_ARC) {
215     /// TODO: this code should be shared with FeatureBuilder somehow
216
217     std::shared_ptr<PlaneGCSSolver_EdgeWrapper> anEntity =
218         std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(aRelated);
219     std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEntity->entity());
220
221     static std::shared_ptr<GeomAPI_Dir2d> OX(new GeomAPI_Dir2d(1.0, 0.0));
222     std::shared_ptr<GeomAPI_Pnt2d> aCenter(
223         new GeomAPI_Pnt2d(*anArc->center.x, *anArc->center.y));
224     std::shared_ptr<GeomAPI_Pnt2d> aStart(
225         new GeomAPI_Pnt2d(*anArc->start.x, *anArc->start.y));
226
227     *anArc->rad = aStart->distance(aCenter);
228
229     std::shared_ptr<GeomAPI_Dir2d> aDir(new GeomAPI_Dir2d(aStart->xy()->decreased(aCenter->xy())));
230     *anArc->startAngle = OX->angle(aDir);
231
232     aDir = std::shared_ptr<GeomAPI_Dir2d>(
233         new GeomAPI_Dir2d((*anArc->end.x) - aCenter->x(), (*anArc->end.y) - aCenter->y()));
234     *anArc->endAngle = OX->angle(aDir);
235   }
236
237   return isUpdated;
238 }
239
240 bool PlaneGCSSolver_Storage::update(AttributePtr theAttribute, bool theForce)
241 {
242   if (!theAttribute->isInitialized())
243     return false;
244
245   AttributePtr anAttribute = theAttribute;
246   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
247   if (aRefAttr) {
248     if (aRefAttr->isObject()) {
249       FeaturePtr aFeature;
250       /// TODO: Check resultToFeatureOrAttribute() precisely.
251       resultToFeatureOrAttribute(aRefAttr->object(), aFeature, anAttribute);
252       if (aFeature)
253         return update(aFeature, theForce);
254     } else
255       anAttribute = aRefAttr->attr();
256   }
257
258   EntityWrapperPtr aRelated = entity(anAttribute);
259   FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
260   if (!aRelated) { // Attribute does not exist, create it.
261     // First of all check if the parent feature exists. If not, add it.
262     if (aFeature && myFeatureMap.find(aFeature) == myFeatureMap.end())
263       return update(aFeature, theForce); // theAttribute has been processed while adding feature
264     return aRelated.get() != 0;
265   }
266
267   bool isUpdated = updateValues(anAttribute, aRelated);
268   if (isUpdated) {
269     setNeedToResolve(true);
270     notify(aFeature);
271   }
272   return isUpdated;
273 }
274
275 void PlaneGCSSolver_Storage::makeExternal(const EntityWrapperPtr& theEntity)
276 {
277   if (theEntity->isExternal())
278     return;
279
280   removeArcConstraints(theEntity);
281
282   GCS::SET_pD aParameters = PlaneGCSSolver_Tools::parameters(theEntity);
283   mySketchSolver->removeParameters(aParameters);
284   theEntity->setExternal(true);
285   myNeedToResolve = true;
286 }
287
288 void PlaneGCSSolver_Storage::makeNonExternal(const EntityWrapperPtr& theEntity)
289 {
290   if (!theEntity->isExternal())
291     return;
292
293   GCS::SET_pD aParameters = PlaneGCSSolver_Tools::parameters(theEntity);
294   mySketchSolver->addParameters(aParameters);
295   theEntity->setExternal(false);
296
297   createArcConstraints(theEntity);
298
299   myNeedToResolve = true;
300 }
301
302
303 void PlaneGCSSolver_Storage::createArcConstraints(const EntityWrapperPtr& theArc)
304 {
305   if (!theArc || theArc->type() != ENTITY_ARC || theArc->isExternal())
306     return;
307
308   EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theArc);
309   std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEdge->entity());
310
311   // Additional constaints to fix arc's extra DoF (if the arc is not external):
312   std::list<GCSConstraintPtr> anArcConstraints;
313   // 1. distances from center till start and end points are equal to radius
314   anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
315       anArc->center, anArc->start, anArc->rad)));
316   anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
317       anArc->center, anArc->end, anArc->rad)));
318   // 2. angles of start and end points should be equal to the arc angles
319   anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle(
320       anArc->center, anArc->start, anArc->startAngle)));
321   anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle(
322       anArc->center, anArc->end, anArc->endAngle)));
323
324   ConstraintWrapperPtr aWrapper(
325       new PlaneGCSSolver_ConstraintWrapper(anArcConstraints, CONSTRAINT_UNKNOWN));
326   aWrapper->setId(++myConstraintLastID);
327   constraintsToSolver(aWrapper, mySketchSolver);
328
329   myArcConstraintMap[theArc] = aWrapper;
330 }
331
332 void PlaneGCSSolver_Storage::removeArcConstraints(const EntityWrapperPtr& theArc)
333 {
334   std::map<EntityWrapperPtr, ConstraintWrapperPtr>::iterator
335       aFound = myArcConstraintMap.find(theArc);
336   if (aFound != myArcConstraintMap.end()) {
337     mySketchSolver->removeConstraint(aFound->second->id());
338     myArcConstraintMap.erase(aFound);
339   }
340 }
341
342
343 bool PlaneGCSSolver_Storage::removeConstraint(ConstraintPtr theConstraint)
344 {
345   std::map<ConstraintPtr, ConstraintWrapperPtr>::iterator
346       aFound = myConstraintMap.find(theConstraint);
347   if (aFound != myConstraintMap.end()) {
348     ConstraintWrapperPtr aCW = aFound->second;
349     ConstraintID anID = aCW->id();
350
351     // Remove solver's constraints
352     mySketchSolver->removeConstraint(anID);
353
354     // Remove value if exists
355     const ScalarWrapperPtr& aValue = aCW->valueParameter();
356     if (aValue) {
357       GCS::SET_pD aParToRemove;
358       aParToRemove.insert(aValue->scalar());
359       removeParameters(aParToRemove);
360     }
361
362     // Remove constraint
363     myConstraintMap.erase(aFound);
364
365     if (anID != CID_MOVEMENT)
366       myNeedToResolve = true;
367
368     // notify subscibers
369     notify(theConstraint);
370   }
371   return true;
372 }
373
374 void PlaneGCSSolver_Storage::removeInvalidEntities()
375 {
376   PlaneGCSSolver_EntityDestroyer aDestroyer;
377
378   // Remove invalid constraints
379   std::list<ConstraintPtr> anInvalidConstraints;
380   std::map<ConstraintPtr, ConstraintWrapperPtr>::const_iterator
381       aCIter = myConstraintMap.begin();
382   for (; aCIter != myConstraintMap.end(); ++aCIter)
383     if (!aCIter->first->data() || !aCIter->first->data()->isValid())
384       anInvalidConstraints.push_back(aCIter->first);
385   std::list<ConstraintPtr>::const_iterator anInvCIt = anInvalidConstraints.begin();
386   for (; anInvCIt != anInvalidConstraints.end(); ++anInvCIt)
387     removeConstraint(*anInvCIt);
388
389   // Remove invalid features
390   std::list<FeaturePtr> anInvalidFeatures;
391   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
392   for (; aFIter != myFeatureMap.end(); aFIter++)
393     if (!aFIter->first->data() || !aFIter->first->data()->isValid()) {
394       anInvalidFeatures.push_back(aFIter->first);
395       if (aFIter->second)
396         aDestroyer.remove(aFIter->second);
397
398       // remove invalid arc
399       removeArcConstraints(aFIter->second);
400     }
401   std::list<FeaturePtr>::const_iterator anInvFIt = anInvalidFeatures.begin();
402   for (; anInvFIt != anInvalidFeatures.end(); ++anInvFIt)
403     removeFeature(*anInvFIt);
404
405   // Remove invalid attributes
406   std::list<AttributePtr> anInvalidAttributes;
407   std::map<AttributePtr, EntityWrapperPtr>::const_iterator anAttrIt = myAttributeMap.begin();
408   for (; anAttrIt != myAttributeMap.end(); ++anAttrIt) {
409     FeaturePtr anOwner = ModelAPI_Feature::feature(anAttrIt->first->owner());
410     if (!anOwner || !anOwner->data() || !anOwner->data()->isValid()) {
411       anInvalidAttributes.push_back(anAttrIt->first);
412       aDestroyer.remove(anAttrIt->second);
413     }
414   }
415   std::list<AttributePtr>::const_iterator anInvAtIt = anInvalidAttributes.begin();
416   for (; anInvAtIt != anInvalidAttributes.end(); ++anInvAtIt)
417     removeAttribute(*anInvAtIt);
418
419   // free memory occupied by parameters
420   removeParameters(aDestroyer.parametersToRemove());
421
422   /// TODO: Think on optimization of checking invalid features and attributes
423 }
424
425
426
427 double* PlaneGCSSolver_Storage::createParameter()
428 {
429   return mySketchSolver->createParameter();
430 }
431
432 void PlaneGCSSolver_Storage::removeParameters(const GCS::SET_pD& theParams)
433 {
434   mySketchSolver->removeParameters(theParams);
435 }
436
437 // indicates attribute containing in the external feature
438 static bool isExternalAttribute(const AttributePtr& theAttribute)
439 {
440   if (!theAttribute)
441     return false;
442   std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
443       std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
444   return aSketchFeature.get() && aSketchFeature->isExternal();
445 }
446
447 static void addOwnerToSet(const AttributePtr& theAttribute, std::set<FeaturePtr>& theFeatures)
448 {
449   FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
450   if (anOwner)
451     theFeatures.insert(anOwner);
452 }
453
454 void PlaneGCSSolver_Storage::refresh() const
455 {
456   const double aTol = 1000. * tolerance; // tolerance to prevent frequent updates
457
458   std::set<FeaturePtr> anUpdatedFeatures;
459
460   std::map<AttributePtr, EntityWrapperPtr>::const_iterator anIt = myAttributeMap.begin();
461   for (; anIt != myAttributeMap.end(); ++anIt) {
462     if (!anIt->first->isInitialized())
463       continue;
464
465     // the external feature always should keep the up to date values, so,
466     // refresh from the solver is never needed
467     if (isExternalAttribute(anIt->first))
468       continue;
469
470     std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
471         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anIt->first);
472     if (aPoint2D) {
473       std::shared_ptr<PlaneGCSSolver_PointWrapper> aPointWrapper =
474           std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
475       GCSPointPtr aGCSPoint = aPointWrapper->point();
476       if (fabs(aPoint2D->x() - (*aGCSPoint->x)) > aTol ||
477           fabs(aPoint2D->y() - (*aGCSPoint->y)) > aTol) {
478         aPoint2D->setValue(*aGCSPoint->x, *aGCSPoint->y);
479         addOwnerToSet(anIt->first, anUpdatedFeatures);
480       }
481       continue;
482     }
483     AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anIt->first);
484     if (aScalar) {
485       ScalarWrapperPtr aScalarWrapper =
486           std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(anIt->second);
487       if (fabs(aScalar->value() - aScalarWrapper->value()) > aTol) {
488         aScalar->setValue(aScalarWrapper->value());
489         addOwnerToSet(anIt->first, anUpdatedFeatures);
490       }
491       continue;
492     }
493   }
494
495   // notify listeners about features update
496   std::set<FeaturePtr>::const_iterator aFIt = anUpdatedFeatures.begin();
497   for (; aFIt != anUpdatedFeatures.end(); ++aFIt)
498     notify(*aFIt);
499 }
500
501 PlaneGCSSolver_Solver::SolveStatus PlaneGCSSolver_Storage::checkDegeneratedGeometry() const
502 {
503   std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
504   for (; aFIt != myFeatureMap.end(); ++aFIt) {
505     EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(aFIt->second);
506     if (anEdge && anEdge->isDegenerated())
507       return PlaneGCSSolver_Solver::STATUS_DEGENERATED;
508   }
509   return PlaneGCSSolver_Solver::STATUS_OK;
510 }