Salome HOME
Task #3235: Projection without link to source shape
authorArtem Zhidkov <Artem.Zhidkov@opencascade.com>
Thu, 2 Jul 2020 11:06:46 +0000 (14:06 +0300)
committerArtem Zhidkov <Artem.Zhidkov@opencascade.com>
Wed, 8 Jul 2020 09:24:30 +0000 (12:24 +0300)
* Improve the Projection feature by an option to break the link with the original shape.
* Update unit-tests for ellipse's projection, because of solved OCCT issue #31016.

24 files changed:
src/GeomAlgoAPI/GeomAlgoAPI_Projection.cpp
src/ModuleBase/ModuleBase_PagedContainer.cpp
src/ModuleBase/ModuleBase_WidgetRadiobox.cpp
src/ModuleBase/ModuleBase_WidgetRadiobox.h
src/PartSet/PartSet_SketcherMgr.cpp
src/SketchAPI/SketchAPI.i
src/SketchAPI/SketchAPI_Projection.cpp
src/SketchAPI/SketchAPI_Projection.h
src/SketchAPI/SketchAPI_Sketch.cpp
src/SketchAPI/SketchAPI_Sketch.h
src/SketchAPI/Test/TestSketch.py
src/SketchPlugin/CMakeLists.txt
src/SketchPlugin/SketchPlugin_Ellipse.cpp
src/SketchPlugin/SketchPlugin_Projection.cpp
src/SketchPlugin/SketchPlugin_Projection.h
src/SketchPlugin/SketchPlugin_SketchEntity.cpp
src/SketchPlugin/SketchPlugin_SketchEntity.h
src/SketchPlugin/SketchPlugin_Validators.cpp
src/SketchPlugin/SketchPlugin_msg_en.ts
src/SketchPlugin/SketchPlugin_msg_fr.ts
src/SketchPlugin/Test/TestProjectionEllipse.py
src/SketchPlugin/Test/TestProjectionWithoutReference.py [new file with mode: 0644]
src/SketchPlugin/plugin-Sketch.xml
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp

index 94c22465a7f3263a2e0a4abf26dec9a905b90deb..f0c836ac26d98cf1a5d6441d38272a9ed964674e 100644 (file)
@@ -42,7 +42,8 @@ GeomCurvePtr GeomAlgoAPI_Projection::project(const GeomCurvePtr& theCurve)
   Handle(Geom_Curve) aCurve = theCurve->impl<Handle_Geom_Curve>();
   Handle(Geom_Plane) aPlane = new Geom_Plane(myPlane->impl<gp_Ax3>());
 
-  Handle(Geom_Curve) aProj = GeomProjLib::Project(aCurve, aPlane);
+  Handle(Geom_Curve) aProj =
+      GeomProjLib::ProjectOnPlane(aCurve, aPlane, aPlane->Axis().Direction(), false);
 
   GeomCurvePtr aProjCurve(new GeomAPI_Curve);
   aProjCurve->setImpl(new Handle_Geom_Curve(aProj));
index 267d2d4cf19454094066a0c2be52a5682e166ac2..f821c793f7df970e045e174f3a8e82418a8a6dc2 100644 (file)
@@ -107,7 +107,8 @@ bool ModuleBase_PagedContainer::restoreValueCustom()
       aCaseId = QString::fromStdString(aStringAttr->value());
     else
       aCaseId = QString::fromStdString(aDefVal.empty() ? aStringAttr->value() : aDefVal);
-    myIsFirst = false;
+    if (myIsFirst)
+      storeValueCustom();
     int idx = myCaseIds.indexOf(aCaseId);
     if (idx == -1)
       idx = currentPageIndex();
index 5c6da879747c7780f952fabf4be6ddf92e1c0bd2..aa76b42ec4a8d97cbb942ab2943f623c006cc2de 100644 (file)
 #include <ModuleBase_WidgetRadiobox.h>
 #include <ModuleBase_PageBase.h>
 
+#include <Config_WidgetAPI.h>
+
 #include <QFormLayout>
 #include <QRadioButton>
 #include <QFrame>
 #include <QButtonGroup>
 
-
 ModuleBase_WidgetRadiobox::ModuleBase_WidgetRadiobox(QWidget* theParent,
                                                      const Config_WidgetAPI* theData)
   : ModuleBase_PagedContainer(theParent, theData)
@@ -35,6 +36,8 @@ ModuleBase_WidgetRadiobox::ModuleBase_WidgetRadiobox(QWidget* theParent,
   myGroup = new QButtonGroup(this);
   myGroup->setExclusive(true);
 
+  myVerticalAlignment = theData->getProperty("align_subs").find("vert") == 0;
+
   connect(myGroup, SIGNAL(buttonToggled(int, bool)), SLOT(onPageChanged()));
 }
 
@@ -68,7 +71,11 @@ int ModuleBase_WidgetRadiobox::addPage(ModuleBase_PageBase* thePage,
 
   //QFrame* aFrame = dynamic_cast<QFrame*>(thePage);
   QWidget* aPage = thePage->pageWidget();
-  myLayout->addRow(aWgt, aPage);
+  if (myVerticalAlignment) {
+    myLayout->addRow(aWgt);
+    myLayout->addRow(aPage);
+  } else
+    myLayout->addRow(aWgt, aPage);
   myGroup->addButton(aButton, myGroup->buttons().count());
 
   bool isDefault = theCaseId.toStdString() == getDefaultValue();
index ef35a0f960604ea1ad0b9f44962527f615d3ccdd..cffb45a2120f82d1313523263ed2970068a8f100 100644 (file)
@@ -59,6 +59,7 @@ protected:
 private:
   QFormLayout* myLayout;
   QButtonGroup* myGroup;
+  bool myVerticalAlignment;
 };
 
 #endif
