Salome HOME
Update projected coordinate axes when changing one coordinate plane to another. CHANGE_SKETCH_PLANE
authorazv <azv@opencascade.com>
Thu, 13 Jun 2019 08:36:52 +0000 (11:36 +0300)
committerazv <azv@opencascade.com>
Thu, 13 Jun 2019 08:36:52 +0000 (11:36 +0300)
src/SketchPlugin/CMakeLists.txt
src/SketchPlugin/SketchPlugin_Sketch.cpp
src/SketchPlugin/SketchPlugin_Sketch.h
src/SketchPlugin/Test/TestChangeSketchPlane3.py [new file with mode: 0644]

index f611de955ed6673eb293499d941bfdd705167320..d72e0c56bf28bd1a262e4d8064f2d56425048513 100644 (file)
@@ -198,6 +198,7 @@ ADD_UNIT_TESTS(
   TestArcBehavior.py
   TestChangeSketchPlane1.py
   TestChangeSketchPlane2.py
+  TestChangeSketchPlane3.py
   TestConstraintAngle.py
   TestConstraintCoincidence.py
   TestConstraintCollinear.py
index 2f51ae2da3a07731069f59eb9d846f0d344798a8..0daeb330d810e76a3eea6ac3d964764e15bc607e 100644 (file)
 #include <Config_PropManager.h>
 
 #include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAlgoAPI_EdgeBuilder.h>
 #include <GeomAlgoAPI_FaceBuilder.h>
 
 #include <GeomAPI_Dir.h>
+#include <GeomAPI_Lin.h>
 #include <GeomAPI_PlanarEdges.h>
 #include <GeomAPI_ShapeIterator.h>
 #include <GeomAPI_Vertex.h>
@@ -249,6 +251,35 @@ bool SketchPlugin_Sketch::isSub(ObjectPtr theObject) const
 }
 
 
+static bool isOrigin(const GeomPointPtr& thePoint, const double theTolerance)
+{
+  return fabs(thePoint->x()) < theTolerance &&
+         fabs(thePoint->y()) < theTolerance &&
+         fabs(thePoint->z()) < theTolerance;
+}
+
+static bool isCoordinateAxis(const GeomDirPtr& theDir, const double theTolerance)
+{
+  return fabs(theDir->x() - 1.0) < theTolerance || fabs(theDir->x() + 1.0) < theTolerance ||
+         fabs(theDir->y() - 1.0) < theTolerance || fabs(theDir->y() + 1.0) < theTolerance ||
+         fabs(theDir->z() - 1.0) < theTolerance || fabs(theDir->z() + 1.0) < theTolerance;
+}
+
+static bool isCoordinatePlane(const GeomAx3Ptr& thePlane)
+{
+  static const double THE_TOLERANCE = 1.e-7;
+  if (!thePlane)
+    return false;
+
+  GeomPointPtr anOrigin = thePlane->origin();
+  GeomDirPtr aNormal = thePlane->normal();
+  GeomDirPtr aDirX = thePlane->dirX();
+
+  return isOrigin(anOrigin, THE_TOLERANCE) &&
+         isCoordinateAxis(aNormal, THE_TOLERANCE) &&
+         isCoordinateAxis(aDirX, THE_TOLERANCE);
+}
+
 void SketchPlugin_Sketch::attributeChanged(const std::string& theID) {
   if (theID == SketchPlugin_SketchEntity::EXTERNAL_ID()) {
     AttributeSelectionPtr aSelAttr = selection(SketchPlugin_SketchEntity::EXTERNAL_ID());
@@ -299,14 +330,28 @@ void SketchPlugin_Sketch::attributeChanged(const std::string& theID) {
       }
     }
   } else if (theID == NORM_ID() || theID == DIRX_ID() || theID == ORIGIN_ID()) {
+    // check if current and previous sketch planes are coordinate planes and they are different
+    GeomAx3Ptr aCurPlane;
+    bool areCoordPlanes = false;
+    if (isPlaneSet()) {
+      aCurPlane = coordinatePlane();
+      areCoordPlanes = isCoordinatePlane(aCurPlane) && isCoordinatePlane(myPlane);
+    }
+
     // send all sub-elements are also updated: all entities become created on different plane
     static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
     std::list<ObjectPtr> aSubs = data()->reflist(SketchPlugin_Sketch::FEATURES_ID())->list();
     std::list<ObjectPtr>::iterator aSub = aSubs.begin();
     for(; aSub != aSubs.end(); aSub++) {
-      if (aSub->get())
+      if (aSub->get()) {
+        if (areCoordPlanes)
+          updateCoordinateAxis(*aSub, aCurPlane);
+
         ModelAPI_EventCreator::get()->sendUpdated(*aSub, anUpdateEvent);
+      }
     }
+    if (aCurPlane)
+      myPlane = aCurPlane;
   }
 }
 
