]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
bos 32359 - Adaptation of SHAPER model
authorasozinov <alexey.sozinov@opencascade.com>
Mon, 28 Nov 2022 08:28:09 +0000 (11:28 +0300)
committerasozinov <alexey.sozinov@opencascade.com>
Tue, 17 Jan 2023 22:42:43 +0000 (01:42 +0300)
40 files changed:
CMakeLists.txt
src/CTestTestfileInstall.cmake
src/Config/plugins.xml.in
src/SAMConverter/CMakeLists.txt [new file with mode: 0644]
src/SAMConverter/SAMConverter.py [new file with mode: 0644]
src/SAMConverter/SAMConverter_ConvertConstraints.py [new file with mode: 0644]
src/SAMConverter/SAMConverter_ConvertPrimitives.py [new file with mode: 0644]
src/SAMConverter/SAMConverter_ConvertSketch.py [new file with mode: 0644]
src/SAMConverter/SAMConverter_Logger.py [new file with mode: 0644]
src/SAMConverter/SAMConverter_SuggestConstraintsFeature.py [new file with mode: 0644]
src/SAMConverter/SAMConverter_msg_fr.ts [new file with mode: 0644]
src/SAMConverter/Test/CMakeLists.txt [new file with mode: 0644]
src/SAMConverter/Test/CTestTestfileInstall.cmake [new file with mode: 0644]
src/SAMConverter/Test/TestSAMConverter_Angle.py [new file with mode: 0644]
src/SAMConverter/Test/TestSAMConverter_Arc.py [new file with mode: 0644]
src/SAMConverter/Test/TestSAMConverter_Circle.py [new file with mode: 0644]
src/SAMConverter/Test/TestSAMConverter_Constraints.py [new file with mode: 0644]
src/SAMConverter/Test/TestSAMConverter_Distance.py [new file with mode: 0644]
src/SAMConverter/Test/TestSAMConverter_Geometrical.py [new file with mode: 0644]
src/SAMConverter/Test/TestSAMConverter_HorisontalDistance.py [new file with mode: 0644]
src/SAMConverter/Test/TestSAMConverter_Length.py [new file with mode: 0644]
src/SAMConverter/Test/TestSAMConverter_Line.py [new file with mode: 0644]
src/SAMConverter/Test/TestSAMConverter_Point.py [new file with mode: 0644]
src/SAMConverter/Test/TestSAMConverter_Primitives.py [new file with mode: 0644]
src/SAMConverter/Test/TestSAMConverter_Radius.py [new file with mode: 0644]
src/SAMConverter/Test/TestSAMConverter_Sketch.py [new file with mode: 0644]
src/SAMConverter/Test/TestSAMConverter_VerticalDistance.py [new file with mode: 0644]
src/SAMConverter/Test/tests.set [new file with mode: 0644]
src/SAMConverter/doc/SAMConverter.rst [new file with mode: 0644]
src/SAMConverter/doc/images/suggest_dialog.png [new file with mode: 0644]
src/SAMConverter/doc/suggestConstraintsFeature.rst [new file with mode: 0644]
src/SAMConverter/icons/suggest_constraints.png [new file with mode: 0644]
src/SAMConverter/plugin-SAM.xml [new file with mode: 0644]
src/SAMConverterAPI/CMakeLists.txt [new file with mode: 0644]
src/SAMConverterAPI/SAMConverterAPI.h [new file with mode: 0644]
src/SAMConverterAPI/SAMConverterAPI.i [new file with mode: 0644]
src/SAMConverterAPI/SAMConverterAPI_SAMConverter.cpp [new file with mode: 0644]
src/SAMConverterAPI/SAMConverterAPI_SAMConverter.h [new file with mode: 0644]
src/SAMConverterAPI/SAMConverterAPI_swig.h [new file with mode: 0644]
src/SketchPlugin/plugin-Sketch.xml

index b28b840f703676f94253bd90989cbadc511bd3a2..6d5592ff948df83e95f3a3de11d66d0b37140c42 100644 (file)
@@ -197,6 +197,7 @@ ADD_SUBDIRECTORY (src/GeomValidators)
 ADD_SUBDIRECTORY (src/FiltersPlugin)
 ADD_SUBDIRECTORY (src/InitializationPlugin)
 ADD_SUBDIRECTORY (src/ParametersPlugin)
+ADD_SUBDIRECTORY (src/SAMConverter)
 ADD_SUBDIRECTORY (src/PythonAddons)
 ADD_SUBDIRECTORY (src/PythonAPI)
 # High Level C++/Python API
@@ -213,6 +214,7 @@ 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 b9e1c1ebf5728b3d470ef6cd0e3471e320dd0257..591d5ca185b0cb7d22a4e45c0a798fa1f46497ba 100644 (file)
@@ -44,6 +44,7 @@ SUBDIRS(ConnectorAPI
         Config
         ExchangeAPI
         ModelGeomAlgo
+        SAMConverter
         Locale
         test_API
 )
index 7c23b377e2d0a272b04a7b945f0a8e59e7c9c188..c3452b99a44fec31efe0a94eac9364512779fe19 100644 (file)
@@ -15,6 +15,8 @@
   <plugin library="SketchPlugin" configuration="plugin-SketchCopy.xml"/>
   <plugin script="ConnectorPlugin" configuration="plugin-Connector.xml" dependency="GEOM"/>
   <plugin library="ParametersPlugin" configuration="plugin-Parameters.xml"/>
+  <plugin script="SAMConverter" configuration="plugin-SAM.xml"/>
+  <!--<plugin script="SAMConverter" configuration="plugin-SAM.xml" dependency="SAM"/>-->
 @DEFAULT_SOLVER@
 <!--
 @ALL_SOLVERS@
