Salome HOME
Merge remote-tracking branch 'origin/ngo/Lot5'
[modules/shaper.git] / src / SketchAPI / SketchAPI_Sketch.cpp
index b207823768c79c5295fb0764603af98862beb291..722cbbaa77e40782003c6940d9f14d61f867801a 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2017  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
 //
 // 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
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 //
-// See http://www.salome-platform.org/ or
-// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 
 #include "SketchAPI_Sketch.h"
 #include "SketchAPI_Rotation.h"
 #include "SketchAPI_Translation.h"
 //--------------------------------------------------------------------------------------
+#include <GeomAPI_Curve.h>
 #include <GeomAPI_Dir2d.h>
+#include <GeomAPI_PlanarEdges.h>
+#include <GeomAPI_ShapeExplorer.h>
 #include <GeomAPI_XY.h>
+#include <GeomAlgoAPI_SketchBuilder.h>
 #include <cmath>
 //--------------------------------------------------------------------------------------
 SketchAPI_Sketch::SketchAPI_Sketch(
@@ -128,6 +131,25 @@ void SketchAPI_Sketch::setPlane(const std::shared_ptr<GeomAPI_Ax3> & thePlane)
   execute();
 }
 
+void SketchAPI_Sketch::setPlane(const ModelHighAPI_Selection & thePlane,
+                                bool theRemoveExternalDependency)
+{
+  FeaturePtr aSketch = feature();
+
+  DocumentPtr aDoc = aSketch->document();
+  bool useVisible = false;
+  FeaturePtr aCurFeatureBefore = aDoc->currentFeature(useVisible);
+  aDoc->setCurrentFeature(aSketch, useVisible);
+
+  if (theRemoveExternalDependency)
+    aSketch->customAction(SketchPlugin_Sketch::ACTION_REMOVE_EXTERNAL());
+
+  setExternal(thePlane);
+
+  aDoc->setCurrentFeature(aCurFeatureBefore, useVisible);
+}
+
+//--------------------------------------------------------------------------------------
 void SketchAPI_Sketch::setExternal(const ModelHighAPI_Selection & theExternal)
 {
   fillAttribute(theExternal, myexternal);
@@ -204,6 +226,78 @@ SketchPtr addSketch(const std::shared_ptr<ModelAPI_Document> & thePart,
 }
 
 
+//--------------------------------------------------------------------------------------
+std::list< std::shared_ptr<SketchAPI_Point> > SketchAPI_Sketch::getFreePoints()
+{
+  std::list< std::shared_ptr<SketchAPI_Point> > aFreePoints;
+  std::list<ResultPtr> aPoints = SketcherPrs_Tools::getFreePoints(compositeFeature());
+  for (std::list<ResultPtr>::iterator anIt = aPoints.begin(); anIt != aPoints.end(); ++anIt) {
+    FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
+    PointPtr aPoint(new SketchAPI_Point(aFeature));
+    aFreePoints.push_back(aPoint);
+  }
+  return aFreePoints;
+}
+
+//--------------------------------------------------------------------------------------
+static GeomCurvePtr untrimmedCurve(GeomShapePtr theShape)
+{
+  GeomCurvePtr aCurve(new GeomAPI_Curve(theShape));
+  if (aCurve->isTrimmed())
+    aCurve = aCurve->basisCurve();
+  return aCurve;
+}
+
+void SketchAPI_Sketch::changeFacesOrder(
+    const std::list<std::list<ModelHighAPI_Selection> >& theFaces)
+{
+  // collect faces of the sketch
+  ResultConstructionPtr aSketchResult =
+      std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(feature()->lastResult());
+  if (!aSketchResult) {
+    // sketch is nested to a boolean operation, thus, it has no result yet.
+    feature()->execute();
+    aSketchResult =
+        std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(feature()->lastResult());
+  }
+  std::list<GeomFacePtr> aFaces;
+  int aFacesNum = aSketchResult->facesNum();
+  for (int i = 0; i < aFacesNum; ++i)
+    aFaces.push_back(aSketchResult->face(i));
+  // find new faces order according to the given lists of edges
+  std::list<GeomFacePtr> aNewFacesOrder;
+  std::list<std::list<ModelHighAPI_Selection> >::const_iterator anIt = theFaces.begin();
+  for (; anIt != theFaces.end(); ++anIt) {
+    // find the appropriate face
+    std::list<GeomFacePtr>::iterator aFIt = aFaces.begin();
+    for (; aFIt != aFaces.end(); ++aFIt) {
+      std::list<ModelHighAPI_Selection>::const_iterator aEdgeIt = anIt->begin();
+      GeomAPI_ShapeExplorer aFExp(*aFIt, GeomAPI_Shape::EDGE);
+      for (; aEdgeIt != anIt->end() && aFExp.more(); ++aEdgeIt, aFExp.next()) {
+        ResultPtr aCurRes = aEdgeIt->resultSubShapePair().first;
+        if (!aCurRes)
+          break;
+        GeomCurvePtr aCurve1 = untrimmedCurve(aCurRes->shape());
+        GeomCurvePtr aCurve2 = untrimmedCurve(aFExp.current());
+        if (!aCurve1->isEqual(aCurve2))
+          break;
+      }
+
+      if (aEdgeIt == anIt->end() && !aFExp.more()) {
+        // face is found
+        aNewFacesOrder.push_back(*aFIt);
+        aFaces.erase(aFIt);
+        break;
+      }
+    }
+  }
+  // place the rest faces at the end of new faces list
+  if (!aFaces.empty())
+    aNewFacesOrder.insert(aNewFacesOrder.end(), aFaces.begin(), aFaces.end());
+  // update the result of the sketch with the new order of faces
+  aSketchResult->setFacesOrder(aNewFacesOrder);
+}
+
 //--------------------------------------------------------------------------------------
 std::shared_ptr<SketchAPI_Point> SketchAPI_Sketch::addPoint(
     double theX, double theY)
@@ -235,18 +329,24 @@ std::shared_ptr<SketchAPI_Point> SketchAPI_Sketch::addPoint(const std::string &
 
 //--------------------------------------------------------------------------------------
 std::shared_ptr<SketchAPI_IntersectionPoint> SketchAPI_Sketch::addIntersectionPoint(
-    const ModelHighAPI_Selection & theExternal)
+    const ModelHighAPI_Selection & theExternal,
+    bool theKeepResult)
 {
   std::shared_ptr<ModelAPI_Feature> aFeature =
     compositeFeature()->addFeature(SketchPlugin_IntersectionPoint::ID());
-  return IntersectionPointPtr(new SketchAPI_IntersectionPoint(aFeature, theExternal));
+  IntersectionPointPtr anIntersection(new SketchAPI_IntersectionPoint(aFeature, theExternal));
+  anIntersection->setIncludeToResult(theKeepResult);
+  return anIntersection;
 }
 std::shared_ptr<SketchAPI_IntersectionPoint> SketchAPI_Sketch::addIntersectionPoint(
-    const std::string & theExternalName)
+    const std::string & theExternalName,
+    bool theKeepResult)
 {
   std::shared_ptr<ModelAPI_Feature> aFeature =
     compositeFeature()->addFeature(SketchPlugin_IntersectionPoint::ID());
-  return IntersectionPointPtr(new SketchAPI_IntersectionPoint(aFeature, theExternalName));
+  IntersectionPointPtr anIntersection(new SketchAPI_IntersectionPoint(aFeature, theExternalName));
+  anIntersection->setIncludeToResult(theKeepResult);
+  return anIntersection;
 }
 
 //--------------------------------------------------------------------------------------
