Salome HOME
Updated copyright comment
[modules/shaper.git] / src / SketchSolver / PlaneGCSSolver / PlaneGCSSolver_UpdateCoincidence.cpp
index 1ac316855a6df221b2c2ed07e6bd43ce4cb27e94..d2f6a625433fe4c63a41d77ec0b18e4f7f82253a 100644 (file)
@@ -1,26 +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_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);
@@ -29,7 +49,9 @@ void PlaneGCSSolver_UpdateCoincidence::attach(SketchSolver_Constraint* theObserv
 void PlaneGCSSolver_UpdateCoincidence::update(const FeaturePtr& theFeature)
 {
   if (theFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
-      theFeature->getKind() == SketchPlugin_ConstraintMiddle::ID()) {
+      theFeature->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID() ||
+      theFeature->getKind() == SketchPlugin_ConstraintMiddle::ID() ||
+      theFeature->getKind() == SketchPlugin_ConstraintCollinear::ID()) {
     myCoincident.clear();
     // notify listeners and stop procesing
     std::list<SketchSolver_Constraint*>::iterator anIt = myObservers.begin();
@@ -49,58 +71,183 @@ 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<std::set<EntityWrapperPtr> >::iterator anIt = myCoincident.begin();
-  std::list<std::set<EntityWrapperPtr> >::iterator
-      aFound[2] = {myCoincident.end(), myCoincident.end()};
-
-  for (; anIt != myCoincident.end(); ++anIt) {
-    if (aFound[0] == myCoincident.end() && anIt->find(theEntity1) != anIt->end())
-      aFound[0] = anIt;
-    if (aFound[1] == myCoincident.end() && anIt->find(theEntity2) != anIt->end())
-      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
-    std::set<EntityWrapperPtr> aNewCoinc;
-    aNewCoinc.insert(theEntity1);
-    aNewCoinc.insert(theEntity2);
-    myCoincident.push_back(aNewCoinc);
-  } else if (aFound[0] == aFound[1]) // same group => already coincident
+    myCoincident.push_back(CoincidentEntities(theEntity1, theEntity2));
+  } 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 (theEntity1->type() == ENTITY_POINT && theEntity2->type() == ENTITY_POINT &&
-       (theEntity1->isExternal() || theEntity2->isExternal())) {
-      bool hasExternal = false;
-      for (int i = 0; i < 2 && !hasExternal; ++i) {
-        if (aFound[i] != myCoincident.end()) {
-          if (theEntity1->isExternal())
-            hasExternal = hasAnotherExternalPoint(*aFound[i], theEntity1);
-          if (!hasExternal && theEntity2->isExternal())
-            hasExternal = hasAnotherExternalPoint(*aFound[i], theEntity2);
-        }
-      }
-      if (hasExternal)
+  } 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;
+      }
     }
 
-    if (aFound[0] == myCoincident.end())
-      aFound[1]->insert(theEntity1);
-    else if (aFound[1] == myCoincident.end())
-      aFound[0]->insert(theEntity2);
-    else { // merge two groups
-      aFound[0]->insert(aFound[1]->begin(), aFound[1]->end());
-      myCoincident.erase(aFound[1]);
-    }
+    // merge
+    aFound[0]->merge(*aFound[1]);
+    myCoincident.erase(aFound[1]);
   }
 
   return isAccepted;
 }
+
+bool PlaneGCSSolver_UpdateCoincidence::isPointOnEntity(
+    const EntityWrapperPtr& thePoint,
+    const EntityWrapperPtr& theEntity)
+{
+  std::list<CoincidentEntities>::iterator anIt = findGroupOfCoincidence(thePoint);
+  if (anIt == myCoincident.end())
+    return false;
+
+  if (anIt->isExist(theEntity))
+    return true;
+
+  if (theEntity->type() == ENTITY_LINE) {
+    std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(
+        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);
+}
+
+
+
+
+
+static const GCS::Point& toPoint(const EntityWrapperPtr& theEntity)
+{
+  PointWrapperPtr aPoint = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theEntity);
+  return *(aPoint->point());
+}
+
+static double squareDistance(const GCS::Point& thePoint1, const GCS::Point& thePoint2)
+{
+  double dx = *thePoint1.x - *thePoint2.x;
+  double dy = *thePoint1.y - *thePoint2.y;
+  return dx * dx + dy * dy;
+}
+
+static bool hasSamePoint(const std::set<EntityWrapperPtr>& theList, const GCS::Point& thePoint)
+{
+  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;
+}
+
+bool hasSamePoint(const std::set<EntityWrapperPtr>& theList,
+                  const EntityWrapperPtr& thePoint)
+{
+  return hasSamePoint(theList, toPoint(thePoint));
+}
+
+
+PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::CoincidentEntities(
+    const EntityWrapperPtr& theEntity1,
+    const EntityWrapperPtr& theEntity2)
+{
+  add(theEntity1);
+  add(theEntity2);
+}
+
+bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::add(
+    const EntityWrapperPtr& theEntity)
+{
+  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;
+}
+
+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);
+}
+
+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::isExist(
+    const EntityWrapperPtr& theEntity) const
+{
+  if (theEntity->type() == ENTITY_POINT) {
+    if (theEntity->isExternal())
+      return myExternalPoints.find(theEntity) != myExternalPoints.end();
+    else
+      return myPoints.find(theEntity) != myPoints.end();
+  }
+
+  return myFeatures.find(theEntity) != myFeatures.end();
+}
+
+bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::isExist(
+    const GCS::Point& thePoint) const
+{
+  return hasSamePoint(myExternalPoints, thePoint) || hasSamePoint(myPoints, thePoint);
+}
+
+EntityWrapperPtr PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::externalPoint() const
+{
+  return myExternalPoints.empty() ? EntityWrapperPtr() : *myExternalPoints.begin();
+}