]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp
Salome HOME
Issue #2971: Naming issue in a group when loading a dump file
[modules/shaper.git] / src / SketchSolver / SketchSolver_ConstraintCoincidence.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 <SketchSolver_ConstraintCoincidence.h>
21 #include <SketchSolver_Error.h>
22 #include <PlaneGCSSolver_Tools.h>
23 #include <PlaneGCSSolver_UpdateCoincidence.h>
24
25 #include <GeomDataAPI_Point2D.h>
26
27 #include <SketchPlugin_Arc.h>
28 #include <SketchPlugin_ConstraintCoincidenceInternal.h>
29 #include <SketchPlugin_Ellipse.h>
30 #include <SketchPlugin_EllipticArc.h>
31 #include <SketchPlugin_Line.h>
32 #include <SketchPlugin_Point.h>
33
34 static void getCoincidentFeatureExtremities(const ConstraintPtr& theConstraint,
35                                             const StoragePtr& theStorage,
36                                             EntityWrapperPtr theExtremities[2])
37 {
38   for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
39     AttributeRefAttrPtr aRefAttr = theConstraint->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
40     if (!aRefAttr || !aRefAttr->isObject())
41       continue;
42
43     FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
44     if (!aFeature)
45       continue;
46
47     if (aFeature->getKind() == SketchPlugin_Line::ID()) {
48       theExtremities[0] = theStorage->entity(aFeature->attribute(SketchPlugin_Line::START_ID()));
49       theExtremities[1] = theStorage->entity(aFeature->attribute(SketchPlugin_Line::END_ID()));
50     } else if (aFeature->getKind() == SketchPlugin_Arc::ID()) {
51       theExtremities[0] = theStorage->entity(aFeature->attribute(SketchPlugin_Arc::START_ID()));
52       theExtremities[1] = theStorage->entity(aFeature->attribute(SketchPlugin_Arc::END_ID()));
53     } else if (aFeature->getKind() == SketchPlugin_EllipticArc::ID()) {
54       theExtremities[0] = theStorage->entity(
55           aFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID()));
56       theExtremities[1] = theStorage->entity(
57           aFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID()));
58     }
59   }
60 }
61
62 static void getPointOwnerAndParent(const AttributeRefAttrPtr theRefAttr,
63                                    AttributePoint2DPtr& thePoint,
64                                    FeaturePtr& theOwner,
65                                    FeaturePtr& theParent)
66 {
67   AttributePtr anAttr = theRefAttr->attr();
68   if (theRefAttr->isObject()) {
69     FeaturePtr anOwner = ModelAPI_Feature::feature(theRefAttr->object());
70     if (anOwner && anOwner->getKind() == SketchPlugin_Point::ID())
71       anAttr = anOwner->attribute(SketchPlugin_Point::COORD_ID());
72     else
73       return;
74   }
75   thePoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
76   if (thePoint) {
77     theOwner = ModelAPI_Feature::feature(thePoint->owner());
78     if (theOwner) {
79       AttributeReferencePtr aParentRef =
80           theOwner->reference(SketchPlugin_SketchEntity::PARENT_ID());
81       theParent = aParentRef ? ModelAPI_Feature::feature(aParentRef->value()) : FeaturePtr();
82     }
83   }
84 }
85
86 static void ellipseDiameters(FeaturePtr theEllipse,
87                              std::pair<std::string, std::string>& theMajorAxis,
88                              std::pair<std::string, std::string>& theMinorAxis)
89 {
90   if (theEllipse->getKind() == SketchPlugin_Ellipse::ID()) {
91     theMajorAxis.first = SketchPlugin_Ellipse::MAJOR_AXIS_START_ID();
92     theMajorAxis.second = SketchPlugin_Ellipse::MAJOR_AXIS_END_ID();
93     theMinorAxis.first = SketchPlugin_Ellipse::MINOR_AXIS_START_ID();
94     theMinorAxis.second = SketchPlugin_Ellipse::MINOR_AXIS_END_ID();
95   } else if (theEllipse->getKind() == SketchPlugin_EllipticArc::ID()) {
96     theMajorAxis.first = SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID();
97     theMajorAxis.second = SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID();
98     theMinorAxis.first = SketchPlugin_EllipticArc::MINOR_AXIS_START_ID();
99     theMinorAxis.second = SketchPlugin_EllipticArc::MINOR_AXIS_END_ID();
100   }
101 }
102
103 static void findDiameterOnEllipse(FeaturePtr theConstruction,
104                                   FeaturePtr theEllipse,
105                                   AttributePtr& theStart,
106                                   AttributePtr& theEnd)
107 {
108   AttributePtr anEllipseAttr;
109   const std::set<AttributePtr>& aRefs = theConstruction->data()->refsToMe();
110   for (std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin();
111        aRefIt != aRefs.end(); ++aRefIt) {
112     FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner());
113     if (anOwner && anOwner->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID()) {
114       AttributeRefAttrPtr aRefAttr;
115       if ((*aRefIt)->id() == SketchPlugin_Constraint::ENTITY_A())
116         aRefAttr = anOwner->refattr(SketchPlugin_Constraint::ENTITY_B());
117       else
118         aRefAttr = anOwner->refattr(SketchPlugin_Constraint::ENTITY_A());
119       anEllipseAttr = aRefAttr->attr();
120       break;
121     }
122   }
123   if (!anEllipseAttr)
124     return;
125
126   std::pair<std::string, std::string> aMajorAxis, aMinorAxis;
127   ellipseDiameters(theEllipse, aMajorAxis, aMinorAxis);
128   if (anEllipseAttr->id() == aMajorAxis.first) {
129     theStart = anEllipseAttr;
130     theEnd = theEllipse->attribute(aMajorAxis.second);
131   }
132   else if (anEllipseAttr->id() == aMajorAxis.second) {
133     theStart = theEllipse->attribute(aMajorAxis.first);
134     theEnd = anEllipseAttr;
135   }
136   else if (anEllipseAttr->id() == aMinorAxis.first) {
137     theStart = anEllipseAttr;
138     theEnd = theEllipse->attribute(aMinorAxis.second);
139   }
140   else if (anEllipseAttr->id() == aMinorAxis.second) {
141     theStart = theEllipse->attribute(aMinorAxis.first);
142     theEnd = anEllipseAttr;
143   }
144 }
145
146 static void processEllipticArcExtremities(SketchSolver_ConstraintType& theType,
147                                           const ConstraintPtr& theConstraint,
148                                           const StoragePtr& theStorage,
149                                           std::vector<EntityWrapperPtr>& theAttributes,
150                                           EntityWrapperPtr theExtremities[2])
151 {
152   AttributePoint2DPtr aPointA, aPointB;
153   FeaturePtr anOwnerA, anOwnerB;
154   FeaturePtr aParentA, aParentB;
155   getPointOwnerAndParent(theConstraint->refattr(SketchPlugin_Constraint::ENTITY_A()),
156                          aPointA, anOwnerA, aParentA);
157   getPointOwnerAndParent(theConstraint->refattr(SketchPlugin_Constraint::ENTITY_B()),
158                          aPointB, anOwnerB, aParentB);
159
160   AttributePtr anAxisStart, anAxisEnd, aPoint;
161   FeaturePtr aConstruction, anEllipticArc;
162   if (aParentA && aParentA == anOwnerB) {
163     aPoint = aPointB;
164     aConstruction = anOwnerA;
165     anEllipticArc = anOwnerB;
166   }
167   else if (aParentB && aParentB == anOwnerA) {
168     aPoint = aPointA;
169     aConstruction = anOwnerB;
170     anEllipticArc = anOwnerA;
171   }
172
173   if (!anEllipticArc || anEllipticArc->getKind() != SketchPlugin_EllipticArc::ID() ||
174       (aPoint->id() != SketchPlugin_EllipticArc::START_POINT_ID() &&
175        aPoint->id() != SketchPlugin_EllipticArc::END_POINT_ID()))
176     return;
177
178   findDiameterOnEllipse(aConstruction, anEllipticArc, anAxisStart, anAxisEnd);
179
180   if (anAxisStart && anAxisEnd) {
181     theAttributes[0] = theStorage->entity(aPoint);
182     theAttributes[1] = theStorage->entity(anAxisStart);
183     theAttributes[2] = theStorage->entity(anAxisEnd);
184     theType = CONSTRAINT_PT_ON_CURVE;
185     getCoincidentFeatureExtremities(theConstraint, theStorage, theExtremities);
186   }
187 }
188
189
190 void SketchSolver_ConstraintCoincidence::process()
191 {
192   cleanErrorMsg();
193   if (!myBaseConstraint || !myStorage) {
194     // Not enough parameters are assigned
195     return;
196   }
197
198   EntityWrapperPtr aValue;
199   std::vector<EntityWrapperPtr> anAttributes;
200   getAttributes(aValue, anAttributes);
201   if (!myErrorMsg.empty())
202     return;
203   if (anAttributes.empty()) {
204     myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
205     return;
206   }
207
208   mySolverConstraint = PlaneGCSSolver_Tools::createConstraint(
209       myBaseConstraint, getType(),
210       aValue, anAttributes[0], anAttributes[1], anAttributes[2], anAttributes[3]);
211
212   myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateCoincidence::GROUP());
213   myStorage->notify(myBaseConstraint);
214 }
215
216 bool SketchSolver_ConstraintCoincidence::remove()
217 {
218   myInSolver = false;
219   myFeatureExtremities[0] = EntityWrapperPtr();
220   myFeatureExtremities[1] = EntityWrapperPtr();
221   return SketchSolver_Constraint::remove();
222 }
223
224 void SketchSolver_ConstraintCoincidence::getAttributes(
225     EntityWrapperPtr& theValue,
226     std::vector<EntityWrapperPtr>& theAttributes)
227 {
228   SketchSolver_Constraint::getAttributes(theValue, theAttributes);
229   if (!myErrorMsg.empty() || !theAttributes[0]) {
230     theAttributes.clear();
231     return;
232   }
233
234   if (theAttributes[1]) {
235     myType = CONSTRAINT_PT_PT_COINCIDENT;
236     // if elliptic arc boundary point is connected with one of ellipse characteristics,
237     // it should be changed from point-point coincidence to coincidence between point
238     // and axis of the ellipse to decrease only 1 DoF instead of 2 DoF and avoid overconstraint.
239     processEllipticArcExtremities(myType, myBaseConstraint, myStorage,
240                                   theAttributes, myFeatureExtremities);
241   } else if (theAttributes[2]) {
242     myType = CONSTRAINT_PT_ON_CURVE;
243     // obtain extremity points of the coincident feature for further checking of multi-coincidence
244     getCoincidentFeatureExtremities(myBaseConstraint, myStorage, myFeatureExtremities);
245   } else
246     myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
247 }
248
249 void SketchSolver_ConstraintCoincidence::notify(const FeaturePtr&      theFeature,
250                                                 PlaneGCSSolver_Update* theUpdater)
251 {
252   PlaneGCSSolver_UpdateCoincidence* anUpdater =
253       static_cast<PlaneGCSSolver_UpdateCoincidence*>(theUpdater);
254   bool isAccepted = anUpdater->addCoincidence(myAttributes.front(), myAttributes.back());
255   // additionally process internal coincidence, set point coincident with ellipse/elliptic arc
256   // for correct processing further coincidences set by the user
257   if (isAccepted &&
258       myBaseConstraint->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID()) {
259     AttributeRefAttrPtr aRefAttrA = myBaseConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
260     AttributeRefAttrPtr aRefAttrB = myBaseConstraint->refattr(SketchPlugin_Constraint::ENTITY_B());
261     if (aRefAttrA && aRefAttrB) {
262       AttributePoint2DPtr anAttrA, anAttrB;
263       FeaturePtr anOwnerA, anOwnerB;
264       FeaturePtr aParentA, aParentB;
265       getPointOwnerAndParent(aRefAttrA, anAttrA, anOwnerA, aParentA);
266       getPointOwnerAndParent(aRefAttrB, anAttrB, anOwnerB, aParentB);
267
268       EntityWrapperPtr aPoint, anEntity;
269       if (aParentA == anOwnerB) {
270         aPoint = myStorage->entity(anAttrA);
271         anEntity = myStorage->entity(anOwnerB);
272       }
273       else if (aParentB == anOwnerA) {
274         aPoint = myStorage->entity(anAttrB);
275         anEntity = myStorage->entity(anOwnerA);
276       }
277       if (aPoint && anEntity)
278         anUpdater->addCoincidence(aPoint, anEntity);
279     }
280   }
281
282   // additionally check the point is coincident to extremity of coincident feature
283   if (myFeatureExtremities[0] && myFeatureExtremities[1]) {
284     EntityWrapperPtr aPoint =
285         myAttributes.front()->type() == ENTITY_POINT ? myAttributes.front() : myAttributes.back();
286
287     for (int i = 0; i < 2; ++i)
288       isAccepted = isAccepted && !anUpdater->isPointOnEntity(aPoint, myFeatureExtremities[i]);
289   }
290
291   if (isAccepted) {
292     if (!myInSolver) {
293       myInSolver = true;
294       myStorage->addConstraint(myBaseConstraint, mySolverConstraint);
295     }
296   } else {
297     if (myInSolver) {
298       myInSolver = false;
299       myStorage->removeConstraint(myBaseConstraint);
300     }
301   }
302 }