@@ -458,19 +558,25 @@ std::shared_ptr<SketchAPI_Arc> SketchAPI_Sketch::addArc(const std::string & theE
 
 //--------------------------------------------------------------------------------------
 std::shared_ptr<SketchAPI_Projection> SketchAPI_Sketch::addProjection(
-    const ModelHighAPI_Selection & theExternalFeature)
+    const ModelHighAPI_Selection & theExternalFeature,
+    bool theKeepResult)
 {
   std::shared_ptr<ModelAPI_Feature> aFeature =
     compositeFeature()->addFeature(SketchPlugin_Projection::ID());
-  return ProjectionPtr(new SketchAPI_Projection(aFeature, theExternalFeature));
+  ProjectionPtr aProjection(new SketchAPI_Projection(aFeature, theExternalFeature));
+  aProjection->setIncludeToResult(theKeepResult);
+  return aProjection;
 }
 
 std::shared_ptr<SketchAPI_Projection> SketchAPI_Sketch::addProjection(
-    const std::string & theExternalName)
+    const std::string & theExternalName,
+    bool theKeepResult)
 {
   std::shared_ptr<ModelAPI_Feature> aFeature =
     compositeFeature()->addFeature(SketchPlugin_Projection::ID());
-  return ProjectionPtr(new SketchAPI_Projection(aFeature, theExternalName));
+  ProjectionPtr aProjection(new SketchAPI_Projection(aFeature, theExternalName));
+  aProjection->setIncludeToResult(theKeepResult);
+  return aProjection;
 }
 
 //--------------------------------------------------------------------------------------
