]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
[bos #32540] [EDF] Shaper constrains suggestions - Connection with AI Inference Engine jfa/32540
authorjfa <jfa@opencascade.com>
Tue, 27 Dec 2022 11:21:51 +0000 (14:21 +0300)
committerjfa <jfa@opencascade.com>
Tue, 27 Dec 2022 11:21:51 +0000 (14:21 +0300)
13 files changed:
src/SAMConverter/SAMConverter.py
src/SAMConverter/SAMConverter_SuggestConstraintsFeature.py
src/SAMConverter/Test/CMakeLists.txt
src/SAMConverter/Test/TestSAMConverter_scenario1.py [new file with mode: 0644]
src/SAMConverter/Test/TestSAMConverter_scenario2.py [new file with mode: 0644]
src/SAMConverter/Test/data/ecrou_sam_scenario1.py [new file with mode: 0644]
src/SAMConverter/Test/data/ecrou_scenario1.py [new file with mode: 0644]
src/SAMConverter/Test/data/plaque_trouee_sam_sc2.py [new file with mode: 0644]
src/SAMConverter/Test/data/plaque_trouee_shaper_sc2.py [new file with mode: 0644]
src/SAMConverter/Test/data/predict_engine_mock_scenario1.py [new file with mode: 0644]
src/SAMConverter/Test/data/predict_engine_mock_scenario2.py [new file with mode: 0644]
src/SAMConverter/Test/tests.set
src/SketchPlugin/SketchPlugin_Plugin.cpp

index 7cd95b94bdbabc99f6ed251100c253e156095fa4..b34469629f480efc6cf77db8a22ee8586e669d80 100644 (file)
@@ -23,6 +23,8 @@
 import ModelAPI
 
 from SAMConverter_SuggestConstraintsFeature import SuggestConstraintsFeature
+from SAMConverter_SuggestConstraintsFeature import getPathToSketchConstraintsFinder
+from SAMConverter_SuggestConstraintsFeature import getSketchConstraintsFinder
 
 ## @ingroup Plugins
 #  The main class for management the construction features as plugin.
@@ -41,8 +43,7 @@ class SAMConverter(ModelAPI.ModelAPI_Plugin):
             print("SAMConverter: No such feature %s" % theFeatureID)
 
 ## The plugin created on module importing (from c++)
-isSHAPER_SUGGESTION_GENERATOR = True
-#TODO
+isSHAPER_SUGGESTION_GENERATOR = getPathToSketchConstraintsFinder()
 if isSHAPER_SUGGESTION_GENERATOR:
     plugin = SAMConverter()
     ## Main session of the application
index 5020a8a1955e76baee46761be557d378371114fa..75d6f4129c07bdb4c6285cf2473d0e4e6ce4522c 100644 (file)
@@ -33,6 +33,52 @@ import salome
 from salome.shaper import model
 
 import os
+import sys
+import pathlib
+import importlib.util
+
+## Method to get path to AI Inference Engine
+# \return None if the path is not found
+def getPathToSketchConstraintsFinder():
+    ai_engine_path = os.environ.get('SHAPER_SKETCH_CONSTRAINT_SUGGESTION_AI')
+    if not ai_engine_path:
+        print('SHAPER_SKETCH_CONSTRAINT_SUGGESTION_AI variable is not set')
+        return None
+
+    print(ai_engine_path)
+    if not os.path.isfile(ai_engine_path):
+        print('{} is not a file'.format(ai_engine_path))
+        return None
+
+    file_extension = pathlib.Path(ai_engine_path).suffix
+    if file_extension == '.py' or file_extension == '.pyc':
+        return ai_engine_path
+    else:
+        print('{} is not a python file'.format(ai_engine_path))
+        pass
+
+    return None
+
+## Method to get  AI Inference Engine class
+# \return None if it is not found
+def getSketchConstraintsFinder():
+    ai_engine_path = getPathToSketchConstraintsFinder()
+    if not ai_engine_path:
+        return
+
+    p = pathlib.Path(ai_engine_path)
+    ai_engine_name = p.stem
+    ai_spec = importlib.util.spec_from_file_location(ai_engine_name, ai_engine_path)
+    ai_engine = importlib.util.module_from_spec(ai_spec)
+    ai_spec.loader.exec_module(ai_engine)
+
+    if not hasattr(ai_engine, 'AIEngine'):
+        print('There is no AIEngine in {}'.format(ai_engine_path))
+        return
+
+    ai_class_inst = getattr(ai_engine, 'AIEngine')()
+    return ai_class_inst
+
 
 ## @ingroup Plugins
 #  Feature to suggest constraints using a Machine Learning model
@@ -56,8 +102,6 @@ class SuggestConstraintsFeature(ModelAPI.ModelAPI_Feature):
     ## False: Otherwise.
     def isAction(self):
         return False
-        #TODO
-        #return True
 
     def isMacro(self):
         """
@@ -92,7 +136,9 @@ class SuggestConstraintsFeature(ModelAPI.ModelAPI_Feature):
                               'SketchLine',
                               # Next entities not compability with SAM, but it's avaliable elements
                               'SketchProjection',
-                              'SketchIntersection']
+                              'SketchIntersection',
+                              'SketchMultiRotation',
+                              'SketchMultiTranslation']
         nonConvertablePrimitive = []
         nonConvertableConstraint = []
 
@@ -117,9 +163,9 @@ class SuggestConstraintsFeature(ModelAPI.ModelAPI_Feature):
         ## Check that all primitives and constraints is compability with SAM
         nonConvertablePrimitive, nonConvertableConstraint = self.isConvertedSketch()
         if len(nonConvertablePrimitive) > 0 or len(nonConvertableConstraint) > 0 :
-            logger.debug("SuggestConstraints", f'Primitives and constraints are incompatible with the SAM format. The sequence therefore cannot be translated.')
+            logger.debug("SuggestConstraints %s", f'Primitives and constraints are incompatible with the SAM format. The sequence therefore cannot be translated.')
             if len(nonConvertablePrimitive) > 0:
-                logger.debug("SuggestConstraints", f'List of primitives not compatible with SAM: {nonConvertablePrimitive}')
+                logger.debug("SuggestConstraints %s", f'List of primitives not compatible with SAM: {nonConvertablePrimitive}')
             if len(nonConvertableConstraint) > 0:
                 logger.debug(f'List of constraints not compatible with SAM: {nonConvertableConstraint}')
             ### For users
@@ -130,16 +176,23 @@ class SuggestConstraintsFeature(ModelAPI.ModelAPI_Feature):
                 EventsAPI.Events_InfoMessage("SuggestConstraints", f'The primitives: {nonConvertablePrimitive} are not currently taken into account by the model.', self).send()
             else:
                 EventsAPI.Events_InfoMessage("SuggestConstraints", f'The primitives: {nonConvertablePrimitive} and constraints {nonConvertableConstraint} are not currently taken into account by the model.', self).send()
-            return
+            return None
 
-        exchange_elements = convert_sketch(self.Sketch)
+        exchange_sketch = convert_sketch(self.Sketch)
         print("SuggestConstraintsFeature: convertToSAM")
 
-        pass
+        return exchange_sketch
 
-    ## Exports all shapes and groups into the GEOM module.
+    ## TODO: Apply new constraints
     def execute(self):
-        ## Find skecth
+        #ApplyNewConstraints()
+        # TMP
+        self.PredictConstraints()
+
+
+    ## Convert current sketch to SAM format and pass it to AI Inference Engine
+    def PredictConstraints(self):
+        # 1. Find skecth
         aSession = ModelAPI.ModelAPI_Session.get()
         aPartSet = aSession.moduleDocument()
         self.Part = model.activeDocument()
@@ -148,8 +201,20 @@ class SuggestConstraintsFeature(ModelAPI.ModelAPI_Feature):
                 self.Sketch = SketchAPI_Sketch(feat)
                 break
 
+        # 2. Convert Sketch to SAM format
         print("SuggestConstraintsFeature: execute")
-        self.convertToSAM()
-        # TODO: Lot3 and Lot4
+        exchange_sketch = self.convertToSAM()
+        # TODO: obtain also mapping
 
-        pass
+        # 3. Pass SAM model to AI Inference Engine
+        #    and get the list of predicted constraints
+        ai_class_inst = getSketchConstraintsFinder()
+        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
+
+        return predicted_list
index 6860ac008f8138094cee182f02050c9bd29363ad..e8a3d70f539652b9b625347933c2c7999512b992 100644 (file)
@@ -43,3 +43,4 @@ INSTALL(FILES CTestTestfileInstall.cmake
   RENAME CTestTestfile.cmake)
 
 INSTALL(FILES tests.set DESTINATION ${TEST_INSTALL_DIRECTORY})
+INSTALL(DIRECTORY data DESTINATION ${TEST_INSTALL_DIRECTORY})
diff --git a/src/SAMConverter/Test/TestSAMConverter_scenario1.py b/src/SAMConverter/Test/TestSAMConverter_scenario1.py
new file mode 100644 (file)
index 0000000..c70131e
--- /dev/null
@@ -0,0 +1,43 @@
+import os
+import sys
+sys.path.append('data/')
+
+import SAMConverter
+
+if __name__ == "__main__" :
+    from ecrou_sam_scenario1 import ecrou_sam
+    from ecrou_scenario1 import Sketch_1
+
+    # If SHAPER_SKETCH_CONSTRAINT_SUGGESTION_AI is set, use it (suppose it is true AI Engine)
+    # Otherwise, set it to the special mock for scenario1
+    isAIEngineEnvSet = True
+    ai_engine_path = os.environ.get('SHAPER_SKETCH_CONSTRAINT_SUGGESTION_AI')
+    if not ai_engine_path or ai_engine_path == "":
+        isAIEngineEnvSet = False
+        this_script_path = os.path.dirname(os.path.realpath(sys.argv[0] or 'something'))
+        os.environ['SHAPER_SKETCH_CONSTRAINT_SUGGESTION_AI'] = os.path.join(this_script_path, 'data', 'predict_engine_mock_scenario1.py')
+        pass
+
+    ai_engine = SAMConverter.getSketchConstraintsFinder()
+    assert(ai_engine)
+
+    # 1. Predict constraints on SAM model
+    pred = ai_engine.Predict(ecrou_sam)
+    for key,value in pred.items() :
+        print(f' {key} : {value}')
+        pass
+
+    # 2. Predict constraints on Shaper model (convert to SAM beforehand)
+    aFeature = SAMConverter.SuggestConstraintsFeature()
+    pred_shaper = aFeature.PredictConstraints()
+    for key,value in pred_shaper.items() :
+        print(f' {key} : {value}')
+        pass
+
+    if not isAIEngineEnvSet:
+        os.environ.pop('SHAPER_SKETCH_CONSTRAINT_SUGGESTION_AI', None)
+        pass
+
+    # for i, x in enumerate(ecrou_sam.sequence):
+    #     if 'Line' in str(x) :
+    #         print(i, x)
diff --git a/src/SAMConverter/Test/TestSAMConverter_scenario2.py b/src/SAMConverter/Test/TestSAMConverter_scenario2.py
new file mode 100644 (file)
index 0000000..2e8d3fe
--- /dev/null
@@ -0,0 +1,43 @@
+import os
+import sys
+sys.path.append('data/')
+
+import SAMConverter
+
+if __name__ == "__main__" :
+    from plaque_trouee_sam_sc2 import plaque_trouee_sam
+    from plaque_trouee_shaper_sc2 import Sketch_1
+
+    # If SHAPER_SKETCH_CONSTRAINT_SUGGESTION_AI is set, use it (suppose it is true AI Engine)
+    # Otherwise, set it to the special mock for scenario1
+    isAIEngineEnvSet = True
+    ai_engine_path = os.environ.get('SHAPER_SKETCH_CONSTRAINT_SUGGESTION_AI')
+    if not ai_engine_path or ai_engine_path == "":
+        isAIEngineEnvSet = False
+        this_script_path = os.path.dirname(os.path.realpath(sys.argv[0] or 'something'))
+        os.environ['SHAPER_SKETCH_CONSTRAINT_SUGGESTION_AI'] = os.path.join(this_script_path, 'data', 'predict_engine_mock_scenario2.py')
+        pass
+
+    ai_engine = SAMConverter.getSketchConstraintsFinder()
+    assert(ai_engine)
+
+    # 1. Predict constraints on SAM model
+    pred = ai_engine.Predict(plaque_trouee_sam)
+    for key,value in pred.items() :
+        print(f' {key} : {value}')
+        pass
+
+    # 2. Predict constraints on Shaper model (convert to SAM beforehand)
+    aFeature = SAMConverter.SuggestConstraintsFeature()
+    pred_shaper = aFeature.PredictConstraints()
+    for key,value in pred_shaper.items() :
+        print(f' {key} : {value}')
+        pass
+
+    if not isAIEngineEnvSet:
+        os.environ.pop('SHAPER_SKETCH_CONSTRAINT_SUGGESTION_AI', None)
+        pass
+
+    # for i, x in enumerate(ecrou_sam.sequence):
+    #     if 'Line' in str(x) :
+    #         print(i, x)
diff --git a/src/SAMConverter/Test/data/ecrou_sam_scenario1.py b/src/SAMConverter/Test/data/ecrou_sam_scenario1.py
new file mode 100644 (file)
index 0000000..35c3e2f
--- /dev/null
@@ -0,0 +1,66 @@
+from sam.sketch import Sketch
+from sam.catalog_primitive import Point, Circle, Line
+from sam.catalog_constraint import *
+
+nb = 6
+k = 13
+ecrou_sam = Sketch()
+
+# Add Origin Point
+point_origin = Point(status_construction=True, point=[0., 0.])
+ecrou_sam.add(point_origin)
+
+# Add Circle
+circle = Circle(status_construction=False, center=[0., 0.], radius=3.9)
+ecrou_sam.add(circle)
+
+# Add Constraint radius + coincident
+ecrou_sam.add(Coincident(references = [circle.center, point_origin]))
+
+# Add Line
+
+line_1 = Line(status_construction=True, pnt1 = [3.9,0.], pnt2= [7.505553499465127, 0.])
+ecrou_sam.add(line_1)
+ecrou_sam.add(Coincident(references = [circle, line_1.pnt1]))
+ecrou_sam.add(Horizontal(references = [line_1]))
+
+# Traduction de SketchProjection ??,
+# line_2 = ???
+
+
+# Add line 3
+line_3 = Line(status_construction=False, pnt1 = [7.505553499465127, 0], pnt2= [3.752776749732566, 6.499999999999992]) 
+ecrou_sam.add(line_3)
+ecrou_sam.add(Coincident(references = [line_1.pnt2, line_3.pnt1]))
+ecrou_sam.add(Distance( references = [point_origin, line_3], distance_min=k/2))
+
+# Add line 4 
+line_4 = Line(status_construction=True, pnt1 = [3.752776749732566, 6.499999999999992], pnt2= [1.950000000000005, 3.377499074759307]) 
+ecrou_sam.add(line_4)
+ecrou_sam.add(Coincident(references =  [line_3.pnt2, line_4.pnt1]))
+ecrou_sam.add(Coincident(references = [line_4.pnt2, circle]))
+ecrou_sam.add(Equal(references = [line_1, line_4]))
+
+
+# Manque la rotation multiple -> add multiple line
+line_5 = Line(status_construction=False, pnt1 = [3.7527767497325644, 6.499999999999993], pnt2= [-3.7527767497325604, 6.499999999999996]) 
+ecrou_sam.add(line_5)
+ecrou_sam.add(Coincident(references =  [line_4.pnt2, line_5.pnt1]))
+
+line_6 = Line(status_construction=False, pnt1 = [-3.752776749732562, 6.499999999999995], pnt2= [-7.505553499465128, 4.884981308350689e-15]) 
+ecrou_sam.add(line_6)
+ecrou_sam.add(Coincident(references =  [line_5.pnt2, line_6.pnt1]))
+
+line_7 = Line(status_construction=False, pnt1 = [-7.505553499465128, 3.1086244689504383e-15], pnt2= [-3.7527767497325693, -6.499999999999991]) 
+ecrou_sam.add(line_7)
+ecrou_sam.add(Coincident(references =  [line_6.pnt2, line_7.pnt1]))
+
+line_8 = Line(status_construction=False, pnt1 = [-3.7527767497325675, -6.499999999999992], pnt2= [3.7527767497325577, -6.499999999999998]) 
+ecrou_sam.add(line_8)
+ecrou_sam.add(Coincident(references =  [line_7.pnt2, line_8.pnt1]))
+
+line_9 = Line(status_construction=False, pnt1 = [3.7527767497325595, -6.4999999999999964], pnt2= [7.505553499465128, -8.43769498715119e-15]) 
+ecrou_sam.add(line_9)
+ecrou_sam.add(Coincident(references =  [line_8.pnt2, line_9.pnt1]))
+
+ecrou_sam.add(Coincident(references =  [line_9.pnt2, line_3.pnt1]))
diff --git a/src/SAMConverter/Test/data/ecrou_scenario1.py b/src/SAMConverter/Test/data/ecrou_scenario1.py
new file mode 100644 (file)
index 0000000..9689055
--- /dev/null
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""L'écrou - CAO avec SHAPER
+
+Copyright 2020 EDF
+Gérald NICOLAS
++33.1.78.19.43.52
+"""
+from salome.shaper import model
+from SketchAPI import *
+__revision__ = "V03.02"
+
+import salome
+
+salome.salome_init()
+
+###
+# SHAPER component
+###
+
+
+model.begin()
+partSet = model.moduleDocument()
+
+# Create Part
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+model.addParameter(Part_1_doc, "nb", "6")
+model.addParameter(Part_1_doc, "k", "13")
+
+# Create Sketch
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+
+# Create SketchProjection
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+
+# Create SketchCircle
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 3.9)
+Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+
+# Create SketchLine
+SketchLine_1 = Sketch_1.addLine(3.9, 0, 7.505553499465127, 0)
+SketchLine_1.setAuxiliary(True)
+Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchCircle_1.results()[1])
+Sketch_1.setHorizontal(SketchLine_1.result())
+
+# Create SketchProjection
+SketchProjection_2 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_2 = SketchProjection_2.createdFeature()
+Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.result())
+
+# Create SketchLine
+SketchLine_3 = Sketch_1.addLine(7.505553499465127, 0, 3.752776749732566, 6.499999999999992)
+Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_3.startPoint())
+Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_3.result(), "k/2", True)
+
+# Create SketchLine
+SketchLine_4 = Sketch_1.addLine(3.752776749732566, 6.499999999999992, 1.950000000000005, 3.377499074759307)
+SketchLine_4.setAuxiliary(True)
+Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchCircle_1.results()[1])
+Sketch_1.setEqual(SketchLine_1.result(), SketchLine_4.result())
+
+
+
+# Create SketchMultiRotation
+SketchMultiRotation_1 = Sketch_1.addRotation([SketchLine_3.result()], SketchAPI_Point(SketchPoint_1).coordinates(), 360, "nb", True)
+[SketchLine_5, SketchLine_6, SketchLine_7, SketchLine_8, SketchLine_9] = SketchMultiRotation_1.rotated()
+
+model.do()
+
+
+model.end()
+
+
+if salome.sg.hasDesktop():
+    salome.sg.updateObjBrowser()
diff --git a/src/SAMConverter/Test/data/plaque_trouee_sam_sc2.py b/src/SAMConverter/Test/data/plaque_trouee_sam_sc2.py
new file mode 100644 (file)
index 0000000..1f8a565
--- /dev/null
@@ -0,0 +1,51 @@
+from sam.sketch import Sketch
+from sam.catalog_primitive import Arc, Line
+from sam.catalog_constraint import *
+
+H = 150
+L = 100
+a = 10
+
+plaque_trouee_sam = Sketch()
+
+
+line_1 = Line(status_construction=False, pnt1 = [0.0, 10.0], pnt2= [0.0, 150.0])
+plaque_trouee_sam.add(line_1)
+
+line_2 = Line(status_construction=False, pnt1 = [0.0, 150.0], pnt2= [100.0, 150.0])
+plaque_trouee_sam.add(line_2)
+plaque_trouee_sam.add(Coincident(references = [line_1.pnt2, line_2.pnt1]))
+
+line_3 = Line(status_construction=False, pnt1 = [100.0, 150.0], pnt2= [100.0, 0.0])
+plaque_trouee_sam.add(line_3)
+plaque_trouee_sam.add(Coincident(references = [line_2.pnt2, line_3.pnt1]))
+
+line_4 = Line(status_construction=False, pnt1 = [100.0, 0.0], pnt2= [10.0, 0.0])
+plaque_trouee_sam.add(line_4)
+# plaque_trouee_sam.add(Coincident(references = [line_3.pnt2, line_4.pnt1]))
+
+line_5 = Line(status_construction=False, pnt1 = [0.0, 0.0], pnt2= [0.0, 100.0])
+plaque_trouee_sam.add(line_5)
+
+line_6 = Line(status_construction=False, pnt1 = [0.0, 0.0], pnt2= [100.0, 0.0])
+plaque_trouee_sam.add(line_6)
+
+arc= Arc(status_construction=False, center=[0., 0.], radius=10.0, angles=[0., 90.])
+plaque_trouee_sam.add(arc)
+
+plaque_trouee_sam.add(Coincident(references = [line_4.pnt1, line_6]))
+# plaque_trouee_sam.add(Vertical(references = [line_1]))
+# plaque_trouee_sam.add(Vertical(references = [line_3]))
+# plaque_trouee_sam.add(Horizontal(references = [line_4]))
+# plaque_trouee_sam.add(Horizontal(references = [line_2]))
+
+plaque_trouee_sam.add(Coincident(references = [line_1.pnt1, line_5]))
+plaque_trouee_sam.add(Coincident(references = [line_4.pnt1, line_6]))
+
+# plaque_trouee_sam.add(Length(references = [line_3], length = L))
+# plaque_trouee_sam.add(Length(references = [line_2], length = H))
+plaque_trouee_sam.add(Coincident(references = [arc.center, line_6]))
+plaque_trouee_sam.add(Coincident(references = [arc, line_1.pnt1]))
+plaque_trouee_sam.add(Coincident(references = [arc, line_4.pnt2]))
+plaque_trouee_sam.add(Radius(references = [arc], radius = a))
+
diff --git a/src/SAMConverter/Test/data/plaque_trouee_shaper_sc2.py b/src/SAMConverter/Test/data/plaque_trouee_shaper_sc2.py
new file mode 100644 (file)
index 0000000..96167ca
--- /dev/null
@@ -0,0 +1,150 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""1/4 de plaque trouée ; CAO avec SHAPER
+
+Copyright 2020 EDF
+Gérald NICOLAS
++33.1.78.19.43.52
+"""
+__revision__ = "V04.01"
+
+
+import os
+import sys
+import salome
+
+salome.salome_init()
+
+###
+### SHAPER component
+###
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+
+### Create Part
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+model.addParameter(Part_1_doc, "H", '150')
+model.addParameter(Part_1_doc, "L", '100')
+model.addParameter(Part_1_doc, "a", '10')
+model.addParameter(Part_1_doc, "DZ", '30.')
+
+### Create Sketch
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+
+### Create SketchLine
+SketchLine_1 = Sketch_1.addLine(0, 10, 0, 150)
+
+### Create SketchLine
+SketchLine_2 = Sketch_1.addLine(0, 150, 100, 150)
+Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+
+### Create SketchLine
+SketchLine_3 = Sketch_1.addLine(100, 150, 100, 0)
+Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+
+### Create SketchLine
+SketchLine_4 = Sketch_1.addLine(100, 0, 10, 0)
+# Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+# Sketch_1.setVertical(SketchLine_1.result())
+# Sketch_1.setVertical(SketchLine_3.result())
+# Sketch_1.setHorizontal(SketchLine_4.result())
+# Sketch_1.setHorizontal(SketchLine_2.result())
+
+### Create SketchProjection
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OY"), False)
+SketchLine_5 = SketchProjection_1.createdFeature()
+Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_5.result())
+
+### Create SketchProjection
+SketchProjection_2 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_6 = SketchProjection_2.createdFeature()
+Sketch_1.setCoincident(SketchLine_4.startPoint(), SketchLine_6.result())
+# Sketch_1.setLength(SketchLine_3.result(), "H")
+# Sketch_1.setLength(SketchLine_2.result(), "L")
+
+### Create SketchArc
+SketchArc_1 = Sketch_1.addArc(0, 0, 0, 10, 10, 0, True)
+Sketch_1.setCoincident(SketchArc_1.center(), SketchAPI_Line(SketchLine_6).startPoint())
+Sketch_1.setCoincident(SketchArc_1.startPoint(), SketchLine_1.startPoint())
+Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_4.endPoint())
+Sketch_1.setRadius(SketchArc_1.results()[1], "a")
+model.do()
+
+### Create Face
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchArc_1_2r-SketchLine_4r-SketchLine_3r-SketchLine_2r-SketchLine_1r")])
+Face_1.result().setName("Plaque")
+
+### Create Extrusion
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Plaque")], model.selection(), "DZ", 0)
+
+### Create Group
+Group_1 = model.addGroup(Part_1_doc, "FACE", [model.selection("FACE", "Plaque/From_Face")])
+Group_1.setName("face_Zm")
+Group_1.result().setName("face_Zm")
+
+### Create Group
+Group_2 = model.addGroup(Part_1_doc, "FACE", [model.selection("FACE", "Plaque/To_Face")])
+Group_2.setName("face_Zp")
+Group_2.result().setName("face_Zp")
+
+### Create Group
+Group_3 = model.addGroup(Part_1_doc, "FACE", [model.selection("FACE", "Plaque/Generated_Face&Sketch_1/SketchLine_1")])
+Group_3.setName("gauche")
+Group_3.result().setName("gauche")
+
+### Create Group
+Group_4 = model.addGroup(Part_1_doc, "FACE", [model.selection("FACE", "Plaque/Generated_Face&Sketch_1/SketchLine_2")])
+Group_4.setName("haut")
+Group_4.result().setName("haut")
+
+### Create Group
+Group_5 = model.addGroup(Part_1_doc, "FACE", [model.selection("FACE", "Plaque/Generated_Face&Sketch_1/SketchLine_3")])
+Group_5.setName("droite")
+Group_5.result().setName("droite")
+
+### Create Group
+Group_6 = model.addGroup(Part_1_doc, "FACE", [model.selection("FACE", "Plaque/Generated_Face&Sketch_1/SketchLine_4")])
+Group_6.setName("bas")
+Group_6.result().setName("bas")
+
+### Create Group
+Group_7 = model.addGroup(Part_1_doc, "FACE", [model.selection("FACE", "Plaque/Generated_Face&Sketch_1/SketchArc_1_2")])
+Group_7.setName("trou")
+Group_7.result().setName("trou")
+
+### Create Group
+Group_8 = model.addGroup(Part_1_doc, "EDGE", [model.selection("EDGE", "[Plaque/Generated_Face&Sketch_1/SketchArc_1_2][Plaque/From_Face]")])
+Group_8.setName("arc_Zm")
+Group_8.result().setName("arc_Zm")
+
+### Create Group
+Group_9 = model.addGroup(Part_1_doc, "EDGE", [model.selection("EDGE", "[Plaque/Generated_Face&Sketch_1/SketchArc_1_2][Plaque/To_Face]")])
+Group_9.setName("arc_Zp")
+Group_9.result().setName("arc_Zp")
+
+### Create Group
+Group_10 = model.addGroup(Part_1_doc, "EDGE", [model.selection("EDGE", "[Plaque/Generated_Face&Sketch_1/SketchArc_1_2][Plaque/Generated_Face&Sketch_1/SketchLine_4]")])
+Group_10.setName("verticale")
+Group_10.result().setName("verticale")
+
+### Create Group
+Group_11 = model.addGroup(Part_1_doc, "VERTEX", [model.selection("VERTEX", "[Plaque/Generated_Face&Sketch_1/SketchArc_1_2][Plaque/Generated_Face&Sketch_1/SketchLine_1][Plaque/From_Face]")])
+Group_11.setName("A")
+Group_11.result().setName("A")
+
+### Create Group
+Group_12 = model.addGroup(Part_1_doc, "VERTEX", [model.selection("VERTEX", "[Plaque/Generated_Face&Sketch_1/SketchArc_1_2][Plaque/Generated_Face&Sketch_1/SketchLine_4][Plaque/From_Face]")])
+Group_12.setName("B")
+Group_12.result().setName("B")
+
+model.end()
+
+
+if salome.sg.hasDesktop():
+  salome.sg.updateObjBrowser()
diff --git a/src/SAMConverter/Test/data/predict_engine_mock_scenario1.py b/src/SAMConverter/Test/data/predict_engine_mock_scenario1.py
new file mode 100644 (file)
index 0000000..21781c2
--- /dev/null
@@ -0,0 +1,43 @@
+# 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
+#
+
+# AIEngine mock for scenario 1
+
+class AIEngine:
+
+    ## The constructor.
+    def __init__(self):
+        pass
+
+    def Predict(self, sam_model):
+        print('AIEngine.Predict() !!!')
+        
+        circle = sam_model.sequence[1]
+        line_1 = sam_model.sequence[3]
+        line_4 = sam_model.sequence[9]
+        line_5 = sam_model.sequence[13]
+        line_8 = sam_model.sequence[19]
+
+        prediction = {"SUGGESTION_1" : { 'primitives' : [line_1, line_4],  'suggested_constraint' : 'ANGLE',    'score' : 0.98 },
+                      "SUGGESTION_2" : { 'primitives' : [circle],          'suggested_constraint' : 'RADIUS',   'score' : 0.58 }, 
+                      "SUGGESTION_3" : { 'primitives' : [line_8, line_1],  'suggested_constraint' : 'EQUAL',    'score' : 0.4 },
+                      "SUGGESTION_4" : { 'primitives' : [line_5, line_1],  'suggested_constraint' : 'DISTANCE', 'score' : 0.01 },  
+                      }
+
+        return prediction
diff --git a/src/SAMConverter/Test/data/predict_engine_mock_scenario2.py b/src/SAMConverter/Test/data/predict_engine_mock_scenario2.py
new file mode 100644 (file)
index 0000000..f20d4a9
--- /dev/null
@@ -0,0 +1,43 @@
+# 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
+#
+
+# AIEngine mock
+
+class AIEngine:
+
+    ## The constructor.
+    def __init__(self):
+        pass
+
+    def Predict(self, sam_model):
+        print('AIEngine.Predict() !!!')
+        
+        line_1 = sam_model.sequence[0]
+        line_2 = sam_model.sequence[1]
+        line_3 = sam_model.sequence[3]
+        line_4 = sam_model.sequence[5]
+        line_5 = sam_model.sequence[6]
+        line_8 = sam_model.sequence[7]
+
+        prediction = {"SUGGESTION_1" : { 'primitives' : [line_1, line_4], 'suggested_constraint' : 'COINCIDENCE', 'score' : 0.6 },
+                      "SUGGESTION_2" : { 'primitives' : [line_4],         'suggested_constraint' : 'LENGHT',      'score' : 0.58 }, 
+                      "SUGGESTION_3" : { 'primitives' : [line_8, line_1], 'suggested_constraint' : 'EQUAL',       'score' : 0.4 },
+                      "SUGGESTION_4" : { 'primitives' : [line_4],         'suggested_constraint' : 'VERTICAL',    'score' : 0.01 },  
+                      }
+        return prediction
index 86799645cff70bd067d921610ef463eb3325114e..54f3127555e4ea5dcb10390fa4c118396235bf23 100644 (file)
@@ -32,4 +32,6 @@ SET(TEST_NAMES
            TestSAMConverter_Radius
            TestSAMConverter_Sketch
            TestSAMConverter_VerticalDistance
+           TestSAMConverter_scenario1
+           TestSAMConverter_scenario2
 )
index 01cc1bc74ff49e175ee5eee7dbcd5eb69b68621c..22f4e92014470372a5888806d7d733d49abc1ba2 100644 (file)
@@ -368,6 +368,8 @@ std::shared_ptr<ModelAPI_FeatureStateMessage> SketchPlugin_Plugin
       aMsg->setState(SketchPlugin_Offset::ID(), aHasSketchPlane);
       // SketchRectangle is a python feature, so its ID is passed just as a string
       aMsg->setState("SketchRectangle", aHasSketchPlane);
+      // SuggestConstraints is a python feature, so its ID is passed just as a string
+      aMsg->setState("SuggestConstraints", aHasSketchPlane);
     }
   }
   return aMsg;