]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
First implementation of polyline in Sketcher
authorlucasjerome <jerome.lucas@cegsenslab.fr>
Fri, 5 Mar 2021 14:32:26 +0000 (15:32 +0100)
committerlucasjerome <jerome.lucas@cegsenslab.fr>
Fri, 5 Mar 2021 14:32:26 +0000 (15:32 +0100)
12 files changed:
src/PartSet/CMakeLists.txt
src/PartSet/PartSet_Module.cpp
src/PartSet/PartSet_WidgetPolylinePoints.cpp [new file with mode: 0644]
src/PartSet/PartSet_WidgetPolylinePoints.h [new file with mode: 0644]
src/SketchPlugin/CMakeLists.txt
src/SketchPlugin/SketchPlugin_Plugin.cpp
src/SketchPlugin/SketchPlugin_Polyline.cpp [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_Polyline.h [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_Validators.cpp
src/SketchPlugin/SketchPlugin_Validators.h
src/SketchPlugin/icons/polyline.png [new file with mode: 0644]
src/SketchPlugin/plugin-Sketch.xml

index d158d3470a1dd3c72cb080ddcbd64ccdebd844ae..6e27b6b61a72b066f774a9edae3dc06c1ada9a4c 100644 (file)
@@ -62,6 +62,7 @@ SET(PROJECT_HEADERS
     PartSet_TreeNodes.h
     PartSet_FieldStepPrs.h
     PartSet_WidgetBSplinePoints.h
+    PartSet_WidgetPolylinePoints.h
     PartSet_BSplineWidget.h
 )
 
@@ -81,6 +82,7 @@ SET(PROJECT_MOC_HEADERS
     PartSet_WidgetSketchCreator.h
     PartSet_WidgetSketchLabel.h
     PartSet_WidgetBSplinePoints.h
+    PartSet_WidgetPolylinePoints.h
     PartSet_ExternalPointsMgr.h
     PartSet_BSplineWidget.h
 )
@@ -116,6 +118,7 @@ SET(PROJECT_SOURCES
     PartSet_TreeNodes.cpp
     PartSet_FieldStepPrs.cpp
     PartSet_WidgetBSplinePoints.cpp
+    PartSet_WidgetPolylinePoints.cpp
     PartSet_BSplineWidget.cpp
 )
 
index c6a6197c32ea0b6acd1827407f4f8c86f95fbfce..82e6c7496d0f15b77fd747a910b56d98bd85bd1e 100644 (file)
@@ -23,6 +23,7 @@
 #include "PartSet_Tools.h"
 #include "PartSet_PreviewPlanes.h"
 #include "PartSet_WidgetBSplinePoints.h"
+#include "PartSet_WidgetPolylinePoints.h"
 #include "PartSet_WidgetPoint2d.h"
 #include "PartSet_WidgetPoint2DFlyout.h"
 #include "PartSet_WidgetShapeSelector.h"
@@ -927,6 +928,13 @@ ModuleBase_ModelWidget* PartSet_Module::createWidgetByType(const std::string& th
     aBSplineWgt->setSketch(mySketchMgr->activeSketch());
     aWgt = aBSplineWgt;
   }
+  else if (theType == "sketch-polyline_selector") {
+    PartSet_WidgetPolylinePoints* aBSplineWgt =
+        new PartSet_WidgetPolylinePoints(theParent, aWorkshop, theWidgetApi);
+    aBSplineWgt->setSketch(mySketchMgr->activeSketch());
+    aWgt = aBSplineWgt;
+  }
+
   else if (theType == WDG_DOUBLEVALUE_EDITOR) {
     aWgt = new PartSet_WidgetEditor(theParent, aWorkshop, theWidgetApi);
   } else if (theType == "export_file_selector") {
diff --git a/src/PartSet/PartSet_WidgetPolylinePoints.cpp b/src/PartSet/PartSet_WidgetPolylinePoints.cpp
new file mode 100644 (file)
index 0000000..44371b7
--- /dev/null
@@ -0,0 +1,462 @@
+// Copyright (C) 2019-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
+//
+
+#include <PartSet_WidgetPolylinePoints.h>
+
+#include <PartSet_CenterPrs.h>
+#include <PartSet_ExternalObjectsMgr.h>
+#include <PartSet_Module.h>
+#include <PartSet_SketcherReentrantMgr.h>
+#include <PartSet_WidgetPoint2d.h>
+
+#include <XGUI_Tools.h>
+#include <XGUI_Workshop.h>
+#include <XGUI_Displayer.h>
+
+#include <ModuleBase_ISelection.h>
+#include <ModuleBase_IViewer.h>
+#include <ModuleBase_IViewWindow.h>
+#include <ModuleBase_LabelValue.h>
+#include <ModuleBase_Tools.h>
+#include <ModuleBase_ViewerPrs.h>
+#include <ModuleBase_WidgetValidator.h>
+#include <ModuleBase_WidgetValidated.h>
+
+#include <Config_Keywords.h>
+#include <Config_WidgetAPI.h>
+
+#include <Events_Loop.h>
+
+#include <ModelAPI_Events.h>
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_AttributeRefAttrList.h>
+#include <ModelAPI_CompositeFeature.h>
+
+#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_IPresentable.h>
+
+#include <SketchPlugin_Feature.h>
+
+#include <QGridLayout>
+#include <QGroupBox>
+#include <QMouseEvent>
+#include <QGraphicsEffect>
+#include <QScrollArea>
+
+static const double MaxCoordinate = 1e12;
+
+static bool IsPointCreated = false;
+
+PartSet_WidgetPolylinePoints::PartSet_WidgetPolylinePoints(QWidget* theParent,
+                                             ModuleBase_IWorkshop* theWorkshop,
+                                             const Config_WidgetAPI* theData)
+: ModuleBase_ModelWidget(theParent, theData), myWorkshop(theWorkshop),
+  myValueIsCashed(false), myIsFeatureVisibleInCash(true),
+  myXValueInCash(0), myYValueInCash(0), myFinished(false)
+{
+  QVBoxLayout* aMainLayout = new QVBoxLayout(this);
+  ModuleBase_Tools::zeroMargins(aMainLayout);
+
+  // the control should accept the focus, so the boolean flag is corrected to be true
+  myIsObligatory = true;
+  QString aPageName = translate(theData->getProperty(CONTAINER_PAGE_NAME));
+  myBox = new QGroupBox(aPageName, theParent);
+  myBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+  myBox->setFlat(false);
+  aMainLayout->addWidget(myBox);
+
+  theData->getBooleanAttribute(DOUBLE_WDG_ACCEPT_EXPRESSIONS, true);
+
+  QVBoxLayout* aLayout = new QVBoxLayout(myBox);
+  ModuleBase_Tools::adjustMargins(aLayout);
+
+  myScrollArea = new QScrollArea(myBox);
+  myScrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+  myScrollArea->setWidgetResizable(true);
+  myScrollArea->setFrameStyle(QFrame::NoFrame);
+  aLayout->addWidget(myScrollArea);
+
+  QWidget* aContainer = new QWidget(myScrollArea);
+  QVBoxLayout* aBoxLay = new QVBoxLayout(aContainer);
+  aBoxLay->setContentsMargins(0, 0, 0, 0);
+
+  myGroupBox = new QWidget(aContainer);
+  QGridLayout* aGroupLay = new QGridLayout(myGroupBox);
+  ModuleBase_Tools::adjustMargins(aGroupLay);
+  aGroupLay->setSpacing(4);
+  aGroupLay->setColumnStretch(1, 1);
+  createNextPoint();
+  aBoxLay->addWidget(myGroupBox);
+  aBoxLay->addStretch(1);
+
+  myScrollArea->setWidget(aContainer);
+
+  myWidgetValidator = new ModuleBase_WidgetValidator(this, myWorkshop);
+
+}
+
+void PartSet_WidgetPolylinePoints::createNextPoint()
+{
+  storeCurentValue();
+
+  QGridLayout* aGroupLay = dynamic_cast<QGridLayout*>(myGroupBox->layout());
+  int row = (int)myXSpin.size();
+
+  QString aPoleStr = translate("Point %1");
+  aPoleStr = aPoleStr.arg(myXSpin.size() + 1);
+
+  QGroupBox* aPoleGroupBox = new QGroupBox(aPoleStr, myGroupBox);
+  QGridLayout* aPoleLay = new QGridLayout(aPoleGroupBox);
+  ModuleBase_Tools::adjustMargins(aPoleLay);
+  aPoleLay->setSpacing(2);
+  aPoleLay->setColumnStretch(1, 1);
+
+  myXSpin.push_back(new ModuleBase_LabelValue(aPoleGroupBox, tr("X")));
+  aPoleLay->addWidget(myXSpin.back(), 0, 1);
+  myYSpin.push_back(new ModuleBase_LabelValue(aPoleGroupBox, tr("Y")));
+  aPoleLay->addWidget(myYSpin.back(), 1, 1);
+
+  aGroupLay->addWidget(aPoleGroupBox, row, 1);
+  IsPointCreated = true;
+}
+
+void PartSet_WidgetPolylinePoints::removeLastPoint()
+{
+  QGridLayout* aGroupLay = dynamic_cast<QGridLayout*>(myGroupBox->layout());
+  QWidget* aXSpin = myXSpin.back();
+  QWidget* aYSpin = myYSpin.back();
+  QWidget* aBox = myXSpin.back()->parentWidget();
+  myYSpin.pop_back();
+  myXSpin.pop_back();
+
+  aGroupLay->removeWidget(aXSpin);
+  aGroupLay->removeWidget(aYSpin);
+  aGroupLay->removeWidget(aBox);
+
+  aBox->deleteLater();
+
+  // update polyline feature attributes
+  storeValueCustom();
+}
+
+
+PartSet_WidgetPolylinePoints::~PartSet_WidgetPolylinePoints()
+{
+}
+
+bool PartSet_WidgetPolylinePoints::setPoint(double theX, double theY)
+{
+  if (fabs(theX) >= MaxCoordinate || fabs(theY) >= MaxCoordinate)
+    return false;
+
+  myXSpin.back()->setValue(theX);
+  myYSpin.back()->setValue(theY);
+
+  storeValue();
+  return true;
+}
+
+void PartSet_WidgetPolylinePoints::storePoints() const
+{
+
+  std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
+  AttributePoint2DArrayPtr aPointArray = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+      aData->attribute(attributeID()));
+
+  int aSize = (int)myXSpin.size();
+  aPointArray->setSize(aSize);
+
+  std::vector<ModuleBase_LabelValue*>::const_iterator aXIt = myXSpin.begin();
+  std::vector<ModuleBase_LabelValue*>::const_iterator aYIt = myYSpin.begin();
+  for (int anIndex = 0; aXIt != myXSpin.end() && aYIt != myYSpin.end(); ++anIndex, ++aXIt, ++aYIt)
+    aPointArray->setPnt(anIndex, (*aXIt)->value(), (*aYIt)->value());
+
+}
+
+bool PartSet_WidgetPolylinePoints::storeValueCustom()
+{
+  std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
+  if (!aData || !aData->isValid()) // can be on abort of sketcher element
+    return false;
+  AttributePoint2DArrayPtr aPointArray = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+      aData->attribute(attributeID()));
+
+  PartSet_WidgetPolylinePoints* that = (PartSet_WidgetPolylinePoints*) this;
+  bool isBlocked = that->blockSignals(true);
+  bool isImmutable = aPointArray->setImmutable(true);
+
+  if (myFeature->isMacro()) {
+    // Moving points of macro-features has been processed directly (without solver)
+    storePoints();
+    updateObject(myFeature);
+
+  } else {
+    if (!aPointArray->isInitialized()) {
+      storePoints();
+    }
+    std::shared_ptr<ModelAPI_ObjectMovedMessage> aMessage(
+        new ModelAPI_ObjectMovedMessage(this));
+    aMessage->setMovedAttribute(aPointArray, aPointArray->size() - 1);
+    aMessage->setOriginalPosition(aPointArray->pnt(aPointArray->size() - 1));
+    aMessage->setCurrentPosition(myXSpin.back()->value(), myYSpin.back()->value());
+    Events_Loop::loop()->send(aMessage);
+  }
+
+  aPointArray->setImmutable(isImmutable);
+  that->blockSignals(isBlocked);
+
+  return true;
+}
+
+bool PartSet_WidgetPolylinePoints::restoreValueCustom()
+{
+
+  std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
+  AttributePoint2DArrayPtr aPointArray = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+      aData->attribute(attributeID()));
+
+  if (aPointArray->isInitialized()) {
+    while ((int)myXSpin.size() < aPointArray->size())
+      createNextPoint();
+
+    std::vector<ModuleBase_LabelValue*>::iterator aXIt = myXSpin.begin();
+    std::vector<ModuleBase_LabelValue*>::iterator aYIt = myYSpin.begin();
+    for (int anIndex = 0; aXIt != myXSpin.end() && aYIt != myYSpin.end();
+         ++anIndex, ++aXIt, ++aYIt) {
+      GeomPnt2dPtr aPoint = aPointArray->pnt(anIndex);
+      (*aXIt)->setValue(aPoint->x());
+      (*aYIt)->setValue(aPoint->y());
+    }
+  }
+  else {
+    if (myXSpin.empty())
+      createNextPoint();
+
+    myXSpin.back()->setValue(0.0);
+    myYSpin.back()->setValue(0.0);
+  }
+
+  return true;
+}
+
+static void storeArray(const std::vector<ModuleBase_LabelValue*>& theLabels,
+                       std::vector<double>& theValues)
+{
+  theValues.clear();
+  theValues.reserve(theLabels.size());
+  for (std::vector<ModuleBase_LabelValue*>::const_iterator anIt = theLabels.begin();
+       anIt != theLabels.end(); ++anIt)
+    theValues.push_back((*anIt)->value());
+}
+
+void PartSet_WidgetPolylinePoints::storeCurentValue()
+{
+  myValueIsCashed = true;
+  myIsFeatureVisibleInCash = XGUI_Displayer::isVisible(
+                       XGUI_Tools::workshop(myWorkshop)->displayer(), myFeature);
+
+  storeArray(myXSpin, myXValueInCash);
+  storeArray(myYSpin, myYValueInCash);
+}
+
+static void restoreArray(std::vector<double>& theCacheValues,
+                         std::vector<ModuleBase_LabelValue*>& theLabels)
+{
+  std::vector<double>::iterator aCIt = theCacheValues.begin();
+  std::vector<ModuleBase_LabelValue*>::iterator anIt = theLabels.begin();
+  for (; anIt != theLabels.end(); ++anIt) {
+    if (aCIt != theCacheValues.end())
+      (*anIt)->setValue(*aCIt++);
+    else
+      (*anIt)->setValue(0.0);
+  }
+  theCacheValues.clear();
+}
+
+bool PartSet_WidgetPolylinePoints::restoreCurentValue()
+{
+  bool aRestoredAndHidden = true;
+
+  bool isVisible = myIsFeatureVisibleInCash;
+
+  myValueIsCashed = false;
+  myIsFeatureVisibleInCash = true;
+  // fill the control widgets by the cashed value
+  restoreArray(myXValueInCash, myXSpin);
+  restoreArray(myYValueInCash, myYSpin);
+
+  // store value to the model
+  storeValueCustom();
+  if (isVisible) {
+    setValueState(Stored);
+    aRestoredAndHidden = false;
+  }
+  else
+    aRestoredAndHidden = true;
+
+  return aRestoredAndHidden;
+}
+
+QList<QWidget*> PartSet_WidgetPolylinePoints::getControls() const
+{
+  QList<QWidget*> aControls;
+  aControls.append(myScrollArea);
+  return aControls;
+}
+
+void PartSet_WidgetPolylinePoints::selectionModes(int& theModuleSelectionModes, QIntList& theModes)
+{
+  theModuleSelectionModes = -1;
+  theModes << TopAbs_VERTEX;
+}
+
+void PartSet_WidgetPolylinePoints::deactivate()
+{
+  // the value of the control should be stored to model if it was not
+  // initialized yet. It is important when we leave this control by Tab key.
+  // It should not be performed by the widget activation as the preview
+  // is visualized with default value. Line point is moved to origin.
+  AttributePtr anAttribute = myFeature->data()->attribute(attributeID());
+  if (anAttribute && !anAttribute->isInitialized())
+    storeValue();
+
+  ModuleBase_ModelWidget::deactivate();
+}
+
+void PartSet_WidgetPolylinePoints::mouseReleased(ModuleBase_IViewWindow* theWindow,
+                                                QMouseEvent* theEvent)
+{
+  // the contex menu release by the right button should not be processed by this widget
+  if (theEvent->button() != Qt::LeftButton)
+    return;
+
+  ModuleBase_ISelection* aSelection = myWorkshop->selection();
+  Handle(V3d_View) aView = theWindow->v3dView();
+
+  QList<ModuleBase_ViewerPrsPtr> aList = aSelection->getSelected(ModuleBase_ISelection::Viewer);
+  ModuleBase_ViewerPrsPtr aFirstValue =
+    aList.size() > 0 ? aList.first() : ModuleBase_ViewerPrsPtr();
+  if (!aFirstValue.get() && myPreSelected.get()) {
+    aFirstValue = myPreSelected;
+  }
+
+  TopoDS_Shape aSelectedShape;
+  ObjectPtr aSelectedObject;
+
+  // if we have selection and use it
+  if (aFirstValue.get() &&  aFirstValue->shape().get()) {
+    GeomShapePtr aGeomShape = aFirstValue->shape();
+    aSelectedShape = aGeomShape->impl<TopoDS_Shape>();
+    aSelectedObject = aFirstValue->object();
+
+    FeaturePtr aSelectedFeature = ModelAPI_Feature::feature(aSelectedObject);
+    std::shared_ptr<SketchPlugin_Feature> aSPFeature;
+    if (aSelectedFeature.get())
+      aSPFeature = std::dynamic_pointer_cast<SketchPlugin_Feature>(aSelectedFeature);
+
+    bool isSketchExternalFeature = aSPFeature.get() && aSPFeature->isExternal();
+    if ((!aSPFeature && !aSelectedShape.IsNull()) || isSketchExternalFeature) {
+      ObjectPtr aFixedObject =
+          PartSet_Tools::findFixedObjectByExternal(aSelectedShape, aSelectedObject, mySketch);
+      if (aFixedObject)
+        aSelectedObject = aFixedObject;
+      else if (!isSketchExternalFeature) {
+        FeaturePtr aCreatedFeature;
+        aSelectedObject = PartSet_Tools::createFixedObjectByExternal(
+            aGeomShape, aSelectedObject, mySketch, false, aCreatedFeature);
+      }
+    }
+  }
+  // The selection could be a center of an external circular object
+  else if (aFirstValue.get() && (!aFirstValue->interactive().IsNull())) {
+    Handle(PartSet_CenterPrs) aAIS =
+        Handle(PartSet_CenterPrs)::DownCast(aFirstValue->interactive());
+    if (!aAIS.IsNull()) {
+      gp_Pnt aPntComp = aAIS->Component()->Pnt();
+      GeomVertexPtr aVertPtr(new GeomAPI_Vertex(aPntComp.X(), aPntComp.Y(), aPntComp.Z()));
+      aSelectedShape = aVertPtr->impl<TopoDS_Shape>();
+
+      aSelectedObject =
+          PartSet_Tools::findFixedObjectByExternal(aSelectedShape, aAIS->object(), mySketch);
+      if (!aSelectedObject.get())
+      {
+        FeaturePtr aCreatedFeature;
+        aSelectedObject = PartSet_Tools::createFixedByExternalCenter(aAIS->object(), aAIS->edge(),
+            aAIS->centerType(), mySketch, false, aCreatedFeature);
+      }
+    }
+  }
+
+  GeomPnt2dPtr aSelectedPoint = PartSet_Tools::getPnt2d(aView, aSelectedShape, mySketch);
+  if (!aSelectedPoint) {
+    aSelectedPoint = PartSet_Tools::getPnt2d(theEvent, theWindow, mySketch);
+    setValueState(Stored); // in case of edge selection, Apply state should also be updated
+  }
+  // next pole of B-spline
+  createNextPoint();
+}
+
+void PartSet_WidgetPolylinePoints::mouseMoved(ModuleBase_IViewWindow* theWindow,
+                                             QMouseEvent* theEvent)
+{
+  PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(myWorkshop->module());
+
+  if (myFinished || isEditingMode() || aModule->sketchReentranceMgr()->isInternalEditActive())
+    return;
+
+  gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWindow->v3dView());
+
+  double aX = 0, aY = 0;
+  PartSet_Tools::convertTo2D(aPoint, mySketch, theWindow->v3dView(), aX, aY);
+  if (myState != ModifiedInViewer)
+    storeCurentValue();
+
+  setPoint(aX, aY);
+
+  if (IsPointCreated) {
+    QPoint aPnt = myGroupBox->geometry().bottomLeft();
+    myScrollArea->ensureVisible(aPnt.x(), aPnt.y());
+    IsPointCreated = false;
+  }
+}
+
+
+bool PartSet_WidgetPolylinePoints::processEscape()
+{
+  bool isProcessed = !isEditingMode();
+  if (isProcessed) {
+    // remove widgets corrsponding to the last pole/weight of B-spline
+    removeLastPoint();
+    myFinished = true;
+
+    emit focusOutWidget(this);
+  }
+  return isProcessed;
+}
+
+bool PartSet_WidgetPolylinePoints::useSelectedShapes() const
+{
+  return true;
+}
+
+
+
diff --git a/src/PartSet/PartSet_WidgetPolylinePoints.h b/src/PartSet/PartSet_WidgetPolylinePoints.h
new file mode 100644 (file)
index 0000000..bde911d
--- /dev/null
@@ -0,0 +1,152 @@
+// Copyright (C) 2019-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
+//
+
+#ifndef PartSet_WidgetPolylinePoints_H
+#define PartSet_WidgetPolylinePoints_H
+
+#include "PartSet.h"
+#include "PartSet_MouseProcessor.h"
+
+#include <ModuleBase_ModelWidget.h>
+
+#include <QObject>
+
+class GeomAPI_Pnt2d;
+class ModelAPI_CompositeFeature;
+class ModuleBase_LabelValue;
+class PartSet_ExternalObjectsMgr;
+class QGroupBox;
+class QScrollArea;
+
+/**\class PartSet_WidgetPolylinePoints
+ * \ingroup Modules
+ * \brief Implementation of model widget to provide widget to input a list of 2D points
+ *        of polyline
+ * In XML can be defined as following:
+ * \code
+ * <sketch-polyline_selector id="points"/>
+ * \endcode
+ */
+class PARTSET_EXPORT PartSet_WidgetPolylinePoints : public ModuleBase_ModelWidget,
+                                                   public PartSet_MouseProcessor
+{
+Q_OBJECT
+public:
+  /// Constructor
+  /// \param theParent the parent object
+  /// \param theWorkshop a current workshop
+  /// \param theData the widget configuation. The attribute of the model widget is obtained from
+  PartSet_WidgetPolylinePoints(QWidget* theParent, ModuleBase_IWorkshop* theWorkshop,
+                              const Config_WidgetAPI* theData);
+  /// Destructor
+  virtual ~PartSet_WidgetPolylinePoints();
+
+  /// Fills given container with selection modes if the widget has it
+  /// \param [out] theModuleSelectionModes module additional modes, -1 means all default modes
+  /// \param theModes [out] a container of modes
+  virtual void selectionModes(int& theModuleSelectionModes, QIntList& theModes);
+
+  /// Fills the attribute with the value of the selected owner
+  /// \param thePrs a selected owner
+  bool setSelectionCustom(const std::shared_ptr<ModuleBase_ViewerPrs>& theValue);
+
+  /// Returns list of widget controls
+  /// \return a control list
+  virtual QList<QWidget*> getControls() const;
+
+  /// The methiod called when widget is deactivated
+  virtual void deactivate();
+
+  /// \returns the sketch instance
+  std::shared_ptr<ModelAPI_CompositeFeature> sketch() const { return mySketch; }
+
+  /// Set sketch instance
+  void setSketch(std::shared_ptr<ModelAPI_CompositeFeature> theSketch) { mySketch = theSketch; }
+
+  /// Fill the widget values by given point
+  /// \param theX the X coordinate
+  /// \param theY the Y coordinate
+  /// \returns True in case of success
+  bool setPoint(double theX, double theY);
+
+  /// Returns true if the event is processed.
+  virtual bool processEscape();
+
+  /// Returns true if the attribute can be changed using the selected shapes in the viewer
+  /// and creating a coincidence constraint to them. This control use them.
+  virtual bool useSelectedShapes() const;
+
+  /// Processing the mouse move event in the viewer
+  /// \param theWindow a view window
+  /// \param theEvent a mouse event
+  virtual void mouseMoved(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent);
+
+  /// Processing the mouse release event in the viewer
+  /// \param theWindow a view window
+  /// \param theEvent a mouse event
+  virtual void mouseReleased(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent);
+
+protected:
+  /// Saves the internal parameters to the given feature
+  /// \return True in success
+  virtual bool storeValueCustom();
+
+  /// Restore value from attribute data to the widget's control
+  virtual bool restoreValueCustom();
+
+  /// Store current value in cashed value
+  void storeCurentValue();
+
+  /// Restore cashed value in the model attribute
+  /// \return boolean state if the restored feature shoud be hidden
+  bool restoreCurentValue();
+
+private:
+  /// Create labels for the next B-spline point
+  void createNextPoint();
+  /// Remove labels for the last B-spline point
+  void removeLastPoint();
+
+  /// Save polyline points to corresponding attributes
+  void storePoints() const;
+
+protected:
+  ModuleBase_IWorkshop* myWorkshop; ///< workshop
+
+private:
+  QGroupBox* myBox;
+  QWidget* myGroupBox;  ///< the parent group box for all intenal widgets
+  QScrollArea* myScrollArea;
+  std::vector<ModuleBase_LabelValue*> myXSpin; ///< the label for the X coordinate
+  std::vector<ModuleBase_LabelValue*> myYSpin; ///< the label for the Y coordinate
+
+  /// value used as selection in mouse release method
+  std::shared_ptr<ModuleBase_ViewerPrs> myPreSelected;
+
+  /// it is important during restart operation
+  CompositeFeaturePtr mySketch;
+
+  bool myValueIsCashed; /// boolean state if the value is cashed during value state change
+  bool myIsFeatureVisibleInCash; /// boolean value if the feature was visible when cash if filled
+  std::vector<double> myXValueInCash; /// the cashed X value during value state change
+  std::vector<double> myYValueInCash; /// the cashed Y value during value state change
+
+  bool myFinished; /// \c true if building the polyline is finished (escape pressed)
+};
+#endif
index 3fcc4e38983062588a70b457fcd7732c1dbfbae7..b39e86b7cc4109516a0e715d3f4b73442a00cbdc 100644 (file)
@@ -56,6 +56,7 @@ SET(PROJECT_HEADERS
     SketchPlugin_Feature.h
     SketchPlugin_IntersectionPoint.h
     SketchPlugin_Line.h
+    SketchPlugin_Polyline.h
     SketchPlugin_MacroArc.h
     SketchPlugin_MacroArcReentrantMessage.h
     SketchPlugin_MacroBSpline.h
@@ -112,6 +113,7 @@ SET(PROJECT_SOURCES
     SketchPlugin_Feature.cpp
     SketchPlugin_IntersectionPoint.cpp
     SketchPlugin_Line.cpp
+    SketchPlugin_Polyline.cpp
     SketchPlugin_MacroArc.cpp
     SketchPlugin_MacroBSpline.cpp
     SketchPlugin_MacroCircle.cpp
index b71ff3c37889f6dda4790a9aed34e0863bab772a..f2c9440833eef310c493a4be12cb996bba0287c1 100644 (file)
@@ -49,6 +49,7 @@
 #include <SketchPlugin_MacroArc.h>
 #include <SketchPlugin_MacroBSpline.h>
 #include <SketchPlugin_MacroCircle.h>
+#include <SketchPlugin_Polyline.h>
 #include <SketchPlugin_MultiRotation.h>
 #include <SketchPlugin_MultiTranslation.h>
 #include <SketchPlugin_Offset.h>
@@ -155,6 +156,8 @@ SketchPlugin_Plugin::SketchPlugin_Plugin()
                               new SketchPlugin_MultiRotationAngleValidator);
   aFactory->registerValidator("SketchPlugin_BSplineValidator",
                               new SketchPlugin_BSplineValidator);
+  aFactory->registerValidator("SketchPlugin_PolylineValidator",
+                              new SketchPlugin_PolylineValidator);
   aFactory->registerValidator("SketchPlugin_CurveFittingValidator",
                               new SketchPlugin_CurveFittingValidator);
 
@@ -279,6 +282,8 @@ FeaturePtr SketchPlugin_Plugin::createFeature(std::string theFeatureID)
     return FeaturePtr(new SketchPlugin_EllipticArc);
   } else if (theFeatureID == SketchPlugin_MacroEllipticArc::ID()) {
     return FeaturePtr(new SketchPlugin_MacroEllipticArc);
+  } else if (theFeatureID == SketchPlugin_Polyline::ID()) {
+    return FeaturePtr(new SketchPlugin_Polyline);
   } else if (theFeatureID == SketchPlugin_CurveFitting::ID()) {
     return FeaturePtr(new SketchPlugin_CurveFitting);
   } else if (theFeatureID == SketchPlugin_SketchDrawer::ID()) {
@@ -362,6 +367,7 @@ std::shared_ptr<ModelAPI_FeatureStateMessage> SketchPlugin_Plugin
       aMsg->setState(SketchPlugin_MacroCircle::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_MacroEllipse::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_MacroEllipticArc::ID(), aHasSketchPlane);
+      aMsg->setState(SketchPlugin_Polyline::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_ConstraintDistanceHorizontal::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_ConstraintDistanceVertical::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_CurveFitting::ID(), aHasSketchPlane);
diff --git a/src/SketchPlugin/SketchPlugin_Polyline.cpp b/src/SketchPlugin/SketchPlugin_Polyline.cpp
new file mode 100644 (file)
index 0000000..c73fd7a
--- /dev/null
@@ -0,0 +1,182 @@
+// Copyright (C) 2014-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
+//
+
+#include "SketchPlugin_Polyline.h"
+
+#include "SketchPlugin_Line.h"
+#include "SketchPlugin_Sketch.h"
+
+#include "SketchPlugin_ConstraintCoincidence.h"
+
+#include <ModelAPI_AttributeSelection.h>
+#include <ModelAPI_AttributeBoolean.h>
+#include <ModelAPI_Data.h>
+#include <ModelAPI_Validator.h>
+#include <ModelAPI_Session.h>
+
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <GeomDataAPI_Point2D.h>
+#include <GeomAlgoAPI_PointBuilder.h>
+#include <GeomAlgoAPI_EdgeBuilder.h>
+#include <GeomAlgoAPI_CompoundBuilder.h>
+#include <SketchPlugin_Tools.h>
+
+#include <iostream>
+
+SketchPlugin_Polyline::SketchPlugin_Polyline()
+    : SketchPlugin_SketchEntity()
+{}
+
+void SketchPlugin_Polyline::initAttributes()
+{
+  SketchPlugin_SketchEntity::initAttributes();
+}
+
+void SketchPlugin_Polyline::initDerivedClassAttributes()
+{
+
+  data()->addAttribute(POINTS_ID(), GeomDataAPI_Point2DArray::typeId());
+
+}
+
+void SketchPlugin_Polyline::execute()
+{
+  createLineFeature();
+}
+
+void  SketchPlugin_Polyline::createLineFeature()
+{
+  AttributePoint2DArrayPtr aPointsArray =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POINTS_ID()));
+
+  getAISObject(AISObjectPtr());
+
+  if (aPointsArray->isInitialized())
+  {
+    FeaturePtr aLastline;
+    FeaturePtr aFirstline;
+    // collect points
+    for (int anIndex = 1; anIndex < aPointsArray->size(); ++anIndex) {
+
+      FeaturePtr aLine = sketch()->addFeature(SketchPlugin_Line::ID());
+      if (anIndex ==1) {
+        aFirstline = aLine;
+      }
+      std::shared_ptr<GeomDataAPI_Point2D> aStartA = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        aLine->attribute(SketchPlugin_Line::START_ID()));
+
+      aStartA->setValue(aPointsArray->pnt(anIndex-1));
+
+      std::shared_ptr<GeomDataAPI_Point2D> aEndA = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        aLine->attribute(SketchPlugin_Line::END_ID()));
+
+      aEndA->setValue(aPointsArray->pnt(anIndex));
+
+      aLine->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(
+          boolean(AUXILIARY_ID())->value());
+
+      if (aLastline) {
+        // Initialize new line with first point equal to end of previous
+        std::shared_ptr<ModelAPI_Data> aSFData = aLastline->data();
+        std::shared_ptr<GeomDataAPI_Point2D> aSPoint =
+                                    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+                                                aSFData->attribute(SketchPlugin_Line::END_ID()));
+        std::shared_ptr<ModelAPI_Data> aNFData = aLine->data();
+        std::shared_ptr<GeomDataAPI_Point2D> aNPoint =
+                                    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+                                              aNFData->attribute(SketchPlugin_Line::START_ID()));
+        aNPoint->setValue(aSPoint->x(), aSPoint->y());
+        SketchPlugin_ConstraintCoincidence::createCoincidenceFeature(sketch(), aSPoint, aNPoint);
+      }
+
+      aLine->execute();
+      aLastline = aLine;
+    }
+    // Initialize new line with first point equal to end of previous
+    std::shared_ptr<ModelAPI_Data> aSFData = aLastline->data();
+    std::shared_ptr<GeomDataAPI_Point2D> aSPoint =
+                                           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+                                                aSFData->attribute(SketchPlugin_Line::END_ID()));
+    std::shared_ptr<ModelAPI_Data> aNFData = aFirstline->data();
+    std::shared_ptr<GeomDataAPI_Point2D> aNPoint =
+                                           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+                                              aNFData->attribute(SketchPlugin_Line::START_ID()));
+
+    double aDistance = aSPoint->pnt()->distance(aNPoint->pnt());
+    if (aDistance < 1) {
+      aNPoint->setValue(aSPoint->x(), aSPoint->y());
+      SketchPlugin_ConstraintCoincidence::createCoincidenceFeature(sketch(), aSPoint, aNPoint);
+    }
+  }
+}
+
+const std::string& SketchPlugin_Polyline::getKind()
+{
+  static std::string MY_KIND = SketchPlugin_Polyline::ID();
+  return MY_KIND;
+}
+
+void SketchPlugin_Polyline::attributeChanged(const std::string& theID) {
+}
+
+AISObjectPtr SketchPlugin_Polyline::getAISObject(AISObjectPtr thePrevious)
+{
+
+  SketchPlugin_Sketch* aSketch = sketch();
+  if (!aSketch)
+    return AISObjectPtr();
+
+  AttributePoint2DArrayPtr aPointsArray =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POINTS_ID()));
+
+  if (aPointsArray->size() < 2)
+    return AISObjectPtr();
+
+  std::list<GeomShapePtr> aShapes;
+
+  // convert points to vertices
+  std::list<GeomPointPtr> aPoles3D;
+  for (int anIndex = 0; anIndex < aPointsArray->size()-1; ++anIndex) {
+
+    GeomPnt2dPtr aPoint1 = aPointsArray->pnt(anIndex);
+    GeomPnt2dPtr aPoint2 = aPointsArray->pnt(anIndex + 1);
+    GeomPointPtr aPole3D1 = aSketch->to3D(aPoint1->x(), aPoint1->y());
+    GeomPointPtr aPole3D2 = aSketch->to3D(aPoint2->x(), aPoint2->y());
+    aShapes.push_back(GeomAlgoAPI_PointBuilder::vertex(aPole3D1));
+
+    GeomShapePtr anEdge =
+      GeomAlgoAPI_EdgeBuilder::line(aPole3D1, aPole3D2);
+    if (anEdge)
+      aShapes.push_back(anEdge);
+
+  }
+
+  GeomShapePtr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
+
+  AISObjectPtr anAIS = thePrevious;
+  if (!anAIS)
+    anAIS.reset(new GeomAPI_AISObject());
+  anAIS->createShape(aCompound);
+
+  // Modify attributes
+  SketchPlugin_Tools::customizeFeaturePrs(anAIS, boolean(AUXILIARY_ID())->value());
+
+  return anAIS;
+}
\ No newline at end of file
diff --git a/src/SketchPlugin/SketchPlugin_Polyline.h b/src/SketchPlugin/SketchPlugin_Polyline.h
new file mode 100644 (file)
index 0000000..7decbf4
--- /dev/null
@@ -0,0 +1,89 @@
+// Copyright (C) 2014-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
+//
+
+#ifndef SketchPlugin_Polyline_H_
+#define SketchPlugin_Polyline_H_
+
+#include <ModelAPI_IReentrant.h>
+
+#include "SketchPlugin.h"
+#include <SketchPlugin_SketchEntity.h>
+#include <SketchPlugin_Sketch.h>
+#include <list>
+
+#include <GeomAPI_IPresentable.h>
+
+class GeomAPI_Pnt2d;
+
+/**\class SketchPlugin_Polyline
+ * \ingroup Plugins
+ * \brief Feature for creation of polyline in PartSet.
+ */
+class SketchPlugin_Polyline : public SketchPlugin_SketchEntity,
+                               public GeomAPI_IPresentable
+{
+ public:
+  /// Arc feature kind
+  inline static const std::string& ID()
+  {
+    static const std::string SKETCH_LINE_ID("SketchPolyline");
+    return SKETCH_LINE_ID;
+  }
+
+  /// list of polyline points
+  inline static const std::string& POINTS_ID()
+  {
+    static const std::string ID("points");
+    return ID;
+  }
+
+  /// Returns the kind of a feature
+  SKETCHPLUGIN_EXPORT virtual const std::string& getKind();
+
+  /// Request for initialization of data model of the feature: adding all attributes
+  virtual void initAttributes();
+
+  /// Creates a new part document if needed
+  SKETCHPLUGIN_EXPORT virtual void execute();
+
+  /// Reimplemented from ModelAPI_Feature::isMacro().
+  /// \returns true
+  SKETCHPLUGIN_EXPORT virtual bool isMacro() const {return true;};
+
+  SKETCHPLUGIN_EXPORT virtual bool isPreviewNeeded() const {return false;};
+
+  /// Called on change of any argument-attribute of this object
+  SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
+
+  /// Returns the AIS preview
+  virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
+
+  /// Use plugin manager for features creation
+  SketchPlugin_Polyline();
+
+private:
+
+  void createLineFeature();
+
+protected:
+  /// \brief Initializes attributes of derived class.
+  virtual void initDerivedClassAttributes();
+};
+
+#endif
index 18c9f81c248112f3850cf229782089f9d1ba88ae..ed7f110dfe0b45288eccbfd6ba6ca023bae35cc7 100644 (file)
@@ -1966,6 +1966,18 @@ bool SketchPlugin_BSplineValidator::isValid(const AttributePtr& theAttribute,
   return true;
 }
 