\ No newline at end of file
index 4aadcdd978db8a92d40eed95a105ced09b25065b..b52154da9ceb5dd2b88e414a797af7528f638b7f 100644 (file)
@@ -2266,7 +2266,7 @@ bool isIncludeToResult(const ObjectPtr& theObject)
   for (aIt = aRefsToMe.cbegin(); aIt != aRefsToMe.cend(); ++aIt) {
     if ((*aIt)->id() == SketchPlugin_Projection::PROJECTED_FEATURE_ID()) {
       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*aIt)->owner());
-      if (aFeature.get()) {
+      if (aFeature.get() && !aFeature->isMacro()) {
         anAttr = aFeature->data()->boolean(SketchPlugin_Projection::INCLUDE_INTO_RESULT());
         if (anAttr.get())
           return anAttr->value();
index 98bc2c6ab68649ccffe298263cc51dfaa39638f0..66b07c3cc3603105f2a6d4ef40fdaa1670f17914 100644 (file)
 %feature("kwargs") SketchAPI_BSpline::controlPolygon;
 %feature("kwargs") SketchAPI_Ellipse::construction;
 %feature("kwargs") SketchAPI_EllipticArc::construction;
-%feature("kwargs") SketchAPI_Sketch::addSpline;
-%feature("kwargs") SketchAPI_Sketch::addInterpolation;
 %feature("kwargs") SketchAPI_Sketch::addApproximation;
+%feature("kwargs") SketchAPI_Sketch::addInterpolation;
+%feature("kwargs") SketchAPI_Sketch::addProjection;
+%feature("kwargs") SketchAPI_Sketch::addSpline;
 %feature("kwargs") SketchAPI_Sketch::setAngle;
 
 // shared pointers
index 225188378008f850cb73ef2af2e6e1944ff12613..bee330063ecb5c3658fe1746e655e3d247057881 100644 (file)
@@ -56,16 +56,6 @@ SketchAPI_Projection::SketchAPI_Projection(
   }
 }
 
-SketchAPI_Projection::SketchAPI_Projection(
-    const std::shared_ptr<ModelAPI_Feature> & theFeature,
-    const std::string & theExternalName)
-: SketchAPI_SketchEntity(theFeature)
-{
-  if (initialize()) {
-    setByExternalName(theExternalName);
-  }
-}
-
 SketchAPI_Projection::~SketchAPI_Projection()
 {
 
@@ -79,14 +69,18 @@ void SketchAPI_Projection::setExternalFeature(const ModelHighAPI_Selection & the
   execute(true);
 }
 
-void SketchAPI_Projection::setByExternalName(const std::string& theExternalName)
+void SketchAPI_Projection::setIncludeToResult(bool theKeepResult)
 {
-  setExternalFeature(ModelHighAPI_Selection("EDGE", theExternalName));
+  fillAttribute(theKeepResult, includeToResult());
+  execute(true);
 }
 
-void SketchAPI_Projection::setIncludeToResult(bool theKeepResult)
+void SketchAPI_Projection::setKeepReferenceToOriginal(bool theKeepRefToOriginal)
 {
-  fillAttribute(theKeepResult, includeToResult());
+  // the Fixed constraint should be assigned explicitly
+  fillAttribute(false, feature()->boolean(SketchPlugin_Projection::MAKE_FIXED()));
+  fillAttribute(theKeepRefToOriginal ? "true" : "false",
+                feature()->string(SketchPlugin_Projection::KEEP_REFERENCE_ID()));
   execute(true);
 }
 
index d064f170d77e4b0f229c3a35222a4d7602a746f0..cfa3af1ac21e24fb51d59b3ee324729cb628518d 100644 (file)
@@ -43,10 +43,6 @@ public:
   SKETCHAPI_EXPORT
   SketchAPI_Projection(const std::shared_ptr<ModelAPI_Feature> & theFeature,
                        const ModelHighAPI_Selection & theExternalFeature);
-  /// Constructor with values
-  SKETCHAPI_EXPORT
-  SketchAPI_Projection(const std::shared_ptr<ModelAPI_Feature> & theFeature,
-                       const std::string & theExternalName);
   /// Destructor
   SKETCHAPI_EXPORT
   virtual ~SketchAPI_Projection();
@@ -66,14 +62,14 @@ public:
   SKETCHAPI_EXPORT
   void setExternalFeature(const ModelHighAPI_Selection & theExternalLine);
 
-  /// Set by external name
-  SKETCHAPI_EXPORT
-  void setByExternalName(const std::string & theExternalName);
-
   /// Set flag to include projection to result or not
   SKETCHAPI_EXPORT
   void setIncludeToResult(bool theKeepResult);
 
+  /// Set flag to keep the reference to the original shape
+  SKETCHAPI_EXPORT
+  void setKeepReferenceToOriginal(bool theKeepRefToOriginal);
+
   /// Returns created feature
   SKETCHAPI_EXPORT
   std::shared_ptr<SketchAPI_SketchEntity> createdFeature() const;
index 2f6ffcdfab9befdf7692b55cb511d53a661b5fd5..e76cfb3a21199146d85031975feb9fd6e33a557b 100644 (file)
@@ -861,23 +861,15 @@ std::shared_ptr<SketchAPI_BSpline> SketchAPI_Sketch::addApproximation(
 //--------------------------------------------------------------------------------------
 std::shared_ptr<SketchAPI_Projection> SketchAPI_Sketch::addProjection(
     const ModelHighAPI_Selection & theExternalFeature,
-    bool theKeepResult)
-{
-  std::shared_ptr<ModelAPI_Feature> aFeature =
-    compositeFeature()->addFeature(SketchPlugin_Projection::ID());
-  ProjectionPtr aProjection(new SketchAPI_Projection(aFeature, theExternalFeature));
-  aProjection->setIncludeToResult(theKeepResult);
-  return aProjection;
-}
-
-std::shared_ptr<SketchAPI_Projection> SketchAPI_Sketch::addProjection(
-    const std::string & theExternalName,
-    bool theKeepResult)
+    bool keepResult,
+    bool keepRefToOriginal)
 {
   std::shared_ptr<ModelAPI_Feature> aFeature =
     compositeFeature()->addFeature(SketchPlugin_Projection::ID());
-  ProjectionPtr aProjection(new SketchAPI_Projection(aFeature, theExternalName));
-  aProjection->setIncludeToResult(theKeepResult);
+  ProjectionPtr aProjection(new SketchAPI_Projection(aFeature));
+  aProjection->setIncludeToResult(keepResult);
+  aProjection->setKeepReferenceToOriginal(keepRefToOriginal);
+  aProjection->setExternalFeature(theExternalFeature);
   return aProjection;
 }
 
index 3911015dea0dff208139a6968572a1718082e881..2bdf2a570d45c22facd60346bc1896a0583d866f 100644 (file)
@@ -358,12 +358,8 @@ public:
   SKETCHAPI_EXPORT
   std::shared_ptr<SketchAPI_Projection> addProjection(
       const ModelHighAPI_Selection & theExternalFeature,
-      bool theKeepResult = false);
-
-  /// Add projection
-  SKETCHAPI_EXPORT
-  std::shared_ptr<SketchAPI_Projection> addProjection(const std::string & theExternalName,
-                                                      bool theKeepResult = false);
+      bool keepResult = false,
+      bool keepRefToOriginal = true);
 
   /// Add mirror
   SKETCHAPI_EXPORT
index b12543d8b1cf68e3673c2f2ba49ad1988d3ee724..ea656e9398a04ddd62a162e89b3109b1a1e4232b 100644 (file)
@@ -173,7 +173,7 @@ class SketchTestCase(unittest.TestCase):
     def test_arc_by_projection(self):
         """ Test 10. Create arc by projection of external feature
         """
-        self.sketch.addProjection("[Cylinder_2_1/Face_1][Cylinder_2_1/Face_3]")
+        self.sketch.addProjection(model.selection("EDGE", "[Cylinder_2_1/Face_1][Cylinder_2_1/Face_3]"))
         model.do()
         anArc = SketchAPI.SketchAPI_Arc(model.lastSubFeature(self.sketch, "SketchArc"))
 
index aa51871dcc30652436fd14f040a746f4a7c3ee92..8093a9062b653f925c4b17ef085e77204eb787e9 100644 (file)
@@ -336,6 +336,7 @@ ADD_UNIT_TESTS(
   TestProjectionEllipticArc.py
   TestProjectionIntoResult.py
   TestProjectionUpdate.py
+  TestProjectionWithoutReference.py
   TestRectangle.py
   TestRemainingDoF.py
   TestRemoveBSpline.py
index f5ca951760467791ec47f1520de2726ae40e08ff..6ff0a30216d053d61726816b6a0dd2982ac810c8 100644 (file)
@@ -134,7 +134,7 @@ bool SketchPlugin_Ellipse::fillCharacteristicPoints()
     return false;
   }
 
-  data()->blockSendAttributeUpdated(true);
+  bool aWasBlocked = data()->blockSendAttributeUpdated(true);
   GeomPnt2dPtr aCenter2d = aCenterAttr->pnt();
   GeomPnt2dPtr aFocus2d = aFocusAttr->pnt();
   GeomDir2dPtr aMajorDir2d(new GeomAPI_Dir2d(aFocus2d->x() - aCenter2d->x(),
@@ -144,7 +144,9 @@ bool SketchPlugin_Ellipse::fillCharacteristicPoints()
   AttributeDoublePtr aMajorRadiusAttr = real(MAJOR_RADIUS_ID());
   double aFocalDist = aCenter2d->distance(aFocus2d);
   double aMajorRadius = sqrt(aFocalDist * aFocalDist + aMinorRadius * aMinorRadius);
-  aMajorRadiusAttr->setValue(aMajorRadius);
+  if (!aMajorRadiusAttr->isInitialized() ||
+      fabs(aMajorRadiusAttr->value() - aMajorRadius) > tolerance)
+    aMajorRadiusAttr->setValue(aMajorRadius);
 
   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(SECOND_FOCUS_ID()))
     ->setValue(2.0 * aCenter2d->x() - aFocus2d->x(), 2.0 * aCenter2d->y() - aFocus2d->y());
@@ -160,7 +162,7 @@ bool SketchPlugin_Ellipse::fillCharacteristicPoints()
   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(MINOR_AXIS_END_ID()))
       ->setValue(aCenter2d->x() + aMinorDir2d->x() * aMinorRadius,
                  aCenter2d->y() + aMinorDir2d->y() * aMinorRadius);
-  data()->blockSendAttributeUpdated(false);
+  data()->blockSendAttributeUpdated(aWasBlocked);
 
   return true;
 }
