Salome HOME
Merge remote-tracking branch 'origin/CEA_2019_TranslationToFrench' into CEA_2019
[modules/shaper.git] / src / SketchSolver / PlaneGCSSolver / PlaneGCSSolver_UpdateCoincidence.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_UpdateCoincidence.h>
21 #include <PlaneGCSSolver_EdgeWrapper.h>
22 #include <PlaneGCSSolver_PointWrapper.h>
23 #include <SketchSolver_Constraint.h>
24
25 #include <SketchPlugin_ConstraintCoincidence.h>
26 #include <SketchPlugin_ConstraintCoincidenceInternal.h>
27 #include <SketchPlugin_ConstraintCollinear.h>
28 #include <SketchPlugin_ConstraintMiddle.h>
29
30 static bool hasSamePoint(const std::set<EntityWrapperPtr>& theList,
31                          const EntityWrapperPtr& thePoint);
32
33
34 void PlaneGCSSolver_UpdateCoincidence::attach(SketchSolver_Constraint* theObserver,
35                                               const std::string& theType)
36 {
37   if (theType == GROUP()) {
38     std::list<SketchSolver_Constraint*>::iterator aPlaceToAdd = myObservers.end();
39     // point-point coincidence is placed first,
40     // other constraints are sorted by their type
41     for (aPlaceToAdd = myObservers.begin(); aPlaceToAdd != myObservers.end(); ++aPlaceToAdd)
42       if ((*aPlaceToAdd)->getType() > theObserver->getType())
43         break;
44     myObservers.insert(aPlaceToAdd, theObserver);
45   } else
46     myNext->attach(theObserver, theType);
47 }
48
49 void PlaneGCSSolver_UpdateCoincidence::update(const FeaturePtr& theFeature)
50 {
51   if (theFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
52       theFeature->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID() ||
53       theFeature->getKind() == SketchPlugin_ConstraintMiddle::ID() ||
54       theFeature->getKind() == SketchPlugin_ConstraintCollinear::ID()) {
55     myCoincident.clear();
56     // notify listeners and stop procesing
57     std::list<SketchSolver_Constraint*>::iterator anIt = myObservers.begin();
58     for (; anIt != myObservers.end(); ++anIt)
59       (*anIt)->notify(theFeature, this);
60   } else
61     myNext->update(theFeature);
62 }
63
64 static bool hasAnotherExternalPoint(const std::set<EntityWrapperPtr>& theCoincidences,
65                                     const EntityWrapperPtr& thePoint)
66 {
67   std::set<EntityWrapperPtr>::const_iterator anIt = theCoincidences.begin();
68   for (; anIt != theCoincidences.end(); ++anIt)
69     if ((*anIt)->type() == ENTITY_POINT && (*anIt)->isExternal() && *anIt != thePoint)
70       return true;
71   return false;
72 }
73
74 bool PlaneGCSSolver_UpdateCoincidence::addCoincidence(
75     const EntityWrapperPtr& theEntity1,
76     const EntityWrapperPtr& theEntity2)
77 {
78   bool isAccepted = true;
79   std::list<CoincidentEntities>::iterator aFound[2] = {
80     findGroupOfCoincidence(theEntity1),
81     findGroupOfCoincidence(theEntity2)
82   };
83
84   if (aFound[0] == myCoincident.end() && aFound[1] == myCoincident.end()) {
85     // new group of coincidence
86     myCoincident.push_back(CoincidentEntities(theEntity1, theEntity2));
87   } else if (aFound[0] == myCoincident.end()) {
88     isAccepted = addToGroupOfCoincidence(*aFound[1], theEntity1);
89   } else if (aFound[1] == myCoincident.end()) {
90     isAccepted = addToGroupOfCoincidence(*aFound[0], theEntity2);
91   } else if (aFound[0] == aFound[1]) { // same group => already coincident
92     isAccepted = false;
93   } else { // merge two groups
94     // first check the external points are equal
95     EntityWrapperPtr anExternal0 = aFound[0]->externalPoint();
96     EntityWrapperPtr anExternal1 = aFound[1]->externalPoint();
97     if (anExternal0 && anExternal1) {
98       std::set<EntityWrapperPtr> anExtList;
99       anExtList.insert(anExternal0);
100       if (hasSamePoint(anExtList, anExternal1)) {
101         // no need to add coincidence, because all points are
102         // already coincident to correct external points
103         isAccepted = false;
104       }
105     }
106
107     // merge
108     aFound[0]->merge(*aFound[1]);
109     myCoincident.erase(aFound[1]);
110   }
111
112   return isAccepted;
113 }
114
115 bool PlaneGCSSolver_UpdateCoincidence::isPointOnEntity(
116     const EntityWrapperPtr& thePoint,
117     const EntityWrapperPtr& theEntity)
118 {
119   std::list<CoincidentEntities>::iterator anIt = findGroupOfCoincidence(thePoint);
120   if (anIt == myCoincident.end())
121     return false;
122
123   if (anIt->isExist(theEntity))
124     return true;
125
126   if (theEntity->type() == ENTITY_LINE) {
127     std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(
128         std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theEntity)->entity());
129     return anIt->isExist(aLine->p1) || anIt->isExist(aLine->p2);
130   }
131   return false;
132 }
133
134 std::list<PlaneGCSSolver_UpdateCoincidence::CoincidentEntities>::iterator
135   PlaneGCSSolver_UpdateCoincidence::findGroupOfCoincidence(const EntityWrapperPtr& theEntity)
136 {
137   if (theEntity->type() != ENTITY_POINT)
138     return myCoincident.end();
139
140   std::list<CoincidentEntities>::iterator aFound = myCoincident.begin();
141   for (; aFound != myCoincident.end(); ++aFound)
142     if (aFound->isExist(theEntity))
143       break;
144   return aFound;
145 }
146
147 bool PlaneGCSSolver_UpdateCoincidence::addToGroupOfCoincidence(
148     CoincidentEntities& theGroup, const EntityWrapperPtr& theEntity)
149 {
150   if (theGroup.isExist(theEntity))
151     return false;
152   return theGroup.add(theEntity);
153 }
154
155
156
157
158
159 static const GCS::Point& toPoint(const EntityWrapperPtr& theEntity)
160 {
161   PointWrapperPtr aPoint = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theEntity);
162   return *(aPoint->point());
163 }
164
165 static double squareDistance(const GCS::Point& thePoint1, const GCS::Point& thePoint2)
166 {
167   double dx = *thePoint1.x - *thePoint2.x;
168   double dy = *thePoint1.y - *thePoint2.y;
169   return dx * dx + dy * dy;
170 }
171
172 static bool hasSamePoint(const std::set<EntityWrapperPtr>& theList, const GCS::Point& thePoint)
173 {
174   std::set<EntityWrapperPtr>::const_iterator anIt = theList.begin();
175   for (; anIt != theList.end(); ++anIt)
176     if (squareDistance(thePoint, toPoint(*anIt)) < 1.e-14)
177       return true;
178   return false;
179 }
180
181 bool hasSamePoint(const std::set<EntityWrapperPtr>& theList,
182                   const EntityWrapperPtr& thePoint)
183 {
184   return hasSamePoint(theList, toPoint(thePoint));
185 }
186
187
188 PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::CoincidentEntities(
189     const EntityWrapperPtr& theEntity1,
190     const EntityWrapperPtr& theEntity2)
191 {
192   add(theEntity1);
193   add(theEntity2);
194 }
195
196 bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::add(
197     const EntityWrapperPtr& theEntity)
198 {
199   bool isAdded = true;
200   if (theEntity->type() == ENTITY_POINT) {
201     if (theEntity->isExternal()) {
202       isAdded = !hasSamePoint(myExternalPoints, theEntity);
203       myExternalPoints.insert(theEntity);
204     } else
205       myPoints.insert(theEntity);
206   } else
207     myFeatures.insert(theEntity);
208   return isAdded;
209 }
210
211 void PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::remove(
212     const EntityWrapperPtr& theEntity)
213 {
214   if (theEntity->type() == ENTITY_POINT) {
215     if (theEntity->isExternal())
216       myExternalPoints.erase(theEntity);
217     else
218       myPoints.erase(theEntity);
219   } else
220     myFeatures.erase(theEntity);
221 }
222
223 void PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::merge(
224     const CoincidentEntities& theOther)
225 {
226   myExternalPoints.insert(theOther.myExternalPoints.begin(), theOther.myExternalPoints.end());
227   myPoints.insert(theOther.myPoints.begin(), theOther.myPoints.end());
228   myFeatures.insert(theOther.myFeatures.begin(), theOther.myFeatures.end());
229 }
230
231 bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::isExist(
232     const EntityWrapperPtr& theEntity) const
233 {
234   if (theEntity->type() == ENTITY_POINT) {
235     if (theEntity->isExternal())
236       return myExternalPoints.find(theEntity) != myExternalPoints.end();
237     else
238       return myPoints.find(theEntity) != myPoints.end();
239   }
240
241   return myFeatures.find(theEntity) != myFeatures.end();
242 }
243
244 bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::isExist(
245     const GCS::Point& thePoint) const
246 {
247   return hasSamePoint(myExternalPoints, thePoint) || hasSamePoint(myPoints, thePoint);
248 }
249
250 EntityWrapperPtr PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::externalPoint() const
251 {
252   return myExternalPoints.empty() ? EntityWrapperPtr() : *myExternalPoints.begin();
253 }