Salome HOME
Adjust processing of multi coincidences
[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 <SketchSolver_Constraint.h>
9
10 #include <SketchPlugin_ConstraintCoincidence.h>
11 #include <SketchPlugin_ConstraintMiddle.h>
12
13 void PlaneGCSSolver_UpdateCoincidence::attach(SketchSolver_Constraint* theObserver,
14                                               const std::string& theType)
15 {
16   if (theType == GROUP()) {
17     std::list<SketchSolver_Constraint*>::iterator aPlaceToAdd = myObservers.end();
18     // point-point coincidence is placed first
19     if (theObserver->getType() == CONSTRAINT_PT_PT_COINCIDENT) {
20       for (aPlaceToAdd = myObservers.begin(); aPlaceToAdd != myObservers.end(); ++aPlaceToAdd)
21         if ((*aPlaceToAdd)->getType() != CONSTRAINT_PT_PT_COINCIDENT)
22           break;
23     }
24     myObservers.insert(aPlaceToAdd, theObserver);
25   } else
26     myNext->attach(theObserver, theType);
27 }
28
29 void PlaneGCSSolver_UpdateCoincidence::update(const FeaturePtr& theFeature)
30 {
31   if (theFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
32       theFeature->getKind() == SketchPlugin_ConstraintMiddle::ID()) {
33     myCoincident.clear();
34     // notify listeners and stop procesing
35     std::list<SketchSolver_Constraint*>::iterator anIt = myObservers.begin();
36     for (; anIt != myObservers.end(); ++anIt)
37       (*anIt)->notify(theFeature, this);
38   } else
39     myNext->update(theFeature);
40 }
41
42 static bool hasAnotherExternalPoint(const std::set<EntityWrapperPtr>& theCoincidences,
43                                     const EntityWrapperPtr& thePoint)
44 {
45   std::set<EntityWrapperPtr>::const_iterator anIt = theCoincidences.begin();
46   for (; anIt != theCoincidences.end(); ++anIt)
47     if ((*anIt)->type() == ENTITY_POINT && (*anIt)->isExternal() && *anIt != thePoint)
48       return true;
49   return false;
50 }
51
52 bool PlaneGCSSolver_UpdateCoincidence::checkCoincidence(
53     const EntityWrapperPtr& theEntity1,
54     const EntityWrapperPtr& theEntity2)
55 {
56   bool isAccepted = true;
57
58   std::list<CoincidentEntities>::iterator anIt = myCoincident.begin();
59   std::list<CoincidentEntities>::iterator
60       aFound[2] = {myCoincident.end(), myCoincident.end()};
61
62   for (; anIt != myCoincident.end(); ++anIt) {
63     if (anIt->isExist(theEntity1))
64       aFound[0] = anIt;
65     if (anIt->isExist(theEntity2))
66       aFound[1] = anIt;
67     if (aFound[0] != myCoincident.end() && aFound[1] != myCoincident.end())
68       break;
69   }
70
71   if (aFound[0] == myCoincident.end() && aFound[1] == myCoincident.end()) {
72     // new group of coincidence
73     myCoincident.push_back(CoincidentEntities(theEntity1, theEntity2));
74   } else if (aFound[0] == aFound[1]) // same group => already coincident
75     isAccepted = false;
76   else {
77     if (aFound[0] == myCoincident.end())
78       isAccepted = aFound[1]->isNewCoincidence(theEntity2, theEntity1);
79     else if (aFound[1] == myCoincident.end())
80       isAccepted = aFound[0]->isNewCoincidence(theEntity1, theEntity2);
81     else { // merge two groups
82       isAccepted = aFound[0]->isNewCoincidence(theEntity1, *(aFound[1]), theEntity2);
83       myCoincident.erase(aFound[1]);
84     }
85   }
86
87   return isAccepted;
88 }
89
90
91
92
93 PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::CoincidentEntities(
94     const EntityWrapperPtr& theEntity1,
95     const EntityWrapperPtr& theEntity2)
96 {
97   if (theEntity1->isExternal() && theEntity2->isExternal()) {
98     myExternalAndConnected[theEntity1] = std::set<EntityWrapperPtr>();
99     myExternalAndConnected[theEntity2] = std::set<EntityWrapperPtr>();
100   } else if (theEntity1->isExternal())
101     myExternalAndConnected[theEntity1].insert(theEntity2);
102   else if (theEntity2->isExternal())
103     myExternalAndConnected[theEntity2].insert(theEntity1);
104   else {
105     std::set<EntityWrapperPtr> aGroup;
106     aGroup.insert(theEntity1);
107     aGroup.insert(theEntity2);
108     myExternalAndConnected[EntityWrapperPtr()] = aGroup;
109   }
110 }
111
112 bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::hasExternal() const
113 {
114   return myExternalAndConnected.size() != 1 ||
115          myExternalAndConnected.find(EntityWrapperPtr()) == myExternalAndConnected.end();
116 }
117
118 bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::isExist(
119     const EntityWrapperPtr& theEntity) const
120 {
121   std::map<EntityWrapperPtr, std::set<EntityWrapperPtr> >::const_iterator
122       anIt = myExternalAndConnected.begin();
123   for (; anIt != myExternalAndConnected.end(); ++anIt)
124     if (anIt->first == theEntity ||
125         anIt->second.find(theEntity) != anIt->second.end())
126       return true;
127   return false;
128 }
129
130 bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::isNewCoincidence(
131     const EntityWrapperPtr& theEntityExist,
132     const EntityWrapperPtr& theOtherEntity)
133 {
134   if (theOtherEntity->isExternal()) {
135     if (hasExternal()) {
136       if (myExternalAndConnected.find(theOtherEntity) == myExternalAndConnected.end())
137         myExternalAndConnected[theOtherEntity] = std::set<EntityWrapperPtr>();
138       return false;
139     } else {
140       myExternalAndConnected[theOtherEntity] = myExternalAndConnected[EntityWrapperPtr()];
141       myExternalAndConnected.erase(EntityWrapperPtr());
142       return true;
143     }
144   }
145
146   if (theEntityExist->isExternal()) {
147     myExternalAndConnected[theEntityExist].insert(theOtherEntity);
148     return true;
149   }
150
151   std::map<EntityWrapperPtr, std::set<EntityWrapperPtr> >::iterator
152       anIt = myExternalAndConnected.begin();
153   for (; anIt != myExternalAndConnected.end(); ++anIt)
154     if (anIt->second.find(theEntityExist) != anIt->second.end()) {
155       anIt->second.insert(theOtherEntity);
156       break;
157     }
158   return true;
159 }
160
161 bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::isNewCoincidence(
162     const EntityWrapperPtr&   theEntityExist,
163     const CoincidentEntities& theOtherGroup,
164     const EntityWrapperPtr&   theEntityInOtherGroup)
165 {
166   bool hasExt[2] = {hasExternal(), theOtherGroup.hasExternal()};
167   if (hasExt[0] && hasExt[1]) {
168     myExternalAndConnected.insert(theOtherGroup.myExternalAndConnected.begin(),
169                                   theOtherGroup.myExternalAndConnected.end());
170     return false;
171   } else if (!hasExt[0] && !hasExt[1]) {
172     std::map<EntityWrapperPtr, std::set<EntityWrapperPtr> >::const_iterator
173         aFound = theOtherGroup.myExternalAndConnected.find(EntityWrapperPtr());
174
175     myExternalAndConnected[EntityWrapperPtr()].insert(
176         aFound->second.begin(), aFound->second.end());
177     return true;
178   } else {
179     std::map<EntityWrapperPtr, std::set<EntityWrapperPtr> > aSource, aDest;
180     EntityWrapperPtr aTarget;
181     if (hasExt[0]) {
182       aDest = myExternalAndConnected;
183       aSource = theOtherGroup.myExternalAndConnected;
184       aTarget = theEntityExist;
185     } else {
186       aSource = myExternalAndConnected;
187       aDest = theOtherGroup.myExternalAndConnected;
188       aTarget = theEntityInOtherGroup;
189     }
190
191     std::map<EntityWrapperPtr, std::set<EntityWrapperPtr> >::const_iterator
192         aFound = aSource.find(EntityWrapperPtr());
193
194     std::map<EntityWrapperPtr, std::set<EntityWrapperPtr> >::iterator anIt = aDest.begin();
195     for (; anIt != aDest.end(); ++anIt)
196       if (anIt->first == aTarget ||
197           anIt->second.find(aTarget) != anIt->second.end()) {
198         anIt->second.insert(aFound->second.begin(), aFound->second.end());
199         break;
200       }
201     return true;
202   }
203   // impossible case
204   return false;
205 }