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