index e0e6222bccc7da99c49019f70065687d0a3053c3..9133b197d9b7e41ad005435b53e336ff9f70454c 100644 (file)
@@ -35,6 +35,7 @@
 #include <ModelAPI_AttributeDouble.h>
 #include <ModelAPI_AttributeDoubleArray.h>
 #include <ModelAPI_AttributeInteger.h>
+#include <ModelAPI_AttributeString.h>
 #include <ModelAPI_ResultConstruction.h>
 #include <ModelAPI_Session.h>
 #include <ModelAPI_Validator.h>
 #include <cmath>
 
 static const double tolerance = 1.e-7;
+static const std::string THE_KEEP_REF("true");
+
+static bool isKeepReference(AttributeStringPtr theAttr)
+{
+  return !theAttr || !theAttr->isInitialized() || theAttr->value() == THE_KEEP_REF;
+}
 
 
 SketchPlugin_Projection::SketchPlugin_Projection()
@@ -71,6 +78,7 @@ void SketchPlugin_Projection::initDerivedClassAttributes()
 {
   data()->addAttribute(EXTERNAL_FEATURE_ID(), ModelAPI_AttributeSelection::typeId());
   data()->addAttribute(PROJECTED_FEATURE_ID(), ModelAPI_AttributeRefAttr::typeId());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PROJECTED_FEATURE_ID());
   data()->attribute(PROJECTED_FEATURE_ID())->setIsArgument(false);
 
   data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
