Salome HOME
Update copyrights
[modules/shaper.git] / src / SketchSolver / SketchSolver_ConstraintCollinear.cpp
index 194d47aa012ddbb9ab0b4ef7ef732f3e12b54f55..6ca71f8e6bf72e70db447227ffb5ba93375510fa 100644 (file)
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+// Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+//
+// 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 <SketchSolver_ConstraintCollinear.h>
-#include <SketchSolver_Manager.h>
+#include <SketchSolver_Error.h>
+
+#include <PlaneGCSSolver_ConstraintWrapper.h>
+#include <PlaneGCSSolver_EdgeWrapper.h>
+#include <PlaneGCSSolver_PointWrapper.h>
+#include <PlaneGCSSolver_UpdateCoincidence.h>
 
 #include <SketchPlugin_Line.h>
 
-SketchSolver_ConstraintCollinear::SketchSolver_ConstraintCollinear(ConstraintPtr theConstraint)
-  : SketchSolver_Constraint(theConstraint)
+static ConstraintWrapperPtr createPointsOnLine(
+    std::shared_ptr<PlaneGCSSolver_PointWrapper>  thePoint1,
+    std::shared_ptr<PlaneGCSSolver_PointWrapper>  thePoint2,
+    std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theLine)
 {
+  std::shared_ptr<GCS::Line> aGCSLine = std::dynamic_pointer_cast<GCS::Line>(theLine->entity());
+
+  std::list<GCSConstraintPtr> aConstrList;
+  if (thePoint1)
+    aConstrList.push_back( GCSConstraintPtr(
+        new GCS::ConstraintPointOnLine(*thePoint1->point(), *aGCSLine)) );
+  if (thePoint2)
+    aConstrList.push_back( GCSConstraintPtr(
+        new GCS::ConstraintPointOnLine(*thePoint2->point(), *aGCSLine)) );
+
+  return aConstrList.empty() ?  ConstraintWrapperPtr() : ConstraintWrapperPtr(
+      new PlaneGCSSolver_ConstraintWrapper(aConstrList, CONSTRAINT_COLLINEAR));
 }
 
-void SketchSolver_ConstraintCollinear::notifyCoincidenceChanged(
-    EntityWrapperPtr theCoincAttr1,
-    EntityWrapperPtr theCoincAttr2)
+
+void SketchSolver_ConstraintCollinear::process()
 {
-  bool used = true;
+  cleanErrorMsg();
+  if (!myBaseConstraint || !myStorage) {
+    // Not enough parameters are assigned
+    return;
+  }
+
+  EntityWrapperPtr aValue;
+  std::vector<EntityWrapperPtr> anAttributes;
+  getAttributes(aValue, anAttributes);
+  if (!myErrorMsg.empty())
+    return;
+  if (anAttributes.empty()) {
+    myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
+    return;
+  }
 
-  // obtain IDs of all boundary points of lines
-  EntityID aPointIDs[4];
   for (int i = 0; i < 2; ++i) {
-    AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-        myBaseConstraint->attribute(SketchPlugin_Constraint::ATTRIBUTE(i)));
-    if (!aRefAttr->object())
-      continue;
+    AttributeRefAttrPtr aRefAttr = myBaseConstraint->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
     FeaturePtr aLine = ModelAPI_Feature::feature(aRefAttr->object());
-    AttributePtr aLinePt = aLine->attribute(SketchPlugin_Line::START_ID());
-    aPointIDs[2*i] = myStorage->entity(aLinePt)->id();
-    aLinePt = aLine->attribute(SketchPlugin_Line::END_ID());
-    aPointIDs[2*i + 1] = myStorage->entity(aLinePt)->id();
+    myPoints[2*i] = myStorage->entity(aLine->attribute(SketchPlugin_Line::START_ID()));
+    myPoints[2*i + 1] = myStorage->entity(aLine->attribute(SketchPlugin_Line::END_ID()));
   }
 
