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