1 // Copyright (C) 2014-2023 CEA, EDF
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include <PlaneGCSSolver_UpdateCoincidence.h>
21 #include <PlaneGCSSolver_EdgeWrapper.h>
22 #include <PlaneGCSSolver_PointWrapper.h>
23 #include <SketchSolver_Constraint.h>
25 #include <SketchPlugin_ConstraintCoincidence.h>
26 #include <SketchPlugin_ConstraintCoincidenceInternal.h>
27 #include <SketchPlugin_ConstraintCollinear.h>
28 #include <SketchPlugin_ConstraintMiddle.h>
30 static bool hasSamePoint(const std::set<EntityWrapperPtr>& theList,
31 const EntityWrapperPtr& thePoint);
34 void PlaneGCSSolver_UpdateCoincidence::attach(SketchSolver_Constraint* theObserver,
35 const std::string& theType)
37 if (theType == GROUP()) {
38 std::list<SketchSolver_Constraint*>::iterator aPlaceToAdd = myObservers.end();
39 // point-point coincidence is placed first,
40 // other constraints are sorted by their type
41 for (aPlaceToAdd = myObservers.begin(); aPlaceToAdd != myObservers.end(); ++aPlaceToAdd)
42 if ((*aPlaceToAdd)->getType() > theObserver->getType())
44 myObservers.insert(aPlaceToAdd, theObserver);
46 myNext->attach(theObserver, theType);
49 void PlaneGCSSolver_UpdateCoincidence::update(const FeaturePtr& theFeature)
51 if (theFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
52 theFeature->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID() ||
53 theFeature->getKind() == SketchPlugin_ConstraintMiddle::ID() ||
54 theFeature->getKind() == SketchPlugin_ConstraintCollinear::ID()) {
56 // notify listeners and stop procesing
57 std::list<SketchSolver_Constraint*>::iterator anIt = myObservers.begin();
58 for (; anIt != myObservers.end(); ++anIt)
59 (*anIt)->notify(theFeature, this);
61 myNext->update(theFeature);
64 static bool hasAnotherExternalPoint(const std::set<EntityWrapperPtr>& theCoincidences,
65 const EntityWrapperPtr& thePoint)
67 std::set<EntityWrapperPtr>::const_iterator anIt = theCoincidences.begin();
68 for (; anIt != theCoincidences.end(); ++anIt)
69 if ((*anIt)->type() == ENTITY_POINT && (*anIt)->isExternal() && *anIt != thePoint)
74 bool PlaneGCSSolver_UpdateCoincidence::addCoincidence(
75 const EntityWrapperPtr& theEntity1,
76 const EntityWrapperPtr& theEntity2)
78 bool isAccepted = true;
79 std::list<CoincidentEntities>::iterator aFound[2] = {
80 findGroupOfCoincidence(theEntity1),
81 findGroupOfCoincidence(theEntity2)
84 if (aFound[0] == myCoincident.end() && aFound[1] == myCoincident.end()) {
85 // new group of coincidence
86 myCoincident.push_back(CoincidentEntities(theEntity1, theEntity2));
87 } else if (aFound[0] == myCoincident.end()) {
88 isAccepted = addToGroupOfCoincidence(*aFound[1], theEntity1);
89 } else if (aFound[1] == myCoincident.end()) {
90 isAccepted = addToGroupOfCoincidence(*aFound[0], theEntity2);
91 } else if (aFound[0] == aFound[1]) { // same group => already coincident
93 } else { // merge two groups
94 // first check the external points are equal
95 EntityWrapperPtr anExternal0 = aFound[0]->externalPoint();
96 EntityWrapperPtr anExternal1 = aFound[1]->externalPoint();
97 if (anExternal0 && anExternal1) {
98 std::set<EntityWrapperPtr> anExtList;
99 anExtList.insert(anExternal0);
100 if (hasSamePoint(anExtList, anExternal1)) {
101 // no need to add coincidence, because all points are
102 // already coincident to correct external points
108 aFound[0]->merge(*aFound[1]);
109 myCoincident.erase(aFound[1]);
115 bool PlaneGCSSolver_UpdateCoincidence::isPointOnEntity(
116 const EntityWrapperPtr& thePoint,
117 const EntityWrapperPtr& theEntity)
119 std::list<CoincidentEntities>::iterator anIt = findGroupOfCoincidence(thePoint);
120 if (anIt == myCoincident.end())
123 if (anIt->isExist(theEntity))
126 if (theEntity->type() == ENTITY_LINE) {
127 std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(
128 std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theEntity)->entity());
129 return anIt->isExist(aLine->p1) || anIt->isExist(aLine->p2);
134 std::list<PlaneGCSSolver_UpdateCoincidence::CoincidentEntities>::iterator
135 PlaneGCSSolver_UpdateCoincidence::findGroupOfCoincidence(const EntityWrapperPtr& theEntity)
137 if (theEntity->type() != ENTITY_POINT)
138 return myCoincident.end();
140 std::list<CoincidentEntities>::iterator aFound = myCoincident.begin();
141 for (; aFound != myCoincident.end(); ++aFound)
142 if (aFound->isExist(theEntity))
147 bool PlaneGCSSolver_UpdateCoincidence::addToGroupOfCoincidence(
148 CoincidentEntities& theGroup, const EntityWrapperPtr& theEntity)
150 if (theGroup.isExist(theEntity))
152 return theGroup.add(theEntity);
159 static const GCS::Point& toPoint(const EntityWrapperPtr& theEntity)
161 PointWrapperPtr aPoint = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theEntity);
162 return *(aPoint->point());
165 static double squareDistance(const GCS::Point& thePoint1, const GCS::Point& thePoint2)
167 double dx = *thePoint1.x - *thePoint2.x;
168 double dy = *thePoint1.y - *thePoint2.y;
169 return dx * dx + dy * dy;
172 static bool hasSamePoint(const std::set<EntityWrapperPtr>& theList, const GCS::Point& thePoint)
174 std::set<EntityWrapperPtr>::const_iterator anIt = theList.begin();
175 for (; anIt != theList.end(); ++anIt)
176 if (squareDistance(thePoint, toPoint(*anIt)) < 1.e-14)
181 bool hasSamePoint(const std::set<EntityWrapperPtr>& theList,
182 const EntityWrapperPtr& thePoint)
184 return hasSamePoint(theList, toPoint(thePoint));
188 PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::CoincidentEntities(
189 const EntityWrapperPtr& theEntity1,
190 const EntityWrapperPtr& theEntity2)
196 bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::add(
197 const EntityWrapperPtr& theEntity)
200 if (theEntity->type() == ENTITY_POINT) {
201 if (theEntity->isExternal()) {
202 isAdded = !hasSamePoint(myExternalPoints, theEntity);
203 myExternalPoints.insert(theEntity);
205 myPoints.insert(theEntity);
207 myFeatures.insert(theEntity);
211 void PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::remove(
212 const EntityWrapperPtr& theEntity)
214 if (theEntity->type() == ENTITY_POINT) {
215 if (theEntity->isExternal())
216 myExternalPoints.erase(theEntity);
218 myPoints.erase(theEntity);
220 myFeatures.erase(theEntity);
223 void PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::merge(
224 const CoincidentEntities& theOther)
226 myExternalPoints.insert(theOther.myExternalPoints.begin(), theOther.myExternalPoints.end());
227 myPoints.insert(theOther.myPoints.begin(), theOther.myPoints.end());
228 myFeatures.insert(theOther.myFeatures.begin(), theOther.myFeatures.end());
231 bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::isExist(
232 const EntityWrapperPtr& theEntity) const
234 if (theEntity->type() == ENTITY_POINT) {
235 if (theEntity->isExternal())
236 return myExternalPoints.find(theEntity) != myExternalPoints.end();
238 return myPoints.find(theEntity) != myPoints.end();
241 return myFeatures.find(theEntity) != myFeatures.end();
244 bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::isExist(
245 const GCS::Point& thePoint) const
247 return hasSamePoint(myExternalPoints, thePoint) || hasSamePoint(myPoints, thePoint);
250 EntityWrapperPtr PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::externalPoint() const
252 return myExternalPoints.empty() ? EntityWrapperPtr() : *myExternalPoints.begin();