diff --git a/src/SAMConverter/CMakeLists.txt b/src/SAMConverter/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e4988d8
--- /dev/null
@@ -0,0 +1,48 @@
+# 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)
+INCLUDE(UnitTest)
+
+SET(PYTHON_FILES
+    SAMConverter.py
+    SAMConverter_SuggestConstraintsFeature.py
+    SAMConverter_ConvertSketch.py
+    SAMConverter_ConvertPrimitives.py
+    SAMConverter_ConvertConstraints.py
+    SAMConverter_Logger.py
+)
+
+SET(XML_RESOURCES
+  plugin-SAM.xml
+)
+
+SET(TEXT_RESOURCES
+    SAMConverter_msg_fr.ts
+)
+
+SOURCE_GROUP ("Resource Files" FILES ${TEXT_RESOURCES})
+
+ADD_CUSTOM_TARGET(SAMConverter SOURCES ${PYTHON_FILES} ${XML_RESOURCES} ${TEXT_RESOURCES})
+
+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
diff --git a/src/SAMConverter/SAMConverter.py b/src/SAMConverter/SAMConverter.py
new file mode 100644 (file)
index 0000000..4c57c3b
--- /dev/null
@@ -0,0 +1,51 @@
+# 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
+#
+
+## @package Plugins
+#  Python plugin for working with SAM format
+
+import ModelAPI
+
+from SAMConverter_SuggestConstraintsFeature import SuggestConstraintsFeature
+
+## @ingroup Plugins
+#  The main class for management the construction features as plugin.
+class SAMConverter(ModelAPI.ModelAPI_Plugin):
+
+    ## The constructor.
+    def __init__(self):
+        ModelAPI.ModelAPI_Plugin.__init__(self)
+        pass
+
+    ## Creates the feature objects of this plugin by the feature string ID.
+    def createFeature(self, theFeatureID):
+        if theFeatureID == SuggestConstraintsFeature.ID():
+            return SuggestConstraintsFeature().__disown__()
+        else:
+            print("SAMConverter: No such feature %s" % theFeatureID)
+
+## The plugin created on module importing (from c++)
+isSHAPER_SUGGESTION_GENERATOR = True
+#TODO
+if isSHAPER_SUGGESTION_GENERATOR:
+    plugin = SAMConverter()
+    ## Main session of the application
+    aSession = ModelAPI.ModelAPI_Session.get()
+    aSession.registerPlugin(plugin)
+    pass
diff --git a/src/SAMConverter/SAMConverter_ConvertConstraints.py b/src/SAMConverter/SAMConverter_ConvertConstraints.py
new file mode 100644 (file)
index 0000000..f6bbec7
--- /dev/null
@@ -0,0 +1,70 @@
+from sam.catalog_constraint import *
+
+import math
+
+from SketchAPI import *
+from SAMConverter_Logger import logger
+
+
+def get_params_value(entity):
+    try :
+        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}')
+    return None
+
+class ShapertoSAMConstraints:
+
+    def convert(entity, refs):
+        entity_type = entity.getKind()
+        if entity_type == 'SketchConstraintAngle':
+            return Angle(references = refs, angle = get_params_value(entity))
+
+        if entity_type == 'SketchConstraintCoincidence':
+            return Coincident(references = refs)
+
+        if entity_type == 'SketchConstraintDistance':
+            return Distance(references = refs, distance_min = get_params_value(entity))
+
+        if entity_type == 'SketchConstraintDistanceHorizontal':
+            return HorizontalDistance(references = refs, distance_min = get_params_value(entity))
+
+        if entity_type == 'SketchConstraintDistanceVertical':
+            return VerticalDistance(references = refs, distance_min = get_params_value(entity))
+
+        if entity_type == 'SketchConstraintEqual':
+            return Equal(references = refs)
+
+        if entity_type == 'SketchConstraintHorizontal':
+            return Horizontal(references = refs)
+
+        if entity_type == 'SketchConstraintMiddle' :
+            return Midpoint(references = refs)
+
+        if entity_type == 'SketchConstraintParallel' :
+            return Parallel(references = refs)
+
+        if entity_type == 'SketchConstraintPerpendicular' :
+            return Perpendicular(references = refs)
+
+        if entity_type == 'SketchConstraintTangent' :
+            return Tangent(references = refs)
+
+        if entity_type == 'SketchConstraintVertical':
+            return Vertical(references = refs)
+
+        if entity_type == 'SketchConstraintRadius':
+            return Radius(references = refs, radius = get_params_value(entity))
+
+        if entity_type == 'SketchConstraintLength':
+            return Length(references = refs, length = get_params_value(entity))
+
+        return None
diff --git a/src/SAMConverter/SAMConverter_ConvertPrimitives.py b/src/SAMConverter/SAMConverter_ConvertPrimitives.py
new file mode 100644 (file)
index 0000000..4abb0e6
--- /dev/null
@@ -0,0 +1,93 @@
+from sam.catalog_primitive import Arc, Line, Circle, Point
+
+import math
+
+from ModelAPI import *
+from SketchAPI import *
+from GeomAPI import *
+from SAMConverter_Logger import logger
+
+def convert_angle(angle):
+    a =  int(angle / 360)
+    if math.fabs(angle)  >= 360. :
+        return angle - a * 360
+    else :
+        return angle
+
+class ShapertoSAMPrimitive:
+
+    def convert(entity):
+        entity_type = entity.getKind()
+        if entity_type == 'SketchPoint':
+            return ShapertoSAMPrimitive.convert_point(entity)
+        if entity_type == 'SketchArc':
+            return ShapertoSAMPrimitive.convert_arc(entity)
+        if entity_type == 'SketchCircle':
+            return ShapertoSAMPrimitive.convert_circle(entity)
+        if entity_type == 'SketchLine':
+            return ShapertoSAMPrimitive.convert_line(entity)
+        if entity_type == 'SketchProjection':
+            return ShapertoSAMPrimitive.convert_projection(entity)
+        if entity_type == 'SketchIntersection':
+            return ShapertoSAMPrimitive.convert_intersection(entity)
+        return None, {}
+
+    def check_construction(entity):
+        auxAttr = entity.auxiliary()
+        return auxAttr is not None and auxAttr.value()
+
+    def convert_point(entity):
+        feat = SketchAPI_Point(entity)
+        p1 = feat.coordinates()
+        return Point(status_construction= ShapertoSAMPrimitive.check_construction(entity), point = [p1.x(), p1.y()]), {}
+
+    def convert_line(entity):
+        feat = SketchAPI_Line(entity)
+
+        p1 = feat.startPoint()
+        p2 = feat.endPoint()
+        line = Line(status_construction=ShapertoSAMPrimitive.check_construction(entity), pnt1= [p1.x(), p1.y()], pnt2= [p2.x(), p2.y()])
+        return line, {(p1.x(), p1.y(), feat.name()) : line.pnt1, (p2.x(), p2.y(), feat.name()) : line.pnt2}
+
+    def convert_circle(entity):
+        feat = SketchAPI_Circle(entity)
+        c = feat.center()
+        radius = feat.radius()
+
+        circle =  Circle(status_construction=ShapertoSAMPrimitive.check_construction(entity),
+                        center = [c.x(), c.y()],
+                        radius= radius.value())#feat.radius().value())
+        return circle, {(c.x(), c.y(), feat.name()) : circle.center}
+
+    def convert_arc(entity):
+        status = ShapertoSAMPrimitive.check_construction(entity)
+        feat = SketchAPI_Arc(entity)
+        c = feat.center()
+        s = entity.defaultResult()
+        edge = GeomAPI_Edge(s.shape())
+        a0,a1 = edge.getRange()
+        start_angle = convert_angle(math.degrees(a0))
+        end_angle = convert_angle(math.degrees(a1))
+
+        arc = Arc(status_construction=status,
+                        center = [c.x(), c.y()],
+                        radius= feat.radius().value(),
+                        angles= [start_angle, end_angle])
+        arc.add_points_startend()
+        return arc, {(c.x(), c.y(), feat.name()) : arc.center}
+
+    # Not need convert to SAM
+    def convert_intersection(entity):
+        return None, {}
+
+    # Not need convert to SAM
+    def convert_projection(entity):
+        feature_feat = entity.feature()
+        feat =  ModelAPI.objectToFeature(feature_feat)
+        attr = feat.refattr("ProjectedFeature")
+
+        proj_feat = ModelAPI_Feature.feature(attr.object())
+        proj_entity = SketchAPI_SketchEntity(proj_feat)
+        entity_type = proj_entity.getKind()
+
+        return None, {}
diff --git a/src/SAMConverter/SAMConverter_ConvertSketch.py b/src/SAMConverter/SAMConverter_ConvertSketch.py
new file mode 100644 (file)
index 0000000..f59889b
--- /dev/null
@@ -0,0 +1,68 @@
+from SAMConverter_Logger import logger
+
+from SAMConverter_ConvertPrimitives import ShapertoSAMPrimitive
+from SAMConverter_ConvertConstraints import ShapertoSAMConstraints
+from sam.sketch import Sketch
+
+from ModelAPI import *
+from SketchAPI import *
+from GeomDataAPI import *
+
+def convert_sketch(sketch: object): # a shaper sketch
+
+       dictionary = {}
+       exchange_sketch = Sketch()
+
+       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()
+
+                       convert, update_mapping = ShapertoSAMPrimitive.convert(entity)
+                       if convert is not None:
+                               mapping[entity.name()] = convert
+
+                       mapping.update(update_mapping)
+
+                       if convert is not None:
+                               exchange_sketch.add(convert)
+                               dictionary[convert] = entity
+
+       logger.debug(f'Mapping; {mapping}')
+
+       # 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 = []
+                       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()))
+
+                       convert = ShapertoSAMConstraints.convert(entity, refs)
+                       exchange_sketch.add(convert)
+                       dictionary[convert] = entity
+
+       return exchange_sketch, dictionary
diff --git a/src/SAMConverter/SAMConverter_Logger.py b/src/SAMConverter/SAMConverter_Logger.py
new file mode 100644 (file)
index 0000000..2a3f3b1
--- /dev/null
@@ -0,0 +1,4 @@
+import logging
+
+logging.basicConfig(level=logging.DEBUG)
+logger = logging.getLogger()
diff --git a/src/SAMConverter/SAMConverter_SuggestConstraintsFeature.py b/src/SAMConverter/SAMConverter_SuggestConstraintsFeature.py
new file mode 100644 (file)
index 0000000..f8cb0fb
--- /dev/null
@@ -0,0 +1,171 @@
+# 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
+#
+
+## @package Plugins
+#  SuggestConstraintsFeature class definition
+
+from SAMConverter_ConvertSketch import *
+from SAMConverter_ConvertPrimitives import *
+from SAMConverter_ConvertConstraints import *
+
+import ModelAPI
+import EventsAPI
+
+from SketchAPI import *
+import salome
+
+from salome.shaper import model
+
+import os
+
+def createErrorMessage(nonConvertablePrimitive, nonConvertableConstraint):
+    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}'
+    if len(nonConvertableConstraint) > 0:
+         devMessage = devMessage + f'List of constraints not compatible with SAM: {nonConvertableConstraint}'
+    ### For users
+    userMessage = f'Impossible to apply the suggested constraints.'
+    if len(nonConvertablePrimitive) == 0:
+        userMessage = userMessage + f'The constraints {nonConvertableConstraint} are not currently taken into account by the model.'
+    elif len(nonConvertableConstraint) == 0:
+        userMessage = userMessage + f'The primitives: {nonConvertablePrimitive} are not currently taken into account by the model.'
+    else:
+        userMessage = userMessage + "SuggestConstraints", f'The primitives: {nonConvertablePrimitive} and constraints {nonConvertableConstraint} are not currently taken into account by the model.'
+
+    return userMessage, devMessage
+
+## @ingroup Plugins
+#  Feature to suggest constraints using a Machine Learning model
+class SuggestConstraintsFeature(ModelAPI.ModelAPI_Feature):
+
+    ## The constructor.
+    def __init__(self):
+        ModelAPI.ModelAPI_Feature.__init__(self)
+        pass
+
+    @staticmethod
+    ## Export kind. Static.
+    def ID():
+        return "SuggestConstraints"
+
+    ## Returns the kind of a feature.
+    def getKind(self):
+        return SuggestConstraintsFeature.ID()
+
+    ## True: This feature is action: has no property panel and executes immediately.
+    ## False: Otherwise.
+    def isAction(self):
+        return False
+        #TODO
+        #return True
+
+    def isMacro(self):
+        """
+        Override Feature.isMacro().
+        Suggest constraint feature is macro: removes itself on the creation transaction finish.
+        """
+        return True
+
+    ## Init attributes
+    def initAttributes(self):
+        pass
+
+    ## Check that sketch can convert in SAM format
+    def isConvertedSketch(self):
+        # this elements is compability with SAM format
+        avaliable_elements = [ # Constraints
+                              'SketchConstraintAngle',
+                              'SketchConstraintCoincidence',
+                              'SketchConstraintDistance',
+                              'SketchConstraintDistanceHorizontal',
+                              'SketchConstraintDistanceVertical',
+                              'SketchConstraintEqual',
+                              'SketchConstraintHorizontal',
+                              'SketchConstraintMiddle',
+                              'SketchConstraintParallel',
+                              'SketchConstraintPerpendicular',
+                              'SketchConstraintTangent',
+                              'SketchConstraintVertical',
+                              'SketchConstraintRadius',
+                              'SketchConstraintLength',
+                              # Primitives
+                              'SketchPoint',
+                              'SketchArc',
+                              'SketchCircle',
+                              'SketchLine']
+
+        additional_elements = [# Next entities not compability with SAM, but it's avaliable elements
+                              'SketchProjection',
+                              'SketchIntersectionPoint',
+                              # skip this elements (not primitive/constraint)
+                              'SketchMultiRotation',
+                              'SketchMultiTranslation']
+
+        nonConvertablePrimitive = []
+        nonConvertableConstraint = []
+
+        # Iterate by all features from Sketch
+        for sub in self.Sketch.features().list():
+            feat =  ModelAPI.objectToFeature(sub)
+            if feat is None :
+                continue
+
+            entity = SketchAPI_SketchEntity(feat)
+            entity_type = entity.getKind()
+            if entity_type == 'SuggestConstraints':
+                continue
+            if not entity_type in avaliable_elements and not entity_type in additional_elements:
+                if 'Constraint' in entity_type :
+                    nonConvertableConstraint.append(entity_type)
+                else:
+                    nonConvertablePrimitive.append(entity_type)
+        return nonConvertablePrimitive, nonConvertableConstraint
+
+    ## convert result in SAM format
+    def convertToSAM(self):
+        ## Check that all primitives and constraints is compability with SAM
+        nonConvertablePrimitive, nonConvertableConstraint = self.isConvertedSketch()
+        if len(nonConvertablePrimitive) > 0 or len(nonConvertableConstraint) > 0 :
+            userMessage, devMessage = createErrorMessage(nonConvertablePrimitive, nonConvertableConstraint)
+            logger.debug(self.getKind(), devMessage)
+            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)
+        pass
+
+    ## Exports all shapes and groups into the GEOM module.
+    def execute(self):
+        ## Find skecth
+        aSession = ModelAPI.ModelAPI_Session.get()
+        aPartSet = aSession.moduleDocument()
+        self.Part = model.activeDocument()
+        for feat in self.Part.allFeatures():
+            if feat.getKind() == "Sketch":
+                self.Sketch = SketchAPI_Sketch(feat)
+                break
+
+        self.convertToSAM()
+        # TODO: Lot3 and Lot4
+
+        pass
diff --git a/src/SAMConverter/SAMConverter_msg_fr.ts b/src/SAMConverter/SAMConverter_msg_fr.ts
new file mode 100644 (file)
index 0000000..0a0273b
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="fr_FR">
+  <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>Les primitives et les contraintes sont incompatibles avec le format SAM. La séquence ne peut donc pas être traduite. Liste des primitives non compatibles avec SAM: %1. Liste des contraintes non compatibles avec 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 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>
+</TS>
diff --git a/src/SAMConverter/Test/CMakeLists.txt b/src/SAMConverter/Test/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6860ac0
--- /dev/null
@@ -0,0 +1,45 @@
+# 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(tests.set)
+
+SET(TEST_INSTALL_DIRECTORY "${SALOME_SHAPER_INSTALL_TESTS}/SAMConverter")
+
+SALOME_GENERATE_TESTS_ENVIRONMENT(tests_env)
+
+
+FOREACH(tfile ${TEST_NAMES})
+  SET(TEST_NAME ${COMPONENT_NAME}_${tfile})
+  ADD_TEST(NAME ${TEST_NAME}
+           COMMAND ${PYTHON_EXECUTABLE} -B ${CMAKE_CURRENT_SOURCE_DIR}/testme.py ${CMAKE_CURRENT_SOURCE_DIR}/${tfile}.py)
+  SET_TESTS_PROPERTIES(${TEST_NAME} PROPERTIES ENVIRONMENT "${tests_env};SHAPER_UNIT_TEST_IN_PROGRESS=1")
+  SET_TESTS_PROPERTIES(${TEST_NAME} PROPERTIES LABELS "${COMPONENT_NAME}")
+ENDFOREACH()
+
+# salome test
+FOREACH(tfile ${TEST_NAMES})
+  INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${tfile}.py
+          DESTINATION ${TEST_INSTALL_DIRECTORY})
+ENDFOREACH()
+
+INSTALL(FILES CTestTestfileInstall.cmake
+  DESTINATION ${TEST_INSTALL_DIRECTORY}
+  RENAME CTestTestfile.cmake)
+
+INSTALL(FILES tests.set DESTINATION ${TEST_INSTALL_DIRECTORY})
diff --git a/src/SAMConverter/Test/CTestTestfileInstall.cmake b/src/SAMConverter/Test/CTestTestfileInstall.cmake
new file mode 100644 (file)
index 0000000..798d8a9
--- /dev/null
@@ -0,0 +1,31 @@
+# Copyright (C) 2016-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(tests.set)
+
+SET(COMPONENT_NAME SHAPER)
+SET(PYTHON_TEST_DRIVER "$ENV{KERNEL_ROOT_DIR}/bin/salome/appliskel/python_test_driver.py")
+SET(TIMEOUT        300)
+
+
+FOREACH(tfile ${TEST_NAMES})
+  SET(TEST_NAME ${COMPONENT_NAME}_${tfile})
+  ADD_TEST(${TEST_NAME} python ${PYTHON_TEST_DRIVER} ${TIMEOUT} ${tfile}.py)
+  SET_TESTS_PROPERTIES(${TEST_NAME} PROPERTIES LABELS "${COMPONENT_NAME}")
+ENDFOREACH()
diff --git a/src/SAMConverter/Test/TestSAMConverter_Angle.py b/src/SAMConverter/Test/TestSAMConverter_Angle.py
new file mode 100644 (file)
index 0000000..bd4e396
--- /dev/null
@@ -0,0 +1,43 @@
+import unittest
+
+import salome
+salome.standalone()
+
+import sys
+sys.path.append('sam')
+
+from SAMConverter_Logger import logger
+from SAMConverter_ConvertConstraints import *
+from SAMConverter_ConvertPrimitives import *
+
+from salome.shaper import model
+
+class TestConvertAngle(unittest.TestCase):
+
+    def test_convert_angle_Line_Line(self):
+        model.begin()
+        partSet = model.moduleDocument()
+
+        ### Create Sketch
+        Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+
+        ### Add primitives
+        SketchLine_1 = Sketch_1.addLine(3.9, 0, 8, 0)
+        SketchLine_2 = Sketch_1.addLine(-3.9, 1., 8, 0.5)
+        SketchCoincident = Sketch_1.setAngle(SketchLine_1.result(), SketchLine_2.result(), 40)
+        model.do()
+        model.end()
+
+        sam_line1, _ = ShapertoSAMPrimitive.convert(SketchLine_1)
+        sam_line2, _ = ShapertoSAMPrimitive.convert(SketchLine_2)
+        sam_constraint = ShapertoSAMConstraints.convert(SketchCoincident, refs = [sam_line1, sam_line2])
+
+        # Check type
+        self.assertEqual(sam_constraint.get_name(), 'ANGLE')
+
+        # Check Angle value
+        self.assertEqual(sam_constraint.angle, 40)
+
+        # Check references
+        self.assertEqual(sam_constraint.references[0], sam_line1)
+        self.assertEqual(sam_constraint.references[1], sam_line2)
diff --git a/src/SAMConverter/Test/TestSAMConverter_Arc.py b/src/SAMConverter/Test/TestSAMConverter_Arc.py
new file mode 100644 (file)
index 0000000..69e61ba
--- /dev/null
@@ -0,0 +1,94 @@
+import unittest
+
+import salome
+salome.standalone()
+
+import sys
+sys.path.append('sam')
+
+from SAMConverter_Logger import logger
+from SAMConverter_ConvertPrimitives import *
+
+
+from salome.shaper import model
+from sam.catalog_primitive import Arc, Line, Circle, Point
+from math import sqrt, acos, degrees, fabs
+
+
+
+
+def compute_parameter(center_x, center_y, start_x, start_y, end_x, end_y):
+    center  = (center_x, center_y)
+
+    # First step, translate the arc such that center became the origin
+    start_2_x = start_x - center_x
+    start_2_y = start_y - center_y
+    end_2_x = end_x - center_x
+    end_2_y = end_y - center_y
+
+    # Compute radius
+    radius_s = sqrt(start_2_x*start_2_x + start_2_y*start_2_y)
+    radius_e = sqrt(end_2_x*end_2_x + end_2_y*end_2_y)
+
+    # Compute start angle start and end
+    angle_s = convert_angle(degrees(acos(start_2_x/radius_s)))
+    angle_e = convert_angle(degrees(acos(end_2_x/radius_e)))
+
+    return center, (radius_s, radius_e), (angle_s, angle_e)
+
+class TestConvertArc(unittest.TestCase):
+
+    def test_convert_arc(self):
+
+        model.begin()
+        partSet = model.moduleDocument()
+
+        ### Create Sketch
+        Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+
+        ### Create SketchArc
+        SketchArc_1 = Sketch_1.addArc(0, 0, 0, 10, 10, 0, False) # center x, center y, start x, start y, endx, endy
+        SketchArc_2 = Sketch_1.addArc(5., 1, 5.5, 1, 5, 1.5, False)
+        SketchArc_2.setAuxiliary(True)
+        model.do()
+        model.end()
+
+        # Test 1 : SketchArc_1
+        sam_arc, mapping_info = ShapertoSAMPrimitive.convert(SketchArc_1)
+
+        # - Verify the circle information
+        center, (radius_s, radius_e), (angle_s, angle_e) = compute_parameter(0, 0, 0, 10, 10, 0) # compute expected parms
+        self.assertAlmostEqual(radius_e, radius_s, delta = 10e-5)
+        self.assertEqual(sam_arc.radius, radius_e)
+        self.assertEqual(sam_arc.center.x, center[0])
+        self.assertEqual(sam_arc.center.y, center[1])
+        self.assertEqual(sam_arc.angle_start, angle_s)
+        self.assertEqual(sam_arc.angle_end, angle_e)
+        self.assertEqual(sam_arc.radian, False)
+        self.assertEqual(sam_arc.is_construction(), False)
+
+        # - Verify the mapping information
+        self.assertIn((0.0, 0.0, 'SketchArc_1'), mapping_info)
+        self.assertEqual(str(mapping_info[(0.0, 0.0, 'SketchArc_1')]), 'Point P(0.0, 0.0)')
+
+        # Test 2 : SketchArc_2
+        sam_arc, mapping_info = ShapertoSAMPrimitive.convert(SketchArc_2)
+
+        # - Verify the circle information
+        center, (radius_s, radius_e), (angle_s, angle_e) = compute_parameter(5., 1, 5.5, 1, 5, 1.5) # compute expected parms
+        self.assertAlmostEqual(radius_e, radius_s, delta = 10e-5)
+        self.assertAlmostEqual(sam_arc.radius, radius_e, delta = 10e-2)
+        self.assertEqual(sam_arc.center.x, center[0])
+        self.assertEqual(sam_arc.center.y, center[1])
+        self.assertEqual(convert_angle(sam_arc.angle_start), angle_s)
+        self.assertEqual(convert_angle(sam_arc.angle_end), angle_e)
+        self.assertEqual(sam_arc.radian, False)
+        self.assertEqual(sam_arc.is_construction(), True)
+
+
+        # - Verify the mapping information
+        self.assertIn((5.0, 1.0, 'SketchArc_2'), mapping_info)
+        self.assertEqual(str(mapping_info[(5.0, 1.0, 'SketchArc_2')]), 'Point P(5.0, 1.0)')
+
+        if salome.sg.hasDesktop():
+            salome.sg.updateObjBrowser()
diff --git a/src/SAMConverter/Test/TestSAMConverter_Circle.py b/src/SAMConverter/Test/TestSAMConverter_Circle.py
new file mode 100644 (file)
index 0000000..6aed96a
--- /dev/null
@@ -0,0 +1,63 @@
+import unittest
+
+import salome
+salome.standalone()
+
+import sys
+sys.path.append('sam')
+
+from SAMConverter_Logger import logger
+from SAMConverter_ConvertPrimitives import *
+
+
+from salome.shaper import model
+from sam.catalog_primitive import Arc, Line, Circle, Point
+
+
+class TestConvertCircle(unittest.TestCase):
+
+    def test_convert_circle(self):
+
+        model.begin()
+        partSet = model.moduleDocument()
+
+        ### Create Sketch
+        Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+
+        ### Create SketchCircle
+        SketchCircle_1 = Sketch_1.addCircle(1., 0, 30)
+        SketchCircle_2 = Sketch_1.addCircle(10., 4, 50)
+        SketchCircle_2.setAuxiliary(True)
+        model.do()
+        model.end()
+
+        # Test 1 : SketchCircle_1
+        sam_circle, mapping_info = ShapertoSAMPrimitive.convert(SketchCircle_1)
+
+        # - Verify the circle information
+        self.assertEqual(sam_circle.radius, 30.0)
+        self.assertEqual(sam_circle.center.x, 1.)
+        self.assertEqual(sam_circle.center.y, 0.)
+        self.assertEqual(sam_circle.is_construction(), False)
+
+        # Verify the mapping information
+        self.assertIn((1.0, 0.0, 'SketchCircle_1'), mapping_info)
+        self.assertEqual(str(mapping_info[(1.0, 0.0, 'SketchCircle_1')]), 'Point P(1.0, 0.0)')
+
+        # Test 2 : SketchCircle_2
+        sam_circle, mapping_info = ShapertoSAMPrimitive.convert(SketchCircle_2)
+
+        # - Verify the circle information
+        self.assertEqual(sam_circle.radius, 50.0)
+        self.assertEqual(sam_circle.center.x, 10.)
+        self.assertEqual(sam_circle.center.y, 4.)
+        self.assertEqual(sam_circle.is_construction(), True)
+
+        # Verify the mapping information
+        self.assertIn((10.0, 4.0, 'SketchCircle_2'), mapping_info)
+        self.assertEqual(str(mapping_info[(10.0, 4.0, 'SketchCircle_2')]), 'Point P(10.0, 4.0)')
+
+
+        self.assertTrue(True)
+        if salome.sg.hasDesktop():
+            salome.sg.updateObjBrowser()
diff --git a/src/SAMConverter/Test/TestSAMConverter_Constraints.py b/src/SAMConverter/Test/TestSAMConverter_Constraints.py
new file mode 100644 (file)
index 0000000..0782f8b
--- /dev/null
@@ -0,0 +1,46 @@
+from TestSAMConverter_Angle import TestConvertAngle
+from TestSAMConverter_Distance import TestConvertDistance
+from TestSAMConverter_Geometrical import TestConvertGeometrical
+from TestSAMConverter_HorisontalDistance import TestConverHorizontalDistance
+from TestSAMConverter_Length import TestConvertLength
+from TestSAMConverter_Radius import TestConvertRadius
+from TestSAMConverter_VerticalDistance import TestConvertVerticalDistance
+
+### convert angle test
+angle_test = TestConvertAngle()
+#angle_test.test_convert_angle()
+angle_test.test_convert_angle_Line_Line()
+
+### convert distance test
+dist_test = TestConvertDistance()
+dist_test.test_convert_distance_Point_Line()
+dist_test.test_convert_distance_Point_Point()
+
+### convert horizontal distance
+hDist_test = TestConverHorizontalDistance()
+hDist_test.test_convert_distance_Point_Circle()
+hDist_test.test_convert_distance_Point_Line()
+hDist_test.test_convert_distance_Point_Point()
+
+### convert vertical distance
+vDist_test = TestConvertVerticalDistance()
+vDist_test.test_convert_distance_Point_Circle()
+vDist_test.test_convert_distance_Point_Line()
+vDist_test.test_convert_distance_Point_Point()
+
+### convert geometrical constraints test
+geom_test = TestConvertGeometrical()
+geom_test.test_convert_coincidence()
+geom_test.test_convert_equal()
+geom_test.test_convert_horizontal()
+geom_test.test_convert_midpoint()
+geom_test.test_convert_parallel()
+geom_test.test_convert_perpendicular()
+geom_test.test_convert_tangent()
+geom_test.test_convert_vertical()
+
+len_test = TestConvertLength()
+len_test.test_convert_length()
+
+rad_test = TestConvertRadius()
+rad_test.test_convert_radius()
diff --git a/src/SAMConverter/Test/TestSAMConverter_Distance.py b/src/SAMConverter/Test/TestSAMConverter_Distance.py
new file mode 100644 (file)
index 0000000..1d7b3a7
--- /dev/null
@@ -0,0 +1,73 @@
+import unittest
+
+import salome
+salome.standalone()
+from SketchAPI import *
+
+import sys
+sys.path.append('sam')
+
+from SAMConverter_Logger import logger
+from SAMConverter_ConvertConstraints import *
+from SAMConverter_ConvertPrimitives import *
+
+from salome.shaper import model
+
+class TestConvertDistance(unittest.TestCase):
+
+    def test_convert_distance_Point_Point(self):
+        model.begin()
+        partSet = model.moduleDocument()
+
+        ### Create Sketch
+        Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+
+        ### Create SketchPoint
+        SketchPoint_1 = Sketch_1.addPoint(1., 0)
+        SketchPoint_2 = Sketch_1.addPoint(4., 0)
+        constraint = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchAPI_Point(SketchPoint_2).coordinates(), 2, True)
+        model.do()
+        model.end()
+
+        sam_point1, mapping_info = ShapertoSAMPrimitive.convert(SketchPoint_1)
+        sam_point2, mapping_info = ShapertoSAMPrimitive.convert(SketchPoint_2)
+        sam_constraint = ShapertoSAMConstraints.convert(constraint, refs = [sam_point1, sam_point2])
+
+        # Check type
+        self.assertEqual(sam_constraint.get_name(), 'DISTANCE')
+
+        # Check references
+        self.assertEqual(sam_constraint.references[0], sam_point1)
+        self.assertEqual(sam_constraint.references[1], sam_point2)
+
+        # Check value
+        self.assertEqual(sam_constraint.distance_min, 2)
+
+
+    def test_convert_distance_Point_Line(self):
+        model.begin()
+        partSet = model.moduleDocument()
+
+        ### Create Sketch
+        Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+
+        ### Create SketchPoint and SketchLine
+        SketchPoint_1 = Sketch_1.addPoint(1., 0)
+        SketchLine_1 = Sketch_1.addLine(3.9, 0, 8, 0)
+        constraint = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_1.result(), 2, True)
+        model.do()
+        model.end()
+
+        sam_point, mapping_info = ShapertoSAMPrimitive.convert(SketchPoint_1)
+        sam_line, mapping_info = ShapertoSAMPrimitive.convert(SketchLine_1)
+        sam_constraint = ShapertoSAMConstraints.convert(constraint, refs = [sam_point, sam_line])
+
+        # Check type
+        self.assertEqual(sam_constraint.get_name(), 'DISTANCE')
+
+        # Check references
+        self.assertEqual(sam_constraint.references[0], sam_point)
+        self.assertEqual(sam_constraint.references[1], sam_line)
+
+        # Check value
+        self.assertEqual(sam_constraint.distance_min, 2)
diff --git a/src/SAMConverter/Test/TestSAMConverter_Geometrical.py b/src/SAMConverter/Test/TestSAMConverter_Geometrical.py
new file mode 100644 (file)
index 0000000..5762171
--- /dev/null
@@ -0,0 +1,253 @@
+import unittest
+
+import salome
+salome.standalone()
+
+import sys
+sys.path.append('sam')
+
+from SAMConverter_Logger import logger
+from SAMConverter_ConvertConstraints import *
+from SAMConverter_ConvertPrimitives import *
+
+from salome.shaper import model
+
+class TestConvertGeometrical(unittest.TestCase):
+
+    def test_convert_coincidence(self):
+        model.begin()
+        partSet = model.moduleDocument()
+
+        ### Create Sketch
+        Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+
+        ### Create SketchLine
+        SketchLine_1 = Sketch_1.addLine(3.9, 0, 8, 0)
+        SketchLine_2 = Sketch_1.addLine(-3.9, 1., 8, 0.5)
+        SketchCoincident = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+        model.do()
+        model.end()
+
+        sam_line1, _ = ShapertoSAMPrimitive.convert(SketchLine_1)
+        sam_line2, _ = ShapertoSAMPrimitive.convert(SketchLine_2)
+        sam_constraint = ShapertoSAMConstraints.convert(SketchCoincident, refs = [sam_line1, sam_line2])
+
+        # Check type
+        self.assertEqual(sam_constraint.get_name(), 'COINCIDENT')
+
+        # Check references
+        self.assertEqual(sam_constraint.references[0], sam_line1)
+        self.assertEqual(sam_constraint.references[1], sam_line2)
+
+        # Check references
+        # - Verify the line 1 information
+        self.assertEqual(sam_line1.pnt1.x, 3.9)
+        self.assertEqual(sam_line1.pnt1.y, 0.)
+        self.assertEqual(sam_line1.pnt2.x, 8)
+        self.assertEqual(sam_line1.pnt2.y, 0.)
+        self.assertEqual(sam_line1.is_construction(), False)
+
+        # - Verify the line 2 information
+        self.assertEqual(sam_line2.pnt1.x, 8.0)
+        self.assertEqual(sam_line2.pnt1.y, 0.)
+        self.assertEqual(sam_line2.pnt2.x, 8)
+        self.assertEqual(sam_line2.pnt2.y, 0.5)
+        self.assertEqual(sam_line2.is_construction(), False)
+
+    def test_convert_equal(self):
+        model.begin()
+        partSet = model.moduleDocument()
+
+        ### Create Sketch
+        Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+
+        ### Create SketchLine
+        SketchLine_1 = Sketch_1.addLine(3.9, 0, 8, 0)
+        SketchLine_2 = Sketch_1.addLine(-3.9, 1., 8, 0.5)
+        constraint = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_2.result())
+        model.do()
+        model.end()
+
+        sam_line1, _ = ShapertoSAMPrimitive.convert(SketchLine_1)
+        sam_line2, _ = ShapertoSAMPrimitive.convert(SketchLine_2)
+        sam_constraint = ShapertoSAMConstraints.convert(constraint, refs = [sam_line1, sam_line2])
+
+        # Check type
+        self.assertEqual(sam_constraint.get_name(), 'EQUAL')
+
+        # Check references
+        self.assertEqual(sam_constraint.references[0], sam_line1)
+        self.assertEqual(sam_constraint.references[1], sam_line2)
+
+
+        # Check references
+        # - Verify the line 1 information
+        #TODO: The coordinates may differ from expected, but length of line is equal
+        #self.assertAlmostEqual(sam_line1.pnt1.x, 3.678, delta = 10e-3)
+        #self.assertEqual(sam_line1.pnt1.y, 0.)
+        #self.assertAlmostEqual(sam_line1.pnt2.x, 10.846, delta=10e-3)
+        #self.assertEqual(sam_line1.pnt2.y, 0.)
+        self.assertEqual(sam_line1.is_construction(), False)
+
+        # - Verify the line 2 information
+        #self.assertAlmostEqual(sam_line2.pnt1.x, -1.531, delta=10e-3)
+        #self.assertAlmostEqual(sam_line2.pnt1.y, 0.900, delta=10e-3)
+        #self.assertAlmostEqual(sam_line2.pnt2.x, 5.631, delta=10e-3)
+        #self.assertAlmostEqual(sam_line2.pnt2.y, 0.599, delta = 10e-3)
+        self.assertEqual(sam_line2.is_construction(), False)
+
+
+    def test_convert_horizontal(self):
+        model.begin()
+        partSet = model.moduleDocument()
+
+        ### Create Sketch
+        Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+
+        ### Create SketchLine
+        SketchLine_1 = Sketch_1.addLine(3.9, 0, 8, 1)
+        constraint = Sketch_1.setHorizontal(SketchLine_1.result())
+        model.do()
+        model.end()
+
+        sam_line1, _ = ShapertoSAMPrimitive.convert(SketchLine_1)
+        sam_constraint = ShapertoSAMConstraints.convert(constraint, refs = [sam_line1])
+
+        # Check type
+        self.assertEqual(sam_constraint.get_name(), 'HORIZONTAL')
+
+        # Check references
+        self.assertEqual(sam_constraint.references[0], sam_line1)
+
+        # Check references
+        # - Verify the line 1 information
+        self.assertEqual(sam_line1.pnt1.x, 3.9)
+        self.assertEqual(sam_line1.pnt1.y, 0.)
+        self.assertEqual(sam_line1.pnt2.x, 8)
+        self.assertEqual(sam_line1.pnt2.y, 0.)
+        self.assertEqual(sam_line1.is_construction(), False)
+
+
+    def test_convert_midpoint(self):
+        model.begin()
+        partSet = model.moduleDocument()
+
+        ### Create Sketch
+        Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+
+        ### Create SketchLine and SketchCircle
+        SketchLine_1 = Sketch_1.addLine(3.9, 0, 8, 0)
+        SketchCircle_1 = Sketch_1.addCircle(-17.41591725155751, 16.35177358773851, 29.02191596082682)
+        constraint = Sketch_1.setMiddlePoint(SketchLine_1.result(), SketchCircle_1.center())
+        model.do()
+        model.end()
+
+        sam_line1, _ = ShapertoSAMPrimitive.convert(SketchLine_1)
+        sam_circle, _ = ShapertoSAMPrimitive.convert(SketchCircle_1)
+        sam_constraint = ShapertoSAMConstraints.convert(constraint, refs = [sam_line1, sam_circle])
+
+        # Check type
+        self.assertEqual(sam_constraint.get_name(), 'MIDPOINT')
+
+        # Check references
+        self.assertEqual(sam_constraint.references[0], sam_line1)
+        self.assertEqual(sam_constraint.references[1], sam_circle)
+
+    def test_convert_parallel(self):
+        model.begin()
+        partSet = model.moduleDocument()
+
+        ### Create Sketch
+        Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+
+        ### Create SketchCircle
+        SketchLine_1 = Sketch_1.addLine(3.9, 0, 8, 0)
+        SketchLine_2 = Sketch_1.addLine(-3.9, 1., 8, 0.5)
+        SketchCoincident = Sketch_1.setParallel(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+        model.do()
+        model.end()
+
+        sam_line1, _ = ShapertoSAMPrimitive.convert(SketchLine_1)
+        sam_line2, _ = ShapertoSAMPrimitive.convert(SketchLine_2)
+        sam_constraint = ShapertoSAMConstraints.convert(SketchCoincident, refs = [sam_line1, sam_line2])
+
+        # Check type
+        self.assertEqual(sam_constraint.get_name(), 'PARALLEL')
+
+        # Check references
+        self.assertEqual(sam_constraint.references[0], sam_line1)
+        self.assertEqual(sam_constraint.references[1], sam_line2)
+
+    def test_convert_perpendicular(self):
+        model.begin()
+        partSet = model.moduleDocument()
+
+        ### Create Sketch
+        Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+
+        ### Create SketchCircle
+        SketchLine_1 = Sketch_1.addLine(3.9, 0, 8, 0)
+        SketchLine_2 = Sketch_1.addLine(-3.9, 1., 8, 0.5)
+        SketchCoincident = Sketch_1.setPerpendicular(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+        model.do()
+        model.end()
+
+        sam_line1, _ = ShapertoSAMPrimitive.convert(SketchLine_1)
+        sam_line2, _ = ShapertoSAMPrimitive.convert(SketchLine_2)
+        sam_constraint = ShapertoSAMConstraints.convert(SketchCoincident, refs = [sam_line1, sam_line2])
+
+        # Check type
+        self.assertEqual(sam_constraint.get_name(), 'PERPENDICULAR')
+
+        # Check references
+        self.assertEqual(sam_constraint.references[0], sam_line1)
+        self.assertEqual(sam_constraint.references[1], sam_line2)
+
+
+    def test_convert_tangent(self):
+        model.begin()
+        partSet = model.moduleDocument()
+
+        ### Create Sketch
+        Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+
+        ### Create SketchCircle
+        SketchLine_1 = Sketch_1.addLine(3.9, 0, 8, 0)
+        SketchCircle_1 = Sketch_1.addCircle(-17.41591725155751, 16.35177358773851, 29.02191596082682)
+        constraint = Sketch_1.setTangent(SketchLine_1.result(), SketchCircle_1.center())
+        model.do()
+        model.end()
+
+        sam_line1, _ = ShapertoSAMPrimitive.convert(SketchLine_1)
+        sam_circle, _ = ShapertoSAMPrimitive.convert(SketchCircle_1)
+        sam_constraint = ShapertoSAMConstraints.convert(constraint, refs = [sam_line1, sam_circle])
+
+        # Check type
+        self.assertEqual(sam_constraint.get_name(), 'TANGENT')
+
+        # Check references
+        self.assertEqual(sam_constraint.references[0], sam_line1)
+        self.assertEqual(sam_constraint.references[1], sam_circle)
+
+
+    def test_convert_vertical(self):
+        model.begin()
+        partSet = model.moduleDocument()
+
+        ### Create Sketch
+        Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+
+        ### Create SketchCircle
+        SketchLine_1 = Sketch_1.addLine(3.9, 0, 8, 0)
+        constraint = Sketch_1.setVertical(SketchLine_1.result())
+        model.do()
+        model.end()
+
+        sam_line1, _ = ShapertoSAMPrimitive.convert(SketchLine_1)
+        sam_constraint = ShapertoSAMConstraints.convert(constraint, refs = [sam_line1])
+
+        # Check type
+        self.assertEqual(sam_constraint.get_name(), 'VERTICAL')
+
+        # Check references
+        self.assertEqual(sam_constraint.references[0], sam_line1)
diff --git a/src/SAMConverter/Test/TestSAMConverter_HorisontalDistance.py b/src/SAMConverter/Test/TestSAMConverter_HorisontalDistance.py
new file mode 100644 (file)
index 0000000..c1f0754
--- /dev/null
@@ -0,0 +1,101 @@
+import unittest
+
+import salome
+salome.standalone()
+from SketchAPI import *
+
+import sys
+sys.path.append('sam')
+
+from SAMConverter_Logger import logger
+from SAMConverter_ConvertConstraints import *
+from SAMConverter_ConvertPrimitives import *
+
+from salome.shaper import model
+
+class TestConverHorizontalDistance(unittest.TestCase):
+
+    def test_convert_distance_Point_Point(self):
+        model.begin()
+        partSet = model.moduleDocument()
+
+        ### Create Sketch
+        Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+
+        ### Create SketchCircle
+        SketchPoint_1 = Sketch_1.addPoint(1., 0)
+        SketchPoint_2 = Sketch_1.addPoint(4., 0)
+        constraint = Sketch_1.setHorizontalDistance(SketchPoint_1.coordinates(), SketchPoint_2.coordinates(), 10)
+        model.do()
+        model.end()
+
+        sam_point, mapping_info = ShapertoSAMPrimitive.convert(SketchPoint_1)
+        sam_line, mapping_info = ShapertoSAMPrimitive.convert(SketchPoint_2)
+        sam_constraint = ShapertoSAMConstraints.convert(constraint, refs = [sam_point, sam_line])
+
+        # Check type
+        self.assertEqual(sam_constraint.get_name(), 'HORIZONTAL_DISTANCE')
+
+        # Check references
+        self.assertEqual(sam_constraint.references[0], sam_point)
+        self.assertEqual(sam_constraint.references[1], sam_line)
+
+        # Check value
+        self.assertEqual(sam_constraint.distance_min, 10.0)
+
+
+    def test_convert_distance_Point_Line(self):
+        model.begin()
+        partSet = model.moduleDocument()
+
+        ### Create Sketch
+        Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+
+        ### Create SketchCircle
+        SketchPoint_1 = Sketch_1.addPoint(1., 0)
+        SketchLine_1 = Sketch_1.addLine(3.9, 0, 8, 0)
+        constraint = Sketch_1.setHorizontalDistance(SketchPoint_1.coordinates(), SketchLine_1.startPoint(), 2)
+        model.do()
+        model.end()
+
+        sam_point, mapping_info = ShapertoSAMPrimitive.convert(SketchPoint_1)
+        sam_line, mapping_info = ShapertoSAMPrimitive.convert(SketchLine_1)
+        sam_constraint = ShapertoSAMConstraints.convert(constraint, refs = [sam_point, sam_line])
+
+        # Check type
+        self.assertEqual(sam_constraint.get_name(), 'HORIZONTAL_DISTANCE')
+
+        # Check references
+        self.assertEqual(sam_constraint.references[0], sam_point)
+        self.assertEqual(sam_constraint.references[1], sam_line)
+
+        # Check value
+        self.assertEqual(sam_constraint.distance_min, 2)
+
+    def test_convert_distance_Point_Circle(self):
+        model.begin()
+        partSet = model.moduleDocument()
+
+        ### Create Sketch
+        Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+
+        ### Create SketchCircle
+        SketchPoint_1 = Sketch_1.addPoint(1., 0)
+        SketchCircle_1 = Sketch_1.addCircle(-17.41591725155751, 16.35177358773851, 29.02191596082682)
+        constraint = Sketch_1.setHorizontalDistance( SketchPoint_1.coordinates(), SketchCircle_1.center(), 6)
+        model.do()
+        model.end()
+
+        sam_point, mapping_info = ShapertoSAMPrimitive.convert(SketchPoint_1)
+        sam_circle, mapping_info = ShapertoSAMPrimitive.convert(SketchCircle_1)
+        sam_constraint = ShapertoSAMConstraints.convert(constraint, refs = [sam_point, sam_circle])
+
+        # Check type
+        self.assertEqual(sam_constraint.get_name(), 'HORIZONTAL_DISTANCE')
+
+        # Check references
+        self.assertEqual(sam_constraint.references[0], sam_point)
+        self.assertEqual(sam_constraint.references[1], sam_circle)
+
+        # Check value
+        self.assertEqual(sam_constraint.distance_min, 6)
diff --git a/src/SAMConverter/Test/TestSAMConverter_Length.py b/src/SAMConverter/Test/TestSAMConverter_Length.py
new file mode 100644 (file)
index 0000000..6f1e754
--- /dev/null
@@ -0,0 +1,48 @@
+import unittest
+
+import salome
+salome.standalone()
+
+import sys
+sys.path.append('sam')
+
+from SAMConverter_Logger import logger
+from SAMConverter_ConvertConstraints import *
+from SAMConverter_ConvertPrimitives import *
+
+from salome.shaper import model
+
+class TestConvertLength(unittest.TestCase):
+
+    def test_convert_length(self):
+        model.begin()
+        partSet = model.moduleDocument()
+
+        ### Create Sketch
+        Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+
+        ### Create SketchCircle
+        SketchLine_1 = Sketch_1.addLine(3.9, 0, 8, 0)
+        SketchLength_1 = Sketch_1.setLength(SketchLine_1.result(), 10)
+        model.do()
+        model.end()
+
+        sam_line, mapping_info = ShapertoSAMPrimitive.convert(SketchLine_1)
+        sam_length = ShapertoSAMConstraints.convert(SketchLength_1, refs = [sam_line])
+
+        # Check type
+        self.assertEqual(sam_length.get_name(), 'LENGTH')
+
+        # Check Length value
+        self.assertEqual(sam_length.length, 10)
+
+        # Check references
+        # - Verify the line information
+        ref_sam_line = sam_length.references[0] # Check that it is the same instance object
+        self.assertEqual(sam_line, ref_sam_line)
+        #TODO: X coordinate may differ from expected, but length is correct
+        #self.assertAlmostEqual(ref_sam_line.pnt1.x, 0.828, delta=10e-4) # - temporarily commented line
+        self.assertEqual(ref_sam_line.pnt1.y, 0.)
+        #self.assertAlmostEqual(ref_sam_line.pnt2.x, 10.828, delta=10e-4) # - temporarily commented line
+        self.assertEqual(ref_sam_line.pnt2.y, 0.)
+        self.assertEqual(ref_sam_line.is_construction(), False)
diff --git a/src/SAMConverter/Test/TestSAMConverter_Line.py b/src/SAMConverter/Test/TestSAMConverter_Line.py
new file mode 100644 (file)
index 0000000..2355c39
--- /dev/null
@@ -0,0 +1,69 @@
+import unittest
+
+import salome
+salome.standalone()
+
+import sys
+sys.path.append('sam')
+
+from SAMConverter_Logger import logger
+from SAMConverter_ConvertPrimitives import *
+
+
+from salome.shaper import model
+from sam.catalog_primitive import Arc, Line, Circle, Point
+
+
+class TestConvertLine(unittest.TestCase):
+
+    def test_convert_line(self):
+
+        model.begin()
+        partSet = model.moduleDocument()
+
+        ### Create Sketch
+        Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+
+        ### Create SketchLine
+        SketchLine_1 = Sketch_1.addLine(3.9, 0, 8, 0)
+        SketchLine_2 = Sketch_1.addLine(0., 0, 1., 1)
+        SketchLine_2.setAuxiliary(True)
+        model.do()
+        model.end()
+
+        # Test 1 : SketchLine_1
+        sam_line, mapping_info = ShapertoSAMPrimitive.convert(SketchLine_1)
+
+        # - Verify the line information
+        self.assertEqual(sam_line.pnt1.x, 3.9)
+        self.assertEqual(sam_line.pnt1.y, 0.)
+        self.assertEqual(sam_line.pnt2.x, 8)
+        self.assertEqual(sam_line.pnt2.y, 0.)
+        self.assertEqual(sam_line.is_construction(), False)
+
+        # - Verify the mapping information
+        self.assertIn((3.9, 0.0, 'SketchLine_1'), mapping_info)
+        self.assertIn((8.0, 0.0, 'SketchLine_1'), mapping_info)
+        self.assertEqual(str(mapping_info[(3.9, 0.0, 'SketchLine_1')]), 'Point P(3.9, 0.0)')
+        self.assertEqual(str(mapping_info[(8.0, 0.0, 'SketchLine_1')]), 'Point P(8.0, 0.0)')
+
+        # Test 1 : SketchLine_2
+        sam_line, mapping_info = ShapertoSAMPrimitive.convert(SketchLine_2)
+
+        # - Verify the line information
+        self.assertEqual(sam_line.pnt1.x, 0.)
+        self.assertEqual(sam_line.pnt1.y, 0.)
+        self.assertEqual(sam_line.pnt2.x, 1.)
+        self.assertEqual(sam_line.pnt2.y, 1.)
+        self.assertEqual(sam_line.is_construction(), True)
+
+        # - Verify the mapping information
+        self.assertIn((0., 0.0, 'SketchLine_2'), mapping_info)
+        self.assertIn((1., 1., 'SketchLine_2'), mapping_info)
+        self.assertEqual(str(mapping_info[(0., 0.0, 'SketchLine_2')]), 'Point P(0.0, 0.0)')
+        self.assertEqual(str(mapping_info[(1., 1., 'SketchLine_2')]), 'Point P(1.0, 1.0)')
+
+
+        self.assertTrue(True)
+        if salome.sg.hasDesktop():
+            salome.sg.updateObjBrowser()
diff --git a/src/SAMConverter/Test/TestSAMConverter_Point.py b/src/SAMConverter/Test/TestSAMConverter_Point.py
new file mode 100644 (file)
index 0000000..ad551b0
--- /dev/null
@@ -0,0 +1,59 @@
+import unittest
+
+import salome
+salome.standalone()
+
+import sys
+sys.path.append('sam')
+
+from SAMConverter_Logger import logger
+from SAMConverter_ConvertPrimitives import *
+
+
+from salome.shaper import model
+from sam.catalog_primitive import Arc, Line, Circle, Point
+
+
+class TestConvertPoint(unittest.TestCase):
+
+    def test_convert_point(self):
+
+        model.begin()
+        partSet = model.moduleDocument()
+
+        ### Create Sketch
+        Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+
+        ### Create SketchPoint
+        SketchPoint_1 = Sketch_1.addPoint(1., 0)
+        SketchPoint_2 = Sketch_1.addPoint(10., 4)
+        SketchPoint_2.setAuxiliary(True)
+        model.do()
+        model.end()
+
+        # Test 1 : SketchPoint_1
+        sam_point, mapping_info = ShapertoSAMPrimitive.convert(SketchPoint_1)
+
+        # - Verify the point information
+        self.assertEqual(sam_point.x, 1.)
+        self.assertEqual(sam_point.y, 0.)
+        self.assertEqual(sam_point.is_construction(), False)
+
+        # Verify the mapping information
+        self.assertDictEqual(mapping_info, {})
+
+        # Test 2 : SketchPoint_2
+        sam_point, mapping_info = ShapertoSAMPrimitive.convert(SketchPoint_2)
+
+        # - Verify the point information
+        self.assertEqual(sam_point.x, 10.)
+        self.assertEqual(sam_point.y, 4.)
+        self.assertEqual(sam_point.is_construction(), True)
+
+        # Verify the mapping information
+        self.assertDictEqual(mapping_info, {})
+
+
+        self.assertTrue(True)
+        if salome.sg.hasDesktop():
+            salome.sg.updateObjBrowser()
diff --git a/src/SAMConverter/Test/TestSAMConverter_Primitives.py b/src/SAMConverter/Test/TestSAMConverter_Primitives.py
new file mode 100644 (file)
index 0000000..f801087
--- /dev/null
@@ -0,0 +1,16 @@
+from TestSAMConverter_Arc import TestConvertArc
+from TestSAMConverter_Circle import TestConvertCircle
+from TestSAMConverter_Line import TestConvertLine
+from TestSAMConverter_Point import TestConvertPoint
+
+line = TestConvertLine()
+line.test_convert_line()
+
+point = TestConvertPoint()
+point.test_convert_point()
+
+arc = TestConvertArc()
+arc.test_convert_arc()
+
+cir = TestConvertCircle()
+cir.test_convert_circle()
diff --git a/src/SAMConverter/Test/TestSAMConverter_Radius.py b/src/SAMConverter/Test/TestSAMConverter_Radius.py
new file mode 100644 (file)
index 0000000..1deb204
--- /dev/null
@@ -0,0 +1,46 @@
+import unittest
+
+import salome
+salome.standalone()
+
+import sys
+sys.path.append('sam')
+
+from SAMConverter_Logger import logger
+from SAMConverter_ConvertConstraints import *
+from SAMConverter_ConvertPrimitives import *
+
+from salome.shaper import model
+
+class TestConvertRadius(unittest.TestCase):
+
+    def test_convert_radius(self):
+        model.begin()
+        partSet = model.moduleDocument()
+
+        ### Create Sketch
+        Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+
+        ### Create SketchCircle
+        SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+        SketchRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 40)
+        model.do()
+        model.end()
+
+        sam_circle, mapping_info = ShapertoSAMPrimitive.convert(SketchCircle_1)
+        sam_radius = ShapertoSAMConstraints.convert(SketchRadius_1, refs = [sam_circle])
+
+        # Check type
+        self.assertEqual(sam_radius.get_name(), 'RADIUS')
+
+        # Check Radius value
+        self.assertEqual(sam_radius.radius, 40)
+
+        # Check references
+        # - Verify the circle information
+        ref_sam_circle = sam_radius.references[0] # Check that it is the same instance object
+        self.assertEqual(sam_circle, ref_sam_circle)
+        self.assertEqual(ref_sam_circle.radius, 40.0)
+        self.assertEqual(ref_sam_circle.center.x, 0.)
+        self.assertEqual(ref_sam_circle.center.y, 0.)
+        self.assertEqual(ref_sam_circle.is_construction(), False)
diff --git a/src/SAMConverter/Test/TestSAMConverter_Sketch.py b/src/SAMConverter/Test/TestSAMConverter_Sketch.py
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/src/SAMConverter/Test/TestSAMConverter_VerticalDistance.py b/src/SAMConverter/Test/TestSAMConverter_VerticalDistance.py
new file mode 100644 (file)
index 0000000..97e2388
--- /dev/null
@@ -0,0 +1,100 @@
+import unittest
+
+import salome
+salome.standalone()
+from SketchAPI import *
+
+import sys
+sys.path.append('sam')
+
+from SAMConverter_Logger import logger
+from SAMConverter_ConvertConstraints import *
+from SAMConverter_ConvertPrimitives import *
+
+from salome.shaper import model
+
+class TestConvertVerticalDistance(unittest.TestCase):
+
+    def test_convert_distance_Point_Point(self):
+        model.begin()
+        partSet = model.moduleDocument()
+
+        ### Create Sketch
+        Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+
+        ### Create SketchPoint
+        SketchPoint_1 = Sketch_1.addPoint(1., 0)
+        SketchPoint_2 = Sketch_1.addPoint(4., 0)
+        constraint = Sketch_1.setVerticalDistance(SketchPoint_1.coordinates(), SketchPoint_2.coordinates(), 10)
+        model.do()
+        model.end()
+
+        sam_point1, mapping_info = ShapertoSAMPrimitive.convert(SketchPoint_1)
+        sam_point2, mapping_info = ShapertoSAMPrimitive.convert(SketchPoint_2)
+        sam_constraint = ShapertoSAMConstraints.convert(constraint, refs = [sam_point1, sam_point2])
+
+        # Check type
+        self.assertEqual(sam_constraint.get_name(), 'VERTICAL_DISTANCE')
+
+        # Check references
+        self.assertEqual(sam_constraint.references[0], sam_point1)
+        self.assertEqual(sam_constraint.references[1], sam_point2)
+
+        # Check value
+        self.assertEqual(sam_constraint.distance_min, 10.0)
+
+
+    def test_convert_distance_Point_Line(self):
+        model.begin()
+        partSet = model.moduleDocument()
+
+        ### Create Sketch
+        Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+
+        ### Create SketchPoint and SketchLine
+        SketchPoint_1 = Sketch_1.addPoint(1., 0)
+        SketchLine_1 = Sketch_1.addLine(3.9, 0, 8, 0)
+        constraint = Sketch_1.setVerticalDistance(SketchPoint_1.coordinates(), SketchLine_1.startPoint(), 2)
+        model.do()
+        model.end()
+
+        sam_point, mapping_info = ShapertoSAMPrimitive.convert(SketchPoint_1)
+        sam_line, mapping_info = ShapertoSAMPrimitive.convert(SketchLine_1)
+        sam_constraint = ShapertoSAMConstraints.convert(constraint, refs = [sam_point, sam_line])
+
+        # Check type
+        self.assertEqual(sam_constraint.get_name(), 'VERTICAL_DISTANCE')
+
+        # Check references
+        self.assertEqual(sam_constraint.references[0], sam_point)
+        self.assertEqual(sam_constraint.references[1], sam_line)
+
+        # Check value
+        self.assertEqual(sam_constraint.distance_min, 2)
+
+    def test_convert_distance_Point_Circle(self):
+        model.begin()
+        partSet = model.moduleDocument()
+
+        ### Create Sketch
+        Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+
+        ### Create SketchPoint and SketchCircle
+        SketchPoint_1 = Sketch_1.addPoint(1., 0)
+        SketchCircle_1 = Sketch_1.addCircle(-17.41591725155751, 16.35177358773851, 29.02191596082682)
+        constraint = Sketch_1.setVerticalDistance( SketchPoint_1.coordinates(), SketchCircle_1.center(), 6)
+        model.do()
+        model.end()
+
+        sam_point, mapping_info = ShapertoSAMPrimitive.convert(SketchPoint_1)
+        sam_circle, mapping_info = ShapertoSAMPrimitive.convert(SketchCircle_1)
+        sam_constraint = ShapertoSAMConstraints.convert(constraint, refs = [sam_point, sam_circle])
+
+        # Check type
+        self.assertEqual(sam_constraint.get_name(), 'VERTICAL_DISTANCE')
+        # Check references
+        self.assertEqual(sam_constraint.references[0], sam_point)
+        self.assertEqual(sam_constraint.references[1], sam_circle)
+
+        # Check value
+        self.assertEqual(sam_constraint.distance_min, 6)
diff --git a/src/SAMConverter/Test/tests.set b/src/SAMConverter/Test/tests.set
new file mode 100644 (file)
index 0000000..8679964
--- /dev/null
@@ -0,0 +1,35 @@
+# Copyright (C) 2021-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
+#
+
+SET(TEST_NAMES
+           TestSAMConverter_Angle
+           TestSAMConverter_Arc
+           TestSAMConverter_Circle
+           TestSAMConverter_Constraints
+           TestSAMConverter_Distance
+           TestSAMConverter_Geometrical
+           TestSAMConverter_HorisontalDistance
+           TestSAMConverter_Length
+           TestSAMConverter_Line
+           TestSAMConverter_Point
+           TestSAMConverter_Primitives
+           TestSAMConverter_Radius
+           TestSAMConverter_Sketch
+           TestSAMConverter_VerticalDistance
+)
diff --git a/src/SAMConverter/doc/SAMConverter.rst b/src/SAMConverter/doc/SAMConverter.rst
new file mode 100644 (file)
index 0000000..abe01e3
--- /dev/null
@@ -0,0 +1,15 @@
+
+.. _sAMPlugin:
+
+SAM plug-in
+================
+
+SAM plug-in implements features for Sketch conversion to SAM format and to call Suggest Constraints macro.
+
+It provides the following features:
+
+.. toctree::
+   :titlesonly:
+   :maxdepth: 1
+
+   suggestConstraintsFeature.rst
diff --git a/src/SAMConverter/doc/images/suggest_dialog.png b/src/SAMConverter/doc/images/suggest_dialog.png
new file mode 100644 (file)
index 0000000..02c810b
Binary files /dev/null and b/src/SAMConverter/doc/images/suggest_dialog.png differ
diff --git a/src/SAMConverter/doc/suggestConstraintsFeature.rst b/src/SAMConverter/doc/suggestConstraintsFeature.rst
new file mode 100644 (file)
index 0000000..e1457ce
--- /dev/null
@@ -0,0 +1,15 @@
+
+.. _suggestConstraints:
+
+Suggest constraint
+================
+
+This feature provide TODO!!!!!
+Activate only in edit mode.
+
+The following property panel appears:
+
+Result
+""""""
+
+Created new constraints, suggested using ML
\ No newline at end of file
diff --git a/src/SAMConverter/icons/suggest_constraints.png b/src/SAMConverter/icons/suggest_constraints.png
new file mode 100644 (file)
index 0000000..196cf55
Binary files /dev/null and b/src/SAMConverter/icons/suggest_constraints.png differ
diff --git a/src/SAMConverter/plugin-SAM.xml b/src/SAMConverter/plugin-SAM.xml
new file mode 100644 (file)
index 0000000..d25fdfd
--- /dev/null
@@ -0,0 +1,12 @@
+<plugin>
+  <workbench id="Sketch">
+    <group id="Automatic constraints">
+      <feature
+        id="SuggestConstraints"
+        title="Suggest constraints"
+        tooltip="Suggest constraints using a Machine Learning model"
+        icon="icons/SAM/suggest_constraints.png"
+        helpfile="SAMConverter/SAMPlugin.html"/>
+    </group>
+  </workbench>
+</plugin>
diff --git a/src/SAMConverterAPI/CMakeLists.txt b/src/SAMConverterAPI/CMakeLists.txt
new file mode 100644 (file)
index 0000000..009a00e
--- /dev/null
@@ -0,0 +1,91 @@
+# 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
new file mode 100644 (file)
index 0000000..84f91fd
--- /dev/null
@@ -0,0 +1,37 @@
+// 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
new file mode 100644 (file)
index 0000000..a61cdf6
--- /dev/null
@@ -0,0 +1,41 @@
+// 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
new file mode 100644 (file)
index 0000000..5ea46c7
--- /dev/null
@@ -0,0 +1,29 @@
+// 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
new file mode 100644 (file)
index 0000000..a4955af
--- /dev/null
@@ -0,0 +1,38 @@
+// 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
new file mode 100644 (file)
index 0000000..d9c4ee6
--- /dev/null
@@ -0,0 +1,27 @@
+// 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_ */
index 86b234c51909ff957f29cf0a18559ff0a77ab21a..aaecd91f88ab58a28d18c53852e1f724d007a8ff 100644 (file)
@@ -19,7 +19,7 @@
                 SketchConstraintMirror SketchConstraintAngle
                 SketchMultiRotation SketchMultiTranslation
                 SketchOffset
-                SketchConstraintCollinear SketchConstraintMiddle"
+                SketchConstraintCollinear SketchConstraintMiddle SuggestConstraints"
         when_nested="accept abort"
         title="Sketch"
         tooltip="Create sketch"