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