@@ -503,13 +609,14 @@ std::shared_ptr<SketchAPI_Rotation> SketchAPI_Sketch::addRotation(
     const ModelHighAPI_RefAttr & theCenter,
     const ModelHighAPI_Double & theAngle,
     const ModelHighAPI_Integer & theNumberOfObjects,
-    bool theFullValue)
+    bool theFullValue,
+    bool theReversed)
 {
   std::shared_ptr<ModelAPI_Feature> aFeature =
     compositeFeature()->addFeature(SketchPlugin_MultiRotation::ID());
   return RotationPtr(
     new SketchAPI_Rotation(aFeature, theObjects, theCenter,
-                           theAngle, theNumberOfObjects, theFullValue));
+                           theAngle, theNumberOfObjects, theFullValue, theReversed));
 }
 
 //--------------------------------------------------------------------------------------
@@ -559,9 +666,9 @@ std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setAngle(
   fillAttribute(SketcherPrs_Tools::ANGLE_DIRECT,
       aFeature->integer(SketchPlugin_ConstraintAngle::TYPE_ID()));
   // fill the value before llines to avoid calculation of angle value by the Angle feature
-  fillAttribute(theValue, aFeature->real(SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID()));
   fillAttribute(theLine1, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A()));
   fillAttribute(theLine2, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B()));
+  fillAttribute(theValue, aFeature->real(SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID()));
   aFeature->execute();
   return InterfacePtr(new ModelHighAPI_Interface(aFeature));
 }
@@ -575,10 +682,9 @@ std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setAngleComplementary(
       compositeFeature()->addFeature(SketchPlugin_ConstraintAngle::ID());
   fillAttribute(SketcherPrs_Tools::ANGLE_COMPLEMENTARY,
       aFeature->integer(SketchPlugin_ConstraintAngle::TYPE_ID()));
-  fillAttribute(theValue, aFeature->real(SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID()));
   fillAttribute(theLine1, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A()));
   fillAttribute(theLine2, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B()));
-//  fillAttribute(theValue, aFeature->real(SketchPlugin_Constraint::VALUE()));
+  fillAttribute(theValue, aFeature->real(SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID()));
   aFeature->execute();
   return InterfacePtr(new ModelHighAPI_Interface(aFeature));
 }
@@ -592,10 +698,9 @@ std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setAngleBackward(
       compositeFeature()->addFeature(SketchPlugin_ConstraintAngle::ID());
   fillAttribute(SketcherPrs_Tools::ANGLE_BACKWARD,
       aFeature->integer(SketchPlugin_ConstraintAngle::TYPE_ID()));
-  fillAttribute(theValue, aFeature->real(SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID()));
   fillAttribute(theLine1, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A()));
   fillAttribute(theLine2, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B()));
-//  fillAttribute(theValue, aFeature->real(SketchPlugin_Constraint::VALUE()));
+  fillAttribute(theValue, aFeature->real(SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID()));
   aFeature->execute();
   return InterfacePtr(new ModelHighAPI_Interface(aFeature));
 }
@@ -665,7 +770,8 @@ std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setHorizontalDistance(
       compositeFeature()->addFeature(SketchPlugin_ConstraintDistanceHorizontal::ID());
   fillAttribute(thePoint1, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A()));
   fillAttribute(thePoint2, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B()));
-  fillAttribute(theValue, aFeature->real(SketchPlugin_Constraint::VALUE()));
+  fillAttribute(theValue,
+      aFeature->real(SketchPlugin_ConstraintDistanceAlongDir::DISTANCE_VALUE_ID()));
   aFeature->execute();
   return InterfacePtr(new ModelHighAPI_Interface(aFeature));
 }