+bool SketchPlugin_PolylineValidator::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;
+
+  return true;
+}
+
 bool SketchPlugin_CurveFittingValidator::isValid(const FeaturePtr& theFeature,
                                                  const std::list<std::string>& theArguments,
                                                  Events_InfoMessage& theError) const
index 01c1f4f3a739524e9034781006d9919b7613b381..7409dafd05f85fff4a7ff740778dd8606af55973 100644 (file)
@@ -546,6 +546,21 @@ class SketchPlugin_BSplineValidator : public ModelAPI_AttributeValidator
                        Events_InfoMessage& theError) const;
 };
 
+/**\class SketchPlugin_PolylineValidator
+ * \ingroup Validators
+ * \brief Validator for checking points of polyline.
+ */
+class SketchPlugin_PolylineValidator : public ModelAPI_AttributeValidator
+{
+  //! returns true if attribute is valid
+  //! \param theAttribute the checked attribute
+  //! \param theArguments arguments of the attribute
+  //! \param theError error message
+  virtual bool isValid(const AttributePtr& theAttribute,
+                       const std::list<std::string>& theArguments,
+                       Events_InfoMessage& theError) const;
+};
+
 /**\class SketchPlugin_CurveFittingValidator
  * \ingroup Validators
  * \brief Validator for the selected vertices for the curve fitting feature.
diff --git a/src/SketchPlugin/icons/polyline.png b/src/SketchPlugin/icons/polyline.png
new file mode 100644 (file)
index 0000000..8ed9356
Binary files /dev/null and b/src/SketchPlugin/icons/polyline.png differ
index 824e6281b2c9b60f4145dc74efe6a0fd50fbb68b..411884a6483af4ae14cf0e8c2f3479bea912c1ed 100644 (file)
@@ -3,7 +3,7 @@
     <group id="Linear geometry">
       <feature
         id="Sketch"
-        nested="SketchPoint SketchIntersectionPoint SketchLine
+        nested="SketchPoint SketchIntersectionPoint SketchLine SketchPolyline
                 SketchCircle SketchMacroCircle SketchArc SketchMacroArc
                 SketchEllipse SketchMacroEllipse SketchEllipticArc SketchMacroEllipticArc
                 SketchBSpline SketchMacroBSpline SketchMacroBSplinePeriodic SketchBSplinePeriodic
         <boolvalue id="Auxiliary" label="Auxiliary" default="false" tooltip="Construction element" obligatory="0" change_visual_attributes="true"/>
         <validator id="GeomValidators_Different" parameters="StartPoint,EndPoint"/>
       </feature>
+      <!-- SketchPolyline -->
+      <feature id="SketchPolyline" title="Polyline" tooltip="Create polyline" icon="icons/Sketch/polyline.png"
+               helpfile="lineFeature.html">
+        <sketch-polyline_selector id="points"
+                          title="Points"
+                          tooltip="Polyline points"
+                          enable_value="enable_by_preferences">
+          <validator id="SketchPlugin_PolylineValidator"/>
+        </sketch-polyline_selector>
+        <boolvalue id="Auxiliary" label="Auxiliary" default="false" tooltip="Construction element" obligatory="0" change_visual_attributes="true"/>
+      </feature>
     </group>
     <group id="Conical geometry">
       <!-- SketchCircle is a hidden feature. It is created inside SketchMacroCircle. -->