@@ -433,3 +478,95 @@ bool SketchPlugin_Sketch::removeLinksToExternal()
     document()->removeFeature(*anIt);
   return true;
 }
+
+
+static ObjectPtr findAxis(GeomShapePtr theAxisToCompare,
+                          ObjectPtr theOX,
+                          ObjectPtr theOY,
+                          ObjectPtr theOZ)
+{
+  if (theAxisToCompare) {
+    ObjectPtr anAxes[] = { theOX, theOY, theOZ };
+    for (int i = 0; i < 3; ++i) {
+      ResultPtr anAx = std::dynamic_pointer_cast<ModelAPI_Result>(anAxes[i]);
+      if (anAx && theAxisToCompare->isEqual(anAx->shape()))
+        return anAxes[i];
+    }
+  }
+  return ObjectPtr();
+}
+
+static ObjectPtr findAxis(ObjectPtr theAxisToCompare,
+                          ObjectPtr theOX,
+                          ObjectPtr theOY,
+                          ObjectPtr theOZ)
+{
+  if (theAxisToCompare == theOX)
+    return theOX;
+  else if (theAxisToCompare == theOY)
+    return theOY;
+  else if (theAxisToCompare == theOZ)
+    return theOZ;
+  // nothing helped, search by shape
+  ResultPtr anAxis = std::dynamic_pointer_cast<ModelAPI_Result>(theAxisToCompare);
+  return findAxis(anAxis ? anAxis->shape() : GeomShapePtr(), theOX, theOY, theOZ);
+}
+
+GeomShapePtr axisOnNewPlane(ObjectPtr theAxis, GeomAx3Ptr theOldPlane, GeomAx3Ptr theNewPlane)
+{
+  ResultPtr anAxis = std::dynamic_pointer_cast<ModelAPI_Result>(theAxis);
+  if (!anAxis)
+    return GeomShapePtr();
+
+  GeomEdgePtr anAxisEdge = anAxis->shape()->edge();
+  GeomLinePtr anAxisLine = anAxisEdge->line();
+  GeomDirPtr anAxisDir = anAxisLine->direction();
+
+  double aFirstParam, aLastParam;
+  anAxisEdge->getRange(aFirstParam, aLastParam);
+
+  if (theOldPlane->dirX()->isParallel(anAxisDir))
+    anAxisDir = theNewPlane->dirX();
+  else if (theOldPlane->dirY()->isParallel(anAxisDir))
+    anAxisDir = theNewPlane->dirY();
+  else if (theOldPlane->normal()->isParallel(anAxisDir))
+    anAxisDir = theNewPlane->normal();
+
+  GeomPointPtr aFirstPoint(new GeomAPI_Pnt(aFirstParam * anAxisDir->x(),
+                                           aFirstParam * anAxisDir->y(),
+                                           aFirstParam * anAxisDir->z()));
+  GeomPointPtr aLastPoint(new GeomAPI_Pnt(aLastParam * anAxisDir->x(),
+                                          aLastParam * anAxisDir->y(),
+                                          aLastParam * anAxisDir->z()));
+  return GeomAlgoAPI_EdgeBuilder::line(aFirstPoint, aLastPoint);
+}
+
+void  SketchPlugin_Sketch::updateCoordinateAxis(ObjectPtr theSub, GeomAx3Ptr thePlane)
+{
+  FeaturePtr aFeature = ModelAPI_Feature::feature(theSub);
+  if (!aFeature)
+    return;
+
+  DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
+  ObjectPtr anOX = aRootDoc->objectByName(ModelAPI_ResultConstruction::group(), "OX");
+  ObjectPtr anOY = aRootDoc->objectByName(ModelAPI_ResultConstruction::group(), "OY");
+  ObjectPtr anOZ = aRootDoc->objectByName(ModelAPI_ResultConstruction::group(), "OZ");
+
+  AttributeSelectionPtr anExtFeature;
+  if (aFeature->getKind() == SketchPlugin_Projection::ID())
+    anExtFeature = aFeature->selection(SketchPlugin_Projection::EXTERNAL_FEATURE_ID());
+  else if (aFeature->getKind() == SketchPlugin_IntersectionPoint::ID())
+    anExtFeature = aFeature->selection(SketchPlugin_IntersectionPoint::EXTERNAL_FEATURE_ID());
+  else
+    return;
+
+  ObjectPtr aContext = anExtFeature->context();
+  GeomShapePtr aShape = anExtFeature->value();
+  if (!aShape) { // selected object is a construction
+    ObjectPtr anAxis = findAxis(aContext, anOX, anOY, anOZ);
+    GeomShapePtr aNewAxis = axisOnNewPlane(anAxis, myPlane, thePlane);
+    anAxis = findAxis(aNewAxis, anOX, anOY, anOZ);
+    if (anAxis)
+      anExtFeature->setValue(anAxis, aShape);
+  }
+}
index d94893db0e90a12c930b3d26dc2412098254b35d..124ff670c0e843d1a9a0fbbc124bb2f4bd0da732 100644 (file)
@@ -177,6 +177,10 @@ class SketchPlugin_Sketch : public ModelAPI_CompositeFeature, public GeomAPI_ICu
     std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
       aData->attribute(NORM_ID()));
 