@@ -679,7 +785,8 @@ std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setVerticalDistance(
       compositeFeature()->addFeature(SketchPlugin_ConstraintDistanceVertical::ID());
   fillAttribute(thePoint1, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A()));
   fillAttribute(thePoint2, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B()));
-  fillAttribute(theValue, aFeature->real(SketchPlugin_Constraint::VALUE()));
+  fillAttribute(theValue,
+      aFeature->real(SketchPlugin_ConstraintDistanceAlongDir::DISTANCE_VALUE_ID()));
   aFeature->execute();
   return InterfacePtr(new ModelHighAPI_Interface(aFeature));
 }
@@ -831,9 +938,7 @@ std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setVertical(
 static std::shared_ptr<GeomAPI_Pnt2d> pointCoordinates(const AttributePtr& thePoint)
 {
   AttributePoint2DPtr aPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(thePoint);
-  if (aPnt)
-    return aPnt->pnt();
-  return std::shared_ptr<GeomAPI_Pnt2d>();
+  return aPnt ? aPnt->pnt() : std::shared_ptr<GeomAPI_Pnt2d>();
 }
 
 static std::shared_ptr<GeomAPI_Pnt2d> middlePointOnLine(const FeaturePtr& theFeature)
@@ -904,20 +1009,21 @@ static std::shared_ptr<GeomAPI_Pnt2d> middlePointOnArc(const FeaturePtr& theFeat
 
 static std::shared_ptr<GeomAPI_Pnt2d> middlePoint(const ObjectPtr& theObject)
 {
+  std::shared_ptr<GeomAPI_Pnt2d> aMiddlePoint;
   FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
   if (aFeature) {
+    // move only features of the following types
     const std::string& aFeatureKind = aFeature->getKind();
     if (aFeatureKind == SketchPlugin_Point::ID())
-      return pointCoordinates(aFeature->attribute(SketchPlugin_Point::COORD_ID()));
+      aMiddlePoint = pointCoordinates(aFeature->attribute(SketchPlugin_Point::COORD_ID()));
     else if (aFeatureKind == SketchPlugin_Line::ID())
-      return middlePointOnLine(aFeature);
+      aMiddlePoint = middlePointOnLine(aFeature);
     else if (aFeatureKind == SketchPlugin_Circle::ID())
-      return pointOnCircle(aFeature);
+      aMiddlePoint = pointOnCircle(aFeature);
     else if (aFeatureKind == SketchPlugin_Arc::ID())
-      return middlePointOnArc(aFeature);
+      aMiddlePoint = middlePointOnArc(aFeature);
   }
-  // do not move other types of features
-  return std::shared_ptr<GeomAPI_Pnt2d>();
+  return aMiddlePoint;
 }
 
 void SketchAPI_Sketch::move(const ModelHighAPI_RefAttr& theMovedEntity,
@@ -965,6 +1071,99 @@ std::shared_ptr<GeomAPI_Pnt2d> SketchAPI_Sketch::to2D(const std::shared_ptr<Geom
 
 //--------------------------------------------------------------------------------------
 
+static bool isDifferent(GeomFacePtr theFace1, GeomFacePtr theFace2)
+{
+  // collect edges of the first face
+  std::list<GeomShapePtr> anEdges1;
+  for (GeomAPI_ShapeExplorer anExp(theFace1, GeomAPI_Shape::EDGE); anExp.more(); anExp.next())
+    anEdges1.push_back(anExp.current());
+  // compare edges of faces
+  for (GeomAPI_ShapeExplorer anExp(theFace2, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) {
+    GeomShapePtr aCurrent = anExp.current();
+    bool isFound = false;
+    std::list<GeomShapePtr>::iterator anIt1 = anEdges1.begin();
+    for (; anIt1 != anEdges1.end(); ++anIt1)
+      if (aCurrent->isSameGeometry(*anIt1)) {
+        isFound = true;
+        anEdges1.erase(anIt1);
+        break;
+      }
+    if (!isFound)
+      return true;
+  }
+  return !anEdges1.empty();
+}
+
+static bool isCustomFacesOrder(CompositeFeaturePtr theSketch)
+{
+  ResultConstructionPtr aSketchResult =
+      std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(theSketch->lastResult());
+  if (!aSketchResult)
+    return false;
+
+  std::shared_ptr<GeomAPI_PlanarEdges> aWires =
+      std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(aSketchResult->shape());
+  if (!aWires)
+    return false;
+
+  // collect faces constructed by SketchBuilder algorithm
+  GeomAlgoAPI_SketchBuilder aSketchBuilder(aWires->origin(), aWires->dirX(),
+                                           aWires->norm(), aWires);
+  const ListOfShape& aFaces = aSketchBuilder.faces();
+
+  // compare faces stored in sketch with faces generated by SketchBuilder
+  int aNbSketchFaces = aSketchResult->facesNum();
+  int aFaceIndex = 0;
+  for (ListOfShape::const_iterator aFIt = aFaces.begin();
+       aFIt != aFaces.end() && aFaceIndex < aNbSketchFaces;
+       ++aFIt, ++aFaceIndex) {
+    GeomFacePtr aSketchFace = aSketchResult->face(aFaceIndex);
+    GeomFacePtr aCurFace = (*aFIt)->face();
+    if (isDifferent(aSketchFace, aCurFace))
+      return true;
+  }
+  return false;
+}
+
+static void edgesOfSketchFaces(CompositeFeaturePtr theSketch,
+                               std::list<std::list<ResultPtr> >& theEdges)
+{
+  ResultConstructionPtr aSketchResult =
+      std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(theSketch->lastResult());
+  if (!aSketchResult)
+    return;
+
+  // collect curves of the sketch
+  std::map<GeomCurvePtr, ResultPtr, GeomAPI_Curve::Comparator> aCurves;
+  int aSubNum = theSketch->numberOfSubs();
+  for (int a = 0; a < aSubNum; ++a) {
+    FeaturePtr aSub = theSketch->subFeature(a);
+    const std::list<ResultPtr>& aResults = aSub->results();
+    std::list<ResultPtr>::const_iterator aRes = aResults.cbegin();
+    for (; aRes != aResults.cend(); aRes++) {
+      GeomShapePtr aCurShape = (*aRes)->shape();
+      if (aCurShape && aCurShape->isEdge())
+        aCurves[untrimmedCurve(aCurShape)] = *aRes;
+    }
+  }
+
+  // convert each face to the list of results of its edges
+  int aFacesNum = aSketchResult->facesNum();
+  for (int a = 0; a < aFacesNum; ++a) {
+    theEdges.push_back(std::list<ResultPtr>());
+    std::list<ResultPtr>& aCurEdges = theEdges.back();
+
+    GeomFacePtr aFace = aSketchResult->face(a);
+    for (GeomAPI_ShapeExplorer anExp(aFace, GeomAPI_Shape::EDGE);
+         anExp.more(); anExp.next()) {
+      GeomCurvePtr aCurrent = untrimmedCurve(anExp.current());
+      aCurEdges.push_back(aCurves[aCurrent]);
+    }
+  }
+}
+
+//--------------------------------------------------------------------------------------
+
 void SketchAPI_Sketch::dump(ModelHighAPI_Dumper& theDumper) const
 {
   FeaturePtr aBase = feature();
@@ -1024,4 +1223,24 @@ void SketchAPI_Sketch::dump(ModelHighAPI_Dumper& theDumper) const
   // dump sketch's subfeatures
   CompositeFeaturePtr aCompFeat = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aBase);
   theDumper.processSubs(aCompFeat, true);
+
+  // if face order differs to the order generated by SketchBuilder,
+  // dump the list of faces for correct execution of the script
+  if (isCustomFacesOrder(aCompFeat)) {
+    std::list<std::list<ResultPtr> > aFaces;
+    edgesOfSketchFaces(aCompFeat, aFaces);
+
+    const std::string& aSketchName = theDumper.name(aBase);
+    std::string aMethodName(".changeFacesOrder");
+    std::string aSpaceShift(aSketchName.size() + aMethodName.size(), ' ');
+
+    theDumper << aSketchName << aMethodName << "([";
+    for (std::list<std::list<ResultPtr> >::iterator aFIt = aFaces.begin();
+         aFIt != aFaces.end(); ++aFIt) {
+      if (aFIt != aFaces.begin())
+        theDumper << ",\n" << aSpaceShift << "  ";
+      theDumper << *aFIt;
+    }
+    theDumper << "\n" << aSpaceShift << " ])" << std::endl;
+  }
 }