Salome HOME
Issue #2101: A point cannot be coincident to both, X and Y axises
[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 void PlaneGCSSolver_UpdateCoincidence::attach(SketchSolver_Constraint* theObserver,
17                                               const std::string& theType)
18 {
19   if (theType == GROUP()) {
20     std::list<SketchSolver_Constraint*>::iterator aPlaceToAdd = myObservers.end();
21     // point-point coincidence is placed first
22     if (theObserver->getType() == CONSTRAINT_PT_PT_COINCIDENT) {
23       for (aPlaceToAdd = myObservers.begin(); aPlaceToAdd != myObservers.end(); ++aPlaceToAdd)
24         if ((*aPlaceToAdd)->getType() != CONSTRAINT_PT_PT_COINCIDENT)
25           break;
26     }
27     myObservers.insert(aPlaceToAdd, theObserver);
28   } else
29     myNext->attach(theObserver, theType);
30 }
31
32 void PlaneGCSSolver_UpdateCoincidence::update(const FeaturePtr& theFeature)
33 {
34   if (theFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
35       theFeature->getKind() == SketchPlugin_ConstraintMiddle::ID() ||
36       theFeature->getKind() == SketchPlugin_ConstraintCollinear::ID()) {
37     myCoincident.clear();
38     // notify listeners and stop procesing
39     std::list<SketchSolver_Constraint*>::iterator anIt = myObservers.begin();
40     for (; anIt != myObservers.end(); ++anIt)
41       (*anIt)->notify(theFeature, this);
42   } else
43     myNext->update(theFeature);
44 }
45
46 static bool hasAnotherExternalPoint(const std::set<EntityWrapperPtr>& theCoincidences,
47                                     const EntityWrapperPtr& thePoint)
48 {
49   std::set<EntityWrapperPtr>::const_iterator anIt = theCoincidences.begin();
50   for (; anIt != theCoincidences.end(); ++anIt)
51     if ((*anIt)->type() == ENTITY_POINT && (*anIt)->isExternal() && *anIt != thePoint)
52       return true;
53   return false;
54 }
55
56 bool PlaneGCSSolver_UpdateCoincidence::checkCoincidence(
57     const EntityWrapperPtr& theEntity1,
58     const EntityWrapperPtr& theEntity2)
59 {
60   bool isAccepted = true;
61
62   std::list<CoincidentEntities>::iterator anIt = myCoincident.begin();
63   std::list<CoincidentEntities>::iterator
64       aFound[2] = {myCoincident.end(), myCoincident.end()};
65
66   for (; anIt != myCoincident.end(); ++anIt) {
67     if (anIt->isExist(theEntity1))
68       aFound[0] = anIt;
69     if (anIt->isExist(theEntity2))
70       aFound[1] = anIt;
71     if (aFound[0] != myCoincident.end() && aFound[1] != myCoincident.end())
72       break;
73   }
74
75   if (aFound[0] == myCoincident.end() && aFound[1] == myCoincident.end()) {
76     // new group of coincidence
77     myCoincident.push_back(CoincidentEntities(theEntity1, theEntity2));
78   } else if (aFound[0] == aFound[1]) // same group => already coincident
79     isAccepted = false;
80   else {
81     if (aFound[0] == myCoincident.end())
82       isAccepted = aFound[1]->isNewCoincidence(theEntity2, theEntity1);
83     else if (aFound[1] == myCoincident.end())
84       isAccepted = aFound[0]->isNewCoincidence(theEntity1, theEntity2);
85     else { // merge two groups
86       isAccepted = aFound[0]->isNewCoincidence(theEntity1, *(aFound[1]), theEntity2);
87       myCoincident.erase(aFound[1]);
88     }
89   }
90
91   return isAccepted;
92 }
93
94 bool PlaneGCSSolver_UpdateCoincidence::isPointOnEntity(
95     const EntityWrapperPtr& thePoint,
96     const EntityWrapperPtr& theEntity)
97 {
98   std::list<CoincidentEntities>::iterator anIt = myCoincident.begin();
99   for (; anIt != myCoincident.end(); ++anIt)
100     if (anIt->isExist(thePoint))
101       break;
102
103   if (anIt == myCoincident.end())
104     return false;
105
106   if (anIt->isExist(theEntity))
107     return true;
108
109   if (theEntity->type() == ENTITY_LINE) {
110     std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(
111         std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theEntity)->entity());
112     return anIt->isExist(aLine->p1) || anIt->isExist(aLine->p2);
113   }
114   return false;
115 }
116
117
118
119
120
121 PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::CoincidentEntities(
122     const EntityWrapperPtr& theEntity1,
123     const EntityWrapperPtr& theEntity2)
124 {
125   if (theEntity1->isExternal() && theEntity2->isExternal()) {
126     myExternalAndConnected[theEntity1] = std::set<EntityWrapperPtr>();
127     myExternalAndConnected[theEntity2] = std::set<EntityWrapperPtr>();
128   } else if (theEntity1->isExternal())
129     myExternalAndConnected[theEntity1].insert(theEntity2);
130   else if (theEntity2->isExternal())
131     myExternalAndConnected[theEntity2].insert(theEntity1);
132   else {
133     std::set<EntityWrapperPtr> aGroup;
134     aGroup.insert(theEntity1);
135     aGroup.insert(theEntity2);
136     myExternalAndConnected[EntityWrapperPtr()] = aGroup;
137   }
138 }
139
140 bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::hasExternal() const
141 {
142   return myExternalAndConnected.size() != 1 ||
143          myExternalAndConnected.find(EntityWrapperPtr()) == myExternalAndConnected.end();
144 }
145
146 bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::isExist(
147     const EntityWrapperPtr& theEntity) const
148 {
149   std::map<EntityWrapperPtr, std::set<EntityWrapperPtr> >::const_iterator
150       anIt = myExternalAndConnected.begin();
151   for (; anIt != myExternalAndConnected.end(); ++anIt)
152     if (anIt->first == theEntity ||
153         anIt->second.find(theEntity) != anIt->second.end())
154       return true;
155   return false;
156 }
157
158 static bool isEqual(const GCS::Point& thePoint1, const GCS::Point& thePoint2)
159 {
160   return thePoint1.x == thePoint2.x && thePoint1.y == thePoint2.y;
161 }
162
163 bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::isExist(
164     const GCS::Point& thePoint) const
165 {
166   std::map<EntityWrapperPtr, std::set<EntityWrapperPtr> >::const_iterator
167       anIt = myExternalAndConnected.begin();
168   for (; anIt != myExternalAndConnected.end(); ++anIt) {
169     if (anIt->first && anIt->first->type() == ENTITY_POINT) {
170       const GCSPointPtr& aPoint =
171           std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->first)->point();
172       if (isEqual(*aPoint, thePoint))
173         return true;
174     }
175
176     std::set<EntityWrapperPtr>::const_iterator anEntIt = anIt->second.begin();
177     for (; anEntIt != anIt->second.end(); ++anEntIt)
178       if ((*anEntIt)->type() == ENTITY_POINT) {
179         const GCSPointPtr& aPoint =
180             std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(*anEntIt)->point();
181         if (isEqual(*aPoint, thePoint))
182           return true;
183       }
184   }
185   return false;
186 }
187
188 bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::isNewCoincidence(
189     const EntityWrapperPtr& theEntityExist,
190     const EntityWrapperPtr& theOtherEntity)
191 {
192   if (theOtherEntity->isExternal()) {
193     if (hasExternal()) {
194       if (myExternalAndConnected.find(theOtherEntity) == myExternalAndConnected.end())
195         myExternalAndConnected[theOtherEntity] = std::set<EntityWrapperPtr>();
196       // check whether all external entities are edges
197       bool isNewCoinc = true;
198       std::map<EntityWrapperPtr, std::set<EntityWrapperPtr> >::iterator
199           anIt = myExternalAndConnected.begin();
200       for (; anIt != myExternalAndConnected.end() && isNewCoinc; ++anIt)
201         isNewCoinc = (anIt->first->type() != ENTITY_POINT);
202       return isNewCoinc;
203     } else {
204       myExternalAndConnected[theOtherEntity] = myExternalAndConnected[EntityWrapperPtr()];
205       myExternalAndConnected.erase(EntityWrapperPtr());
206       return true;
207     }
208   }
209
210   if (theEntityExist->isExternal()) {
211     myExternalAndConnected[theEntityExist].insert(theOtherEntity);
212     return true;
213   }
214
215   std::map<EntityWrapperPtr, std::set<EntityWrapperPtr> >::iterator
216       anIt = myExternalAndConnected.begin();
217   for (; anIt != myExternalAndConnected.end(); ++anIt)
218     if (anIt->second.find(theEntityExist) != anIt->second.end()) {
219       anIt->second.insert(theOtherEntity);
220       break;
221     }
222   return true;
223 }
224
225 bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::isNewCoincidence(
226     const EntityWrapperPtr&   theEntityExist,
227     const CoincidentEntities& theOtherGroup,
228     const EntityWrapperPtr&   theEntityInOtherGroup)
229 {
230   bool hasExt[2] = {hasExternal(), theOtherGroup.hasExternal()};
231   if (hasExt[0] && hasExt[1]) {
232     myExternalAndConnected.insert(theOtherGroup.myExternalAndConnected.begin(),
233                                   theOtherGroup.myExternalAndConnected.end());
234     return false;
235   } else if (!hasExt[0] && !hasExt[1]) {
236     std::map<EntityWrapperPtr, std::set<EntityWrapperPtr> >::const_iterator
237         aFound = theOtherGroup.myExternalAndConnected.find(EntityWrapperPtr());
238
239     myExternalAndConnected[EntityWrapperPtr()].insert(
240         aFound->second.begin(), aFound->second.end());
241     return true;
242   } else {
243     std::map<EntityWrapperPtr, std::set<EntityWrapperPtr> > aSource, aDest;
244     EntityWrapperPtr aTarget;
245     if (hasExt[0]) {
246       aDest = myExternalAndConnected;
247       aSource = theOtherGroup.myExternalAndConnected;
248       aTarget = theEntityExist;
249     } else {
250       aSource = myExternalAndConnected;
251       aDest = theOtherGroup.myExternalAndConnected;
252       aTarget = theEntityInOtherGroup;
253     }
254
255     std::map<EntityWrapperPtr, std::set<EntityWrapperPtr> >::const_iterator
256         aFound = aSource.find(EntityWrapperPtr());
257
258     std::map<EntityWrapperPtr, std::set<EntityWrapperPtr> >::iterator anIt = aDest.begin();
259     for (; anIt != aDest.end(); ++anIt)
260       if (anIt->first == aTarget ||
261           anIt->second.find(aTarget) != anIt->second.end()) {
262         anIt->second.insert(aFound->second.begin(), aFound->second.end());
263         break;
264       }
265     return true;
266   }
267   // impossible case
268   return false;
269 }