@@ -81,6 +89,22 @@ void SketchPlugin_Projection::initDerivedClassAttributes()
   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), AUXILIARY_ID());
 }
 
+void SketchPlugin_Projection::initDerivedClassAttributes2()
+{
+  AttributePtr aKeepRefAttr =
+      data()->addAttribute(KEEP_REFERENCE_ID(), ModelAPI_AttributeString::typeId());
+  if (!aKeepRefAttr->isInitialized()) {
+    std::dynamic_pointer_cast<ModelAPI_AttributeString>(aKeepRefAttr)->setValue(THE_KEEP_REF);
+  }
+
+  data()->addAttribute(MAKE_FIXED(), ModelAPI_AttributeBoolean::typeId());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MAKE_FIXED());
+
+  data()->addAttribute(FIXED_CONSTRAINT_ID(), ModelAPI_AttributeReference::typeId());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), FIXED_CONSTRAINT_ID());
+  data()->attribute(FIXED_CONSTRAINT_ID())->setIsArgument(false);
+}
+
 void SketchPlugin_Projection::execute()
 {
   AttributeRefAttrPtr aRefAttr = data()->refattr(PROJECTED_FEATURE_ID());
@@ -88,7 +112,7 @@ void SketchPlugin_Projection::execute()
     return;
   FeaturePtr aProjection = ModelAPI_Feature::feature(aRefAttr->object());
 
-  if (!lastResult().get()) {
+  if (isKeepReference(string(KEEP_REFERENCE_ID())) && !lastResult().get()) {
     bool hasProjResult = aProjection->lastResult().get() != NULL;
     ResultConstructionPtr aConstr = document()->createConstruction(data());
     if (hasProjResult)
@@ -106,6 +130,16 @@ void SketchPlugin_Projection::execute()
   computeProjection(EXTERNAL_FEATURE_ID());
 }
 
+bool SketchPlugin_Projection::isMacro() const
+{
+  if (!data() || !data()->isValid())
+    return false;
+
+  AttributeStringPtr aKeepRefAttr =
+      const_cast<SketchPlugin_Projection*>(this)->string(KEEP_REFERENCE_ID());
+  return !isKeepReference(aKeepRefAttr);
+}
+
 void SketchPlugin_Projection::attributeChanged(const std::string& theID)
 {
   if ((theID == EXTERNAL_FEATURE_ID() || theID == EXTERNAL_ID()) && !myIsComputing) {
@@ -233,25 +267,52 @@ void SketchPlugin_Projection::computeProjection(const std::string& theID)
   if (!isProjected)
     return; // projection is not computed, stop processing
 
-  aProjection->boolean(COPY_ID())->setValue(true);
+  bool keepBackRef = isKeepReference(string(KEEP_REFERENCE_ID()));
+
+  aProjection->boolean(COPY_ID())->setValue(keepBackRef);
   aProjection->execute();
   aRefAttr->setObject(aProjection);
 
   restoreCurrentFeature();
 
-  if (theID == EXTERNAL_FEATURE_ID()) {
-    selection(EXTERNAL_ID())->selectValue(aExtFeature);
+  AttributeBooleanPtr aMakeFixedAttr = boolean(MAKE_FIXED());
+  bool isMakeFixed = aMakeFixedAttr && aMakeFixedAttr->isInitialized() && aMakeFixedAttr->value();
+
+  AttributeReferencePtr aFixedConstrAttr = reference(FIXED_CONSTRAINT_ID());
+  FeaturePtr aFixedConstraint;
+  if (aFixedConstrAttr && aFixedConstrAttr->isInitialized())
+    aFixedConstraint = ModelAPI_Feature::feature(aFixedConstrAttr->value());
 
-    if (aResult) {
-      aResult->setShape(aProjection->lastResult()->shape());
-      setResult(aResult);
-      GeomShapePtr anEmptyVal;
-      aProjection->selection(EXTERNAL_ID())->setValue(lastResult(), anEmptyVal);
+  if (keepBackRef) {
+    if (theID == EXTERNAL_FEATURE_ID()) {
+      selection(EXTERNAL_ID())->selectValue(aExtFeature);
 
-      static const Events_ID anEvent = Events_Loop::eventByName(EVENT_VISUAL_ATTRIBUTES);
-      ModelAPI_EventCreator::get()->sendUpdated(aProjection, anEvent, false);
+      if (aResult) {
+        aResult->setShape(aProjection->lastResult()->shape());
+        setResult(aResult);
+        GeomShapePtr anEmptyVal;
+        aProjection->selection(EXTERNAL_ID())->setValue(lastResult(), anEmptyVal);
+      }
     }
   }
+  else if (isMakeFixed) {
+    // fix the projected entity with the Fixed constraint
+    if (!aFixedConstraint)
+      aFixedConstraint = sketch()->addFeature(SketchPlugin_ConstraintRigid::ID());
+    aFixedConstraint->refattr(SketchPlugin_Constraint::ENTITY_A())->setObject(
+                              aProjection->lastResult());
+  }
+
+
+  // remove Fixed constraint in case of redundance
+  if (aFixedConstraint && (keepBackRef || !isMakeFixed)) {
+    document()->removeFeature(aFixedConstraint);
+    aFixedConstraint = FeaturePtr();
+  }
+  aFixedConstrAttr->setValue(aFixedConstraint);
+
+  static const Events_ID anEvent = Events_Loop::eventByName(EVENT_VISUAL_ATTRIBUTES);
+  ModelAPI_EventCreator::get()->sendUpdated(aProjection, anEvent, false);
 }
 
 bool SketchPlugin_Projection::rebuildProjectedFeature(
index 64f7844b73ea76c353243aed8400abd41ad42725..aea956bc5fb72f683d138b3f166f8a05dc0d3d8e 100644 (file)
@@ -62,6 +62,24 @@ public:
     return MY_INCLUDE;
   }
 
+  static const std::string& KEEP_REFERENCE_ID()
+  {
+    static std::string ID("keep_reference");
+    return ID;
+  }
+
+  static const std::string& MAKE_FIXED()
+  {
+    static std::string ID("make_fixed");
+    return ID;
+  }
+
+  static const std::string& FIXED_CONSTRAINT_ID()
+  {
+    static std::string ID("fixed_constraint");
+    return ID;
+  }
+
   /// Returns true because projected feature is always external
   virtual bool isFixed()
   { return true; }
@@ -79,6 +97,11 @@ public:
   /// Called on change of any argument-attribute of this object: for external point
   SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
 
+  /// Returns true if this feature is used as macro: creates other features and then removed.
+  /// This feature may change its macro-state according to selected item.
+  /// \returns false by default
+  SKETCHPLUGIN_EXPORT virtual bool isMacro() const;
+
   /// Use plugin manager for features creation
   SketchPlugin_Projection();
 
@@ -86,6 +109,9 @@ protected:
   /// \brief Initializes attributes of derived class.
   virtual void initDerivedClassAttributes();
 
+  /// \brief Initializes attributes of keeping the reference to the original shape.
+  virtual void initDerivedClassAttributes2();
+
 private:
   /// \brief Find projection of a feature onto sketch plane
   void computeProjection(const std::string& theID);
index fb64f079c1e1b9fd7c2fbdc09e4bd272939eb835..e44941948ddef954ad378c36e30d6257c85540b5 100644 (file)
@@ -43,4 +43,7 @@ void SketchPlugin_SketchEntity::initAttributes()
   anAttr = data()->addAttribute(PARENT_ID(), ModelAPI_AttributeReference::typeId());
   anAttr->setIsArgument(false);
   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PARENT_ID());
+
+  // initialize the rest of attributes
+  initDerivedClassAttributes2();
 }
index c9a3e29a127a57c758660e73474a31ac433d9832..0fabd0bbb61cf2172f798354cd29f7d2e203e4db 100644 (file)
@@ -227,6 +227,9 @@ protected:
   /// \brief Initializes attributes of derived class.
   virtual void initDerivedClassAttributes(){};
 
+  /// \brief Initializes attributes of derived class which were added recently.
+  virtual void initDerivedClassAttributes2(){};
+
 };
 
 #endif
index feaec5c663f2c320d12352567c584a2c7ece649e..14920c109ad5b1d9dd76c73d0ff88e9ff1cb869a 100644 (file)
@@ -1259,7 +1259,7 @@ bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute,
     std::shared_ptr<GeomAPI_Ellipse> anEllipse = anEdge->ellipse();
     std::shared_ptr<GeomAPI_Dir> anEllipseNormal = anEllipse->normal();
     double aDot = fabs(aNormal->dot(anEllipseNormal));
-    aValid = fabs(aDot - 1.0) <= tolerance * tolerance;
+    aValid = aDot >= 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.");
index aad453f54df1fe134f6148c492643ab31a6c634d..6ee4690a42735494f26d4f1e23b3ce8aef97c03e 100644 (file)
       <translation>Edges in selected point has tangent constraint</translation>
     </message>
   </context>
-  
+
+  <context>
+    <name>SketchProjection</name>
+    <message>
+      <source>Project feature onto sketch plane</source>
+      <translation>Project feature onto sketch plane</translation>
+    </message>
+    <message>
+      <source>Projection</source>
+      <translation>Projection</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchProjection:ExternalFeature</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Select external edge or vertex.</translation>
+    </message>
+    <message>
+      <source>Object</source>
+      <translation>Object</translation>
+    </message>
+    <message>
+      <source>Select external edge or vertex.</source>
+      <translation>Select external edge or vertex.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchProjection:IncludeToResult</name>
+    <message>
+      <source>Include into the sketch result</source>
+      <translation>Include into the sketch result</translation>
+    </message>
+    <message>
+      <source>Include projected feature into the sketch result</source>
+      <translation>Include projected feature into the sketch result</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchProjection:keep_reference</name>
+    <message>
+      <source>A sketch entity will be created without connection to the selected shape.</source>
+      <translation>A sketch entity will be created without connection to the selected shape.</translation>
+    </message>
+    <message>
+      <source>The reference to the original curve is stored. So it can be changed later.</source>
+      <translation>The reference to the original curve is stored. So it can be changed later.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchProjection:make_fixed</name>
+    <message>
+      <source>Assign the Fixed constraint to the result of projection</source>
+      <translation>Assign the Fixed constraint to the result of projection</translation>
+    </message>
+    <message>
+      <source>Make projected curve fixed</source>
+      <translation>Make projected curve fixed</translation>
+    </message>
+  </context>
   <context>
     <name>SketchProjection:ExternalFeature:SketchPlugin_ProjectionValidator</name>
     <message>
       <translation>Error: Selected object is not supported for projection.</translation>
     </message>
   </context>
-  <context>
-    <name>SketchProjection:Model_FeatureValidator</name>
-    <message>
-      <source>Attribute "%1" is not initialized.</source>
-      <translation></translation>
-    </message>
-  </context>
 
   <!-- SketchCurveFitting -->
   <context>
index d509191c4cf755c625a7167ee5396ce11c702a9c..74e55917088470edc0cf85ec69fcbf913ad3729d 100644 (file)
     </message>
   </context>
 
-  <context>
-    <name>SketchProjection:ExternalFeature:SketchPlugin_ProjectionValidator</name>
-    <message>
-      <source>The attribute with the %1 type is not processed</source>
-      <translation>Un argument de type %1 de la fonctionnalité de projection n&apos;est pas pris en charge</translation>
-    </message>
-    <message>
-      <source>The attribute %1 should be an edge</source>
-      <translation>L&apos;attribut %1 doit être une arête</translation>
-    </message>
-    <message>
-      <source>There is no sketch referring to the current feature</source>
-      <translation>La fonction de projection n&apos;a pas d&apos;esquisse</translation>
-    </message>
-    <message>
-      <source>The attribute %1 should be an edge or vertex</source>
-      <translation>L&apos;élément projeté doit être une arête ou un sommet</translation>
-    </message>
-    <message>
-      <source>Unable to project feature from the same sketch</source>
-      <translation>Les fonctions de l&apos;esquisse en cours ne peuvent pas être projetées</translation>
-    </message>
-    <message>
-      <source>Error: Line is orthogonal to the sketch plane.</source>
-      <translation>Erreur: La ligne est orthogonale au plan d&apos;esquisse.</translation>
-    </message>
-    <message>
-      <source>Error: Circle is orthogonal to the sketch plane.</source>
-      <translation>Erreur: Le cercle est orthogonal au plan d&apos;esquisse.</translation>
-    </message>
-    <message>
-      <source>Error: Arc is orthogonal to the sketch plane.</source>
-      <translation>Erreur: L&apos;arc est orthogonal au plan d&apos;esquisse.</translation>
-    </message>
-    <message>
-      <source>Error: Ellipse is orthogonal to the sketch plane.</source>
-      <translation>Erreur: L&apos;ellipse est orthogonale au plan d&apos;esquisse.</translation>
-    </message>
-    <message>
-      <source>Error: Elliptic Arc is orthogonal to the sketch plane.</source>
-      <translation>Erreur: L&apos;arc d&apos;ellipse est orthogonal au plan d&apos;esquisse.</translation>
-    </message>
-    <message>
-      <source>Error: Selected object is not supported for projection.</source>
-      <translation>Erreur: L&apos;objet sélectionné n&apos;est pas pris en charge pour la projection.</translation>
-    </message>
-  </context>
-  <context>
-    <name>SketchProjection:Model_FeatureValidator</name>
-    <message>
-      <source>Attribute "%1" is not initialized.</source>
-      <translation>L&apos;attribut &quot;%1&quot; n&apos;est pas initialisé.</translation>
-    </message>
-  </context>
-  <context>
-    <name>SketchProjection:ExternalFeature</name>
-    <message>
-      <source>Attribute "%1" is not initialized.</source>
-      <translation>L&apos;attribut &quot;%1&quot; n&apos;est pas initialisé.</translation>
-    </message>
-    <message>
-      <source>Object</source>
-      <translation>Objet</translation>
-    </message>
-    <message>
-      <source>Select external edge or vertex.</source>
-      <translation>Sélectionnez une arête externe ou un sommet.</translation>
-    </message>
-  </context>
-
   <context>
     <name>Sketch</name>
     <message>
       <translation>Inclure la fonctionnalité projetée dans le résultat de l&apos;esquisse</translation>
     </message>
   </context>
+  <context>
+    <name>SketchProjection:keep_reference</name>
+    <message>
+      <source>A sketch entity will be created without connection to the selected shape.</source>
+      <translation>Une entité d&apos;esquisse sera créée sans connexion à la forme sélectionnée.</translation>
+    </message>
+    <message>
+      <source>The reference to the original curve is stored. So it can be changed later.</source>
+      <translation>La référence à la courbe d&apos;origine est stockée. Elle peut donc être modifiée ultérieurement.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchProjection:make_fixed</name>
+    <message>
+      <source>Assign the Fixed constraint to the result of projection</source>
+      <translation>Affectez la contrainte Fixe au résultat de la projection</translation>
+    </message>
+    <message>
+      <source>Make projected curve fixed</source>
+      <translation>Fixer la courbe projetée</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchProjection:ExternalFeature:SketchPlugin_ProjectionValidator</name>
+    <message>
+      <source>The attribute with the %1 type is not processed</source>
+      <translation>Un argument de type %1 de la fonctionnalité de projection n&apos;est pas pris en charge</translation>
+    </message>
+    <message>
+      <source>The attribute %1 should be an edge</source>
+      <translation>L&apos;attribut %1 doit être une arête</translation>
+    </message>
+    <message>
+      <source>There is no sketch referring to the current feature</source>
+      <translation>La fonction de projection n&apos;a pas d&apos;esquisse</translation>
+    </message>
+    <message>
+      <source>The attribute %1 should be an edge or vertex</source>
+      <translation>L&apos;élément projeté doit être une arête ou un sommet</translation>
+    </message>
+    <message>
+      <source>Unable to project feature from the same sketch</source>
+      <translation>Les fonctions de l&apos;esquisse en cours ne peuvent pas être projetées</translation>
+    </message>
+    <message>
+      <source>Error: Line is orthogonal to the sketch plane.</source>
+      <translation>Erreur: La ligne est orthogonale au plan d&apos;esquisse.</translation>
+    </message>
+    <message>
+      <source>Error: Circle is orthogonal to the sketch plane.</source>
+      <translation>Erreur: Le cercle est orthogonal au plan d&apos;esquisse.</translation>
+    </message>
+    <message>
+      <source>Error: Arc is orthogonal to the sketch plane.</source>
+      <translation>Erreur: L&apos;arc est orthogonal au plan d&apos;esquisse.</translation>
+    </message>
+    <message>
+      <source>Error: Ellipse is orthogonal to the sketch plane.</source>
+      <translation>Erreur: L&apos;ellipse est orthogonale au plan d&apos;esquisse.</translation>
+    </message>
+    <message>
+      <source>Error: Elliptic Arc is orthogonal to the sketch plane.</source>
+      <translation>Erreur: L&apos;arc d&apos;ellipse est orthogonal au plan d&apos;esquisse.</translation>
+    </message>
+    <message>
+      <source>Error: Selected object is not supported for projection.</source>
+      <translation>Erreur: L&apos;objet sélectionné n&apos;est pas pris en charge pour la projection.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchProjection:Model_FeatureValidator</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>L&apos;attribut &quot;%1&quot; n&apos;est pas initialisé.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SketchProjection:ExternalFeature</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez une arête externe ou un sommet.</translation>
+    </message>
+    <message>
+      <source>Object</source>
+      <translation>Objet</translation>
+    </message>
+    <message>
+      <source>Select external edge or vertex.</source>
+      <translation>Sélectionnez une arête externe ou un sommet.</translation>
+    </message>
+  </context>
 
   <context>
     <name>SketchRectangle</name>
index 713d690f2de3ec000dcf3548e1d72956c3475fa0..8d1985613c5be54d38da9dce95734c45b7342b52 100644 (file)
@@ -49,12 +49,11 @@ model.end()
 
 from GeomAPI import *
 
+circle = SketchCircle_2.results()[-1].resultSubShapePair()[0].shape()
+assert(circle.isEdge() and circle.edge().isCircle())
 ellipse1 = SketchEllipse_1.results()[-1].resultSubShapePair()[0].shape()
 assert(ellipse1.isEdge() and ellipse1.edge().isEllipse())
 ellipse2 = SketchEllipse_2.results()[-1].resultSubShapePair()[0].shape()
 assert(ellipse2.isEdge() and ellipse2.edge().isEllipse())
 
-# TODO [limitation]: projection of an ellipse to non-parallel plane is forbiden (OCCT issue #31016)
-assert(Sketch_2.feature().error() != "")
-
 assert(model.checkPythonDump())
diff --git a/src/SketchPlugin/Test/TestProjectionWithoutReference.py b/src/SketchPlugin/Test/TestProjectionWithoutReference.py
new file mode 100644 (file)
index 0000000..82e5f54
--- /dev/null
@@ -0,0 +1,146 @@
+# Copyright (C) 2020  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
+#
+
+"""
+    Test projection without the reference to the source geometry.
+"""
+
+import unittest
+
+from salome.shaper import model
+from GeomAPI import *
+from ModelAPI import *
+
+__updated__ = "2020-07-07"
+
+CURVES = []
+PLANE = None
+
+class TestProjectionWithoutRef(unittest.TestCase):
+  def setUp(self):
+    model.begin()
+    self.myDocument = model.moduleDocument()
+    self.mySketch = model.addSketch(partSet, model.selection("FACE", PLANE.name()))
+    self.myDOF = 0
+    self.myNbPoints = 1
+    self.myNbLines = 1
+    self.myNbCircles = 0
+    self.myNbArcs = 0
+    self.myNbEllipses = 2
+    self.myNbEllipticArcs = 2
+    self.myNbSplines = 1
+    self.myNbPeriodicSplines = 1
+    self.myNbProjections = 0
+    self.myNbFixedConstraints = 0
+    self.myNbEdgesInSketch = 0
+
+  def tearDown(self):
+    self.checkDOF()
+    model.end()
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", self.myNbPoints)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", self.myNbLines)
+    model.testNbSubFeatures(self.mySketch, "SketchCircle", self.myNbCircles)
+    model.testNbSubFeatures(self.mySketch, "SketchArc", self.myNbArcs)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", self.myNbEllipses)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", self.myNbEllipticArcs)
+    model.testNbSubFeatures(self.mySketch, "SketchBSpline", self.myNbSplines)
+    model.testNbSubFeatures(self.mySketch, "SketchBSplinePeriodic", self.myNbPeriodicSplines)
+    model.testNbSubFeatures(self.mySketch, "SketchProjection", self.myNbProjections)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintRigid", self.myNbFixedConstraints)
+    nbEdges = 0
+    exp = GeomAPI_ShapeExplorer(self.mySketch.defaultResult().shape(), GeomAPI_Shape.EDGE)
+    while exp.more(): nbEdges += 1; exp.next()
+    self.assertEqual(self.myNbEdgesInSketch, nbEdges)
+
+  def checkDOF(self):
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+
+  def test_projection_withref_includeintoresult(self):
+    """ Test 1. Projection with the reference to the original shapes. Projected curves are composed into the sketch result.
+    """
+    for c in CURVES:
+      self.mySketch.addProjection(c, keepResult = True)
+    self.myNbProjections = len(CURVES)
+    self.myNbEdgesInSketch = len(CURVES) - 1
+
+  def test_projection_withref_notincludeintoresult(self):
+    """ Test 2. Projection with the reference to the original shapes. Projected curves are NOT included into the sketch result.
+    """
+    for c in CURVES:
+      self.mySketch.addProjection(c, keepResult = False)
+    self.myNbProjections = len(CURVES)
+
+  def test_projection_withoutref_noconstraints(self):
+    """ Test 3. Projection without the reference to the original shapes. No additional constraints applied.
+    """
+    for c in CURVES:
+      self.mySketch.addProjection(c, keepRefToOriginal = False)
+    model.do()
+    self.myNbEdgesInSketch = len(CURVES) - 1
+    self.myDOF += 2 + 4 + 5 + 7 + 5 + 7 + 6 * 2 + 6 * 2
+
+  def test_projection_withoutref_fixed(self):
+    """ Test 4. Projection without the reference to the original shapes. Additionally, Fixed constraints applied.
+    """
+    model.end()
+    # use the low-level API to access the necessary attributes
+    session = ModelAPI_Session.get()
+    for c in CURVES:
+      session.startOperation()
+      proj = featureToCompositeFeature(self.mySketch.feature()).addFeature("SketchProjection")
+      proj.boolean("IncludeToResult").setValue(False)
+      proj.string("keep_reference").setValue("False")
+      proj.boolean("make_fixed").setValue(True)
+      c.fillAttribute(proj.selection("ExternalFeature"))
+      session.finishOperation()
+    self.myNbEdgesInSketch = len(CURVES) - 1
+    self.myNbFixedConstraints = len(CURVES)
+    model.begin()
+
+
+if __name__ == "__main__":
+    model.begin()
+    partSet = model.moduleDocument()
+    Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+    SketchPoint_1 = Sketch_1.addPoint(35, -40)
+    CURVES.append(model.selection("VERTEX", Sketch_1.name() + "/" + SketchPoint_1.name()))
+    SketchLine_1 = Sketch_1.addLine(20, -15, 40, 15)
+    CURVES.append(model.selection("EDGE", Sketch_1.name() + "/" + SketchLine_1.name()))
+    SketchCircle_1 = Sketch_1.addCircle(65, -30, 20)
+    CURVES.append(model.selection("EDGE", Sketch_1.name() + "/" + SketchCircle_1.defaultResult().data().name()))
+    SketchArc_1 = Sketch_1.addArc(60, 15, 80, 0, 50, 33, False)
+    CURVES.append(model.selection("EDGE", Sketch_1.name() + "/" + SketchArc_1.defaultResult().data().name()))
+    SketchEllipse_1 = Sketch_1.addEllipse(25, 30, 40, 30, 10)
+    CURVES.append(model.selection("EDGE", Sketch_1.name() + "/" + SketchEllipse_1.defaultResult().data().name()))
+    SketchEllipticArc_1 = Sketch_1.addEllipticArc(40, 70, 55, 70, 45, 50, 25, 56, False)
+    CURVES.append(model.selection("EDGE", Sketch_1.name() + "/" + SketchEllipticArc_1.defaultResult().data().name()))
+    SketchBSpline_1_poles = [(95, -50), (130, -10), (100, 10), (125, 45), (90, 70), (55, 45)]
+    SketchBSpline_1 = Sketch_1.addSpline(poles = SketchBSpline_1_poles)
+    CURVES.append(model.selection("EDGE", Sketch_1.name() + "/" + SketchBSpline_1.name()))
+    SketchBSplinePeriodic_1_poles = [(95, 80), (135, 90), (145, 55), (130, 30), (125, 70), (105, 60)]
+    SketchBSplinePeriodic_1 = Sketch_1.addSpline(poles = SketchBSplinePeriodic_1_poles, periodic = True)
+    CURVES.append(model.selection("EDGE", Sketch_1.name() + "/" + SketchBSplinePeriodic_1.name()))
+    model.do()
+    PLANE = model.addPlane(partSet, model.selection("FACE", "XOY"), model.selection("EDGE", "OY"), 45)
+    model.end()
+
+    test_program = unittest.main(exit=False)
+    assert test_program.result.wasSuccessful(), "Test failed"
+    assert model.checkPythonDump()
index ef62acfca3bb04f0e0c12e64477916fa5ed6fe81..f5f6f3f314eb1cbb8690f78d8161f01fbac81ee1 100644 (file)
               use_sketch_plane="false">
           <validator id="SketchPlugin_ProjectionValidator"/>
         </sketch_shape_selector>
