]> SALOME platform Git repositories - modules/shaper.git/blobdiff - src/SketchPlugin/SketchPlugin_Validators.cpp
Salome HOME
Fix for filtering non-periodic B-spline in Tangent constraint (issue #3158)
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_Validators.cpp
index 8e1bccbf6c655d459453992cfb33d4a09a6b2f5e..a541519adbc838f38c73c7ff6346b07b6fce7fa5 100644 (file)
 #include "SketchPlugin_Validators.h"
 
 #include "SketchPlugin_Arc.h"
+#include "SketchPlugin_BSpline.h"
+#include "SketchPlugin_BSplinePeriodic.h"
 #include "SketchPlugin_Circle.h"
 #include "SketchPlugin_ConstraintCoincidence.h"
+#include "SketchPlugin_ConstraintCoincidenceInternal.h"
 #include "SketchPlugin_ConstraintDistance.h"
 #include "SketchPlugin_ConstraintRigid.h"
 #include "SketchPlugin_ConstraintTangent.h"
 #include <GeomAPI_Lin.h>
 #include <GeomAPI_Edge.h>
 #include <GeomAPI_Vertex.h>
+
 #include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
 
 #include <algorithm>
 #include <cmath>
 
 const double tolerance = 1.e-7;
 
+static bool isSpline(FeaturePtr theFeature)
+{
+  return theFeature && (theFeature->getKind() == SketchPlugin_BSpline::ID() ||
+                        theFeature->getKind() == SketchPlugin_BSplinePeriodic::ID());
+}
+
+
 bool SketchPlugin_DistanceAttrValidator::isValid(const AttributePtr& theAttribute,
                                                  const std::list<std::string>& theArguments,
                                                  Events_InfoMessage& theError) const
@@ -155,28 +167,81 @@ bool SketchPlugin_TangentAttrValidator::isValid(const AttributePtr& theAttribute
 
   bool isObject = aRefAttr->isObject();
   ObjectPtr anObject = aRefAttr->object();
-  if (isObject && anObject.get()) {
-    FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
+  if (!isObject || !anObject.get()) {
+    theError = "It uses an empty object";
+    return false;
+  }
 
-    AttributeRefAttrPtr aOtherAttr = anAttributeFeature->data()->refattr(aParamA);
-    ObjectPtr aOtherObject = aOtherAttr->object();
-    FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
-    if (!aOtherFea)
-      return true;
+  FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
 
-    if (aRefFea->getKind() == SketchPlugin_Line::ID() &&
-        aOtherFea->getKind() == SketchPlugin_Line::ID()) {
-      theError = "Two segments cannot be tangent";
-      return false;
-    }
+  AttributeRefAttrPtr aOtherAttr = anAttributeFeature->data()->refattr(aParamA);
+  ObjectPtr aOtherObject = aOtherAttr->object();
+  FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
+  if (!aOtherFea)
     return true;
+
+  if (aRefFea->getKind() == SketchPlugin_Line::ID() &&
+      aOtherFea->getKind() == SketchPlugin_Line::ID()) {
+    theError = "Two segments cannot be tangent";
+    return false;
   }
-  else {
-    theError = "It uses an empty object";
+  else if (isSpline(aRefFea) && isSpline(aOtherFea)) {
+    theError = "Two B-splines cannot be tangent";
     return false;
   }
 
-  return true;
+  bool isValid = true;
+  bool hasSpline = isSpline(aRefFea);
+  if (!hasSpline && isSpline(aOtherFea)) {
+    hasSpline = true;
+    std::swap(aRefFea, aOtherFea);
+  }
+  if (hasSpline) {
+    auto isApplicableCoincidence = [](FeaturePtr theFeature, const std::string& theAttrName) {
+      AttributeRefAttrPtr aRefAttr = theFeature->refattr(theAttrName);
+      if (aRefAttr->isObject())
+        return false;
+      AttributePtr anAttr = aRefAttr->attr();
+      FeaturePtr anOwner = ModelAPI_Feature::feature(anAttr->owner());
+      AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
+      if (aPointAttr) {
+        return anOwner->getKind() == SketchPlugin_BSpline::ID() &&
+              (aPointAttr->id() == SketchPlugin_BSpline::START_ID() ||
+               aPointAttr->id() == SketchPlugin_BSpline::END_ID());
+      }
+
+      AttributePoint2DArrayPtr aPntArray =
+          std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(anAttr);
+      if (aPntArray && anOwner->getKind() == SketchPlugin_BSpline::ID()) {
+        // check index of the pole
+        AttributeIntegerPtr anIndex = theAttrName == SketchPlugin_Constraint::ENTITY_A() ?
+            theFeature->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A()) :
+            theFeature->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
+        return anIndex && (anIndex->value() == 0 || anIndex->value() == aPntArray->size() - 1);
+      }
+      return false;
+    };
+
+    isValid = false;
+    AttributePoint2DArrayPtr aBSplinePoles = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+        aRefFea->attribute(SketchPlugin_BSplineBase::POLES_ID()));
+    // additional check the B-spline edge and the other edge have a coincident boundary point
+    std::set<FeaturePtr> aCoincidences = SketchPlugin_Tools::findCoincidentConstraints(aRefFea);
+    for (std::set<FeaturePtr>::iterator anIt = aCoincidences.begin();
+         anIt != aCoincidences.end() && !isValid; ++anIt) {
+      std::set<FeaturePtr> aCoinc;
+      if (isApplicableCoincidence(*anIt, SketchPlugin_Constraint::ENTITY_A()))
+        SketchPlugin_Tools::findCoincidences(*anIt, SketchPlugin_Constraint::ENTITY_B(),
+                                             aCoinc, true);
+      else if (isApplicableCoincidence(*anIt, SketchPlugin_Constraint::ENTITY_B()))
+        SketchPlugin_Tools::findCoincidences(*anIt, SketchPlugin_Constraint::ENTITY_A(),
+                                             aCoinc, true);
+
+      isValid = aCoinc.find(aOtherFea) != aCoinc.end();
+    }
+  }
+
+  return isValid;
 }
 
 bool SketchPlugin_PerpendicularAttrValidator::isValid(const AttributePtr& theAttribute,
@@ -205,15 +270,17 @@ bool SketchPlugin_PerpendicularAttrValidator::isValid(const AttributePtr& theAtt
     AttributeRefAttrPtr aOtherAttr = anOwner->refattr(aParamA);
     ObjectPtr aOtherObject = aOtherAttr->object();
     FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
-    if (!aOtherFea)
-      return true;
 
     // at least one feature should be a line
     if (aRefFea->getKind() != SketchPlugin_Line::ID() &&
-        aOtherFea->getKind() != SketchPlugin_Line::ID()) {
+        aOtherFea && aOtherFea->getKind() != SketchPlugin_Line::ID()) {
       theError = "At least one feature should be a line";
       return false;
     }
+    else if (isSpline(aRefFea) || isSpline(aOtherFea)) {
+      theError = "B-spline is not supported";
+      return false;
+    }
   }
   else {
     theError = "It uses an empty object";
@@ -292,17 +359,9 @@ bool SketchPlugin_EqualAttrValidator::isValid(const AttributePtr& theAttribute,
   std::string aType[2];
   std::list<std::string> anArguments;
   for (int i = 0; i < 2; i++) {
-    ObjectPtr anObject = aRefAttr[i]->object();
-    if (!anObject.get()) {
-      theError = "An empty object is used.";
-      return false;
-    }
-
-    aFeature = ModelAPI_Feature::feature(anObject);
-    if (!aFeature.get()) {
-      theError = "An empty feature is used.";
-      return false;
-    }
+    aFeature = ModelAPI_Feature::feature(aRefAttr[i]->object());
+    if (!aFeature.get())
+      return true;
 
     aType[i] = aFeature->getKind();
     if (aFeature->getKind() != SketchPlugin_Line::ID() &&
@@ -974,7 +1033,7 @@ bool SketchPlugin_SplitValidator::isValid(const AttributePtr& theAttribute,
   GeomShapePtr anAttrShape = (*anEdgeShapes.begin())->shape();
   std::shared_ptr<SketchPlugin_Feature> aSFeature =
                                 std::dynamic_pointer_cast<SketchPlugin_Feature>(anAttrFeature);
-  if (!aSFeature)
+  if (!aSFeature || aSFeature->isCopy())
     return false;
   SketchPlugin_Sketch* aSketch = aSFeature->sketch();
 
@@ -1123,38 +1182,35 @@ bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute,
   std::shared_ptr<GeomAPI_Dir> aNormal = aPlane->direction();
   std::shared_ptr<GeomAPI_Pnt> anOrigin = aPlane->location();
 
+  bool aValid = true;
   if (anEdge->isLine()) {
     std::shared_ptr<GeomAPI_Lin> aLine = anEdge->line();
     std::shared_ptr<GeomAPI_Dir> aLineDir = aLine->direction();
     double aDot = fabs(aNormal->dot(aLineDir));
-    bool aValid = fabs(aDot - 1.0) >= tolerance * tolerance;
+    aValid = fabs(aDot - 1.0) >= tolerance * tolerance;
     if (!aValid)
       theError = "Error: Line is orthogonal to the sketch plane.";
-    return aValid;
   }
   else if (anEdge->isCircle() || anEdge->isArc()) {
     std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
     std::shared_ptr<GeomAPI_Dir> aCircNormal = aCircle->normal();
     double aDot = fabs(aNormal->dot(aCircNormal));
-    bool aValid = aDot >= tolerance * tolerance;
+    aValid = aDot >= tolerance * tolerance;
     if (!aValid)
       theError.arg(anEdge->isCircle() ? "Error: Circle is orthogonal to the sketch plane."
                                       : "Error: Arc is orthogonal to the sketch plane.");
-    return aValid;
   }
   else if (anEdge->isEllipse()) {
     std::shared_ptr<GeomAPI_Ellipse> anEllipse = anEdge->ellipse();
     std::shared_ptr<GeomAPI_Dir> anEllipseNormal = anEllipse->normal();
     double aDot = fabs(aNormal->dot(anEllipseNormal));
-    bool aValid = fabs(aDot - 1.0) <= tolerance * tolerance;
+    aValid = fabs(aDot - 1.0) <= tolerance * tolerance;
     if (!aValid)
       theError.arg(anEdge->isClosed() ? "Error: Ellipse is orthogonal to the sketch plane."
                                       : "Error: Elliptic Arc is orthogonal to the sketch plane.");
-    return aValid;
   }
 
-  theError = "Error: Selected object is not supported for projection.";
-  return false;
+  return aValid;
 }
 
 
@@ -1779,3 +1835,20 @@ bool SketchPlugin_MultiRotationAngleValidator::isValid(const AttributePtr& theAt
 
   return true;
 }
+
+bool SketchPlugin_BSplineValidator::isValid(const AttributePtr& theAttribute,
+                                            const std::list<std::string>& theArguments,
+                                            Events_InfoMessage& theError) const
+{
+  AttributePoint2DArrayPtr aPolesArray =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute);
+  if (!aPolesArray)
+    return false;
+
+  if (aPolesArray->size() < 2) {
+    theError = "Number of B-spline poles should be 2 or more";
+    return false;
+  }
+
+  return true;
+}