Salome HOME
Using test for testing number of sub-shapes.
[modules/shaper.git] / src / SketchSolver / SketchSolver_ConstraintTangent.cpp
index 37b59fab2b61808d8e48756d107d95e6ed857f90..690587ae238e72030798244b7912f75e8331932d 100644 (file)
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
 #include <SketchSolver_ConstraintTangent.h>
-#include <SketchSolver_Group.h>
 #include <SketchSolver_Error.h>
+#include <SketchSolver_Manager.h>
+
+#include <GeomAPI_Pnt2d.h>
+#include <SketchPlugin_Circle.h>
 
+#include <cmath>
 
-void SketchSolver_ConstraintTangent::process()
+
+/// \brief Check whether the entities has only one shared point
+static bool hasSingleCoincidence(EntityWrapperPtr theEntity1, EntityWrapperPtr theEntity2)
 {
-  cleanErrorMsg();
-  if (!myBaseConstraint || !myStorage || myGroup == 0) {
-    /// TODO: Put error message here
-    return;
+  BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+
+  const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
+  const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
+
+  std::list<EntityWrapperPtr>::const_iterator aStartIt1 = aPoints1.begin();
+  if (theEntity1->type() == ENTITY_ARC) ++aStartIt1; // skip center of arc
+  std::list<EntityWrapperPtr>::const_iterator aStartIt2 = aPoints2.begin();
+  if (theEntity2->type() == ENTITY_ARC) ++aStartIt2; // skip center of arc
+
+  int aNbCoinc = 0;
+  std::list<EntityWrapperPtr>::const_iterator anIt1, anIt2;
+  for (anIt1 = aStartIt1; anIt1 != aPoints1.end(); ++anIt1) {
+    if ((*anIt1)->type() != ENTITY_POINT)
+      continue;
+    std::shared_ptr<GeomAPI_Pnt2d> aPt1 = aBuilder->point(*anIt1);
+    for (anIt2 = aStartIt2; anIt2 != aPoints2.end(); ++anIt2) {
+      if ((*anIt2)->type() != ENTITY_POINT)
+        continue;
+      std::shared_ptr<GeomAPI_Pnt2d> aPt2 = aBuilder->point(*anIt2);
+      if (aPt1->distance(aPt2) < tolerance)
+        ++aNbCoinc;
+    }
   }
-  if (!mySlvsConstraints.empty()) // some data is changed, update constraint
-    update(myBaseConstraint);
+  return aNbCoinc == 1;
+}
+
+/// \brief Check if two connected arcs have centers
+///        in same direction relatively to connection point
+static bool isInternalTangency(EntityWrapperPtr theEntity1, EntityWrapperPtr theEntity2)
+{
+  BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+  return aBuilder->isArcArcTangencyInternal(theEntity1, theEntity2);
+}
 
-  double aValue;
-  std::vector<Slvs_hEntity> anEntID;
-  getAttributes(aValue, anEntID);
-  if (!myErrorMsg.empty())
+
+void SketchSolver_ConstraintTangent::getAttributes(
+    double& theValue,
+    std::vector<EntityWrapperPtr>& theAttributes)
+{
+  SketchSolver_Constraint::getAttributes(theValue, theAttributes);
+  if (!myErrorMsg.empty() || !theAttributes[2] || !theAttributes[3]) {
+    theAttributes.clear();
     return;
+  }
+
   // Check the quantity of entities of each type and their order (arcs first)
   int aNbLines = 0;
   int aNbArcs = 0;
-  Slvs_Entity anEntities[2];
-  myType = SLVS_C_CURVE_CURVE_TANGENT;
-  std::vector<Slvs_hEntity>::iterator anEntIter = anEntID.begin();
-  for (; anEntIter != anEntID.end(); anEntIter++) {
-    Slvs_Entity anEnt = myStorage->getEntity(*anEntIter);
-    if (anEnt.type == SLVS_E_LINE_SEGMENT) {
-      if (aNbLines == 0)
-        anEntities[1 + aNbLines] = anEnt;
-      aNbLines++;
-      myType = SLVS_C_ARC_LINE_TANGENT;
+  int aNbCircles = 0;
+  bool isSwap = false; // whether need to swap arguments (arc goes before line)
+  std::vector<EntityWrapperPtr>::iterator anEntIt = theAttributes.begin() + 2;
+  for (; anEntIt != theAttributes.end(); ++anEntIt) {
+    if ((*anEntIt)->type() == ENTITY_LINE)
+      ++aNbLines;
+    else if ((*anEntIt)->type() == ENTITY_ARC) {
+      ++aNbArcs;
+      isSwap = aNbLines > 0;
     }
-    else if (anEnt.type == SLVS_E_ARC_OF_CIRCLE) {
-      if (aNbArcs < 2)
-        anEntities[aNbArcs] = anEnt;
-      aNbArcs++;
+    else if ((*anEntIt)->type() == ENTITY_CIRCLE) {
+      ++aNbCircles;
+      isSwap = aNbLines > 0;
     }
   }
 
-  if (aNbLines + aNbArcs != 2) {
-    myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
-    return;
-  } else if (aNbArcs < 1) {
+  if (aNbArcs < 1 && aNbCircles < 1) {
     myErrorMsg = SketchSolver_Error::INCORRECT_TANGENCY_ATTRIBUTE();
     return;
   }
-
-  // It is necessary to identify which points of entities are coincident
-  int aSlvsOtherFlag = 0;
-  int aSlvsOther2Flag = 0;
-  // Obtain start and end points of entities
-  Slvs_hEntity aPointsToFind[4];
-  for (int i = 0; i < 2; i++) {
-    int aShift = anEntities[i].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0;
-    aPointsToFind[2*i]  = anEntities[i].point[aShift];
-    aPointsToFind[2*i+1]= anEntities[i].point[aShift+1];
+  if (aNbLines == 1) {
+    if (aNbArcs == 1)
+      myType = CONSTRAINT_TANGENT_ARC_LINE;
+    else if (aNbCircles == 1)
+      myType = CONSTRAINT_TANGENT_CIRCLE_LINE;
+  }
+  else if (aNbArcs == 2) {
+    myType = CONSTRAINT_TANGENT_ARC_ARC;
+    isArcArcInternal = isInternalTangency(theAttributes[2], theAttributes[3]);
   }
-  // Search coincident points
-  bool isPointFound = false;
-  for (int i = 0; i < 2 && !isPointFound; i++)
-    for (int j = 2; j < 4 && !isPointFound; j++)
-      if (myStorage->isCoincident(aPointsToFind[i], aPointsToFind[j])) {
-        aSlvsOtherFlag = i;
-        aSlvsOther2Flag = j - 2;
-        isPointFound = true;
-      }
-  if (!isPointFound) {
-    // There is no coincident points between tangential objects. Generate error message
-    myErrorMsg = SketchSolver_Error::NO_COINCIDENT_POINTS();
+  else {
+    myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
     return;
   }
 
-  Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(),
-      getType(), myGroup->getWorkplaneId(), aValue,
-      SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, anEntities[0].h, anEntities[1].h);
-  aConstraint.other = aSlvsOtherFlag;
-  aConstraint.other2 = aSlvsOther2Flag;
-  aConstraint.h = myStorage->addConstraint(aConstraint);
-  mySlvsConstraints.push_back(aConstraint.h);
-  adjustConstraint();
+  if (myType == CONSTRAINT_TANGENT_ARC_LINE &&
+      !hasSingleCoincidence(theAttributes[2], theAttributes[3]))
+    myErrorMsg = SketchSolver_Error::TANGENCY_FAILED();
+
+  if (isSwap) {
+    EntityWrapperPtr aTemp = theAttributes[2];
+    theAttributes[2] = theAttributes[3];
+    theAttributes[3] = aTemp;
+  }
 }
 
+void SketchSolver_ConstraintTangent::adjustConstraint()
+{
+  if (myType == CONSTRAINT_TANGENT_CIRCLE_LINE) {
+    ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front();
+    AttributePtr aCircleCenter = aConstraint->entities().front()->baseAttribute();
+    if (!aCircleCenter)
+      return;
+    FeaturePtr aCircle = ModelAPI_Feature::feature(aCircleCenter->owner());
+    AttributeDoublePtr aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+        aCircle->attribute(SketchPlugin_Circle::RADIUS_ID()));
+
+    if (fabs(aRadius->value()) == fabs(aConstraint->value()))
+      return;
+
+    aConstraint->setValue(aRadius->value());
+
+    // Adjust the sign of constraint value
+    BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+    aBuilder->adjustConstraint(aConstraint);
+    myStorage->addConstraint(myBaseConstraint, aConstraint);
+  }
+  else if (myType == CONSTRAINT_TANGENT_ARC_ARC) {
+    ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front();
+    if (isArcArcInternal != isInternalTangency(
+        aConstraint->entities().front(), aConstraint->entities().back())) {
+      // fully rebuld constraint, because it is unable to access attributes of PlaneGCS constraint
+      remove();
+      process();
+    }
+  }
+}