-        <boolvalue id="IncludeToResult" label="Include into the sketch result" default="true" tooltip="Include projected feature into the sketch result"
-                   change_visual_attributes="true"/>
+        <radiobox id="keep_reference"
+                  align_subs="vertical">
+          <radio id="true"
+                 title="Keep reference to the original shape"
+                 tooltip="The reference to the original curve is stored. So it can be changed later.">
+            <boolvalue id="IncludeToResult"
+                       label="Include into the sketch result"
+                       default="true"
+                       tooltip="Include projected feature into the sketch result"
+                       change_visual_attributes="true"/>
+          </radio>
+          <radio id="false"
+                 title="Break connection with the original shape"
+                 tooltip="A sketch entity will be created without connection to the selected shape.">
+            <boolvalue id="make_fixed"
+                       label="Make projected curve fixed"
+                       default="true"
+                       tooltip="Assign the Fixed constraint to the result of projection"/>
+          </radio>
+        </radiobox>
         <validator id="PartSet_ProjectionSelection"/>
       </feature>
 
index 0ecc2291a99583d22f379100b437ca4c4aee24bc..6d6d5beab268a1f975d37c34519d02d9dd4cb0b3 100644 (file)
@@ -114,7 +114,7 @@ static bool hasReference(std::shared_ptr<SketchPlugin_Feature> theFeature,
   for (std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin();
        aRefIt != aRefs.end(); ++aRefIt) {
      FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner());
-     if (anOwner && anOwner->getKind() == theFeatureKind)
+     if (anOwner && !anOwner->isMacro() && anOwner->getKind() == theFeatureKind)
        return true;
   }
   return false;