Salome HOME
Updated copyright comment
[modules/shaper.git] / src / SketchSolver / PlaneGCSSolver / PlaneGCSSolver_UpdateCoincidence.cpp
index 6e66ae26e36aecda630584ac3a0bea60b5db40e1..d2f6a625433fe4c63a41d77ec0b18e4f7f82253a 100644 (file)
@@ -1,29 +1,46 @@
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File:    PlaneGCSSolver_UpdateCoincidence.cpp
-// Created: 17 Feb 2017
-// Author:  Artem ZHIDKOV
+// Copyright (C) 2014-2024  CEA, EDF
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
 
 #include <PlaneGCSSolver_UpdateCoincidence.h>
-#include <PlaneGCSSolver_EntityWrapper.h>
+#include <PlaneGCSSolver_EdgeWrapper.h>
 #include <PlaneGCSSolver_PointWrapper.h>
 #include <SketchSolver_Constraint.h>
 
 #include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintCoincidenceInternal.h>
 #include <SketchPlugin_ConstraintCollinear.h>
 #include <SketchPlugin_ConstraintMiddle.h>
 
+static bool hasSamePoint(const std::set<EntityWrapperPtr>& theList,
+                         const EntityWrapperPtr& thePoint);
+
+
 void PlaneGCSSolver_UpdateCoincidence::attach(SketchSolver_Constraint* theObserver,
                                               const std::string& theType)
 {
   if (theType == GROUP()) {
     std::list<SketchSolver_Constraint*>::iterator aPlaceToAdd = myObservers.end();
-    // point-point coincidence is placed first
-    if (theObserver->getType() == CONSTRAINT_PT_PT_COINCIDENT) {
-      for (aPlaceToAdd = myObservers.begin(); aPlaceToAdd != myObservers.end(); ++aPlaceToAdd)
-        if ((*aPlaceToAdd)->getType() != CONSTRAINT_PT_PT_COINCIDENT)
-          break;
-    }
+    // point-point coincidence is placed first,
+    // other constraints are sorted by their type
+    for (aPlaceToAdd = myObservers.begin(); aPlaceToAdd != myObservers.end(); ++aPlaceToAdd)
+      if ((*aPlaceToAdd)->getType() > theObserver->getType())
+        break;
     myObservers.insert(aPlaceToAdd, theObserver);
   } else
     myNext->attach(theObserver, theType);
@@ -32,6 +49,7 @@ void PlaneGCSSolver_UpdateCoincidence::attach(SketchSolver_Constraint* theObserv
 void PlaneGCSSolver_UpdateCoincidence::update(const FeaturePtr& theFeature)
 {
   if (theFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
+      theFeature->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID() ||
       theFeature->getKind() == SketchPlugin_ConstraintMiddle::ID() ||
       theFeature->getKind() == SketchPlugin_ConstraintCollinear::ID()) {
     myCoincident.clear();
@@ -53,39 +71,42 @@ static bool hasAnotherExternalPoint(const std::set<EntityWrapperPtr>& theCoincid
   return false;
 }
 
-bool PlaneGCSSolver_UpdateCoincidence::checkCoincidence(
+bool PlaneGCSSolver_UpdateCoincidence::addCoincidence(
     const EntityWrapperPtr& theEntity1,
     const EntityWrapperPtr& theEntity2)
 {
   bool isAccepted = true;
-
-  std::list<CoincidentEntities>::iterator anIt = myCoincident.begin();
-  std::list<CoincidentEntities>::iterator
-      aFound[2] = {myCoincident.end(), myCoincident.end()};
-
-  for (; anIt != myCoincident.end(); ++anIt) {
-    if (anIt->isExist(theEntity1))
-      aFound[0] = anIt;
-    if (anIt->isExist(theEntity2))
-      aFound[1] = anIt;
-    if (aFound[0] != myCoincident.end() && aFound[1] != myCoincident.end())
-      break;
-  }
+  std::list<CoincidentEntities>::iterator aFound[2] = {
+    findGroupOfCoincidence(theEntity1),
+    findGroupOfCoincidence(theEntity2)
+  };
 
   if (aFound[0] == myCoincident.end() && aFound[1] == myCoincident.end()) {
     // new group of coincidence
     myCoincident.push_back(CoincidentEntities(theEntity1, theEntity2));
-  } else if (aFound[0] == aFound[1]) // same group => already coincident
+  } else if (aFound[0] == myCoincident.end()) {
+    isAccepted = addToGroupOfCoincidence(*aFound[1], theEntity1);
+  } else if (aFound[1] == myCoincident.end()) {
+    isAccepted = addToGroupOfCoincidence(*aFound[0], theEntity2);
+  } else if (aFound[0] == aFound[1]) { // same group => already coincident
     isAccepted = false;
-  else {
-    if (aFound[0] == myCoincident.end())
-      isAccepted = aFound[1]->isNewCoincidence(theEntity2, theEntity1);
-    else if (aFound[1] == myCoincident.end())
-      isAccepted = aFound[0]->isNewCoincidence(theEntity1, theEntity2);
-    else { // merge two groups
-      isAccepted = aFound[0]->isNewCoincidence(theEntity1, *(aFound[1]), theEntity2);
-      myCoincident.erase(aFound[1]);
+  } else { // merge two groups
+    // first check the external points are equal
+    EntityWrapperPtr anExternal0 = aFound[0]->externalPoint();
+    EntityWrapperPtr anExternal1 = aFound[1]->externalPoint();
+    if (anExternal0 && anExternal1) {
+      std::set<EntityWrapperPtr> anExtList;
+      anExtList.insert(anExternal0);
+      if (hasSamePoint(anExtList, anExternal1)) {
+        // no need to add coincidence, because all points are
+        // already coincident to correct external points
+        isAccepted = false;
+      }
     }
+
+    // merge
+    aFound[0]->merge(*aFound[1]);
+    myCoincident.erase(aFound[1]);
   }
 
   return isAccepted;
@@ -95,11 +116,7 @@ bool PlaneGCSSolver_UpdateCoincidence::isPointOnEntity(
     const EntityWrapperPtr& thePoint,
     const EntityWrapperPtr& theEntity)
 {
-  std::list<CoincidentEntities>::iterator anIt = myCoincident.begin();
-  for (; anIt != myCoincident.end(); ++anIt)
-    if (anIt->isExist(thePoint))
-      break;
-
+  std::list<CoincidentEntities>::iterator anIt = findGroupOfCoincidence(thePoint);
   if (anIt == myCoincident.end())
     return false;
 
@@ -108,156 +125,129 @@ bool PlaneGCSSolver_UpdateCoincidence::isPointOnEntity(
 
   if (theEntity->type() == ENTITY_LINE) {
     std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(
-        std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(theEntity)->entity());
+        std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theEntity)->entity());
     return anIt->isExist(aLine->p1) || anIt->isExist(aLine->p2);
   }
   return false;
 }
 
+std::list<PlaneGCSSolver_UpdateCoincidence::CoincidentEntities>::iterator
+  PlaneGCSSolver_UpdateCoincidence::findGroupOfCoincidence(const EntityWrapperPtr& theEntity)
+{
+  if (theEntity->type() != ENTITY_POINT)
+    return myCoincident.end();
+
+  std::list<CoincidentEntities>::iterator aFound = myCoincident.begin();
+  for (; aFound != myCoincident.end(); ++aFound)
+    if (aFound->isExist(theEntity))
+      break;
+  return aFound;
+}
+
+bool PlaneGCSSolver_UpdateCoincidence::addToGroupOfCoincidence(
+    CoincidentEntities& theGroup, const EntityWrapperPtr& theEntity)
+{
+  if (theGroup.isExist(theEntity))
+    return false;
+  return theGroup.add(theEntity);
+}
 
 
 
 
-PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::CoincidentEntities(
-    const EntityWrapperPtr& theEntity1,
-    const EntityWrapperPtr& theEntity2)
+
+static const GCS::Point& toPoint(const EntityWrapperPtr& theEntity)
 {
-  if (theEntity1->isExternal() && theEntity2->isExternal()) {
-    myExternalAndConnected[theEntity1] = std::set<EntityWrapperPtr>();
-    myExternalAndConnected[theEntity2] = std::set<EntityWrapperPtr>();
-  } else if (theEntity1->isExternal())
-    myExternalAndConnected[theEntity1].insert(theEntity2);
-  else if (theEntity2->isExternal())
-    myExternalAndConnected[theEntity2].insert(theEntity1);
-  else {
-    std::set<EntityWrapperPtr> aGroup;
-    aGroup.insert(theEntity1);
-    aGroup.insert(theEntity2);
-    myExternalAndConnected[EntityWrapperPtr()] = aGroup;
-  }
+  PointWrapperPtr aPoint = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theEntity);
+  return *(aPoint->point());
 }
 
-bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::hasExternal() const
+static double squareDistance(const GCS::Point& thePoint1, const GCS::Point& thePoint2)
 {
-  return myExternalAndConnected.size() != 1 ||
-         myExternalAndConnected.find(EntityWrapperPtr()) == myExternalAndConnected.end();
+  double dx = *thePoint1.x - *thePoint2.x;
+  double dy = *thePoint1.y - *thePoint2.y;
+  return dx * dx + dy * dy;
 }
 
-bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::isExist(
-    const EntityWrapperPtr& theEntity) const
+static bool hasSamePoint(const std::set<EntityWrapperPtr>& theList, const GCS::Point& thePoint)
 {
-  std::map<EntityWrapperPtr, std::set<EntityWrapperPtr> >::const_iterator
-      anIt = myExternalAndConnected.begin();
-  for (; anIt != myExternalAndConnected.end(); ++anIt)
-    if (anIt->first == theEntity ||
-        anIt->second.find(theEntity) != anIt->second.end())
+  std::set<EntityWrapperPtr>::const_iterator anIt = theList.begin();
+  for (; anIt != theList.end(); ++anIt)
+    if (squareDistance(thePoint, toPoint(*anIt)) < 1.e-14)
       return true;
   return false;
 }
 
-static bool isEqual(const GCS::Point& thePoint1, const GCS::Point& thePoint2)
+bool hasSamePoint(const std::set<EntityWrapperPtr>& theList,
+                  const EntityWrapperPtr& thePoint)
 {
-  return thePoint1.x == thePoint2.x && thePoint1.y == thePoint2.y;
+  return hasSamePoint(theList, toPoint(thePoint));
 }
 
-bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::isExist(
-    const GCS::Point& thePoint) const
-{
-  std::map<EntityWrapperPtr, std::set<EntityWrapperPtr> >::const_iterator
-      anIt = myExternalAndConnected.begin();
-  for (; anIt != myExternalAndConnected.end(); ++anIt) {
-    if (anIt->first && anIt->first->type() == ENTITY_POINT) {
-      const GCSPointPtr& aPoint =
-          std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->first)->point();
-      if (isEqual(*aPoint, thePoint))
-        return true;
-    }
 
-    std::set<EntityWrapperPtr>::const_iterator anEntIt = anIt->second.begin();
-    for (; anEntIt != anIt->second.end(); ++anEntIt)
-      if ((*anEntIt)->type() == ENTITY_POINT) {
-        const GCSPointPtr& aPoint =
-            std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(*anEntIt)->point();
-        if (isEqual(*aPoint, thePoint))
-          return true;
-      }
-  }
-  return false;
+PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::CoincidentEntities(
+    const EntityWrapperPtr& theEntity1,
+    const EntityWrapperPtr& theEntity2)
+{
+  add(theEntity1);
+  add(theEntity2);
 }
 
-bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::isNewCoincidence(
-    const EntityWrapperPtr& theEntityExist,
-    const EntityWrapperPtr& theOtherEntity)
+bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::add(
+    const EntityWrapperPtr& theEntity)
 {
-  if (theOtherEntity->isExternal()) {
-    if (hasExternal()) {
-      if (myExternalAndConnected.find(theOtherEntity) == myExternalAndConnected.end())
-        myExternalAndConnected[theOtherEntity] = std::set<EntityWrapperPtr>();
-      return false;
-    } else {
-      myExternalAndConnected[theOtherEntity] = myExternalAndConnected[EntityWrapperPtr()];
-      myExternalAndConnected.erase(EntityWrapperPtr());
-      return true;
-    }
-  }
+  bool isAdded = true;
+  if (theEntity->type() == ENTITY_POINT) {
+    if (theEntity->isExternal()) {
+      isAdded = !hasSamePoint(myExternalPoints, theEntity);
+      myExternalPoints.insert(theEntity);
+    } else
+      myPoints.insert(theEntity);
+  } else
+    myFeatures.insert(theEntity);
+  return isAdded;
+}
 
-  if (theEntityExist->isExternal()) {
-    myExternalAndConnected[theEntityExist].insert(theOtherEntity);
-    return true;
-  }
+void PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::remove(
+    const EntityWrapperPtr& theEntity)
+{
+  if (theEntity->type() == ENTITY_POINT) {
+    if (theEntity->isExternal())
+      myExternalPoints.erase(theEntity);
+    else
+      myPoints.erase(theEntity);
+  } else
+    myFeatures.erase(theEntity);
+}
 
-  std::map<EntityWrapperPtr, std::set<EntityWrapperPtr> >::iterator
-      anIt = myExternalAndConnected.begin();
-  for (; anIt != myExternalAndConnected.end(); ++anIt)
-    if (anIt->second.find(theEntityExist) != anIt->second.end()) {
-      anIt->second.insert(theOtherEntity);
-      break;
-    }
-  return true;
+void PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::merge(
+    const CoincidentEntities& theOther)
+{
+  myExternalPoints.insert(theOther.myExternalPoints.begin(), theOther.myExternalPoints.end());
+  myPoints.insert(theOther.myPoints.begin(), theOther.myPoints.end());
+  myFeatures.insert(theOther.myFeatures.begin(), theOther.myFeatures.end());
 }
 
-bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::isNewCoincidence(
-    const EntityWrapperPtr&   theEntityExist,
-    const CoincidentEntities& theOtherGroup,
-    const EntityWrapperPtr&   theEntityInOtherGroup)
+bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::isExist(
+    const EntityWrapperPtr& theEntity) const
 {
-  bool hasExt[2] = {hasExternal(), theOtherGroup.hasExternal()};
-  if (hasExt[0] && hasExt[1]) {
-    myExternalAndConnected.insert(theOtherGroup.myExternalAndConnected.begin(),
-                                  theOtherGroup.myExternalAndConnected.end());
-    return false;
-  } else if (!hasExt[0] && !hasExt[1]) {
-    std::map<EntityWrapperPtr, std::set<EntityWrapperPtr> >::const_iterator
-        aFound = theOtherGroup.myExternalAndConnected.find(EntityWrapperPtr());
+  if (theEntity->type() == ENTITY_POINT) {
+    if (theEntity->isExternal())
+      return myExternalPoints.find(theEntity) != myExternalPoints.end();
+    else
+      return myPoints.find(theEntity) != myPoints.end();
+  }
 
-    myExternalAndConnected[EntityWrapperPtr()].insert(
-        aFound->second.begin(), aFound->second.end());
-    return true;
-  } else {
-    std::map<EntityWrapperPtr, std::set<EntityWrapperPtr> > aSource, aDest;
-    EntityWrapperPtr aTarget;
-    if (hasExt[0]) {
-      aDest = myExternalAndConnected;
-      aSource = theOtherGroup.myExternalAndConnected;
-      aTarget = theEntityExist;
-    } else {
-      aSource = myExternalAndConnected;
-      aDest = theOtherGroup.myExternalAndConnected;
-      aTarget = theEntityInOtherGroup;
-    }
+  return myFeatures.find(theEntity) != myFeatures.end();
+}
 
-    std::map<EntityWrapperPtr, std::set<EntityWrapperPtr> >::const_iterator
-        aFound = aSource.find(EntityWrapperPtr());
+bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::isExist(
+    const GCS::Point& thePoint) const
+{
+  return hasSamePoint(myExternalPoints, thePoint) || hasSamePoint(myPoints, thePoint);
+}
 
-    std::map<EntityWrapperPtr, std::set<EntityWrapperPtr> >::iterator anIt = aDest.begin();
-    for (; anIt != aDest.end(); ++anIt)
-      if (anIt->first == aTarget ||
-          anIt->second.find(aTarget) != anIt->second.end()) {
-        anIt->second.insert(aFound->second.begin(), aFound->second.end());
-        break;
-      }
-    return true;
-  }
-  // impossible case
-  return false;
+EntityWrapperPtr PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::externalPoint() const
+{
+  return myExternalPoints.empty() ? EntityWrapperPtr() : *myExternalPoints.begin();
 }