+    if (!aNorm->isInitialized() || !aX->isInitialized() ||
+        aNorm->dir()->cross(aX->dir())->squareModulus() < 1.e-14)
+      return std::shared_ptr<GeomAPI_Ax3>();
+
     return std::shared_ptr<GeomAPI_Ax3>(new GeomAPI_Ax3(aC->pnt(), aX->dir(), aNorm->dir()));
   }
 
@@ -258,6 +262,12 @@ private:
   /// Substitute all links to external objects by newly created features.
   /// \return \c true, if all links updated.
   bool removeLinksToExternal();
+
+  /// Update projected coordinate axes
+  void updateCoordinateAxis(ObjectPtr theSub, std::shared_ptr<GeomAPI_Ax3> thePlane);
+
+private:
+  std::shared_ptr<GeomAPI_Ax3> myPlane;
 };
 
 #endif
diff --git a/src/SketchPlugin/Test/TestChangeSketchPlane3.py b/src/SketchPlugin/Test/TestChangeSketchPlane3.py
new file mode 100644 (file)
index 0000000..6746b95
--- /dev/null
@@ -0,0 +1,63 @@
+# Copyright (C) 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
+#
+
+from SketchAPI import *
+from salome.shaper import model
+import math
+
+def checkSketchLine(theLine, theX1, theY1, theX2, theY2, theTolerance = 1.e-7):
+    assert(math.fabs(theLine.startPoint().x() - theX1) < theTolerance)
+    assert(math.fabs(theLine.startPoint().y() - theY1) < theTolerance)
+    assert(math.fabs(theLine.endPoint().x() - theX2) < theTolerance)
+    assert(math.fabs(theLine.endPoint().y() - theY2) < theTolerance)
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamD1 = model.addParameter(Part_1_doc, "D1", "80")
+ParamD2 = model.addParameter(Part_1_doc, "D2", "30")
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(0, 80, 30, 0)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OY"), False)
+SketchLine_2 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_2.result())
+SketchProjection_2 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_3 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_3.result())
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchLine_1.startPoint(), SketchAPI_Line(SketchLine_2).startPoint(), "D1", True)
+SketchConstraintDistance_2 = Sketch_1.setDistance(SketchLine_1.endPoint(), SketchAPI_Line(SketchLine_2).startPoint(), "D2", True)
+model.do()
+model.end()
+model.checkSketch(Sketch_1, 0)
+checkSketchLine(SketchLine_1, 0, ParamD1.value(), ParamD2.value(), 0)
+
+model.begin()
+Sketch_1.setPlane(model.selection("FACE", "PartSet/YOZ"))
+model.end()
+model.checkSketch(Sketch_1, 0)
+checkSketchLine(SketchLine_1, 0, ParamD1.value(), ParamD2.value(), 0)
+
+model.begin()
+Sketch_1.setPlane(model.selection("FACE", "PartSet/XOZ"))
+model.end()
+model.checkSketch(Sketch_1, 0)
+checkSketchLine(SketchLine_1, 0, ParamD1.value(), ParamD2.value(), 0)
+
+assert(model.checkPythonDump())