Salome HOME
Issues #2150 and #2151: Frequently appeared "Conflicting constraints" message for...
[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::addCoincidence(
56     const EntityWrapperPtr& theEntity1,
57     const EntityWrapperPtr& theEntity2)
58 {
59   bool isAccepted = true;
60   std::list<CoincidentEntities>::iterator aFound[2] = {
61     findGroupOfCoincidence(theEntity1),
62     findGroupOfCoincidence(theEntity2)
63   };
64
65   if (aFound[0] == myCoincident.end() && aFound[1] == myCoincident.end()) {
66     // new group of coincidence
67     myCoincident.push_back(CoincidentEntities(theEntity1, theEntity2));
68   } else if (aFound[0] == myCoincident.end()) {
69     isAccepted = addToGroupOfCoincidence(*aFound[1], theEntity1);
70   } else if (aFound[1] == myCoincident.end()) {
71     isAccepted = addToGroupOfCoincidence(*aFound[0], theEntity2);
72   } else if (aFound[0] == aFound[1]) { // same group => already coincident
73     isAccepted = false;
74   } else { // merge two groups
75     EntityWrapperPtr anEntityToAdd = theEntity1;
76     if (theEntity1->isExternal()) { // swap found groups;
77       anEntityToAdd = theEntity2;
78       std::list<CoincidentEntities>::iterator aTempIt = aFound[0];
79       aFound[0] = aFound[1];
80       aFound[1] = aTempIt;
81     }
82
83     aFound[1]->remove(anEntityToAdd);
84     aFound[0]->merge(*aFound[1]);
85     isAccepted = aFound[0]->add(anEntityToAdd);
86     myCoincident.erase(aFound[1]);
87   }
88
89   return isAccepted;
90 }
91
92 bool PlaneGCSSolver_UpdateCoincidence::isPointOnEntity(
93     const EntityWrapperPtr& thePoint,
94     const EntityWrapperPtr& theEntity)
95 {
96   std::list<CoincidentEntities>::iterator anIt = findGroupOfCoincidence(thePoint);
97   if (anIt == myCoincident.end())
98     return false;
99
100   if (anIt->isExist(theEntity))
101     return true;
102
103   if (theEntity->type() == ENTITY_LINE) {
104     std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(
105         std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theEntity)->entity());
106     return anIt->isExist(aLine->p1) || anIt->isExist(aLine->p2);
107   }
108   return false;
109 }
110
111 std::list<PlaneGCSSolver_UpdateCoincidence::CoincidentEntities>::iterator
112   PlaneGCSSolver_UpdateCoincidence::findGroupOfCoincidence(const EntityWrapperPtr& theEntity)
113 {
114   if (theEntity->type() != ENTITY_POINT)
115     return myCoincident.end();
116
117   std::list<CoincidentEntities>::iterator aFound = myCoincident.begin();
118   for (; aFound != myCoincident.end(); ++aFound)
119     if (aFound->isExist(theEntity))
120       break;
121   return aFound;
122 }
123
124 bool PlaneGCSSolver_UpdateCoincidence::addToGroupOfCoincidence(
125     CoincidentEntities& theGroup, const EntityWrapperPtr& theEntity)
126 {
127   if (theGroup.isExist(theEntity))
128     return false;
129
130   theGroup.add(theEntity);
131   return true;
132 }
133
134
135
136
137
138 static const GCS::Point& toPoint(const EntityWrapperPtr& theEntity)
139 {
140   PointWrapperPtr aPoint = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theEntity);
141   return *(aPoint->point());
142 }
143
144 static double squareDistance(const GCS::Point& thePoint1, const GCS::Point& thePoint2)
145 {
146   double dx = *thePoint1.x - *thePoint2.x;
147   double dy = *thePoint1.y - *thePoint2.y;
148   return dx * dx + dy * dy;
149 }
150
151 static bool hasSamePoint(const std::set<EntityWrapperPtr>& theList, const GCS::Point& thePoint)
152 {
153   std::set<EntityWrapperPtr>::const_iterator anIt = theList.begin();
154   for (; anIt != theList.end(); ++anIt)
155     if (squareDistance(thePoint, toPoint(*anIt)) < 1.e-14)
156       return true;
157   return false;
158 }
159
160 static bool hasSamePoint(const std::set<EntityWrapperPtr>& theList, const EntityWrapperPtr& thePoint)
161 {
162   return hasSamePoint(theList, toPoint(thePoint));
163 }
164
165
166 PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::CoincidentEntities(
167     const EntityWrapperPtr& theEntity1,
168     const EntityWrapperPtr& theEntity2)
169 {
170   add(theEntity1);
171   add(theEntity2);
172 }
173
174 bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::add(
175     const EntityWrapperPtr& theEntity)
176 {
177   bool isAdded = true;
178   if (theEntity->type() == ENTITY_POINT) {
179     if (theEntity->isExternal()) {
180       isAdded = !hasSamePoint(myExternalPoints, theEntity);
181       myExternalPoints.insert(theEntity);
182     } else
183       myPoints.insert(theEntity);
184   } else
185     myFeatures.insert(theEntity);
186   return isAdded;
187 }
188
189 void PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::remove(
190     const EntityWrapperPtr& theEntity)
191 {
192   if (theEntity->type() == ENTITY_POINT) {
193     if (theEntity->isExternal())
194       myExternalPoints.erase(theEntity);
195     else
196       myPoints.erase(theEntity);
197   } else
198     myFeatures.erase(theEntity);
199 }
200
201 void PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::merge(
202     const CoincidentEntities& theOther)
203 {
204   myExternalPoints.insert(theOther.myExternalPoints.begin(), theOther.myExternalPoints.end());
205   myPoints.insert(theOther.myPoints.begin(), theOther.myPoints.end());
206   myFeatures.insert(theOther.myFeatures.begin(), theOther.myFeatures.end());
207 }
208
209 bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::isExist(
210     const EntityWrapperPtr& theEntity) const
211 {
212   if (theEntity->type() == ENTITY_POINT) {
213     if (theEntity->isExternal())
214       return myExternalPoints.find(theEntity) != myExternalPoints.end();
215     else
216       return myPoints.find(theEntity) != myPoints.end();
217   }
218
219   return myFeatures.find(theEntity) != myFeatures.end();
220 }
221
222 bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::isExist(
223     const GCS::Point& thePoint) const
224 {
225   return hasSamePoint(myExternalPoints, thePoint) || hasSamePoint(myPoints, thePoint);
226 }