]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
[bos #32541] EDF Shaper constrains suggestions - GUI
authorasozinov <alexey.sozinov@opencascade.com>
Wed, 28 Dec 2022 09:36:53 +0000 (12:36 +0300)
committerasozinov <alexey.sozinov@opencascade.com>
Mon, 23 Jan 2023 10:47:19 +0000 (13:47 +0300)
19 files changed:
CMakeLists.txt
src/PartSet/CMakeLists.txt
src/PartSet/PartSet_Module.cpp
src/PartSet/PartSet_WidgetConstraintSuggestion.cpp [new file with mode: 0644]
src/PartSet/PartSet_WidgetConstraintSuggestion.h [new file with mode: 0644]
src/SAMConverter/CMakeLists.txt
src/SAMConverter/SAMConverter_ConvertConstraints.py
src/SAMConverter/SAMConverter_ConvertSketch.py
src/SAMConverter/SAMConverter_SuggestConstraintsFeature.py
src/SAMConverter/SAMConverter_msg_en.ts [new file with mode: 0644]
src/SAMConverter/SAMConverter_msg_fr.ts
src/SAMConverter/plugin-SAM.xml
src/SAMConverter/sam_widget.xml [new file with mode: 0644]
src/SAMConverterAPI/CMakeLists.txt [deleted file]
src/SAMConverterAPI/SAMConverterAPI.h [deleted file]
src/SAMConverterAPI/SAMConverterAPI.i [deleted file]
src/SAMConverterAPI/SAMConverterAPI_SAMConverter.cpp [deleted file]
src/SAMConverterAPI/SAMConverterAPI_SAMConverter.h [deleted file]
src/SAMConverterAPI/SAMConverterAPI_swig.h [deleted file]

index 6d5592ff948df83e95f3a3de11d66d0b37140c42..ec218bf982f1bb74cc247bdff67852409b00d014 100644 (file)
@@ -214,7 +214,6 @@ ADD_SUBDIRECTORY (src/SketchAPI)
 ADD_SUBDIRECTORY (src/GDMLAPI)
 ADD_SUBDIRECTORY (src/ConnectorAPI)
 ADD_SUBDIRECTORY (src/FiltersAPI)
-ADD_SUBDIRECTORY (src/SAMConverterAPI)
 # Tests
 ADD_SUBDIRECTORY (test.API/SHAPER)
 
index d4a6c3c536bfa44bcbf5bcf98a6ba7ab6b708d8e..0bcb0b808a53993145f5f5b966d41a2eb17129a4 100644 (file)
@@ -63,6 +63,7 @@ SET(PROJECT_HEADERS
     PartSet_FieldStepPrs.h
     PartSet_WidgetBSplinePoints.h
     PartSet_BSplineWidget.h
+    PartSet_WidgetConstraintSuggestion.h
 )
 
 SET(PROJECT_MOC_HEADERS
@@ -81,6 +82,7 @@ SET(PROJECT_MOC_HEADERS
     PartSet_WidgetSketchCreator.h
     PartSet_WidgetSketchLabel.h
     PartSet_WidgetBSplinePoints.h
+    PartSet_WidgetConstraintSuggestion.h
     PartSet_ExternalPointsMgr.h
     PartSet_BSplineWidget.h
 )
@@ -117,6 +119,7 @@ SET(PROJECT_SOURCES
     PartSet_FieldStepPrs.cpp
     PartSet_WidgetBSplinePoints.cpp
     PartSet_BSplineWidget.cpp
+    PartSet_WidgetConstraintSuggestion.cpp
 )
 
 SET(PROJECT_RESOURCES
index eb8cf55898e2dcd9c587995dedc32b5e03e74232..03d47eccba0cf2aa7170086208670a7592012275 100644 (file)
@@ -23,6 +23,7 @@
 #include "PartSet_Tools.h"
 #include "PartSet_PreviewPlanes.h"
 #include "PartSet_WidgetBSplinePoints.h"
+#include "PartSet_WidgetConstraintSuggestion.h"
 #include "PartSet_WidgetPoint2d.h"
 #include "PartSet_WidgetPoint2DFlyout.h"
 #include "PartSet_WidgetShapeSelector.h"
@@ -957,6 +958,12 @@ ModuleBase_ModelWidget* PartSet_Module::createWidgetByType(const std::string& th
     //aPanel->setFeature(theFeature);
     aWgt = aPanel;
   }
+  else if (theType == "constraint_suggestion") {
+    PartSet_WidgetConstraintSuggestion* aConstWgt =
+      new PartSet_WidgetConstraintSuggestion(theParent, aWorkshop, theWidgetApi);
+    aConstWgt->setSketch(mySketchMgr->activeSketch());
+    aWgt = aConstWgt;
+  }
   return aWgt;
 }
 
diff --git a/src/PartSet/PartSet_WidgetConstraintSuggestion.cpp b/src/PartSet/PartSet_WidgetConstraintSuggestion.cpp
new file mode 100644 (file)
index 0000000..6be1455
--- /dev/null
@@ -0,0 +1,343 @@
+// Copyright (C) 2019-2022  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_WidgetConstraintSuggestion.h>
+
+#include <PartSet_ExternalObjectsMgr.h>
+#include <PartSet_Module.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_WidgetAPI.h>
+
+#include <Events_Loop.h>
+
+#include <ModelAPI_Events.h>
+#include <ModelAPI_AttributeStringArray.h>
+#include <ModelAPI_AttributeRefAttrList.h>
+#include <ModelAPI_AttributeString.h>
+#include <ModelAPI_CompositeFeature.h>
+#include <ModelAPI_Session.h>
+
+#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <GeomAPI_Pnt2d.h>
+
+#include <SketchPlugin_Feature.h>
+
+#include <QGridLayout>
+#include <QCheckBox>
+#include <QGroupBox>
+#include <QScrollArea>
+#include <QLabel>
+#include <QPushButton>
+#include <QLineEdit>
+#include <QIntValidator>
+#include <QDoubleValidator>
+
+#include <map>
+
+namespace
+{
+  // Check, that for constraint need input parameter
+  bool isNeedInoutParameter(const std::string& theConstraint)
+  {
+    return theConstraint == "ANGLE" || theConstraint == "DISTANCE" || theConstraint == "HORIZONTAL_DISTANCE"
+      || theConstraint == "VERTICAL_DISTANCE" || theConstraint == "LENGTH" || theConstraint == "RADIUS";
+  }
+}
+
+
+PartSet_WidgetConstraintSuggestion::PartSet_WidgetConstraintSuggestion(QWidget* theParent,
+                                                                      ModuleBase_IWorkshop* theWorkshop,
+                                                                      const Config_WidgetAPI* theData)
+: ModuleBase_ModelWidget(theParent, theData), myWorkshop(theWorkshop)
+{
+  isFirst = true;
+  myMain = new QVBoxLayout(this);
+  ModuleBase_Tools::zeroMargins(myMain);
+
+  // Add Input part of widget
+  QHBoxLayout* aInitLayout = new QHBoxLayout();
+  ModuleBase_Tools::adjustMargins(aInitLayout);
+
+  aInitLayout->addWidget(new QLabel(translate("Number of constraints to propose")));
+
+  myNumSuggest = new QLineEdit(this);
+  myNumSuggest->setToolTip(translate("Input number of suggestions"));
+  QIntValidator* aValidator = new QIntValidator(0, INT_MAX, myNumSuggest);
+  myNumSuggest->setValidator(aValidator);
+  aInitLayout->addWidget(myNumSuggest);
+
+  QPushButton* aSetViewBtn =
+    new QPushButton(QIcon(":icons/plane_view.png"), translate("Launch"));
+  connect(aSetViewBtn, SIGNAL(clicked(bool)), this, SLOT(onLaunchSuggest()));
+  aInitLayout->addWidget(aSetViewBtn);
+
+  myMain->addLayout(aInitLayout);
+
+  myWidgetValidator = new ModuleBase_WidgetValidator(this, myWorkshop);
+  myExternalObjectMgr = new PartSet_ExternalObjectsMgr(theData->getProperty("use_external"),
+    theData->getProperty("can_create_external"), true);
+}
+
+void PartSet_WidgetConstraintSuggestion::ModifyScrollArea()
+{
+  clearScrollAreaContent();
+
+  myFeature->data()->string("action")->setValue("Predict");
+
+  emit valuesChanged();
+
+  updateObject(myFeature);
+
+  AttributeStringArrayPtr score = myFeature->data()->stringArray("scores");
+  AttributeStringArrayPtr sugg = myFeature->data()->stringArray("suggestions");
+  AttributeStringArrayPtr prim = myFeature->data()->stringArray("primitives");
+  AttributeStringArrayPtr cons = myFeature->data()->stringArray("constraints");
+
+  QGridLayout* aGroupLay = dynamic_cast<QGridLayout*>(myGroupBox->layout());
+
+
+  int aCount = std::min(sugg->size(), myNumSuggest->text().toInt());
+  for (int i = 1; i <= aCount; ++i)
+  {
+    QGroupBox* aPoleGroupBox = new QGroupBox("", myGroupBox);
+    int ind = i - 1;
+    Suggestion aCurRecord = Suggestion{ sugg->value(ind),
+                                        cons->value(ind),
+                                        {prim->value(2 * ind), prim->value(2 * ind + 1)},
+                                        atof(score->value(ind).c_str()),
+                                        isNeedInoutParameter(cons->value(ind)) };
+
+    QString aPoleStr = translate("Suggestion %1 (score = %2)");
+    aPoleStr = aPoleStr.arg(i).arg(aCurRecord.score);
+
+
+    QGridLayout* aPoleLay = new QGridLayout(aPoleGroupBox);
+    ModuleBase_Tools::adjustMargins(aPoleLay);
+    aPoleLay->setRowStretch(5, 1);
+    aPoleLay->setColumnStretch(3, 1);
+
+    aCurRecord.applyCheckBox = new QCheckBox(aPoleGroupBox);
+    QLabel* aSugLabel = new QLabel(aPoleStr, aPoleGroupBox);
+    aPoleLay->addWidget(aSugLabel, 0, 0, 2, 2);
+    aPoleLay->addWidget(aCurRecord.applyCheckBox, 0, 2);
+
+    aPoleLay->addWidget(new ModuleBase_LabelValue(aPoleGroupBox, translate("Affected primitives")), 2, 0);
+    aPoleLay->addWidget(new QLabel(QString::fromStdString(aCurRecord.primitives.first), aPoleGroupBox), 3, 0);
+    if (!aCurRecord.primitives.second.empty())
+      aPoleLay->addWidget(new QLabel(QString::fromStdString(aCurRecord.primitives.second), aPoleGroupBox), 4, 0);
+
+    aPoleLay->addWidget(new ModuleBase_LabelValue(aPoleGroupBox, translate("Suggested Constraint")), 2, 1);
+    aPoleLay->addWidget(new QLabel(translate(aCurRecord.constraint), aPoleGroupBox), 3, 1);
+
+    if (aCurRecord.needParameter)
+    {
+      aPoleLay->addWidget(new ModuleBase_LabelValue(aPoleGroupBox, translate("Parameter")), 2, 2);
+      aCurRecord.parameterInput = new QLineEdit(aPoleGroupBox);
+      QDoubleValidator* aValidator = new QDoubleValidator(0, FLT_MAX, 12, aCurRecord.parameterInput);
+      aCurRecord.parameterInput->setValidator(aValidator);
+      aPoleLay->addWidget(aCurRecord.parameterInput, 3, 2);
+    }
+
+    aGroupLay->addWidget(aPoleGroupBox, i + 1, 0);
+    mySuggestions.push_back(aCurRecord);
+  }
+}
+
+void PartSet_WidgetConstraintSuggestion::createSecondWidget()
+{
+  myScrollArea = new QScrollArea(this);
+  myScrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
+  myScrollArea->setWidgetResizable(true);
+  myScrollArea->setFrameStyle(QFrame::NoFrame);
+  myMain->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);
+  aBoxLay->addWidget(myGroupBox);
+
+  ModifyScrollArea();
+
+  myScrollArea->setWidget(aContainer);
+
+  QHBoxLayout* aHBoxLay = new QHBoxLayout(this);
+  QString aDoFStr = translate("Original DoF: %1, New DoF: %2");
+  aDoFStr = aDoFStr.arg(5).arg(6);
+  QLabel* aDoFLabel = new QLabel(aDoFStr, this);
+
+  myUndoButton =
+    new QPushButton(QIcon(":icons/plane_view.png"), translate("Go Back"), this);
+  connect(myUndoButton, SIGNAL(clicked(bool)), this, SLOT(onGoBack()));
+  myUndoButton->setEnabled(false);
+
+  aHBoxLay->addWidget(aDoFLabel);
+  aHBoxLay->addWidget(myUndoButton);
+
+  myMain->addLayout(aHBoxLay);
+
+  QHBoxLayout* aButLay = new QHBoxLayout(this);
+  QPushButton* anApplyBut =
+    new QPushButton(QIcon(":icons/plane_view.png"), translate("Apply"));
+  connect(anApplyBut, SIGNAL(clicked(bool)), this, SLOT(onApply()));
+  QPushButton* anApplyPlusBut =
+    new QPushButton(QIcon(":icons/plane_view.png"), translate("Apply and continue"));
+  connect(anApplyPlusBut, SIGNAL(clicked(bool)), this, SLOT(onApplyAndContinue()));
+  QPushButton* aCloseBut =
+    new QPushButton(QIcon(":icons/plane_view.png"), translate("Cancel"));
+  connect(aCloseBut, SIGNAL(clicked(bool)), this, SLOT(clearScrollAreaContent()));
+  aButLay->addWidget(anApplyBut);
+  aButLay->addWidget(anApplyPlusBut);
+  aButLay->addWidget(aCloseBut);
+
+  myMain->addLayout(aButLay);
+  isFirst = false;
+}
+
+PartSet_WidgetConstraintSuggestion::~PartSet_WidgetConstraintSuggestion()
+{
+  delete myExternalObjectMgr;
+}
+
+bool PartSet_WidgetConstraintSuggestion::storeValueCustom()
+{
+  return true;
+}
+
+bool PartSet_WidgetConstraintSuggestion::restoreValueCustom()
+{
+  return true;
+}
+
+QList<QWidget*> PartSet_WidgetConstraintSuggestion::getControls() const
+{
+  QList<QWidget*> aControls;
+  aControls.append(myNumSuggest);
+  return aControls;
+}
+
+void PartSet_WidgetConstraintSuggestion::deactivate()
+{
+  ModuleBase_ModelWidget::deactivate();
+}
+
+bool PartSet_WidgetConstraintSuggestion::processEscape()
+{
+  bool isProcessed = !isEditingMode();
+  if (isProcessed) {
+    emit focusOutWidget(this);
+  }
+  return isProcessed;
+}
+
+// slot
+void PartSet_WidgetConstraintSuggestion::onLaunchSuggest()
+{
+  if (isFirst)
+  {
+    createSecondWidget();
+  }
+  else
+  {
+    ModifyScrollArea();
+  }
+}
+
+void PartSet_WidgetConstraintSuggestion::onGoBack()
+{
+  SessionPtr aMgr = ModelAPI_Session::get();
+  aMgr->undo();
+
+  updateObject(myFeature);
+}
+
+void PartSet_WidgetConstraintSuggestion::onApplyConstraints(bool theNeedClose)
+{
+  myUndoButton->setEnabled(true);
+
+  myFeature->data()->string("action")->setValue("Apply");
+  std::map<std::string, std::string> anApplyElem;
+  for (auto const& aRecord : mySuggestions)
+  {
+    if (aRecord.applyCheckBox->isChecked())
+    {
+      anApplyElem.insert({ aRecord.suggestionName, aRecord.needParameter ? aRecord.parameterInput->text().toStdString() : "" });
+    }
+  }
+  myFeature->data()->stringArray("apply_suggestions")->setSize(anApplyElem.size());
+  myFeature->data()->stringArray("parameters")->setSize(anApplyElem.size());
+  int i = 0;
+  for (auto const& anElem : anApplyElem)
+  {
+    myFeature->data()->stringArray("apply_suggestions")->setValue(i, anElem.first);
+    myFeature->data()->stringArray("parameters")->setValue(i, anElem.second);
+    ++i;
+  }
+
+  emit valuesChanged();
+
+  updateObject(myFeature);
+  if (!theNeedClose)
+  {
+    clearScrollAreaContent();
+    ModifyScrollArea();
+  }
+}
+
+void PartSet_WidgetConstraintSuggestion::onApply()
+{
+  onApplyConstraints(true);
+}
+
+void PartSet_WidgetConstraintSuggestion::onApplyAndContinue()
+{
+  onApplyConstraints(false);
+}
+
+void PartSet_WidgetConstraintSuggestion::clearScrollAreaContent()
+{
+  for (const auto& aRec : mySuggestions)
+  {
+    QCheckBox* elem = aRec.applyCheckBox;
+    QWidget* aPar = elem->parentWidget();
+    QGridLayout* aGroupLay = dynamic_cast<QGridLayout*>(myGroupBox->layout());
+    aGroupLay->removeWidget(aPar);
+    aPar->deleteLater();
+  }
+  mySuggestions.clear();
+}
diff --git a/src/PartSet/PartSet_WidgetConstraintSuggestion.h b/src/PartSet/PartSet_WidgetConstraintSuggestion.h
new file mode 100644 (file)
index 0000000..0308819
--- /dev/null
@@ -0,0 +1,144 @@
+// Copyright (C) 2019-2022  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_WidgetConstraintSuggestion_H
+#define PartSet_WidgetConstraintSuggestion_H
+
+#include "PartSet.h"
+#include "PartSet_MouseProcessor.h"
+
+#include <ModuleBase_ModelWidget.h>
+
+#include <QObject>
+
+class GeomAPI_Pnt2d;
+class ModelAPI_CompositeFeature;
+class PartSet_ExternalObjectsMgr;
+class QVBoxLayout;
+class QScrollArea;
+class QLineEdit;
+class QCheckBox;
+class QPushButton;
+
+struct Suggestion
+{
+  std::string suggestionName;
+  std::string constraint;
+  std::pair<std::string, std::string> primitives;
+  double score;
+  bool needParameter;
+
+  QLineEdit* parameterInput;
+  QCheckBox* applyCheckBox;
+};
+
+/**\class PartSet_WidgetConstraintSuggestion
+ * \ingroup Modules
+ * \brief Implementation of model widget ro provide widget to
+ *        apply constraints, predicted AI model
+ *
+ * In XML can be defined as following:
+ * \code
+ * <sketch-constraint_suggestion id="suggestions"/>
+ * \endcode
+ */
+class PARTSET_EXPORT PartSet_WidgetConstraintSuggestion : 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_WidgetConstraintSuggestion(QWidget* theParent, ModuleBase_IWorkshop* theWorkshop,
+                                     const Config_WidgetAPI* theData);
+  /// Destructor
+  virtual ~PartSet_WidgetConstraintSuggestion();
+
+  /// 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; }
+
+  /// Returns true if the event is processed.
+  virtual bool processEscape();
+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();
+
+private:
+  /// Create widget with predicted constraints and control button
+  void createSecondWidget();
+
+  /// Chenge predicted constraints
+  void ModifyScrollArea();
+
+  /// Apply user selected constraints
+  void onApplyConstraints(bool theNeedClose);
+
+private slots:
+  /// A slots called after buttons press
+
+  // Launch predict constraints
+  void onLaunchSuggest();
+
+  // Undo operation
+  void onGoBack();
+
+  // Apply and close
+  void onApply();
+
+  // Apply and continue
+  void onApplyAndContinue();
+
+  // Clear content from scroll area
+  void clearScrollAreaContent();
+
+protected:
+  ModuleBase_IWorkshop* myWorkshop; ///< workshop
+
+private:
+  QWidget* myGroupBox;  ///< the parent group box for all intenal widgets
+  QVBoxLayout* myMain;  ///< the main widget
+  QScrollArea* myScrollArea;
+  std::vector<Suggestion> mySuggestions;
+  PartSet_ExternalObjectsMgr* myExternalObjectMgr; ///< reference to external objects manager
+  QLineEdit* myNumSuggest;
+  QPushButton* myUndoButton;
+
+  /// it is important during restart operation
+  CompositeFeaturePtr mySketch;
+
+  bool isFirst;
+};
+
+#endif
index e4988d8e44b2d3330a6f555bfbb0dbe5a26fb556..5464def7ae44919a265ae54894484ec93dddc054 100644 (file)
@@ -31,12 +31,15 @@ SET(PYTHON_FILES
 
 SET(XML_RESOURCES
   plugin-SAM.xml
+  sam_widget.xml
 )
 
 SET(TEXT_RESOURCES
+    SAMConverter_msg_en.ts
     SAMConverter_msg_fr.ts
 )
 
+SOURCE_GROUP ("XML Files" FILES ${XML_RESOURCES})
 SOURCE_GROUP ("Resource Files" FILES ${TEXT_RESOURCES})
 
 ADD_CUSTOM_TARGET(SAMConverter SOURCES ${PYTHON_FILES} ${XML_RESOURCES} ${TEXT_RESOURCES})
@@ -45,4 +48,4 @@ INSTALL(FILES ${PYTHON_FILES} DESTINATION ${SHAPER_INSTALL_PYTHON_FILES})
 INSTALL(FILES ${XML_RESOURCES} ${TEXT_RESOURCES} DESTINATION ${SHAPER_INSTALL_XML_RESOURCES})
 INSTALL(DIRECTORY icons/ DESTINATION ${SHAPER_INSTALL_XML_RESOURCES}/icons/SAMConverter)
 
-ADD_SUBDIRECTORY(Test)
\ No newline at end of file
+ADD_SUBDIRECTORY(Test)
index f6bbec7c3c594cbce18424e37863e380c8d7fb7b..8e691e8c347cf7d465d7557f28d230da363010eb 100644 (file)
@@ -2,20 +2,27 @@ from sam.catalog_constraint import *
 
 import math
 
+from ModelAPI import *
 from SketchAPI import *
 from SAMConverter_Logger import logger
 
 
 def get_params_value(entity):
     try :
-        value_attr = entity.feature().real("ConstraintValue")
+        value_attr = None
+        # For horizontal/vertical distances need take an attribute "DistanceValue"
+        # (returns positive length)
+        # For angle need take an attribute "AngleValue"
+        # (returns positive length)
+        # Otherwise - "ConstraintValue"
+        if (entity.getKind() == "SketchConstraintDistanceHorizontal" or
+            entity.getKind() == "SketchConstraintDistanceVertical"):
+            value_attr = entity.feature().real("DistanceValue")
+        elif entity.getKind() == "SketchConstraintAngle":
+            value_attr = entity.feature().real("AngleValue")
+        else:
+            value_attr = entity.feature().real("ConstraintValue")
         if value_attr is not None:
-            # Constraint value is negative in following cases:
-            # For horizontal distance: if first primitive is to the right of the second
-            # For vertical distance: if first primitive is to the above of the second
-            # For angle: if the angle is counted counterclockwise
-            if "Distance" in entity.getKind() or "Angle" in entity.getKind():
-                return abs(value_attr.value())
             return value_attr.value()
     except Exception as e :
         logger.info(f'Problem with constraint parameters: {e}')
index f59889b576c51a65eacfbfea5039b4a22fcdfccf..c2d0983ea286f38b05c619091c6c6cf92e24e035 100644 (file)
@@ -8,61 +8,60 @@ from ModelAPI import *
 from SketchAPI import *
 from GeomDataAPI import *
 
-def convert_sketch(sketch: object): # a shaper sketch
+# Convert shaper sketch to SAM format
+def convert_sketch(sketch: object):
+    dictionary = {} # dictionary: SAM object (key) : SHAPER object (value)
+    exchange_sketch = Sketch()
 
-       dictionary = {}
-       exchange_sketch = Sketch()
+    mapping = {}
+    # Add the primitives
+    for sub in sketch.features().list():
+        feat =  ModelAPI.objectToFeature(sub)
 
-       mapping = {}
-       # Add the primitives
-       for sub in sketch.features().list():
-               feat =  ModelAPI.objectToFeature(sub)
+        if feat is not None :
+            entity = SketchAPI_SketchEntity(feat)
+            entity_type = entity.getKind()
 
-               if feat is not None :
-                       entity = SketchAPI_SketchEntity(feat)
-                       entity_type = entity.getKind()
+            convert, update_mapping = ShapertoSAMPrimitive.convert(entity)
+            if convert is not None:
+                mapping[entity.name()] = convert
 
-                       convert, update_mapping = ShapertoSAMPrimitive.convert(entity)
-                       if convert is not None:
-                               mapping[entity.name()] = convert
+            mapping.update(update_mapping)
 
-                       mapping.update(update_mapping)
+            if convert is not None:
+                exchange_sketch.add(convert)
+                dictionary.update({convert : entity})
 
-                       if convert is not None:
-                               exchange_sketch.add(convert)
-                               dictionary[convert] = entity
+    logger.debug(f'Mapping; {mapping}')
 
-       logger.debug(f'Mapping; {mapping}')
+    # Add the constraints
+    sketchFeature = featureToCompositeFeature(sketch.feature())
+    n = sketchFeature.numberOfSubs()
+    for i in range(n):
+        entity = sketchFeature.subFeature(i)
+        sketch_entity = SketchAPI_SketchEntity(entity)
+        entity_type = entity.getKind()
 
-       # Add the constraints
-       sketchFeature = featureToCompositeFeature(sketch.feature())
-       n = sketchFeature.numberOfSubs()
-       for i in range(n):
-               entity = sketchFeature.subFeature(i)
-               entity_type = entity.getKind()
-               print(entity_type)
+        if 'Constraint' in entity_type :
+            if entity_type == 'SuggestConstraints':
+                continue
+            refs = []
+            l_attributs = [entity.refattr("ConstraintEntityA"), entity.refattr("ConstraintEntityB"),
+                        entity.refattr("ConstraintEntityC"), entity.refattr("ConstraintEntityD")]
+            for ref in l_attributs:
+                if ref is None: continue
+                if ref.isObject():
+                    attr = ModelAPI_Feature.feature(ref.object())
+                    refs.append(mapping[attr.name()])
 
-               if 'Constraint' in entity_type :
-                       if entity_type == 'SuggestConstraints':
-                               continue
-                       refs = []
-                       print(entity_type)
-                       l_attributs = [entity.refattr("ConstraintEntityA"), entity.refattr("ConstraintEntityB"),
-                                               entity.refattr("ConstraintEntityC"), entity.refattr("ConstraintEntityD")]
-                       for ref in l_attributs:
-                               if ref is None: continue
-                               if ref.isObject():
-                                       attr = ModelAPI_Feature.feature(ref.object())
-                                       refs.append(mapping[attr.name()])
+                else :
+                    attr = ref.attr()
+                    owner = objectToFeature(attr.owner())
+                    elt = geomDataAPI_Point2D(attr).pnt()
+                    refs.append(mapping.get((elt.x(), elt.y(), owner.name()), owner.name()))
 
-                               else :
-                                       attr = ref.attr()
-                                       owner = objectToFeature(attr.owner())
-                                       elt = geomDataAPI_Point2D(attr).pnt()
-                                       refs.append(mapping.get((elt.x(), elt.y(), owner.name()), owner.name()))
+            convert = ShapertoSAMConstraints.convert(sketch_entity, refs)
+            exchange_sketch.add(convert)
+            dictionary.update({convert : entity})
 
-                       convert = ShapertoSAMConstraints.convert(entity, refs)
-                       exchange_sketch.add(convert)
-                       dictionary[convert] = entity
-
-       return exchange_sketch, dictionary
+    return exchange_sketch, dictionary
index 467dd8946a024136116bbab5516b5630aa84dc02..b055441ee0ef58b67c45444a7773099805bf63d6 100644 (file)
@@ -26,6 +26,7 @@ from SAMConverter_ConvertConstraints import *
 
 import ModelAPI
 import EventsAPI
+import ModelHighAPI
 
 from SketchAPI import *
 import salome
@@ -59,7 +60,7 @@ def getPathToSketchConstraintsFinder():
 
     return None
 
-## Method to get  AI Inference Engine class
+## Method to get AI Inference Engine class
 # \return None if it is not found
 def getSketchConstraintsFinder():
     ai_engine_path = getPathToSketchConstraintsFinder()
@@ -79,8 +80,10 @@ def getSketchConstraintsFinder():
     ai_class_inst = getattr(ai_engine, 'AIEngine')()
     return ai_class_inst
 
-
+## Method to create error message
+# \return string messages
 def createErrorMessage(nonConvertablePrimitive, nonConvertableConstraint):
+    ### For developers
     devMessage = f'Primitives and constraints are incompatible with the SAM format. The sequence therefore cannot be translated.\n'
     if len(nonConvertablePrimitive) > 0:
         devMessage = devMessage + f'List of primitives not compatible with SAM: {nonConvertablePrimitive}'
@@ -106,6 +109,36 @@ class SuggestConstraintsFeature(ModelAPI.ModelAPI_Feature):
         ModelAPI.ModelAPI_Feature.__init__(self)
         pass
 
+    @staticmethod
+    def SUGGESTIONS_ID():
+        """Returns ID of list containing names of suggestions."""
+        return "suggestions"
+
+    @staticmethod
+    def PRIMITIVES_ID():
+        """Returns ID of list containing primitives from predicted list."""
+        return "primitives"
+
+    @staticmethod
+    def CONSTRAINTS_ID():
+        """Returns ID of list containing constrint from predicted list."""
+        return "constraints"
+
+    @staticmethod
+    def SCORES_ID():
+        """Returns ID of list containing scores of predicted constraints."""
+        return "scores"
+
+    @staticmethod
+    def APPLY_SUGGESTIONS_ID():
+        """Returns ID of list containing applicable suggestions."""
+        return "apply_suggestions"
+
+    @staticmethod
+    def PARAMETERS_ID():
+        """Returns ID of list containing parameters for applicable suggestions."""
+        return "parameters"
+
     @staticmethod
     ## Export kind. Static.
     def ID():
@@ -129,11 +162,30 @@ class SuggestConstraintsFeature(ModelAPI.ModelAPI_Feature):
 
     ## Init attributes
     def initAttributes(self):
-        pass
+        """Override Feature.initAttributes()"""
+        # The following attributes are filled predicted constraints
+        self.data().addAttribute(self.SUGGESTIONS_ID(),  ModelAPI.ModelAPI_AttributeStringArray_typeId())
+        ModelAPI.ModelAPI_Session.get().validators().registerNotObligatory(self.getKind(), self.SUGGESTIONS_ID())
+        self.data().addAttribute(self.PRIMITIVES_ID(),   ModelAPI.ModelAPI_AttributeStringArray_typeId())
+        ModelAPI.ModelAPI_Session.get().validators().registerNotObligatory(self.getKind(), self.PRIMITIVES_ID())
+        self.data().addAttribute(self.CONSTRAINTS_ID(),  ModelAPI.ModelAPI_AttributeStringArray_typeId())
+        ModelAPI.ModelAPI_Session.get().validators().registerNotObligatory(self.getKind(), self.CONSTRAINTS_ID())
+        self.data().addAttribute(self.SCORES_ID(),       ModelAPI.ModelAPI_AttributeStringArray_typeId())
+        ModelAPI.ModelAPI_Session.get().validators().registerNotObligatory(self.getKind(), self.SCORES_ID())
+
+        # The following attributes are filled with user-selected constraints (name suggestion and parameter, if it necessary)
+        self.data().addAttribute(self.APPLY_SUGGESTIONS_ID(), ModelAPI.ModelAPI_AttributeStringArray_typeId())
+        ModelAPI.ModelAPI_Session.get().validators().registerNotObligatory(self.getKind(), self.APPLY_SUGGESTIONS_ID())
+        self.data().addAttribute(self.PARAMETERS_ID(),        ModelAPI.ModelAPI_AttributeStringArray_typeId())
+        ModelAPI.ModelAPI_Session.get().validators().registerNotObligatory(self.getKind(), self.PARAMETERS_ID())
+
+        # Action for execute method - predict or apply
+        self.data().addAttribute("action", ModelAPI.ModelAPI_AttributeString_typeId())
+        ModelAPI.ModelAPI_Session.get().validators().registerNotObligatory(self.getKind(), "action")
 
     ## Check that sketch can convert in SAM format
     def isConvertedSketch(self):
-        # this elements is compability with SAM format
+        # This elements is compability with SAM format
         avaliable_elements = [ # Constraints
                               'SketchConstraintAngle',
                               'SketchConstraintCoincidence',
@@ -177,9 +229,9 @@ class SuggestConstraintsFeature(ModelAPI.ModelAPI_Feature):
                 continue
             if not entity_type in avaliable_elements and not entity_type in additional_elements:
                 if 'Constraint' in entity_type :
-                    nonConvertableConstraint.append(entity_type)
+                    nonConvertableConstraint.append(entity.name())
                 else:
-                    nonConvertablePrimitive.append(entity_type)
+                    nonConvertablePrimitive.append(entity.name())
         return nonConvertablePrimitive, nonConvertableConstraint
 
     ## convert result in SAM format
@@ -192,18 +244,111 @@ class SuggestConstraintsFeature(ModelAPI.ModelAPI_Feature):
             EventsAPI.Events_InfoMessage(self.getKind(), userMessage, self).send()
             return None
 
-        self.exchange_elements, self.dictionary = convert_sketch(self.Sketch)
-        print(self.dictionary)
-        print("-------------\n\n")
-        print(self.exchange_elements)
-        return self.exchange_elements
-
-    ## TODO: Apply new constraints
+        ## Convert sketch
+        exchange_elements, dictionary = convert_sketch(self.Sketch)
+        return exchange_elements, dictionary
+
+    # fill attributes for show predicted constraints to the user
+    def fillAttributes(self, predicted_list):
+        # example: "SUGGESTION_1":{'primitives':[line_1, line_4],
+        #                          'suggested_constraint':'ANGLE',
+        #                          'score' : 0.98 }
+        self.data().stringArray(self.SUGGESTIONS_ID()).setSize(len(predicted_list))
+        self.data().stringArray(self.PRIMITIVES_ID()).setSize(2 * len(predicted_list))
+        self.data().stringArray(self.CONSTRAINTS_ID()).setSize(len(predicted_list))
+        self.data().stringArray(self.SCORES_ID()).setSize(len(predicted_list))
+        index = 0
+        for key, value in predicted_list.items():
+            self.data().stringArray(self.SUGGESTIONS_ID()).setValue(index, key)
+            primitives = value['primitives']
+            self.data().stringArray(self.PRIMITIVES_ID()).setValue(2 * index, self.dictionary[primitives[0]].name())
+            if len(primitives) == 1:
+                self.data().stringArray(self.PRIMITIVES_ID()).setValue(2 * index + 1, '')
+            else:
+                self.data().stringArray(self.PRIMITIVES_ID()).setValue(2 * index + 1, self.dictionary[primitives[1]].name())
+
+            self.data().stringArray(self.CONSTRAINTS_ID()).setValue(index, value['suggested_constraint'])
+            self.data().stringArray(self.SCORES_ID()).setValue(index, str(value['score']))
+            index = index + 1
+
+    ## Predict constraints and apply new constraints
     def execute(self):
-        #ApplyNewConstraints()
-        # TMP
-        self.PredictConstraints()
+        action = self.data().string("action").value()
+        if action == "Predict":
+            self.predicted_list = self.PredictConstraints()
+        elif action == "Apply":
+            isOk = self.ApplyNewConstraints()
+            if isOk == False:
+                EventsAPI.Events_InfoMessage(self.getKind(), "Cannot apply one or more constraints", self).send()
+
+    ## Apply constraint
+    # \return True is constraint is applicable, False - otherwise
+    def Apply(self, constraint, shape1, shape2 = None, parameter = 0):
+        if constraint == "ANGLE":
+            self.Sketch.setAngle(shape1, shape2, parameter)
+        elif constraint == "DISTANCE":
+            self.Sketch.setDistance(shape1, shape2, parameter)
+        elif constraint == "LENGTH":
+            self.Sketch.setLength(shape1, parameter)
+        elif constraint == "HORIZONTAL_DISTANCE":
+            self.Sketch.setHorizontalDistance(shape1, shape2, parameter)
+        elif constraint == "VERTICAL_DISTANCE":
+            self.Sketch.setVerticalDistance(shape1, shape2, parameter)
+        elif constraint == "RADIUS":
+            self.Sketch.setRadius(shape1, parameter)
+        elif constraint == "COINCIDENT":
+            self.Sketch.setCoincident(shape1, shape2)
+        elif constraint == "EQUAL":
+            self.Sketch.setEqual(shape1, shape2)
+        elif constraint == "HORIZONTAL":
+            self.Sketch.setHorizontal(shape1)
+        elif constraint == "VERTICAL":
+            self.Sketch.setVertical(shape1)
+        elif constraint == "MIDPOINT":
+            self.Sketch.setMiddlePoint(shape1, shape2)
+        elif constraint == "TANGENT":
+            self.Sketch.setTangent(shape1, shape)
+        elif constraint == "PARALLEL":
+            self.Sketch.setParallel(shape1, shape2)
+        elif constraint == "PERPENDICULAR":
+            self.Sketch.setPerpendicular(shape1, shape2)
+        else:
+            return False;
+
+        return True
 
+    ## Apply selected constraints
+    # \return Return True if all constraints have been applied, False - otherwise
+    def ApplyNewConstraints(self):
+        suggestions = self.stringArray(self.APPLY_SUGGESTIONS_ID())
+        parameters = self.stringArray(self.PARAMETERS_ID())
+
+        isSuccess = True
+        for suggestion in range(suggestions.size()):
+            res = self.predicted_list[suggestions.value(suggestion)]
+
+            primitives = res['primitives']
+            constraint = res['suggested_constraint']
+            value = parameters.value(suggestion)
+
+            prim1_shaper = self.dictionary[primitives[0]]
+            if value == '':
+                if len(primitives) == 1:
+                    isSuccess = self.Apply(constraint, prim1_shaper)
+                else:
+                    prim2_shaper = self.dictionary[primitives[1]]
+                    isSuccess = self.Apply(constraint, prim1_shaper, prim2_shaper)
+            else:
+                param = float(value)
+                if len(primitives) == 1:
+                    isSuccess = self.Apply(constraint, prim1_shaper, None, param)
+                else:
+                    prim2_shaper = self.dictionary[primitives[1]]
+                    isSuccess = self.Apply(constraint, prim1_shaper, prim2_shaper, param)
+            if isSuccess == False:
+                break
+
+        return isSuccess
 
     ## Convert current sketch to SAM format and pass it to AI Inference Engine
     def PredictConstraints(self):
@@ -217,9 +362,7 @@ class SuggestConstraintsFeature(ModelAPI.ModelAPI_Feature):
                 break
 
         # 2. Convert Sketch to SAM format
-
-        exchange_sketch = self.convertToSAM()
-        # TODO: obtain also mapping
+        self.exchange_sketch, self.dictionary = self.convertToSAM()
 
         # 3. Pass SAM model to AI Inference Engine
         #    and get the list of predicted constraints
@@ -227,9 +370,7 @@ class SuggestConstraintsFeature(ModelAPI.ModelAPI_Feature):
         if not ai_class_inst:
             return
 
-        predicted_list = ai_class_inst.Predict(exchange_sketch)
-        print(predicted_list)
-
-        # 4. TODO: Show the list of proposed constraints to the user
+        predicted_list = ai_class_inst.Predict(self.exchange_sketch)
+        self.fillAttributes(predicted_list)
 
         return predicted_list
diff --git a/src/SAMConverter/SAMConverter_msg_en.ts b/src/SAMConverter/SAMConverter_msg_en.ts
new file mode 100644 (file)
index 0000000..66956f9
--- /dev/null
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="en_US">
+
+  <context>
+    <name>SketchToSAMConverter</name>
+    <message>
+      <source>Primitives and constraints are incompatible with the SAM format. The sequence therefore cannot be translated. List of primitives not compatible with SAM: % 1. List of constraints not compatible with SAM: %2 </source>
+      <translation>Primitives and constraints are incompatible with the SAM format.The sequence therefore cannot be translated.List of primitives not compatible with SAM: % 1. List of constraints not compatible with SAM: %2</translation>
+    </message>
+    <message>
+      <source>Impossible to apply the suggested constraints. The primitives: %1 and constraints %2 are not currently taken into account by the model.</source>
+      <translation>Impossible to apply the suggested constraints.The primitives: % 1 and constraints % 2 are not currently taken into account by the model.</translation>
+    </message>
+  </context>
+  <context>
+    <name>SuggestConstraints:suggestions</name>
+    <message>
+      <source>Launch</source>
+      <translation>Launch</translation>
+    </message>
+    <message>
+      <source>Input number of suggestions</source>
+      <translation>Input number of suggestions</translation>
+    </message>
+    <message>
+      <source>Number of constraints to propose</source>
+      <translation>Number of constraints to propose</translation>
+    </message>
+    <message>
+      <source>Suggestion %1 (score = %2)</source>
+      <translation>Suggestion %1 (score = %2)</translation>
+    </message>
+    <message>
+      <source>Affected primitives</source>
+      <translation>Affected primitives</translation>
+    </message>
+    <message>
+      <source>Suggested Constraint</source>
+      <translation>Suggested Constraint</translation>
+    </message>
+    <message>
+      <source>Parameter</source>
+      <translation>Parameter</translation>
+    </message>
+    <message>
+      <source>Original DoF: %1, New DoF: %2</source>
+      <translation>Original DoF: %1, New DoF: %2</translation>
+    </message>
+    <message>
+      <source>Go Back</source>
+      <translation>Go Back</translation>
+    </message>
+    <message>
+      <source>Apply</source>
+      <translation>Apply</translation>
+    </message>
+    <message>
+      <source>Apply and continue</source>
+      <translation>Apply and continue</translation>
+    </message>
+    <message>
+      <source>Cancel</source>
+      <translation>Cancel</translation>
+    </message>
+    <message>
+      <source>ANGLE</source>
+      <translation>Angle</translation>
+    </message>
+    <message>
+      <source>DISTANCE</source>
+      <translation>Distance</translation>
+    </message>
+    <message>
+      <source>LENGTH</source>
+      <translation>Length</translation>
+    </message>
+    <message>
+      <source>HORIZONTAL_DISTANCE</source>
+      <translation>Horizontal distance</translation>
+    </message>
+    <message>
+      <source>VERTICAL_DISTANCE</source>
+      <translation>Vertical distance</translation>
+    </message>
+    <message>
+      <source>RADIUS</source>
+      <translation>Radius</translation>
+    </message>
+    <message>
+      <source>COINCIDENT</source>
+      <translation>Coincident</translation>
+    </message>
+    <message>
+      <source>EQUAL</source>
+      <translation>Equal</translation>
+    </message>
+    <message>
+      <source>HORIZONTAL</source>
+      <translation>Horizontal</translation>
+    </message>
+    <message>
+      <source>VERTICAL</source>
+      <translation>Vertical</translation>
+    </message>
+    <message>
+      <source>MIDPOINT</source>
+      <translation>Middle point</translation>
+    </message>
+    <message>
+      <source>TANGENT</source>
+      <translation>Tangent</translation>
+    </message>
+    <message>
+      <source>PARALLEL</source>
+      <translation>Parallel</translation>
+    </message>
+    <message>
+      <source>PERPENDICULAR</source>
+      <translation>Perpendicular</translation>
+    </message>
+  </context>
+</TS>
index 0a0273ba95ce278e6b4909a15ec0cf073976fbe6..3825393359f582de3172f09869e376b492258316 100644 (file)
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE TS>
 <TS version="2.0" language="fr_FR">
+
   <context>
     <name>SketchToSAMConverter</name>
     <message>
       <translation>Impossible d'appliquer les contraintes proposées. Les primitives : %1 et les contraintes %2 ne sont actuellement pas prises en compte par le modèle</translation>
     </message>
   </context>
+  <context>
+    <name>SuggestConstraints:suggestions</name>
+    <message>
+      <source>Launch</source>
+      <translation>lancer</translation>
+    </message>
+    <message>
+      <source>Input number of suggestions</source>
+      <translation>Saisir le nombre de suggestions</translation>
+    </message>
+    <message>
+      <source>Number of constraints to propose</source>
+      <translation>Nombre de contraintes à proposer</translation>
+    </message>
+    <message>
+      <source>Suggestion %1 (score = %2)</source>
+      <translation>Suggestion %1 (score = %2)</translation>
+    </message>
+    <message>
+      <source>Affected primitives</source>
+      <translation>Primitives concernées</translation>
+    </message>
+    <message>
+      <source>Suggested Constraint</source>
+      <translation>Contrainte suggérée</translation>
+    </message>
+    <message>
+      <source>Parameter</source>
+      <translation>Paramètres</translation>
+    </message>
+    <message>
+      <source>Original DoF: %1, New DoF: %2</source>
+      <translation>DoF Initial: %1, Nouveau DoF: %2</translation>
+    </message>
+    <message>
+      <source>Go Back</source>
+      <translation>Go Back</translation>
+    </message>
+    <message>
+      <source>Apply</source>
+      <translation>Appliquer</translation>
+    </message>
+    <message>
+      <source>Apply and continue</source>
+      <translation>Appliquer et continuer</translation>
+    </message>
+    <message>
+      <source>Cancel</source>
+      <translation>Annuler</translation>
+    </message>
+    <message>
+      <source>ANGLE</source>
+      <translation>Angle</translation>
+    </message>
+    <message>
+      <source>DISTANCE</source>
+      <translation>Distance</translation>
+    </message>
+    <message>
+      <source>LENGTH</source>
+      <translation>Longueur</translation>
+    </message>
+    <message>
+      <source>HORIZONTAL_DISTANCE</source>
+      <translation>Distance horizontale</translation>
+    </message>
+    <message>
+      <source>VERTICAL_DISTANCE</source>
+      <translation>Distance verticale</translation>
+    </message>
+    <message>
+      <source>RADIUS</source>
+      <translation>Rayon</translation>
+    </message>
+    <message>
+      <source>COINCIDENT</source>
+      <translation>Coïncident</translation>
+    </message>
+    <message>
+      <source>EQUAL</source>
+      <translation>Égal</translation>
+    </message>
+    <message>
+      <source>HORIZONTAL</source>
+      <translation>Horizontal</translation>
+    </message>
+    <message>
+      <source>VERTICAL</source>
+      <translation>Vertical</translation>
+    </message>
+    <message>
+      <source>MIDPOINT</source>
+      <translation>Point milieu</translation>
+    </message>
+    <message>
+      <source>TANGENT</source>
+      <translation>Tangente</translation>
+    </message>
+    <message>
+      <source>PARALLEL</source>
+      <translation>Parallèle</translation>
+    </message>
+    <message>
+      <source>PERPENDICULAR</source>
+      <translation>Perpendiculaire</translation>
+    </message>
+  </context>
 </TS>
index d25fdfd7a96ffdb1ce90a0a60c2554e44521c117..3fd614c14b49ce381a8439b14e153282eb7a7e28 100644 (file)
@@ -6,7 +6,9 @@
         title="Suggest constraints"
         tooltip="Suggest constraints using a Machine Learning model"
         icon="icons/SAM/suggest_constraints.png"
-        helpfile="SAMConverter/SAMPlugin.html"/>
+        helpfile="SAMConverter/suggestConstraintsFeature.html">
+        <source path="sam_widget.xml"/>
+      </feature>
     </group>
   </workbench>
 </plugin>
diff --git a/src/SAMConverter/sam_widget.xml b/src/SAMConverter/sam_widget.xml
new file mode 100644 (file)
index 0000000..977f9d6
--- /dev/null
@@ -0,0 +1,6 @@
+<source>
+  <constraint_suggestion id="suggestions"
+                         title="Suggest constraints"
+                         tooltip="Suggest constraints using a Machine Learning model">
+  </constraint_suggestion>
+</source>
diff --git a/src/SAMConverterAPI/CMakeLists.txt b/src/SAMConverterAPI/CMakeLists.txt
deleted file mode 100644 (file)
index 009a00e..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-# Copyright (C) 2014-2022  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(Common)
-
-SET(PROJECT_HEADERS
-  SAMConverterAPI.h
-  SAMConverterAPI_SAMConverter.h
-)
-
-SET(PROJECT_SOURCES
-  SAMConverterAPI_SAMConverter.cpp
-)
-
-SET(PROJECT_LIBRARIES
-  ModelAPI
-  ModelHighAPI
-)
-
-INCLUDE_DIRECTORIES(
-  ${PROJECT_SOURCE_DIR}/src/Events
-  ${PROJECT_SOURCE_DIR}/src/ModelAPI
-  ${PROJECT_SOURCE_DIR}/src/ModelHighAPI
-)
-
-# Plugin headers dependency
-INCLUDE_DIRECTORIES(
-  # TODO(spo): modify ConnectorPlugin headers to remove dependency on GeomAPI headers
-  ${PROJECT_SOURCE_DIR}/src/GeomAPI
-  # TODO(spo): it is for *_swig.h files. Can we eliminate it?
-  ${PROJECT_SOURCE_DIR}/src/GeomDataAPI
-  ${PROJECT_SOURCE_DIR}/src/SAMConverter
-)
-
-#TODO(spo): is ${OpenCASCADE_DEFINITIONS} necessary?
-ADD_DEFINITIONS(-DSAMCONVERTERAPI_EXPORTS ${OpenCASCADE_DEFINITIONS})
-ADD_LIBRARY(SAMConverterAPI SHARED ${PROJECT_SOURCES} ${PROJECT_HEADERS})
-TARGET_LINK_LIBRARIES(SAMConverterAPI ${PROJECT_LIBRARIES})
-
-# SWIG wrapper
-
-INCLUDE(PythonAPI)
-
-SET_SOURCE_FILES_PROPERTIES(SAMConverterAPI.i PROPERTIES CPLUSPLUS ON)
-SET_SOURCE_FILES_PROPERTIES(SAMConverterAPI.i PROPERTIES SWIG_DEFINITIONS "-shadow")
-
-#TODO(spo): is ModelAPI necessary or it could be received by INTERFACE_ (may require modern CMake)?
-SET(SWIG_LINK_LIBRARIES
-  ModelHighAPI
-  ModelAPI
-  SAMConverterAPI
-  ${PYTHON_LIBRARIES}
-)
-
-SET(SWIG_MODULE_SAMConverterAPI_EXTRA_DEPS ${SWIG_MODULE_SAMConverterAPI_EXTRA_DEPS}
-  ${PROJECT_SOURCE_DIR}/src/ModelHighAPI/ModelHighAPI.i
-  doxyhelp.i
-  ${PROJECT_HEADERS}
-)
-SET(CMAKE_SWIG_FLAGS -threads -w325,321,302,362,322,383,403)
-
-IF(${CMAKE_VERSION} VERSION_GREATER "3.8.0")
-  SWIG_ADD_LIBRARY(SAMConverterAPI LANGUAGE python SOURCES SAMConverterAPI.i ${PROJECT_HEADERS})
-ELSE()
-  SWIG_ADD_MODULE(SAMConverterAPI python SAMConverterAPI.i ${PROJECT_HEADERS})
-ENDIF()
-SWIG_LINK_LIBRARIES(SAMConverterAPI ${SWIG_LINK_LIBRARIES})
-
-IF(WIN32)
-  SET_TARGET_PROPERTIES(_SAMConverterAPI PROPERTIES DEBUG_OUTPUT_NAME _SAMConverterAPI_d)
-ENDIF(WIN32)
-
-INSTALL(TARGETS _SAMConverterAPI DESTINATION ${SHAPER_INSTALL_SWIG})
-INSTALL(TARGETS SAMConverterAPI DESTINATION ${SHAPER_INSTALL_BIN})
-INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/SAMConverterAPI.py DESTINATION ${SHAPER_INSTALL_SWIG})
\ No newline at end of file
diff --git a/src/SAMConverterAPI/SAMConverterAPI.h b/src/SAMConverterAPI/SAMConverterAPI.h
deleted file mode 100644 (file)
index 84f91fd..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (C) 2014-2022  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 SAMCONVERTERAPI_H
-#define SAMCONVERTERAPI_H
-
-#if defined SAMCONVERTERAPI_EXPORTS
-#if defined WIN32
-#define SAMCONVERTERAPI_EXPORT __declspec( dllexport )
-#else
-#define SAMCONVERTERAPI_EXPORT
-#endif
-#else
-#if defined WIN32
-#define SAMCONVERTERAPI_EXPORT __declspec( dllimport )
-#else
-#define SAMCONVERTERAPI_EXPORT
-#endif
-#endif
-
-#endif
diff --git a/src/SAMConverterAPI/SAMConverterAPI.i b/src/SAMConverterAPI/SAMConverterAPI.i
deleted file mode 100644 (file)
index a61cdf6..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (C) 2014-2022  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
-//
-
-/* SAMConverterAPI.i */
-
-%module SAMConverterAPI
-
-%{
-  #include "SAMConverterAPI_swig.h"
-%}
-
-%include "doxyhelp.i"
-
-// import other modules
-%import "ModelHighAPI.i"
-
-// to avoid error on this
-#define SAMCONVERTERAPI_EXPORT
-
-// standard definitions
-%include "typemaps.i"
-%include "std_shared_ptr.i"
-
-// all supported interfaces
-%include "SAMConverterAPI_SAMConverter.h"
diff --git a/src/SAMConverterAPI/SAMConverterAPI_SAMConverter.cpp b/src/SAMConverterAPI/SAMConverterAPI_SAMConverter.cpp
deleted file mode 100644 (file)
index 5ea46c7..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (C) 2014-2022  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 "SAMConverterAPI_SAMConverter.h"
-//--------------------------------------------------------------------------------------
-#include <ModelAPI_Document.h>
-#include <ModelAPI_Feature.h>
-//--------------------------------------------------------------------------------------
-void suggestConstraints(const std::shared_ptr<ModelAPI_Document> & thePart)
-{
-  // TODO(spo): check that thePart is not empty
-  std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature("SuggestConstraints");
-}
diff --git a/src/SAMConverterAPI/SAMConverterAPI_SAMConverter.h b/src/SAMConverterAPI/SAMConverterAPI_SAMConverter.h
deleted file mode 100644 (file)
index a4955af..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (C) 2014-2022  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 SRC_SAMCONVERTERAPI_SAMCONVERTERAPI_PART_H_
-#define SRC_SAMCONVERTERAPI_SAMCONVERTERAPI_PART_H_
-
-//--------------------------------------------------------------------------------------
-#include "SAMConverterAPI.h"
-//--------------------------------------------------------------------------------------
-#include <memory>
-//--------------------------------------------------------------------------------------
-class ModelAPI_Document;
-//--------------------------------------------------------------------------------------
-/**\ingroup CPPHighAPI
- * \brief Export to GEOM
- */
-SAMCONVERTERAPI_EXPORT
-void suggestConstraints(const std::shared_ptr<ModelAPI_Document> & thePart);
-
-//--------------------------------------------------------------------------------------
-//--------------------------------------------------------------------------------------
-#endif /* SRC_SAMCONVERTERAPI_SAMCONVERTERAPI_PART_H_ */
diff --git a/src/SAMConverterAPI/SAMConverterAPI_swig.h b/src/SAMConverterAPI/SAMConverterAPI_swig.h
deleted file mode 100644 (file)
index d9c4ee6..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (C) 2014-2022  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 SRC_SAMCONVERTERAPI_SAMCONVERTERAPI_SWIG_H_
-#define SRC_SAMCONVERTERAPI_SAMCONVERTERAPI_SWIG_H_
-
-  #include <ModelHighAPI_swig.h>
-
-  #include "SAMConverterAPI_SAMConverter.h"
-
-#endif /* SRC_SAMCONVERTERAPI_SAMCONVERTERAPI_SWIG_H_ */