-  EntityWrapperPtr anAttrs[2] = {theCoincAttr1, theCoincAttr2};
-  for (int i = 0; i < 2 && used; ++i) {
-    if (anAttrs[i]->baseAttribute())
-      used = used && isUsed(anAttrs[i]->baseAttribute());
-    else
-      used = used && isUsed(anAttrs[i]->baseFeature());
-
-    if (!used) {
-      if (anAttrs[i]->type() == ENTITY_POINT) {
-        EntityID anID = anAttrs[i]->id();
-        for (int j = 0; j < 4; ++j)
-          if (anID == aPointIDs[j]) {
-            used = true;
-            break;
-          }
-      }
+  myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateCoincidence::GROUP());
+  myStorage->notify(myBaseConstraint);
+}
+
+void SketchSolver_ConstraintCollinear::notify(const FeaturePtr&      theFeature,
+                                              PlaneGCSSolver_Update* theUpdater)
+{
+  if (theFeature == myBaseConstraint && myInSolver)
+    return; // the constraint is already being updated
+
+  PlaneGCSSolver_UpdateCoincidence* anUpdater =
+      static_cast<PlaneGCSSolver_UpdateCoincidence*>(theUpdater);
+
+  bool isPointOnOppositeLine[4];
+  std::list<EntityWrapperPtr>::reverse_iterator anIt = myAttributes.rbegin();
+  for (int i = 0; i < 2; ++i, ++anIt) {
+    isPointOnOppositeLine[2*i] = anUpdater->isPointOnEntity(myPoints[2*i], *anIt);
+    isPointOnOppositeLine[2*i + 1] = anUpdater->isPointOnEntity(myPoints[2*i + 1], *anIt);
+  }
+
+  // both points of one line is on another line => lines are already collinear,
+  // would like to show "conflicting constraints"
+  if (isPointOnOppositeLine[0] && isPointOnOppositeLine[1])
+    isPointOnOppositeLine[1] = false;
+  if (isPointOnOppositeLine[2] && isPointOnOppositeLine[3])
+    isPointOnOppositeLine[3] = false;
+
+  bool aConstraintToApply[4] = {false, false, false, false};
+  ConstraintWrapperPtr aNewConstraint;
+  std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoints[2];
+  std::shared_ptr<PlaneGCSSolver_EdgeWrapper> aLine;
+
+  if (isPointOnOppositeLine[0] || isPointOnOppositeLine[1]) {
+    // one of points of first line is already on the second line,
+    // make another point of first line to be coincident with second line
+    for (int i = 0; i < 2; ++i) {
+      if (isPointOnOppositeLine[i])
+        continue;
+
+      if (!myIsConstraintApplied[i])
+        aPoints[i] = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(myPoints[i]);
+      aConstraintToApply[i] = true;
     }
+    aLine = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(myAttributes.back());
+  } else {
+    // verify second line and add necessary constraints
+    for (int i = 0; i < 2; ++i) {
+      if (isPointOnOppositeLine[i + 2])
+        continue;
+
+      if (!myIsConstraintApplied[i+2])
+        aPoints[i] = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(myPoints[i + 2]);
+      aConstraintToApply[i+2] = true;
+    }
+    aLine = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(myAttributes.front());
+  }
+
+  bool isNew = false;
+  for (int i = 0; i < 4; ++i) {
+    if (aConstraintToApply[i] != myIsConstraintApplied[i])
+      isNew = true;
+    myIsConstraintApplied[i] = aConstraintToApply[i];
   }
 
-  if (used) {
-    remove();
-    process();
+  if (isNew) {
+    mySolverConstraint = createPointsOnLine(aPoints[0], aPoints[1], aLine);
+    if (myInSolver) {
+      myStorage->removeConstraint(myBaseConstraint);
+      myInSolver = false;
+    }
+    if (mySolverConstraint) {
+      myStorage->addConstraint(myBaseConstraint, mySolverConstraint);
+      myInSolver = true;
+    }
   }
 }