Salome HOME
Merge Dev_2.1.0 with PythonAPI branch
authorspo <sergey.pokhodenko@opencascade.com>
Wed, 9 Dec 2015 08:35:56 +0000 (11:35 +0300)
committerspo <sergey.pokhodenko@opencascade.com>
Wed, 9 Dec 2015 08:35:56 +0000 (11:35 +0300)
101 files changed:
.gitignore
env_linux.sh
src/PythonAPI/CMakeLists.txt
src/PythonAPI/MakeBrick1.py [deleted file]
src/PythonAPI/MakeBrick2.py [deleted file]
src/PythonAPI/MakeBrick3.py [deleted file]
src/PythonAPI/Test/TestFeaturesExtrusion.py [new file with mode: 0644]
src/PythonAPI/Test/TestFeaturesRevolution.py [new file with mode: 0644]
src/PythonAPI/Test/TestMakeBrick1.py [new file with mode: 0644]
src/PythonAPI/Test/TestMakeBrick2.py [new file with mode: 0644]
src/PythonAPI/Test/TestMakeBrick3.py [new file with mode: 0644]
src/PythonAPI/Test/TestModel.py [new file with mode: 0644]
src/PythonAPI/Test/TestShaper.py [new file with mode: 0644]
src/PythonAPI/Test/TestSketcher.py [new file with mode: 0644]
src/PythonAPI/Test/TestSketcherAddArc.py [new file with mode: 0644]
src/PythonAPI/Test/TestSketcherAddCircle.py [new file with mode: 0644]
src/PythonAPI/Test/TestSketcherAddLine.py [new file with mode: 0644]
src/PythonAPI/Test/TestSketcherAddMirror.py [new file with mode: 0644]
src/PythonAPI/Test/TestSketcherAddPoint.py [new file with mode: 0644]
src/PythonAPI/Test/TestSketcherSetAngle.py [new file with mode: 0644]
src/PythonAPI/Test/TestSketcherSetCoincident.py [new file with mode: 0644]
src/PythonAPI/Test/TestSketcherSetEqual.py [new file with mode: 0644]
src/PythonAPI/Test/TestSketcherSetFillet.py [new file with mode: 0644]
src/PythonAPI/Test/TestSketcherSetHorizontal.py [new file with mode: 0644]
src/PythonAPI/Test/TestSketcherSetLength.py [new file with mode: 0644]
src/PythonAPI/Test/TestSketcherSetParallel.py [new file with mode: 0644]
src/PythonAPI/Test/TestSketcherSetPerpendicular.py [new file with mode: 0644]
src/PythonAPI/Test/TestSketcherSetRadius.py [new file with mode: 0644]
src/PythonAPI/Test/TestSketcherSetRigid.py [new file with mode: 0644]
src/PythonAPI/Test/TestSketcherSetTangent.py [new file with mode: 0644]
src/PythonAPI/Test/TestSketcherSetVertical.py [new file with mode: 0644]
src/PythonAPI/doc/Makefile [new file with mode: 0644]
src/PythonAPI/doc/make.bat [new file with mode: 0644]
src/PythonAPI/doc/source/arc.rst [new file with mode: 0644]
src/PythonAPI/doc/source/conf.py [new file with mode: 0644]
src/PythonAPI/doc/source/index.rst [new file with mode: 0644]
src/PythonAPI/doc/source/model/boolean.rst [new file with mode: 0644]
src/PythonAPI/doc/source/model/connection.rst [new file with mode: 0644]
src/PythonAPI/doc/source/model/construction.rst [new file with mode: 0644]
src/PythonAPI/doc/source/model/exchange.rst [new file with mode: 0644]
src/PythonAPI/doc/source/model/extrusion.rst [new file with mode: 0644]
src/PythonAPI/doc/source/model/group.rst [new file with mode: 0644]
src/PythonAPI/doc/source/model/parameter.rst [new file with mode: 0644]
src/PythonAPI/doc/source/model/partition.rst [new file with mode: 0644]
src/PythonAPI/doc/source/model/partset.rst [new file with mode: 0644]
src/PythonAPI/doc/source/model/placement.rst [new file with mode: 0644]
src/PythonAPI/doc/source/model/revolution.rst [new file with mode: 0644]
src/PythonAPI/doc/source/model/rotation.rst [new file with mode: 0644]
src/PythonAPI/doc/source/model/translation.rst [new file with mode: 0644]
src/PythonAPI/doc/source/sketcher.rst [new file with mode: 0644]
src/PythonAPI/examples/MakeBrick1.py [new file with mode: 0644]
src/PythonAPI/examples/MakeBrick2.py [new file with mode: 0644]
src/PythonAPI/examples/MakeBrick3.py [new file with mode: 0644]
src/PythonAPI/examples/__init__.py [new file with mode: 0644]
src/PythonAPI/extension/__init__.py
src/PythonAPI/extension/box.py
src/PythonAPI/geom/missed.py
src/PythonAPI/model/__init__.py [new file with mode: 0644]
src/PythonAPI/model/connection/__init__.py [new file with mode: 0644]
src/PythonAPI/model/connection/connection.py [new file with mode: 0644]
src/PythonAPI/model/construction/__init__.py [new file with mode: 0644]
src/PythonAPI/model/construction/axis.py [new file with mode: 0644]
src/PythonAPI/model/construction/plane.py [new file with mode: 0644]
src/PythonAPI/model/construction/point.py [new file with mode: 0644]
src/PythonAPI/model/errors.py [new file with mode: 0644]
src/PythonAPI/model/exchange/__init__.py [new file with mode: 0644]
src/PythonAPI/model/exchange/exchange.py [new file with mode: 0644]
src/PythonAPI/model/features/__init__.py [new file with mode: 0644]
src/PythonAPI/model/features/boolean.py [new file with mode: 0644]
src/PythonAPI/model/features/extrusion.py [new file with mode: 0644]
src/PythonAPI/model/features/extrusion_boolean.py [new file with mode: 0644]
src/PythonAPI/model/features/extrusion_sketch.py [new file with mode: 0644]
src/PythonAPI/model/features/group.py [new file with mode: 0644]
src/PythonAPI/model/features/partition.py [new file with mode: 0644]
src/PythonAPI/model/features/placement.py [new file with mode: 0644]
src/PythonAPI/model/features/revolution.py [new file with mode: 0644]
src/PythonAPI/model/features/revolution_boolean.py [new file with mode: 0644]
src/PythonAPI/model/features/revolution_sketch.py [new file with mode: 0644]
src/PythonAPI/model/features/roots.py [new file with mode: 0644]
src/PythonAPI/model/features/rotation.py [new file with mode: 0644]
src/PythonAPI/model/features/translation.py [new file with mode: 0644]
src/PythonAPI/model/parameter/__init__.py [new file with mode: 0644]
src/PythonAPI/model/parameter/parameter.py [new file with mode: 0644]
src/PythonAPI/model/partset/__init__.py [new file with mode: 0644]
src/PythonAPI/model/partset/part.py [new file with mode: 0644]
src/PythonAPI/model/roots.py [new file with mode: 0644]
src/PythonAPI/model/services.py [new file with mode: 0644]
src/PythonAPI/model/sketcher/__init__.py [new file with mode: 0644]
src/PythonAPI/model/sketcher/arc.py [new file with mode: 0644]
src/PythonAPI/model/sketcher/circle.py [new file with mode: 0644]
src/PythonAPI/model/sketcher/line.py [new file with mode: 0644]
src/PythonAPI/model/sketcher/mirror.py [new file with mode: 0644]
src/PythonAPI/model/sketcher/point.py [new file with mode: 0644]
src/PythonAPI/model/sketcher/sketch.py [new file with mode: 0644]
src/PythonAPI/model/tools.py [new file with mode: 0644]
src/PythonAPI/modeler/__init__.py [deleted file]
src/PythonAPI/modeler/services.py [deleted file]
src/PythonAPI/pylintrc [new file with mode: 0644]
src/PythonAPI/shaper.py [new file with mode: 0644]
src/PythonAddons/addons_Features.py
src/PythonAddons/macros/box/feature.py

index b3e5bb13fb16b3cafc9c15e28bdc11ef91562fb4..3361c41de623b070d566e552f43cb77123319d36 100644 (file)
@@ -29,4 +29,4 @@ start.bat
 *~
 /.project
 *DFBrowser*
-
+*.pyc
index fa701589b210cc5aa37f24f0b232b9951a48ca89..ef10d0d7dbd4e8aa71e7169036021bcdfd70f856 100644 (file)
@@ -40,7 +40,7 @@ export PATH=${CASROOT}:${PATH}
 
 #------ NewGEOM ------
 export PATH=${NEWGEOM_ROOT_DIR}/bin:${NEWGEOM_ROOT_DIR}/plugins:${PATH}
-export PYTHONPATH=${NEWGEOM_ROOT_DIR}/swig:${NEWGEOM_ROOT_DIR}/plugins:${NEWGEOM_ROOT_DIR}/addons:${NEWGEOM_ROOT_DIR}/pythonAPI:${PYTHONPATH}
+export PYTHONPATH=${NEWGEOM_ROOT_DIR}/swig:${NEWGEOM_ROOT_DIR}/plugins:${NEWGEOM_ROOT_DIR}/addons:${NEWGEOM_ROOT_DIR}/PythonAPI:${PYTHONPATH}
 export LD_LIBRARY_PATH=${NEWGEOM_ROOT_DIR}/bin:${NEWGEOM_ROOT_DIR}/swig:${NEWGEOM_ROOT_DIR}/plugins:${LD_LIBRARY_PATH}
 export NEW_GEOM_CONFIG_FILE=${NEWGEOM_ROOT_DIR}/plugins
 export NewGeomResources=${NEWGEOM_ROOT_DIR}/resources
index c89a7986859a74850eae271b9d9adb61d49b8778..f284d241c5bbab5874abdbb7e4fbe5ebc9fd2725 100644 (file)
@@ -3,4 +3,39 @@
 
 SET(CMAKE_AUTOMOC ON)
 
-INSTALL(DIRECTORY extension geom modeler DESTINATION pythonAPI)
+INSTALL(DIRECTORY extension geom model examples DESTINATION PythonAPI)
+INSTALL(FILES shaper.py DESTINATION PythonAPI)
+
+# --------- Unit tests -----------
+INCLUDE(UnitTest)
+
+ADD_UNIT_TESTS(
+  TestShaper.py
+  TestModel.py
+
+  TestSketcherAddPoint.py
+  TestSketcherAddLine.py
+  TestSketcherAddArc.py
+  TestSketcherAddCircle.py
+  TestSketcherAddMirror.py
+  TestSketcherSetCoincident.py
+  TestSketcherSetTangent.py
+  TestSketcherSetParallel.py
+  TestSketcherSetPerpendicular.py
+  TestSketcherSetHorizontal.py
+  TestSketcherSetVertical.py
+  TestSketcherSetRigid.py
+  TestSketcherSetLength.py
+  TestSketcherSetRadius.py
+  TestSketcherSetAngle.py
+  TestSketcherSetEqual.py
+  TestSketcherSetFillet.py
+
+  TestFeatures.py
+  TestFeaturesExtrusion.py
+  TestFeaturesRevolution.py
+
+  TestMakeBrick1.py
+  TestMakeBrick2.py
+#  TestMakeBrick3.py
+  )
diff --git a/src/PythonAPI/MakeBrick1.py b/src/PythonAPI/MakeBrick1.py
deleted file mode 100644 (file)
index 8320de0..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-# Creation of a box using the end-user API
-# Author: Daniel Brunier-Coulin
-# -----------------------------
-
-import modeler
-
-
-# Initialisation
-
-modeler.begin()
-mypartset = modeler.moduleDocument()
-
-
-# Creating a new Part
-
-mypart = modeler.addPart(mypartset).document()
-
-
-# Creating the base of the box
-
-mybase = modeler.addSketch( mypart, modeler.defaultPlane("XOY") )
-
-l1 = mybase.addLine( 0, 0, 0, 1 )
-l2 = mybase.addLine( 0, 1, 1, 1 )
-l3 = mybase.addLine( 1, 1, 1, 0 )
-l4 = mybase.addLine( 1, 0, 0, 0 )
-
-mybase.setCoincident( l1.endPointData(), l2.startPointData() )
-mybase.setCoincident( l2.endPointData(), l3.startPointData() )
-mybase.setCoincident( l3.endPointData(), l4.startPointData() )
-mybase.setCoincident( l4.endPointData(), l1.startPointData() )
-
-mybase.setParallel( l1.result(), l3.result() )
-mybase.setParallel( l2.result(), l4.result() )
-
-mybase.setPerpendicular( l1.result(), l4.result() )
-
-mywidth  = mybase.setLength( l1.result(), 50 )
-mylength = mybase.setDistance( l1.startPointData(), l3.result(), 50 )
-
-
-# Creating the extrusion
-
-mybox = modeler.addExtrusion( mypart, mybase.selectFace(), 50 )
-
-
-# Creating a cylinder on a face of the box
-
-thisface = "Extrusion_1/LateralFace_2"
-thisxmin = "Extrusion_1/LateralFace_3|Extrusion_1/LateralFace_2"
-thisxmax = "Extrusion_1/LateralFace_2|Extrusion_1/LateralFace_1"
-thiszmin = "Sketch_1/Edge5_1"
-thiszmax = "Extrusion_1/LateralFace_2|Extrusion_1/TopFace_1"
-
-mystand = modeler.addSketch( mypart, thisface )
-c1      = mystand.addCircle( 0, 25, 5)
-mystand.setDistance( c1.centerData(), thisxmin, 10 )
-mystand.setDistance( c1.centerData(), thiszmax, 10 )
-
-myboss = modeler.addExtrusion( mypart, mystand.selectFace(c1.result()), -5 )
-
-
-# Subtracting the cylinder to the box
-
-modeler.addSubtraction( mypart, mybox.result(), myboss.result() )
-modeler.end()
-
-
-# Editing the box
-
-modeler.begin()
-mybase.setValue( mylength, 100 )
-mybox.setSize( 80 )
-modeler.end()
diff --git a/src/PythonAPI/MakeBrick2.py b/src/PythonAPI/MakeBrick2.py
deleted file mode 100644 (file)
index 24865b5..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-# Creation of a box using the end-user API
-# Author: Daniel Brunier-Coulin
-# -----------------------------
-
-import modeler
-import geom
-
-
-# Initialisation
-
-modeler.begin()
-mypartset = modeler.moduleDocument()
-
-
-# Creating a new Part
-
-mypart = modeler.addPart(mypartset).document()
-
-
-# Creating the base of the box
-
-mybase = modeler.addSketch( mypart, modeler.defaultPlane("XOY") )
-
-p1 = geom.Pnt2d( 0, 0 )
-p2 = geom.Pnt2d( 0, 1 )
-p3 = geom.Pnt2d( 1, 1 )
-p4 = geom.Pnt2d( 1, 0 )
-
-line = mybase.addPolygon(p1, p2, p3, p4)
-
-mybase.setParallel( line[0].result(), line[2].result() )
-mybase.setParallel( line[1].result(), line[3].result() )
-mybase.setPerpendicular( line[0].result(), line[3].result() )
-
-mywidth  = mybase.setLength( line[0].result(), 50 )
-mylength = mybase.setDistance( line[0].startPointData(),line[2].result(), 50 )
-
-
-# Creating the extrusion
-
-mybox = modeler.addExtrusion( mypart, mybase.selectFace(), 50 )
-
-
-# Creating a cylinder on a face of the box
-
-thisface = "Extrusion_1/LateralFace_2"
-thisxmin = "Extrusion_1/LateralFace_3|Extrusion_1/LateralFace_2"
-thiszmax = "Extrusion_1/LateralFace_2|Extrusion_1/TopFace_1"
-
-mystand = modeler.addSketch( mypart, thisface )
-circle  = mystand.addCircle( 0, 25, 5)
-mystand.setDistance( circle.centerData(), thisxmin, 10 )
-mystand.setDistance( circle.centerData(), thiszmax, 10 )
-
-myboss = modeler.addExtrusion( mypart, mystand.selectFace(), -5 )
-
-
-# Subtracting the cylinder to the box
-
-modeler.addSubtraction( mypart, mybox.result(), myboss.result() )
-modeler.end()
-
-
-# Editing the box
-
-modeler.begin()
-mybase.setValue( mylength, 100 )
-mybox.setSize( 20 )
-modeler.end()
diff --git a/src/PythonAPI/MakeBrick3.py b/src/PythonAPI/MakeBrick3.py
deleted file mode 100644 (file)
index c314780..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-# Creation of a box using the end-user API
-# Author: Daniel Brunier-Coulin
-# -----------------------------
-
-import modeler
-import extension
-
-
-# Initialisation
-
-modeler.begin()
-mypartset = modeler.moduleDocument()
-
-
-# Creating a new Part
-
-mypart = modeler.addPart(mypartset).document()
-
-
-# Creating the base of the box
-
-extension.addBox( mypart, 10, 20, 30 )
-modeler.end()
-
diff --git a/src/PythonAPI/Test/TestFeaturesExtrusion.py b/src/PythonAPI/Test/TestFeaturesExtrusion.py
new file mode 100644 (file)
index 0000000..decd198
--- /dev/null
@@ -0,0 +1,159 @@
+import unittest
+
+import ModelAPI
+
+import model
+
+#-----------------------------------------------------------------------------
+# Fixtures
+
+class FeaturesAddExtrusionFixture(unittest.TestCase):
+
+    def setUp(self):
+        model.begin()
+        # Create part
+        partset = model.moduleDocument()
+        self.part = model.addPart(partset).document()
+        model.do()
+
+    def tearDown(self):
+        model.end()
+        model.reset()
+
+
+class FeaturesExtrusionFixture(FeaturesAddExtrusionFixture):
+
+    def setUp(self):
+        FeaturesAddExtrusionFixture.setUp(self)
+        # Create extrusion
+        sketch = model.addSketch(self.part, model.defaultPlane("XOY"))
+        circle = sketch.addCircle(0, 0, 10)
+        model.do()
+
+        base = sketch.selectFace(circle.result())
+        self.extrusion = model.addExtrusion(self.part, base, 10, 0)
+        model.do()
+
+    def tearDown(self):
+        FeaturesAddExtrusionFixture.tearDown(self)
+
+#-----------------------------------------------------------------------------
+# TestCases
+
+class FeaturesAddExtrusionTestCase(FeaturesAddExtrusionFixture):
+
+    def test_add_extrusion_no_base(self):
+        try:
+            extrusion = model.addExtrusion(self.part)
+            fail("addExtrusion should assert if base is not None")
+        except AssertionError:
+            pass
+
+    def test_add_extrusion_by_face_and_size(self):
+        sketch = model.addSketch(self.part, model.defaultPlane("XOY"))
+        circle = sketch.addCircle(0, 0, 10)
+        model.do()
+
+        base = sketch.selectFace(circle.result())
+        extrusion = model.addExtrusion(self.part, base, 10, 0)
+        model.do()
+
+        self.assertEqual(extrusion.getCreationMethod().value(), "BySizes")
+        self.assertEqual(extrusion.getToSize().value(), 10)
+        self.assertEqual(extrusion.getFromSize().value(), 0)
+        self.assertEqual(extrusion.getToObject().context(), None)
+        self.assertEqual(extrusion.getToOffset().value(), 0)
+        self.assertEqual(extrusion.getFromObject().context(), None)
+        self.assertEqual(extrusion.getFromOffset().value(), 0)
+
+    def test_add_extrusion_by_face_and_planes(self):
+        # base
+        base_sketch = model.addSketch(self.part, model.defaultPlane("XOY"))
+        base_circle = base_sketch.addCircle(0, 0, 10)
+        # to
+        to_plane = model.defaultPlane("XOY")
+        to_plane.location().setZ(10)
+        to_sketch = model.addSketch(self.part, to_plane)
+        to_circle = to_sketch.addCircle(0, 0, 10)
+        # from
+        from_plane = model.defaultPlane("XOY")
+        from_plane.location().setZ(-10)
+        from_sketch = model.addSketch(self.part, from_plane)
+        from_circle = from_sketch.addCircle(0, 0, 10)
+
+        model.do()
+
+        base = base_sketch.selectFace(base_circle.result())
+        to_object = to_sketch.selectFace(to_circle.result())[0]
+        from_object = from_sketch.selectFace(from_circle.result())[0]
+        extrusion = model.addExtrusion(self.part, base,
+                                       to_object, 15,
+                                       from_object, 20)
+
+        self.assertEqual(extrusion.getCreationMethod().value(), "ByPlanesAndOffsets")
+        self.assertEqual(extrusion.getToSize().value(), 0)
+        self.assertEqual(extrusion.getFromSize().value(), 0)
+#         self.assertEqual(extrusion.getToObject().context(),
+#                          to_sketch.result())
+        self.assertEqual(extrusion.getToOffset().value(), 15)
+#         self.assertEqual(extrusion.getFromObject().context(),
+#                          from_sketch.result())
+        self.assertEqual(extrusion.getFromOffset().value(), 20)
+
+
+class FeaturesExtrusionTestCase(FeaturesExtrusionFixture):
+
+    def test_extrusion_feature_calls(self):
+        # call method of the feature
+        self.assertEqual(self.extrusion.getKind(), "Extrusion")
+
+    def test_extrusion_get_attribute(self):
+        # call method of the feature
+        self.assertTrue(isinstance(self.extrusion.getBase(),
+                                   ModelAPI.ModelAPI_AttributeSelectionList))
+        self.assertTrue(isinstance(self.extrusion.getCreationMethod(),
+                                   ModelAPI.ModelAPI_AttributeString))
+        self.assertTrue(isinstance(self.extrusion.getToSize(),
+                                   ModelAPI.ModelAPI_AttributeDouble))
+        self.assertTrue(isinstance(self.extrusion.getFromSize(),
+                                   ModelAPI.ModelAPI_AttributeDouble))
+        self.assertTrue(isinstance(self.extrusion.getToObject(),
+                                   ModelAPI.ModelAPI_AttributeSelection))
+        self.assertTrue(isinstance(self.extrusion.getToOffset(),
+                                   ModelAPI.ModelAPI_AttributeDouble))
+        self.assertTrue(isinstance(self.extrusion.getFromObject(),
+                                   ModelAPI.ModelAPI_AttributeSelection))
+        self.assertTrue(isinstance(self.extrusion.getFromOffset(),
+                                   ModelAPI.ModelAPI_AttributeDouble))
+
+    def test_extrusion_set_sizes(self):
+        self.extrusion.setSizes(15, 20)
+        self.assertEqual(self.extrusion.getCreationMethod().value(), "BySizes")
+        self.assertEqual(self.extrusion.getToSize().value(), 15)
+        self.assertEqual(self.extrusion.getFromSize().value(), 20)
+        self.assertEqual(self.extrusion.getToObject().context(), None)
+        self.assertEqual(self.extrusion.getToOffset().value(), 0)
+        self.assertEqual(self.extrusion.getFromObject().context(), None)
+        self.assertEqual(self.extrusion.getFromOffset().value(), 0)
+
+    def test_extrusion_set_planes_and_offsets(self):
+        # to
+        to_plane = model.defaultPlane("XOY")
+        to_plane.location().setZ(10)
+        to_sketch = model.addSketch(self.part, to_plane)
+        to_circle = to_sketch.addCircle(0, 0, 10)
+        # from
+        from_plane = model.defaultPlane("XOY")
+        from_plane.location().setZ(-10)
+        from_sketch = model.addSketch(self.part, from_plane)
+        from_circle = from_sketch.addCircle(0, 0, 10)
+
+        model.do()
+
+        to_object = to_sketch.selectFace(to_circle.result())[0]
+        from_object = from_sketch.selectFace(from_circle.result())[0]
+        self.extrusion.setPlanesAndOffsets(to_object, 15, from_object, 20)
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/src/PythonAPI/Test/TestFeaturesRevolution.py b/src/PythonAPI/Test/TestFeaturesRevolution.py
new file mode 100644 (file)
index 0000000..a7fbfde
--- /dev/null
@@ -0,0 +1,204 @@
+import unittest
+
+import ModelAPI
+
+import model
+from model.tools import Selection
+
+#-----------------------------------------------------------------------------
+# Fixtures
+
+class FeaturesAddRevolutionFixture(unittest.TestCase):
+
+    def setUp(self):
+        model.begin()
+        # Create part
+        partset = model.moduleDocument()
+        self.part = model.addPart(partset).document()
+        model.do()
+
+    def tearDown(self):
+        model.end()
+        model.reset()
+
+
+class FeaturesRevolutionFixture(FeaturesAddRevolutionFixture):
+
+    def setUp(self):
+        FeaturesAddRevolutionFixture.setUp(self)
+        # Create revolution
+        # base
+        base_sketch = model.addSketch(self.part, model.defaultPlane("XOY"))
+        circle = base_sketch.addCircle(0, 0, 10)
+        # axis
+        axis_sketch = model.addSketch(self.part, model.defaultPlane("XOY"))
+        line = axis_sketch.addLine(20, -10, 20, 10)
+
+        model.do()
+
+        base = base_sketch.selectFace(circle.lastResult())
+        axis_object = Selection(axis_sketch.firstResult(),
+                                line.firstResult().shape())
+
+        self.revolution = model.addRevolution(self.part, base, axis_object,
+                                              0, 180)
+
+        model.do()
+
+    def tearDown(self):
+        FeaturesAddRevolutionFixture.tearDown(self)
+
+#-----------------------------------------------------------------------------
+# TestCases
+
+class FeaturesAddRevolutionTestCase(FeaturesAddRevolutionFixture):
+
+    def test_add_revolution_no_base(self):
+        try:
+            revolution = model.addRevolution(self.part)
+            fail("addRevolution should assert if base is not None")
+        except AssertionError:
+            pass
+
+    def test_add_revolution_by_face_and_angles(self):
+        # base
+        base_sketch = model.addSketch(self.part, model.defaultPlane("XOY"))
+        circle = base_sketch.addCircle(0, 0, 10)
+        # axis
+        axis_sketch = model.addSketch(self.part, model.defaultPlane("XOY"))
+        line = axis_sketch.addLine(20, -10, 20, 10)
+
+        model.do()
+
+        base = base_sketch.selectFace(circle.lastResult())
+        axis_object = Selection(axis_sketch.firstResult(),
+                                line.firstResult().shape())
+
+        revolution = model.addRevolution(self.part, base, axis_object,
+                                         0, 180)
+
+        self.assertEqual(revolution.getCreationMethod().value(), "ByAngles")
+        self.assertEqual(revolution.getToAngle().value(), 0)
+        self.assertEqual(revolution.getFromAngle().value(), 180)
+        self.assertEqual(revolution.getToObject().context(), None)
+        self.assertEqual(revolution.getToOffset().value(), 0)
+        self.assertEqual(revolution.getFromObject().context(), None)
+        self.assertEqual(revolution.getFromOffset().value(), 0)
+
+    def test_add_revolution_by_face_and_planes(self):
+        # base
+        base_sketch = model.addSketch(self.part, model.defaultPlane("XOY"))
+        base_circle = base_sketch.addCircle(0, 0, 10)
+        # axis
+        axis_sketch = model.addSketch(self.part, model.defaultPlane("XOY"))
+        line = axis_sketch.addLine(20, -10, 20, 10)
+        # to
+        to_plane = model.defaultPlane("XOY")
+        to_plane.location().setZ(10)
+        to_sketch = model.addSketch(self.part, to_plane)
+        to_circle = to_sketch.addCircle(0, 0, 10)
+        # from
+        from_plane = model.defaultPlane("XOY")
+        from_plane.location().setZ(-10)
+        from_sketch = model.addSketch(self.part, from_plane)
+        from_circle = from_sketch.addCircle(0, 0, 10)
+
+        model.do()
+
+        base = base_sketch.selectFace(base_circle.result())
+        axis_object = Selection(axis_sketch.firstResult(),
+                                line.firstResult().shape())
+        to_obejct = to_sketch.selectFace(to_circle.result())[0]
+        from_object = from_sketch.selectFace(from_circle.result())[0]
+
+        revolution = model.addRevolution(self.part, base, axis_object,
+                                         to_obejct, 15,
+                                         from_object, 20)
+
+        self.assertEqual(revolution.getCreationMethod().value(), "ByPlanesAndOffsets")
+        self.assertEqual(revolution.getToAngle().value(), 0)
+        self.assertEqual(revolution.getFromAngle().value(), 0)
+#         self.assertEqual(revolution.getToObject().context(),
+#                          to_sketch.result())
+        self.assertEqual(revolution.getToOffset().value(), 15)
+#         self.assertEqual(revolution.getFromObject().context(),
+#                          from_sketch.result())
+        self.assertEqual(revolution.getFromOffset().value(), 20)
+
+
+class FeaturesRevolutionTestCase(FeaturesRevolutionFixture):
+
+    def test_revolution_feature_calls(self):
+        # call method of the feature
+        self.assertEqual(self.revolution.getKind(), "Revolution")
+
+    def test_revolution_get_attribute(self):
+        # call method of the feature
+        self.assertTrue(isinstance(self.revolution.getBase(),
+                                   ModelAPI.ModelAPI_AttributeSelectionList))
+        self.assertTrue(isinstance(self.revolution.getAxisObject(),
+                                   ModelAPI.ModelAPI_AttributeSelection))
+        self.assertTrue(isinstance(self.revolution.getCreationMethod(),
+                                   ModelAPI.ModelAPI_AttributeString))
+        self.assertTrue(isinstance(self.revolution.getToAngle(),
+                                   ModelAPI.ModelAPI_AttributeDouble))
+        self.assertTrue(isinstance(self.revolution.getFromAngle(),
+                                   ModelAPI.ModelAPI_AttributeDouble))
+        self.assertTrue(isinstance(self.revolution.getToObject(),
+                                   ModelAPI.ModelAPI_AttributeSelection))
+        self.assertTrue(isinstance(self.revolution.getToOffset(),
+                                   ModelAPI.ModelAPI_AttributeDouble))
+        self.assertTrue(isinstance(self.revolution.getFromObject(),
+                                   ModelAPI.ModelAPI_AttributeSelection))
+        self.assertTrue(isinstance(self.revolution.getFromOffset(),
+                                   ModelAPI.ModelAPI_AttributeDouble))
+
+    def test_revolution_set_angles(self):
+        self.revolution.setAngles(90, 270)
+        self.assertEqual(self.revolution.getCreationMethod().value(), "ByAngles")
+        self.assertEqual(self.revolution.getToAngle().value(), 90)
+        self.assertEqual(self.revolution.getFromAngle().value(), 270)
+        self.assertEqual(self.revolution.getToObject().context(), None)
+        self.assertEqual(self.revolution.getToOffset().value(), 0)
+        self.assertEqual(self.revolution.getFromObject().context(), None)
+        self.assertEqual(self.revolution.getFromOffset().value(), 0)
+
+    def test_revolution_set_planes_and_offsets(self):
+        # base
+        base_sketch = model.addSketch(self.part, model.defaultPlane("XOY"))
+        base_circle = base_sketch.addCircle(0, 0, 10)
+        # axis
+        axis_sketch = model.addSketch(self.part, model.defaultPlane("XOY"))
+        line = axis_sketch.addLine(20, -10, 20, 10)
+        # to
+        to_plane = model.defaultPlane("XOY")
+        to_plane.location().setZ(10)
+        to_sketch = model.addSketch(self.part, to_plane)
+        to_circle = to_sketch.addCircle(0, 0, 10)
+        # from
+        from_plane = model.defaultPlane("XOY")
+        from_plane.location().setZ(-10)
+        from_sketch = model.addSketch(self.part, from_plane)
+        from_circle = from_sketch.addCircle(0, 0, 10)
+
+        model.do()
+
+        base = base_sketch.selectFace(base_circle.result())
+        axis_object = Selection(axis_sketch.firstResult(),
+                                line.firstResult().shape())
+        to_obejct = to_sketch.selectFace(to_circle.result())[0]
+        from_object = from_sketch.selectFace(from_circle.result())[0]
+
+        self.revolution.setPlanesAndOffsets(to_obejct, 15, from_object, 20)
+
+        self.assertEqual(self.revolution.getCreationMethod().value(), "ByPlanesAndOffsets")
+        self.assertEqual(self.revolution.getToAngle().value(), 0)
+        self.assertEqual(self.revolution.getFromAngle().value(), 0)
+#         self.assertEqual(self.revolution.getToObject().context(), None)
+        self.assertEqual(self.revolution.getToOffset().value(), 15)
+#         self.assertEqual(self.revolution.getFromObject().context(), None)
+        self.assertEqual(self.revolution.getFromOffset().value(), 20)
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/src/PythonAPI/Test/TestMakeBrick1.py b/src/PythonAPI/Test/TestMakeBrick1.py
new file mode 100644 (file)
index 0000000..2225919
--- /dev/null
@@ -0,0 +1,6 @@
+import unittest
+
+import examples.MakeBrick1
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/src/PythonAPI/Test/TestMakeBrick2.py b/src/PythonAPI/Test/TestMakeBrick2.py
new file mode 100644 (file)
index 0000000..21ea726
--- /dev/null
@@ -0,0 +1,6 @@
+import unittest
+
+import examples.MakeBrick2
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/src/PythonAPI/Test/TestMakeBrick3.py b/src/PythonAPI/Test/TestMakeBrick3.py
new file mode 100644 (file)
index 0000000..bbdb4a9
--- /dev/null
@@ -0,0 +1,6 @@
+import unittest
+
+import examples.MakeBrick3
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/src/PythonAPI/Test/TestModel.py b/src/PythonAPI/Test/TestModel.py
new file mode 100644 (file)
index 0000000..d763777
--- /dev/null
@@ -0,0 +1,18 @@
+import unittest
+import model
+
+class ModelTestCase(unittest.TestCase):
+    def setUp(self):
+        model.begin()
+        partset = model.moduleDocument()
+        self.part = model.addPart(partset).document()
+
+    def tearDown(self):
+        model.end()
+
+    def test_add_sketch(self):
+        plane = model.defaultPlane("XOY")
+        model.addSketch(self.part, plane)
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/src/PythonAPI/Test/TestShaper.py b/src/PythonAPI/Test/TestShaper.py
new file mode 100644 (file)
index 0000000..09c751b
--- /dev/null
@@ -0,0 +1,6 @@
+import unittest
+from shaper import model
+from shaper import geom
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/src/PythonAPI/Test/TestSketcher.py b/src/PythonAPI/Test/TestSketcher.py
new file mode 100644 (file)
index 0000000..b48337b
--- /dev/null
@@ -0,0 +1,16 @@
+import unittest
+import model
+
+# Delta value for almost equal comparisons
+DELTA = 1e-10
+
+class SketcherTestCase(unittest.TestCase):
+    def setUp(self):
+        model.begin()
+        partset = model.moduleDocument()
+        part = model.addPart(partset).document()
+        plane = model.defaultPlane("XOY")
+        self.sketch = model.addSketch(part, plane)
+
+    def tearDown(self):
+        model.end()
diff --git a/src/PythonAPI/Test/TestSketcherAddArc.py b/src/PythonAPI/Test/TestSketcherAddArc.py
new file mode 100644 (file)
index 0000000..1f83a11
--- /dev/null
@@ -0,0 +1,46 @@
+import unittest
+
+import model
+import geom
+from model import WrongNumberOfArguments
+
+from TestSketcher import SketcherTestCase
+
+class SketcherAddArc(SketcherTestCase):    
+    def test_arc_by_coords(self):
+        arc = self.sketch.addArc(0, 1, 0, 0, 1, 1)
+        model.do()
+        self.assertEqual(arc.startPoint().x(), 0)        
+        self.assertEqual(arc.startPoint().y(), 0)
+    
+    def test_arc_by_points(self):
+        center = geom.Pnt2d(0, 1)
+        start = geom.Pnt2d(0, 0)
+        end = geom.Pnt2d(1, 1)
+        arc = self.sketch.addArc(center, start, end)
+        model.do()
+        self.assertEqual(arc.startPoint().x(), 0)        
+        self.assertEqual(arc.startPoint().y(), 0)
+    
+    def test_number_of_args(self):
+        with self.assertRaises(WrongNumberOfArguments):
+            self.sketch.addArc(0, 1, 1, 1)
+        with self.assertRaises(WrongNumberOfArguments):
+            self.sketch.addArc(0, 1)
+            
+    def test_modify_arc(self):
+        arc = self.sketch.addArc(0, 1, 0, 0, 1, 1)
+        arc.setCenter(0, 0)
+        arc.setStartPoint(-1.0, 0)
+        arc.setEndPoint(0, 1.0)
+        model.do()
+        self.assertEqual(arc.center().x(), 0)        
+        self.assertEqual(arc.center().y(), 0)
+        self.assertEqual(arc.startPoint().x(), -1)        
+        self.assertEqual(arc.startPoint().y(), 0)
+        self.assertEqual(arc.endPoint().x(), 0)        
+        self.assertEqual(arc.endPoint().y(), 1)
+        
+    
+if __name__ == "__main__":
+    unittest.main(verbosity=2)
\ No newline at end of file
diff --git a/src/PythonAPI/Test/TestSketcherAddCircle.py b/src/PythonAPI/Test/TestSketcherAddCircle.py
new file mode 100644 (file)
index 0000000..9bc6e4c
--- /dev/null
@@ -0,0 +1,25 @@
+import unittest
+import model
+from TestSketcher import SketcherTestCase
+
+class SketcherAddCircle(SketcherTestCase):    
+    def test_add_cricle(self):
+        circle = self.sketch.addCircle(0, 10, 20)
+        model.do()
+        self.assertEqual(circle.center().x(), 0.0)        
+        self.assertEqual(circle.center().y(), 10.0)
+        self.assertEqual(circle.radius(), 20.0)
+        
+    def test_modify_circle(self):
+        circle = self.sketch.addCircle(0, 10, 20)
+        model.do()
+        circle.setCenter(10, 10)
+        circle.setRadius(30)
+        model.do()
+        self.assertEqual(circle.center().x(), 10.0)        
+        self.assertEqual(circle.center().y(), 10.0)
+        self.assertEqual(circle.radius(), 30.0)
+        
+    
+if __name__ == "__main__":
+    unittest.main(verbosity=2)
\ No newline at end of file
diff --git a/src/PythonAPI/Test/TestSketcherAddLine.py b/src/PythonAPI/Test/TestSketcherAddLine.py
new file mode 100644 (file)
index 0000000..fa4ed94
--- /dev/null
@@ -0,0 +1,24 @@
+import unittest
+import model
+from TestSketcher import SketcherTestCase
+
+class SketcherAddLine(SketcherTestCase):    
+    def test_add_line(self):
+        line = self.sketch.addLine(0, 0, 0, 1)
+        model.do()
+        self.assertEqual(line.getStartPoint().x(), line.getEndPoint().x())        
+        self.assertNotEqual(line.getStartPoint().y(), line.getEndPoint().y())
+
+    def test_modify_line(self):
+        line = self.sketch.addLine(0, 0, 0, 1)
+        model.do()
+        line.setStartPoint(0, 1)
+        line.setEndPoint(1, 1)
+        self.assertEqual(line.getStartPoint().x(), 0)
+        self.assertEqual(line.getStartPoint().y(), 1)
+        self.assertEqual(line.getEndPoint().x(), 1)
+        self.assertEqual(line.getEndPoint().y(), 1)
+
+
+if __name__ == "__main__":
+    unittest.main(verbosity=2)
\ No newline at end of file
diff --git a/src/PythonAPI/Test/TestSketcherAddMirror.py b/src/PythonAPI/Test/TestSketcherAddMirror.py
new file mode 100644 (file)
index 0000000..dc23f09
--- /dev/null
@@ -0,0 +1,29 @@
+import unittest
+import model
+from TestSketcher import SketcherTestCase
+from GeomDataAPI import geomDataAPI_Point2D
+
+import logging
+
+class SketcherAddLine(SketcherTestCase): 
+    def setUp(self):
+        SketcherTestCase.setUp(self)
+        self.line = self.sketch.addLine(0, 0, 0, 1)
+        self.circle_1 = self.sketch.addCircle(30, 0, 10)
+       
+    def test_add_mirror(self):
+        mirror = self.sketch.addMirror(
+            self.line.result(), self.circle_1.result()
+            )
+        model.do()
+        mirrored_objects = mirror.mirroredObjects()
+        mirrored_circle = mirrored_objects.object(0)
+        center = geomDataAPI_Point2D(mirrored_circle.data().attribute("CircleCenter"))
+        self.assertTrue(False,  msg="%s" % center.x())
+        #dir(mirrored_circle)
+        #center = geomDataAPI_Point2D(mirrored_circle.data().attribute("CircleCenter"))
+        #self.assertEqual(center.x(), -30, msg="%s"%(dir(mirrored_circle)))
+        #self.assertTrue(False,  msg="%s" % (dir(mirrored_circle)))
+
+if __name__ == "__main__":
+    unittest.main(verbosity=2)
\ No newline at end of file
diff --git a/src/PythonAPI/Test/TestSketcherAddPoint.py b/src/PythonAPI/Test/TestSketcherAddPoint.py
new file mode 100644 (file)
index 0000000..284d377
--- /dev/null
@@ -0,0 +1,25 @@
+import unittest
+import model
+from TestSketcher import SketcherTestCase
+
+class SketcherAddPoint(SketcherTestCase):    
+    def test_add_point(self):
+        point = self.sketch.addPoint(0, 1)
+        model.do()
+        self.assertEqual(point.pointData().x(), 0.0)        
+        self.assertEqual(point.pointData().y(), 1.0)
+        
+    def test_modify_point(self):
+        point = self.sketch.addPoint(0, 1)
+        point.setValue(1, 2)
+        model.do()
+        self.assertEqual(point.pointData().x(), 1.0)        
+        self.assertEqual(point.pointData().y(), 2.0)
+        
+    def test_empty_args(self):
+        with self.assertRaises(TypeError):
+            self.sketch.addPoint()
+        
+    
+if __name__ == "__main__":
+    unittest.main(verbosity=2)
\ No newline at end of file
diff --git a/src/PythonAPI/Test/TestSketcherSetAngle.py b/src/PythonAPI/Test/TestSketcherSetAngle.py
new file mode 100644 (file)
index 0000000..cbdd5fc
--- /dev/null
@@ -0,0 +1,34 @@
+import unittest
+import model
+import math
+import TestSketcher
+from TestSketcher import SketcherTestCase
+
+class SketcherSetAngle(SketcherTestCase):   
+    def runTest(self):
+        # Set the constraint
+        l1 = self.sketch.addLine(0, 0, 0, 1)
+        l2 = self.sketch.addLine(0, 0, 1, 1)
+        self.sketch.setAngle(l1.result(), l2.result(), 30.0)
+        # Commit the transaction
+        model.do()
+        # Check the result
+        dot_product = (l1.endPointData().x() - l1.startPointData().x()) * \
+                      (l2.endPointData().x() - l2.startPointData().x()) + \
+                      (l1.endPointData().y() - l1.startPointData().y()) * \
+                      (l2.endPointData().y() - l2.startPointData().y())
+        norm_1 = math.sqrt(
+            math.pow((l1.endPointData().x() - l1.startPointData().x()), 2) + 
+            math.pow((l1.endPointData().y() - l1.startPointData().y()), 2)
+            )
+        norm_2 = math.sqrt(
+            math.pow((l2.endPointData().x() - l2.startPointData().x()), 2) + 
+            math.pow((l2.endPointData().y() - l2.startPointData().y()), 2)
+            )
+        angle = math.acos(dot_product / (norm_1 * norm_2))
+        self.assertAlmostEqual(
+            angle * 180 / math.pi, 30.0, delta=TestSketcher.DELTA
+            )
+        
+if __name__ == "__main__":
+    unittest.main()
\ No newline at end of file
diff --git a/src/PythonAPI/Test/TestSketcherSetCoincident.py b/src/PythonAPI/Test/TestSketcherSetCoincident.py
new file mode 100644 (file)
index 0000000..ae07123
--- /dev/null
@@ -0,0 +1,23 @@
+import unittest
+import model
+from TestSketcher import SketcherTestCase
+
+class SketcherSetCoincident(SketcherTestCase):   
+    def test_set_coincident(self):
+        l1 = self.sketch.addLine(0, 0, 0, 1)
+        l2 = self.sketch.addLine(0, 1, 1, 1)
+        self.sketch.setCoincident(l1.endPointData(), l2.startPointData())
+        model.do()
+    
+    def test_none_type_arguments(self):
+        l2 = self.sketch.addLine(0, 1, 1, 1)
+        with self.assertRaises(TypeError):
+            self.sketch.setCoincident(None, l2.startPointData())
+        
+    def test_empty_arguments(self):
+        l1 = self.sketch.addLine(0, 0, 0, 1)
+        with self.assertRaises(TypeError):
+            self.sketch.setCoincident(l1.endPointData())
+
+if __name__ == "__main__":
+    unittest.main(verbosity=2)
\ No newline at end of file
diff --git a/src/PythonAPI/Test/TestSketcherSetEqual.py b/src/PythonAPI/Test/TestSketcherSetEqual.py
new file mode 100644 (file)
index 0000000..4965629
--- /dev/null
@@ -0,0 +1,42 @@
+import unittest
+import model
+import math
+import TestSketcher
+from TestSketcher import SketcherTestCase
+
+class SketcherSetEqual(SketcherTestCase):
+    def test_length_equality(self):
+        # Set the constraint
+        l1 = self.sketch.addLine(0, 0, 0, 1)
+        l2 = self.sketch.addLine(0, 0, 1, 1)
+        self.sketch.setEqual(l1.result(), l2.result())
+        # Commit the transaction
+        model.do()
+        # Check the result
+        length_1 = math.sqrt(
+            math.pow((l1.endPointData().x() - l1.startPointData().x()), 2) +
+            math.pow((l1.endPointData().y() - l1.startPointData().y()), 2)
+            )
+        length_2 = math.sqrt(
+            math.pow((l2.endPointData().x() - l2.startPointData().x()), 2) +
+            math.pow((l2.endPointData().y() - l2.startPointData().y()), 2)
+            )
+        self.assertAlmostEqual(length_1, length_2, delta=TestSketcher.DELTA)
+
+    def test_radius_equality(self):
+        # Set the constraint
+        circle_1 = self.sketch.addCircle(0, 0, 10.0)
+        circle_2 = self.sketch.addCircle(1, 2, 25.0)
+        self.sketch.setEqual(circle_1.result(), circle_2.result())
+        # Commit the transaction
+        model.do()
+        # Check the result
+        self.assertAlmostEqual(
+            circle_1.radiusData().value(),
+            circle_2.radiusData().value(),
+            delta=TestSketcher.DELTA
+            )
+
+if __name__ == "__main__":
+    suite = unittest.TestLoader().loadTestsFromTestCase(SketcherSetEqual)
+    unittest.TextTestRunner(verbosity=2).run(suite)
diff --git a/src/PythonAPI/Test/TestSketcherSetFillet.py b/src/PythonAPI/Test/TestSketcherSetFillet.py
new file mode 100644 (file)
index 0000000..f84b67a
--- /dev/null
@@ -0,0 +1,14 @@
+import unittest
+import model
+from TestSketcher import SketcherTestCase
+
+class SketcherSetFillet(SketcherTestCase):   
+    def runTest(self):
+        l1 = self.sketch.addLine(0, 0, 0, 1)
+        l2 = self.sketch.addLine(0, 1, 1, 1)
+        self.sketch.setCoincident(l1.endPointData(), l2.startPointData())
+        self.sketch.setFillet(l1.result(), l2.result(), 10.0)
+        model.do()
+
+if __name__ == "__main__":
+    unittest.main()
\ No newline at end of file
diff --git a/src/PythonAPI/Test/TestSketcherSetHorizontal.py b/src/PythonAPI/Test/TestSketcherSetHorizontal.py
new file mode 100644 (file)
index 0000000..0b795e7
--- /dev/null
@@ -0,0 +1,13 @@
+import unittest
+import model
+from TestSketcher import SketcherTestCase
+
+class SketcherSetHorizontal(SketcherTestCase):   
+    def runTest(self):
+        line = self.sketch.addLine(0, 0, 1, 1)
+        self.sketch.setHorizontal(line.result())
+        model.do()
+        self.assertEqual(line.startPointData().y(), line.endPointData().y())
+
+if __name__ == "__main__":
+    unittest.main()
\ No newline at end of file
diff --git a/src/PythonAPI/Test/TestSketcherSetLength.py b/src/PythonAPI/Test/TestSketcherSetLength.py
new file mode 100644 (file)
index 0000000..b56650b
--- /dev/null
@@ -0,0 +1,22 @@
+import unittest
+import model
+import math
+import TestSketcher
+from TestSketcher import SketcherTestCase
+
+class SketcherSetLength(SketcherTestCase):   
+    def runTest(self):
+        # Set the constraint
+        line = self.sketch.addLine(0, 0, 0, 1)
+        self.sketch.setLength(line.result(), 25.0)
+        # Commit the transaction
+        model.do()
+        # Check the result
+        length = math.sqrt(
+            math.pow((line.endPointData().x() - line.startPointData().x()), 2) + 
+            math.pow((line.endPointData().y() - line.startPointData().y()), 2)
+            )
+        self.assertAlmostEqual(length, 25.0, delta=TestSketcher.DELTA)
+        
+if __name__ == "__main__":
+    unittest.main()
\ No newline at end of file
diff --git a/src/PythonAPI/Test/TestSketcherSetParallel.py b/src/PythonAPI/Test/TestSketcherSetParallel.py
new file mode 100644 (file)
index 0000000..75c37ec
--- /dev/null
@@ -0,0 +1,13 @@
+import unittest
+import model
+from TestSketcher import SketcherTestCase
+
+class SketcherSetParallel(SketcherTestCase):   
+    def runTest(self):
+        l1 = self.sketch.addLine(0, 0, 0, 1)
+        l2 = self.sketch.addLine(0, 1, 1, 1)
+        self.sketch.setParallel(l1.result(), l2.result())
+        model.do()
+
+if __name__ == "__main__":
+    unittest.main()
\ No newline at end of file
diff --git a/src/PythonAPI/Test/TestSketcherSetPerpendicular.py b/src/PythonAPI/Test/TestSketcherSetPerpendicular.py
new file mode 100644 (file)
index 0000000..b572d9e
--- /dev/null
@@ -0,0 +1,21 @@
+import unittest
+import model
+import TestSketcher
+from TestSketcher import SketcherTestCase
+
+class SketcherSetPerpendicular(SketcherTestCase):
+    """Test case for prependicular constraint testing."""
+    def runTest(self):
+        l1 = self.sketch.addLine(0, 0, 0, 1)
+        l2 = self.sketch.addLine(0, 0, 1, 1)
+        self.sketch.setPerpendicular(l1.result(), l2.result())
+        model.do()
+        
+        dot_product = (l1.endPointData().x() - l1.startPointData().x()) * \
+                      (l2.endPointData().x() - l2.startPointData().x()) + \
+                      (l1.endPointData().y() - l1.startPointData().y()) * \
+                      (l2.endPointData().y() - l2.startPointData().y())
+        self.assertAlmostEqual(dot_product, 0.0, delta=TestSketcher.DELTA)
+
+if __name__ == "__main__":
+    unittest.main()
\ No newline at end of file
diff --git a/src/PythonAPI/Test/TestSketcherSetRadius.py b/src/PythonAPI/Test/TestSketcherSetRadius.py
new file mode 100644 (file)
index 0000000..0cb6ad9
--- /dev/null
@@ -0,0 +1,21 @@
+import unittest
+import model
+from TestSketcher import SketcherTestCase
+
+class SketcherSetRadius(SketcherTestCase):   
+    def test_set_radius(self):
+        circle = self.sketch.addCircle(0, 10, 20)
+        self.sketch.setRadius(circle.result(), 30)
+        model.do()
+        self.assertEqual(circle.radius(), 30.0)
+        
+    def test_modify_radius(self):
+        circle = self.sketch.addCircle(0, 10, 20)
+        radius_constraint = self.sketch.setRadius(circle.result(), 30)
+        model.do()
+        self.sketch.setValue(radius_constraint, 20)
+        model.do()
+        self.assertEqual(circle.radius(), 20.0)
+        
+if __name__ == "__main__":
+    unittest.main(verbosity=2)
\ No newline at end of file
diff --git a/src/PythonAPI/Test/TestSketcherSetRigid.py b/src/PythonAPI/Test/TestSketcherSetRigid.py
new file mode 100644 (file)
index 0000000..4e3e1b6
--- /dev/null
@@ -0,0 +1,15 @@
+import unittest
+import model
+from TestSketcher import SketcherTestCase
+
+class SketcherSetRigid(SketcherTestCase):   
+    def runTest(self):
+        circle = self.sketch.addCircle(0, 10, 20)
+        self.sketch.setRigid(circle.result())
+        model.do()
+        with self.assertRaises(Exception):
+            circle.setCenter(0, 0)
+            model.do()
+        
+if __name__ == "__main__":
+    unittest.main(verbosity=2)
\ No newline at end of file
diff --git a/src/PythonAPI/Test/TestSketcherSetTangent.py b/src/PythonAPI/Test/TestSketcherSetTangent.py
new file mode 100644 (file)
index 0000000..2e78264
--- /dev/null
@@ -0,0 +1,24 @@
+import unittest
+import model
+from TestSketcher import SketcherTestCase
+
+class SketcherSetTangent(SketcherTestCase):
+    def setUp(self):
+        SketcherTestCase.setUp(self)
+        self.line = self.sketch.addLine(0, 0, 0, 1)
+        self.arc = self.sketch.addArc(0, 1, 0, 0, 1, 1)
+        self.sketch.setCoincident(
+            self.line.endPointData(), self.arc.startPoint()
+            )
+        
+    def test_set_tangent(self):
+        self.sketch.setTangent(self.line.result(), self.arc.result())
+        model.do()
+        # TODO : find a way to check that the constraint as been set
+    
+    def test_none_type_arguments(self):
+        with self.assertRaises(TypeError):
+            self.sketch.setTangent(None, self.arc.result())
+
+if __name__ == "__main__":
+    unittest.main(verbosity=2)
\ No newline at end of file
diff --git a/src/PythonAPI/Test/TestSketcherSetVertical.py b/src/PythonAPI/Test/TestSketcherSetVertical.py
new file mode 100644 (file)
index 0000000..cda9f6c
--- /dev/null
@@ -0,0 +1,13 @@
+import unittest
+import model
+from TestSketcher import SketcherTestCase
+
+class SketcherSetVertical(SketcherTestCase):   
+    def runTest(self):
+        line = self.sketch.addLine(0, 0, 1, 1)
+        self.sketch.setVertical(line.result())
+        model.do()
+        self.assertEqual(line.startPointData().x(), line.endPointData().x())
+
+if __name__ == "__main__":
+    unittest.main()
\ No newline at end of file
diff --git a/src/PythonAPI/doc/Makefile b/src/PythonAPI/doc/Makefile
new file mode 100644 (file)
index 0000000..25f986c
--- /dev/null
@@ -0,0 +1,177 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+PAPER         =
+BUILDDIR      = build
+
+# User-friendly check for sphinx-build
+ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
+$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
+endif
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
+
+help:
+       @echo "Please use \`make <target>' where <target> is one of"
+       @echo "  html       to make standalone HTML files"
+       @echo "  dirhtml    to make HTML files named index.html in directories"
+       @echo "  singlehtml to make a single large HTML file"
+       @echo "  pickle     to make pickle files"
+       @echo "  json       to make JSON files"
+       @echo "  htmlhelp   to make HTML files and a HTML help project"
+       @echo "  qthelp     to make HTML files and a qthelp project"
+       @echo "  devhelp    to make HTML files and a Devhelp project"
+       @echo "  epub       to make an epub"
+       @echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+       @echo "  latexpdf   to make LaTeX files and run them through pdflatex"
+       @echo "  latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
+       @echo "  text       to make text files"
+       @echo "  man        to make manual pages"
+       @echo "  texinfo    to make Texinfo files"
+       @echo "  info       to make Texinfo files and run them through makeinfo"
+       @echo "  gettext    to make PO message catalogs"
+       @echo "  changes    to make an overview of all changed/added/deprecated items"
+       @echo "  xml        to make Docutils-native XML files"
+       @echo "  pseudoxml  to make pseudoxml-XML files for display purposes"
+       @echo "  linkcheck  to check all external links for integrity"
+       @echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+       rm -rf $(BUILDDIR)/*
+
+html:
+       $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+       @echo
+       @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+       $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+       @echo
+       @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+       $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+       @echo
+       @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+       $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+       @echo
+       @echo "Build finished; now you can process the pickle files."
+
+json:
+       $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+       @echo
+       @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+       $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+       @echo
+       @echo "Build finished; now you can run HTML Help Workshop with the" \
+             ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+       $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+       @echo
+       @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+             ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+       @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/ShaperpythonAPI.qhcp"
+       @echo "To view the help file:"
+       @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/ShaperpythonAPI.qhc"
+
+devhelp:
+       $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+       @echo
+       @echo "Build finished."
+       @echo "To view the help file:"
+       @echo "# mkdir -p $$HOME/.local/share/devhelp/ShaperpythonAPI"
+       @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/ShaperpythonAPI"
+       @echo "# devhelp"
+
+epub:
+       $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+       @echo
+       @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+       @echo
+       @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+       @echo "Run \`make' in that directory to run these through (pdf)latex" \
+             "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+       @echo "Running LaTeX files through pdflatex..."
+       $(MAKE) -C $(BUILDDIR)/latex all-pdf
+       @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+latexpdfja:
+       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+       @echo "Running LaTeX files through platex and dvipdfmx..."
+       $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
+       @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+       $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+       @echo
+       @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+       $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+       @echo
+       @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+       $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+       @echo
+       @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+       @echo "Run \`make' in that directory to run these through makeinfo" \
+             "(use \`make info' here to do that automatically)."
+
+info:
+       $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+       @echo "Running Texinfo files through makeinfo..."
+       make -C $(BUILDDIR)/texinfo info
+       @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+       $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+       @echo
+       @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+       $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+       @echo
+       @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+       $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+       @echo
+       @echo "Link check complete; look for any errors in the above output " \
+             "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+       $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+       @echo "Testing of doctests in the sources finished, look at the " \
+             "results in $(BUILDDIR)/doctest/output.txt."
+
+xml:
+       $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
+       @echo
+       @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
+
+pseudoxml:
+       $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
+       @echo
+       @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
diff --git a/src/PythonAPI/doc/make.bat b/src/PythonAPI/doc/make.bat
new file mode 100644 (file)
index 0000000..42779eb
--- /dev/null
@@ -0,0 +1,242 @@
+@ECHO OFF\r
+\r
+REM Command file for Sphinx documentation\r
+\r
+if "%SPHINXBUILD%" == "" (\r
+       set SPHINXBUILD=sphinx-build\r
+)\r
+set BUILDDIR=build\r
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source\r
+set I18NSPHINXOPTS=%SPHINXOPTS% source\r
+if NOT "%PAPER%" == "" (\r
+       set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%\r
+       set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%\r
+)\r
+\r
+if "%1" == "" goto help\r
+\r
+if "%1" == "help" (\r
+       :help\r
+       echo.Please use `make ^<target^>` where ^<target^> is one of\r
+       echo.  html       to make standalone HTML files\r
+       echo.  dirhtml    to make HTML files named index.html in directories\r
+       echo.  singlehtml to make a single large HTML file\r
+       echo.  pickle     to make pickle files\r
+       echo.  json       to make JSON files\r
+       echo.  htmlhelp   to make HTML files and a HTML help project\r
+       echo.  qthelp     to make HTML files and a qthelp project\r
+       echo.  devhelp    to make HTML files and a Devhelp project\r
+       echo.  epub       to make an epub\r
+       echo.  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter\r
+       echo.  text       to make text files\r
+       echo.  man        to make manual pages\r
+       echo.  texinfo    to make Texinfo files\r
+       echo.  gettext    to make PO message catalogs\r
+       echo.  changes    to make an overview over all changed/added/deprecated items\r
+       echo.  xml        to make Docutils-native XML files\r
+       echo.  pseudoxml  to make pseudoxml-XML files for display purposes\r
+       echo.  linkcheck  to check all external links for integrity\r
+       echo.  doctest    to run all doctests embedded in the documentation if enabled\r
+       goto end\r
+)\r
+\r
+if "%1" == "clean" (\r
+       for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i\r
+       del /q /s %BUILDDIR%\*\r
+       goto end\r
+)\r
+\r
+\r
+%SPHINXBUILD% 2> nul\r
+if errorlevel 9009 (\r
+       echo.\r
+       echo.The 'sphinx-build' command was not found. Make sure you have Sphinx\r
+       echo.installed, then set the SPHINXBUILD environment variable to point\r
+       echo.to the full path of the 'sphinx-build' executable. Alternatively you\r
+       echo.may add the Sphinx directory to PATH.\r
+       echo.\r
+       echo.If you don't have Sphinx installed, grab it from\r
+       echo.http://sphinx-doc.org/\r
+       exit /b 1\r
+)\r
+\r
+if "%1" == "html" (\r
+       %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished. The HTML pages are in %BUILDDIR%/html.\r
+       goto end\r
+)\r
+\r
+if "%1" == "dirhtml" (\r
+       %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.\r
+       goto end\r
+)\r
+\r
+if "%1" == "singlehtml" (\r
+       %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.\r
+       goto end\r
+)\r
+\r
+if "%1" == "pickle" (\r
+       %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished; now you can process the pickle files.\r
+       goto end\r
+)\r
+\r
+if "%1" == "json" (\r
+       %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished; now you can process the JSON files.\r
+       goto end\r
+)\r
+\r
+if "%1" == "htmlhelp" (\r
+       %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished; now you can run HTML Help Workshop with the ^\r
+.hhp project file in %BUILDDIR%/htmlhelp.\r
+       goto end\r
+)\r
+\r
+if "%1" == "qthelp" (\r
+       %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished; now you can run "qcollectiongenerator" with the ^\r
+.qhcp project file in %BUILDDIR%/qthelp, like this:\r
+       echo.^> qcollectiongenerator %BUILDDIR%\qthelp\ShaperpythonAPI.qhcp\r
+       echo.To view the help file:\r
+       echo.^> assistant -collectionFile %BUILDDIR%\qthelp\ShaperpythonAPI.ghc\r
+       goto end\r
+)\r
+\r
+if "%1" == "devhelp" (\r
+       %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished.\r
+       goto end\r
+)\r
+\r
+if "%1" == "epub" (\r
+       %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished. The epub file is in %BUILDDIR%/epub.\r
+       goto end\r
+)\r
+\r
+if "%1" == "latex" (\r
+       %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.\r
+       goto end\r
+)\r
+\r
+if "%1" == "latexpdf" (\r
+       %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex\r
+       cd %BUILDDIR%/latex\r
+       make all-pdf\r
+       cd %BUILDDIR%/..\r
+       echo.\r
+       echo.Build finished; the PDF files are in %BUILDDIR%/latex.\r
+       goto end\r
+)\r
+\r
+if "%1" == "latexpdfja" (\r
+       %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex\r
+       cd %BUILDDIR%/latex\r
+       make all-pdf-ja\r
+       cd %BUILDDIR%/..\r
+       echo.\r
+       echo.Build finished; the PDF files are in %BUILDDIR%/latex.\r
+       goto end\r
+)\r
+\r
+if "%1" == "text" (\r
+       %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished. The text files are in %BUILDDIR%/text.\r
+       goto end\r
+)\r
+\r
+if "%1" == "man" (\r
+       %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished. The manual pages are in %BUILDDIR%/man.\r
+       goto end\r
+)\r
+\r
+if "%1" == "texinfo" (\r
+       %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.\r
+       goto end\r
+)\r
+\r
+if "%1" == "gettext" (\r
+       %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished. The message catalogs are in %BUILDDIR%/locale.\r
+       goto end\r
+)\r
+\r
+if "%1" == "changes" (\r
+       %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.The overview file is in %BUILDDIR%/changes.\r
+       goto end\r
+)\r
+\r
+if "%1" == "linkcheck" (\r
+       %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Link check complete; look for any errors in the above output ^\r
+or in %BUILDDIR%/linkcheck/output.txt.\r
+       goto end\r
+)\r
+\r
+if "%1" == "doctest" (\r
+       %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Testing of doctests in the sources finished, look at the ^\r
+results in %BUILDDIR%/doctest/output.txt.\r
+       goto end\r
+)\r
+\r
+if "%1" == "xml" (\r
+       %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished. The XML files are in %BUILDDIR%/xml.\r
+       goto end\r
+)\r
+\r
+if "%1" == "pseudoxml" (\r
+       %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.\r
+       goto end\r
+)\r
+\r
+:end\r
diff --git a/src/PythonAPI/doc/source/arc.rst b/src/PythonAPI/doc/source/arc.rst
new file mode 100644 (file)
index 0000000..e9d09aa
--- /dev/null
@@ -0,0 +1,7 @@
+:mod:`model.sketcher.arc` -- Sketch arc object
+----------------------------------------------
+
+.. automodule:: model.sketcher.arc
+
+.. autoclass:: Arc
+   :members:
diff --git a/src/PythonAPI/doc/source/conf.py b/src/PythonAPI/doc/source/conf.py
new file mode 100644 (file)
index 0000000..7e213bc
--- /dev/null
@@ -0,0 +1,271 @@
+# -*- coding: utf-8 -*-
+#
+# Shaper python API documentation build configuration file, created by
+# sphinx-quickstart on Thu Oct 15 11:55:42 2015.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys
+import os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+sys.path.insert(0, os.path.abspath('..'))
+sys.path.insert(0, os.path.abspath('../..'))
+sys.path.insert(0, os.path.abspath('../../..'))
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+    'sphinx.ext.autodoc',
+    'sphinx.ext.doctest',
+    'sphinx.ext.todo',
+    'sphinx.ext.coverage',
+    'sphinx.ext.viewcode',
+    'sphinx.ext.napoleon',
+    'sphinx.ext.autosummary',
+]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'Shaper python API'
+copyright = u'2014-20xx CEA/DEN, EDF R&D'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '0.4'
+# The full version, including alpha/beta/rc tags.
+release = '0.4'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = []
+
+# The reST default role (used for this markup: `text`) to use for all
+# documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+# If true, keep warnings as "system message" paragraphs in the built documents.
+#keep_warnings = False
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# Add any extra paths that contain custom files (such as robots.txt or
+# .htaccess) here, relative to this directory. These files are copied
+# directly to the root of the documentation.
+#html_extra_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'ShaperpythonAPIdoc'
+
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+#  author, documentclass [howto, manual, or own class]).
+latex_documents = [
+  ('index', 'ShaperpythonAPI.tex', u'Shaper python API Documentation',
+   u'Renaud Nédélec', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    ('index', 'shaperpythonapi', u'Shaper python API Documentation',
+     [u'Renaud Nédélec'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+  ('index', 'ShaperpythonAPI', u'Shaper python API Documentation',
+   u'Renaud Nédélec', 'ShaperpythonAPI', 'One line description of project.',
+   'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+#texinfo_no_detailmenu = False
+
+autodoc_member_order = 'bysource'
+        
diff --git a/src/PythonAPI/doc/source/index.rst b/src/PythonAPI/doc/source/index.rst
new file mode 100644 (file)
index 0000000..8d06304
--- /dev/null
@@ -0,0 +1,48 @@
+Shaper textual interface documentation
+======================================
+
+Shaper provides two different textual interfaces that allows you to create
+models through python scripts:
+
+* a "direct" API, which allows you to create geometrical objects
+  without any parametric considerations
+
+* a "parametric" API, which is very close to what is done
+  in the graphical interface and allows you to recalculate a model
+  when a parameter is changed
+
+Parametric API
+--------------
+
+This API is implemented in the model Python package. A script written
+with the parametric API will typically begin with a code like below:
+
+.. doctest:: 
+
+   >>> import model
+   >>> model.begin()
+   >>> partset = model.moduleDocument()
+   >>> part = model.addPart(partset).document()
+   >>> plane = model.defaultPlane("XOY")
+   >>> sketch = model.addSketch(part, plane)
+   >>> line = sketch.addLine(0, 0, 0, 1)
+
+Features
+........
+
+This API provides functions for creating the features listed below.
+These functions return an interface to the feature that allow
+to modify the feature and retrieve data from it.
+
+.. toctree::
+   :maxdepth: 1
+   :glob:
+
+   sketcher
+   model/*
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
diff --git a/src/PythonAPI/doc/source/model/boolean.rst b/src/PythonAPI/doc/source/model/boolean.rst
new file mode 100644 (file)
index 0000000..abe3972
--- /dev/null
@@ -0,0 +1,15 @@
+Boolean
+=======
+
+Create Boolean
+--------------
+
+.. autofunction:: model.addAddition
+.. autofunction:: model.addSubtraction
+.. autofunction:: model.addIntersection
+
+Boolean object
+--------------
+
+.. autoclass:: model.features.boolean.Boolean
+   :members:
diff --git a/src/PythonAPI/doc/source/model/connection.rst b/src/PythonAPI/doc/source/model/connection.rst
new file mode 100644 (file)
index 0000000..5a175fe
--- /dev/null
@@ -0,0 +1,9 @@
+Connection
+----------
+
+This feature is only for SALOME.
+
+Exprot to GEOM
+..............
+
+.. autofunction:: model.exportToGEOM
diff --git a/src/PythonAPI/doc/source/model/construction.rst b/src/PythonAPI/doc/source/model/construction.rst
new file mode 100644 (file)
index 0000000..8f13053
--- /dev/null
@@ -0,0 +1,37 @@
+Construction
+============
+
+Create construction features.
+
+Create a point
+--------------
+
+.. autofunction:: model.addPoint
+
+Point object
+............
+
+.. autoclass:: model.construction.point.Point
+   :members:
+
+Create an axis
+--------------
+
+.. autofunction:: model.addAxis
+
+Axis object
+...........
+
+.. autoclass:: model.construction.axis.Axis
+   :members:
+
+Create a plane
+--------------
+
+.. autofunction:: model.addPlane
+
+Plane object
+............
+
+.. autoclass:: model.construction.plane.Plane
+   :members:
diff --git a/src/PythonAPI/doc/source/model/exchange.rst b/src/PythonAPI/doc/source/model/exchange.rst
new file mode 100644 (file)
index 0000000..737cb77
--- /dev/null
@@ -0,0 +1,26 @@
+Exchange
+========
+
+Export/import features.
+
+Import objects from a file
+--------------------------
+
+.. autofunction:: model.addImport
+
+Import object
+.............
+
+.. autoclass:: model.exchange.exchange.Import
+   :members:
+
+Export objects to a file
+------------------------
+
+.. autofunction:: model.exportToFile
+
+Export object
+.............
+
+.. autoclass:: model.exchange.exchange.Export
+   :members:
diff --git a/src/PythonAPI/doc/source/model/extrusion.rst b/src/PythonAPI/doc/source/model/extrusion.rst
new file mode 100644 (file)
index 0000000..2f81a25
--- /dev/null
@@ -0,0 +1,63 @@
+Extrusion
+=========
+
+.. testsetup::
+
+   import model
+   model.begin()
+   partset = model.moduleDocument()
+   part = model.addPart(partset).document()
+   plane = model.defaultPlane("XOY")
+   sketch = model.addSketch(part, plane)
+   p1 = sketch.addPoint(0, 0)
+   p2 = sketch.addPoint(0, 1)
+   p3 = sketch.addPoint(1, 1)
+   p4 = sketch.addPoint(1, 0)
+   sketch.addPolygon(p1.pointData(), p2.pointData(), p3.pointData(), p4.pointData())
+
+Provided that a sketch has been created before an extrusion can then be created
+by the following code:
+
+.. doctest::
+   
+   >>> base = sketch.selectFace()
+   >>> extrusion = model.addExtrusion(part, base, 10)
+   >>> # Modification of the extrusion
+   >>> extrusion.setSize(20)
+   
+All the ways to create an extrusion and the data access and modification methods
+of the extrusion are documented below
+
+Create an extrusion
+-------------------
+
+.. autofunction:: model.addExtrusion
+
+Extrusion object
+................
+
+.. autoclass:: model.features.extrusion.Extrusion
+   :members:
+
+Create an Extrusion Bolean
+--------------------------
+
+.. autofunction:: model.addExtrusionCut
+.. autofunction:: model.addExtrusionFuse
+
+Extrusion Boolean object
+........................
+
+.. autoclass:: model.features.extrusion_boolean.ExtrusionBoolean
+   :members:
+   
+Create an Extrusion Sketch
+--------------------------
+
+.. autofunction:: model.addExtrusionSketch
+
+Extrusion Sketch object
+.......................
+
+.. autoclass:: model.features.extrusion_sketch.ExtrusionSketch
+   :members:
diff --git a/src/PythonAPI/doc/source/model/group.rst b/src/PythonAPI/doc/source/model/group.rst
new file mode 100644 (file)
index 0000000..b6765a1
--- /dev/null
@@ -0,0 +1,13 @@
+Group
+=====
+
+Create a group
+--------------
+
+.. autofunction:: model.addGroup
+
+Group object
+............
+
+.. autoclass:: model.features.group.Group
+   :members:
diff --git a/src/PythonAPI/doc/source/model/parameter.rst b/src/PythonAPI/doc/source/model/parameter.rst
new file mode 100644 (file)
index 0000000..6b62c9f
--- /dev/null
@@ -0,0 +1,13 @@
+Parameter
+=========
+
+Create a parameter
+------------------
+
+.. autofunction:: model.addParameter
+
+Parameter object
+................
+
+.. autoclass:: model.parameter.parameter.Parameter
+   :members:
diff --git a/src/PythonAPI/doc/source/model/partition.rst b/src/PythonAPI/doc/source/model/partition.rst
new file mode 100644 (file)
index 0000000..75c3b7f
--- /dev/null
@@ -0,0 +1,13 @@
+Partition
+=========
+
+Create a partition
+------------------
+
+.. autofunction:: model.addPartition
+
+Partition object
+................
+
+.. autoclass:: model.features.partition.Partition
+   :members:
diff --git a/src/PythonAPI/doc/source/model/partset.rst b/src/PythonAPI/doc/source/model/partset.rst
new file mode 100644 (file)
index 0000000..5427d7f
--- /dev/null
@@ -0,0 +1,17 @@
+PartSet
+=======
+
+Manipulate Parts in a PartSet.
+
+Manipulate a Part
+-----------------
+
+.. autofunction:: model.addPart
+.. autofunction:: model.duplicatePart
+.. autofunction:: model.removePart
+
+Part object
+...........
+
+.. autoclass:: model.partset.part.Part
+   :members:
diff --git a/src/PythonAPI/doc/source/model/placement.rst b/src/PythonAPI/doc/source/model/placement.rst
new file mode 100644 (file)
index 0000000..3834ce7
--- /dev/null
@@ -0,0 +1,13 @@
+Placement
+=========
+
+Create a placement
+------------------
+
+.. autofunction:: model.addPlacement
+
+Placement object
+................
+
+.. autoclass:: model.features.placement.Placement
+   :members:
diff --git a/src/PythonAPI/doc/source/model/revolution.rst b/src/PythonAPI/doc/source/model/revolution.rst
new file mode 100644 (file)
index 0000000..061904f
--- /dev/null
@@ -0,0 +1,36 @@
+Revolution
+==========
+
+Create a Revolution
+-------------------
+
+.. autofunction:: model.addRevolution
+
+Revolution object
+.................
+
+.. autoclass:: model.features.revolution.Revolution
+   :members:
+
+Create an Revolution Bolean
+---------------------------
+
+.. autofunction:: model.addRevolutionCut
+.. autofunction:: model.addRevolutionFuse
+
+Revolution Boolean object
+.........................
+
+.. autoclass:: model.features.revolution_boolean.RevolutionBoolean
+   :members:
+   
+Create an Revolution Sketch
+---------------------------
+
+.. autofunction:: model.addRevolutionSketch
+
+Revolution Sketch object
+........................
+
+.. autoclass:: model.features.revolution_sketch.RevolutionSketch
+   :members:
diff --git a/src/PythonAPI/doc/source/model/rotation.rst b/src/PythonAPI/doc/source/model/rotation.rst
new file mode 100644 (file)
index 0000000..70619bb
--- /dev/null
@@ -0,0 +1,13 @@
+Rotation
+========
+
+Create a rotation
+-----------------
+
+.. autofunction:: model.addRotation
+
+Rotation object
+...............
+
+.. autoclass:: model.features.rotation.Rotation
+   :members:
diff --git a/src/PythonAPI/doc/source/model/translation.rst b/src/PythonAPI/doc/source/model/translation.rst
new file mode 100644 (file)
index 0000000..6f3f4a9
--- /dev/null
@@ -0,0 +1,13 @@
+Translation
+===========
+
+Create a translation
+--------------------
+
+.. autofunction:: model.addTranslation
+
+Translation object
+..................
+
+.. autoclass:: model.features.translation.Translation
+   :members:
diff --git a/src/PythonAPI/doc/source/sketcher.rst b/src/PythonAPI/doc/source/sketcher.rst
new file mode 100644 (file)
index 0000000..3fb4159
--- /dev/null
@@ -0,0 +1,51 @@
+Sketch interface
+================
+
+.. automodule:: model.sketcher.sketch
+.. :members:
+
+.. currentmodule:: model.sketcher.sketch
+
+Create a sketch
+---------------
+
+.. autosummary::
+   addSketch
+
+Add geometries
+--------------
+
+.. autosummary::
+
+   Sketch.addPoint
+   Sketch.addLine
+   Sketch.addArc
+   Sketch.addCircle
+
+Set constraints
+---------------
+
+.. autosummary::
+
+   Sketch.setRadius
+   Sketch.setParallel
+
+Detailed description
+--------------------
+
+Add a sketch to the document
+............................
+
+.. autofunction:: addSketch
+
+Sketch object
+.............
+
+The sketch object returned by the above described :meth:`~model.sketcher.sketch.addSketch` method
+provides an interface for:
+
+  * creating geometries
+  * setting and modifying constraints
+
+.. autoclass:: Sketch
+   :members:
diff --git a/src/PythonAPI/examples/MakeBrick1.py b/src/PythonAPI/examples/MakeBrick1.py
new file mode 100644 (file)
index 0000000..dd064fb
--- /dev/null
@@ -0,0 +1,72 @@
+# Creation of a box using the end-user API
+# Author: Daniel Brunier-Coulin
+# -----------------------------
+
+import model
+
+
+# Initialisation
+
+model.begin()
+mypartset = model.moduleDocument()
+
+
+# Creating a new Part
+
+mypart = model.addPart(mypartset).document()
+
+
+# Creating the base of the box
+
+mybase = model.addSketch( mypart, model.defaultPlane("XOY") )
+
+l1 = mybase.addLine( 0, 0, 0, 1 )
+l2 = mybase.addLine( 0, 1, 1, 1 )
+l3 = mybase.addLine( 1, 1, 1, 0 )
+l4 = mybase.addLine( 1, 0, 0, 0 )
+
+mybase.setCoincident( l1.endPointData(), l2.startPointData() )
+mybase.setCoincident( l2.endPointData(), l3.startPointData() )
+mybase.setCoincident( l3.endPointData(), l4.startPointData() )
+mybase.setCoincident( l4.endPointData(), l1.startPointData() )
+
+mybase.setParallel( l1.result(), l3.result() )
+mybase.setParallel( l2.result(), l4.result() )
+
+mybase.setPerpendicular( l1.result(), l4.result() )
+
+mywidth  = mybase.setLength( l1.result(), 50 )
+mylength = mybase.setDistance( l1.startPointData(), l3.result(), 50 )
+
+# Creating the extrusion
+
+mybox = model.addExtrusion( mypart, mybase.selectFace(), 50 )
+
+# Creating a cylinder on a face of the box
+
+thisface = "Extrusion_1_1/LateralFace_2"
+thisxmin = "Extrusion_1_1/LateralFace_3|Extrusion_1_1/LateralFace_2"
+thisxmax = "Extrusion_1_1/LateralFace_2|Extrusion_1_1/LateralFace_1"
+thiszmin = "Sketch_1/Edge5_1"
+thiszmax = "Extrusion_1_1/LateralFace_2|Extrusion_1_1/ToFace_1"
+
+mystand = model.addSketch( mypart, thisface )
+
+c1      = mystand.addCircle( 0, 25, 5)
+mystand.setDistance( c1.centerData(), thisxmin, 10 )
+mystand.setDistance( c1.centerData(), thiszmax, 10 )
+
+myboss = model.addExtrusion( mypart, mystand.selectFace(c1.result()), -5 )
+
+# Subtracting the cylinder to the box
+
+model.addSubtraction( mypart, mybox.result(), myboss.result() )
+model.end()
+
+
+# Editing the box
+
+model.begin()
+mybase.setValue( mylength, 100 )
+mybox.setSize( 80 )
+model.end()
diff --git a/src/PythonAPI/examples/MakeBrick2.py b/src/PythonAPI/examples/MakeBrick2.py
new file mode 100644 (file)
index 0000000..2fa09d6
--- /dev/null
@@ -0,0 +1,69 @@
+# Creation of a box using the end-user API
+# Author: Daniel Brunier-Coulin
+# -----------------------------
+
+import model
+import geom
+
+
+# Initialisation
+
+model.begin()
+mypartset = model.moduleDocument()
+
+
+# Creating a new Part
+
+mypart = model.addPart(mypartset).document()
+
+
+# Creating the base of the box
+
+mybase = model.addSketch(mypart, model.defaultPlane("XOY"))
+
+p1 = geom.Pnt2d(0, 0)
+p2 = geom.Pnt2d(0, 1)
+p3 = geom.Pnt2d(1, 1)
+p4 = geom.Pnt2d(1, 0)
+
+line = mybase.addPolygon(p1, p2, p3, p4)
+
+mybase.setParallel(line[0].result(), line[2].result())
+mybase.setParallel(line[1].result(), line[3].result())
+mybase.setPerpendicular(line[0].result(), line[3].result())
+
+mywidth = mybase.setLength(line[0].result(), 50)
+mylength = mybase.setDistance(line[0].startPointData(), line[2].result(), 50)
+
+
+# Creating the extrusion
+
+mybox = model.addExtrusion(mypart, mybase.selectFace(), 50)
+
+
+# Creating a cylinder on a face of the box
+
+thisface = "Extrusion_1_1/LateralFace_2"
+thisxmin = "Extrusion_1_1/LateralFace_3|Extrusion_1_1/LateralFace_2"
+thiszmax = "Extrusion_1_1/LateralFace_2|Extrusion_1_1/ToFace_1"
+
+mystand = model.addSketch(mypart, thisface)
+circle = mystand.addCircle(0, 25, 5)
+mystand.setDistance(circle.centerData(), thisxmin, 10)
+mystand.setDistance(circle.centerData(), thiszmax, 10)
+
+myboss = model.addExtrusion(mypart, mystand.selectFace(), -5)
+
+
+# Subtracting the cylinder to the box
+
+model.addSubtraction(mypart, mybox.result(), myboss.result())
+model.end()
+
+
+# Editing the box
+
+model.begin()
+mybase.setValue(mylength, 100)
+mybox.setSize(20)
+model.end()
diff --git a/src/PythonAPI/examples/MakeBrick3.py b/src/PythonAPI/examples/MakeBrick3.py
new file mode 100644 (file)
index 0000000..94fa252
--- /dev/null
@@ -0,0 +1,24 @@
+# Creation of a box using the end-user API
+# Author: Daniel Brunier-Coulin
+# -----------------------------
+
+import model
+import extension
+
+
+# Initialisation
+
+model.begin()
+mypartset = model.moduleDocument()
+
+
+# Creating a new Part
+
+mypart = model.addPart(mypartset).document()
+
+
+# Creating the base of the box
+
+extension.addBox( mypart, 10, 20, 30 )
+model.end()
+
diff --git a/src/PythonAPI/examples/__init__.py b/src/PythonAPI/examples/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
index 275cb5503abd07913295db07906df76748d0cc5b..b57f516a153db5d92ce347bbc0406bdcadf51905 100644 (file)
@@ -1,4 +1,4 @@
 """User-defined features.
 """
 
-from box import Box as addBox
\ No newline at end of file
+from box import addBox
\ No newline at end of file
index 3a6b641a58b8581097a5530b5ebe91d916e74fc8..c3ef9dcbcbe2c40af7f8dde370f332db0d104108 100644 (file)
@@ -3,22 +3,64 @@ Author: Daniel Brunier-Coulin
 Copyright (C) 2014-20xx CEA/DEN, EDF R&D
 """
 
-import modeler
+from model import Interface
 from macros.box.feature import BoxFeature as MY
 
 
-class Box(modeler.Interface):
-  """Executes the macro-feature Box.
-  """
-  def __init__(self, part, dx, dy, dz):
-    """Constructor"""
-    modeler.Interface.__init__(self, part, MY.ID())
+def addBox(part, *args):
+    """Add Box feature to the part and return Box.
 
-    self.setRealInput( MY.WIDTH_ID(), dx )
-    self.setRealInput( MY.LENGTH_ID(), dy )
-    self.setRealInput( MY.HEIGHT_ID(), dz )
+    Pass all args to Box __init__ function.
+    """
+    feature = part.addFeature(MY.ID())
+    return Box(feature, *args)
 
-    if self.areInputValid():
-      self.execute()
-    else:
-      raise Exception("cannot make the Box")
\ No newline at end of file
+
+class Box(Interface):
+    """Executes the macro-feature Box.
+
+    Box(feature) -> feature interface without initialization
+    Extrusion(feature, dx, dy, dz) ->
+        feature interface initialized from arguments:
+        - dx, dy, dz -- box dimensions
+    """
+
+    def __init__(self, feature, *args):
+        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
+        Interface.__init__(self, feature)
+        assert(self._feature.getKind() == MY.ID())
+
+        self._width = self._feature.real(MY.WIDTH_ID())
+        self._length = self._feature.real(MY.LENGTH_ID())
+        self._height = self._feature.real(MY.HEIGHT_ID())
+
+        assert(self._width)
+        assert(self._length)
+        assert(self._height)
+
+        if not args:
+            return
+
+        assert(len(args) == 3)
+        dx, dy, dz = args
+        self.setWidth(dx)
+        self.setLength(dy)
+        self.setHeight(dz)
+
+        self.execute()
+        pass
+
+    def setWidth(self, width):
+        """B.setWidth(float) -- modify width attribute"""
+        self._fillAttribute(self._width, width)
+        pass
+
+    def setLength(self, length):
+        """B.setLength(float) -- modify length attribute"""
+        self._fillAttribute(self._length, length)
+        pass
+
+    def setHeight(self, height):
+        """B.setHeight(float) -- modify height attribute"""
+        self._fillAttribute(self._height, height)
+        pass
index f5a6cfca81bba58c2f7e4941090a7882c3de83eb..247cfef3a99d0d7926396484f50ce7cf85323b28 100644 (file)
@@ -2,7 +2,7 @@
 # Author: Daniel Brunier-Coulin
 # -----------------------------
 
-from GeomAPI import *
+#from GeomAPI import *
 
 
 class Ax3:
diff --git a/src/PythonAPI/model/__init__.py b/src/PythonAPI/model/__init__.py
new file mode 100644 (file)
index 0000000..3a8c553
--- /dev/null
@@ -0,0 +1,28 @@
+"""This package defines the Parametric Geometry API of the Modeler.
+
+All features are available via model.add*() functions. Exceptions are:
+- exportToFile() - from Exchange plugin
+- duplicatePart(), removePart() - from PartSet plugin
+- exportToGEOM() - from Connection plugin
+"""
+
+# General purpose functions and abstract root classes
+
+from services  import *
+from roots     import *
+from tools import Selection
+
+# Built-in features
+
+from sketcher.sketch  import addSketch
+from connection import *
+from construction import *
+from exchange import *
+from features import *
+from parameter import *
+from partset import *
+
+# Custom exceptions
+
+from errors import WrongNumberOfArguments
+from errors import FeatureInputInvalid
diff --git a/src/PythonAPI/model/connection/__init__.py b/src/PythonAPI/model/connection/__init__.py
new file mode 100644 (file)
index 0000000..514b7f9
--- /dev/null
@@ -0,0 +1,4 @@
+"""Package for Connection plugin for the Parametric Geometry API of the Modeler.
+"""
+
+from connection import exportToGEOM
\ No newline at end of file
diff --git a/src/PythonAPI/model/connection/connection.py b/src/PythonAPI/model/connection/connection.py
new file mode 100644 (file)
index 0000000..da54458
--- /dev/null
@@ -0,0 +1,16 @@
+"""Export to GEOM Interface
+Author: Sergey Pokhodenko
+Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+"""
+
+from model.roots import Interface
+
+
+def exportToGEOM(part):
+    """Export the Part to GEOM module.
+
+    Args:
+        part (ModelAPI_Document): part document
+    """
+    feature = part.addFeature("ExportToGEOM")
+    feature.execute()
diff --git a/src/PythonAPI/model/construction/__init__.py b/src/PythonAPI/model/construction/__init__.py
new file mode 100644 (file)
index 0000000..e56746d
--- /dev/null
@@ -0,0 +1,6 @@
+"""Package for Construction plugin for the Parametric Geometry API of the Modeler.
+"""
+
+from point import addPoint
+from axis import addAxis
+from plane import addPlane
diff --git a/src/PythonAPI/model/construction/axis.py b/src/PythonAPI/model/construction/axis.py
new file mode 100644 (file)
index 0000000..ee92f4a
--- /dev/null
@@ -0,0 +1,101 @@
+"""Axis Interface
+Author: Sergey Pokhodenko
+Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+"""
+
+from model.roots import Interface
+
+
+def addAxis(part, *args):
+    """Add an Axis feature to the Part.
+
+    .. function:: addAxis(part, p1, p2)
+
+    Args:
+        part (ModelAPI_Document): part document
+        p1 (Selection): first point
+        p2 (Selection): second point
+
+    .. function:: addAxis(part, face)
+
+    Args:
+        part (ModelAPI_Document): part document
+        face (Selection): cylindrical face
+
+    Returns:
+        Axis: axis object
+    """
+    assert(args)
+    feature = part.addFeature("Axis")
+    return Axis(feature, *args)
+
+
+class Axis(Interface):
+    """Interface class for Axis feature.
+
+    .. function:: Axis(feature)
+
+        Create interface for the feature without initialization.
+
+    .. function:: Axis(feature, p1, p2)
+
+        Create interface for the feature and initialize the feature with arguments.
+
+    .. function:: Axis(feature, face)
+
+        Create interface for the feature and initialize the feature with arguments.
+    """
+
+    def __init__(self, feature, *args):
+        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
+        Interface.__init__(self, feature)
+        assert(self._feature.getKind() == "Axis")
+
+        self._CreationMethod = self._feature.data().string("CreationMethod")
+        self._FirstPoint = self._feature.data().selection("FirstPoint")
+        self._SecondPoint = self._feature.data().selection("SecondPoint")
+        self._CylindricalFace = self._feature.data().selection("CylindricalFace")
+
+        assert(self._CreationMethod)
+        assert(self._FirstPoint)
+        assert(self._SecondPoint)
+        assert(self._CylindricalFace)
+
+        if not args:
+            return
+
+        assert(len(args) in (1, 2))
+        if len(args) == 2:
+            self.setPoints(*args)
+        elif len(args) == 1:
+            self.setCylindricalFace(*args)
+
+        self.execute()
+        pass
+
+    def __clear(self):
+        self._fillAttribute(self._CreationMethod, "AxisByPointsCase")
+        self._fillAttribute(self._FirstPoint, None)
+        self._fillAttribute(self._SecondPoint, None)
+        self._fillAttribute(self._CylindricalFace, None)
+
+    def setPoints(self, p1, p2):
+        """Modify points attribute of the feature.
+
+        See __init__.
+        """
+        self.__clear()
+        self._fillAttribute(self._CreationMethod, "AxisByPointsCase")
+        self._fillAttribute(self._FirstPoint, p1)
+        self._fillAttribute(self._SecondPoint, p2)
+        pass
+
+    def setCylindricalFace(self, face):
+        """Modify CylindricalFace attribute of the feature.
+
+        See __init__.
+        """
+        self.__clear()
+        self._fillAttribute(self._CreationMethod, "AxisByCylindricalFaceCase")
+        self._fillAttribute(self._CylindricalFace, face)
+        pass
diff --git a/src/PythonAPI/model/construction/plane.py b/src/PythonAPI/model/construction/plane.py
new file mode 100644 (file)
index 0000000..c51e530
--- /dev/null
@@ -0,0 +1,116 @@
+"""Plane Interface
+Author: Sergey Pokhodenko
+Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+"""
+
+from model.roots import Interface
+
+
+def addPlane(part, *args):
+    """Add a Plane feature to the Part and return Plane.
+
+    .. function:: addPartition(part, face, distance)
+
+    Args:
+        part (ModelAPI_Document): part document
+        face (Selection): plane face
+        distance (double): distance
+
+    .. function:: addPartition(part, a, b, c, d)
+
+    Args:
+        part (ModelAPI_Document): part document
+        a (double): general equation parameter
+        b (double): general equation parameter
+        c (double): general equation parameter
+        d (double): general equation parameter
+
+    Returns:
+        Plane: plane object
+    """
+    assert(args)
+    feature = part.addFeature("Plane")
+    return Plane(feature, *args)
+
+
+class Plane(Interface):
+    """Interface class for Plane feature.
+
+    .. function:: Plane(feature)
+
+        Create interface for the feature without initialization.
+
+    .. function:: Plane(feature, face, distance)
+
+        Create interface for the feature and initialize the feature with arguments.
+
+    .. function:: Plane(feature, a, b, c, d)
+
+        Create interface for the feature and initialize the feature with arguments.
+    """
+
+    def __init__(self, feature, *args):
+        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
+        Interface.__init__(self, feature)
+        assert(self._feature.getKind() == "Plane")
+
+        self._CreationMethod = self._feature.data().string("CreationMethod")
+        self._plane_face = self._feature.data().selection("planeFace")
+        self._distance = self._feature.data().real("distance")
+        self._a = self._feature.data().real("A")
+        self._b = self._feature.data().real("B")
+        self._c = self._feature.data().real("C")
+        self._d = self._feature.data().real("D")
+
+        assert(self._CreationMethod)
+        assert(self._plane_face)
+        assert(self._distance)
+        assert(self._a)
+        assert(self._b)
+        assert(self._c)
+        assert(self._d)
+
+        if not args:
+            return
+
+        assert(len(args) in (2, 4))
+        if len(args) == 2:
+            self.setFaceAndDistance(*args)
+        elif len(args) == 4:
+            self.setGeneralEquation(*args)
+
+        self.execute()
+        pass
+
+    def __clear(self):
+        self._fillAttribute(self._CreationMethod, "PlaneByFaceAndDistance")
+        self._fillAttribute(self._plane_face, None)
+        self._fillAttribute(self._distance, 0)
+        self._fillAttribute(self._a, 0)
+        self._fillAttribute(self._b, 0)
+        self._fillAttribute(self._c, 0)
+        self._fillAttribute(self._d, 0)
+
+    def setFaceAndDistance(self, face, distance):
+        """Modify face and distance attribute of the feature.
+
+        See __init__.
+        """
+        self.__clear()
+        self._fillAttribute(self._CreationMethod, "PlaneByFaceAndDistance")
+        self._fillAttribute(self._plane_face, face)
+        self._fillAttribute(self._distance, distance)
+        pass
+
+    def setGeneralEquation(self, a, b, c, d):
+        """Modify GeneralEquation parameters of the feature.
+
+        See __init__.
+        """
+        self.__clear()
+        self._fillAttribute(self._CreationMethod, "PlaneByGeneralEquation")
+        self._fillAttribute(self._a, a)
+        self._fillAttribute(self._b, b)
+        self._fillAttribute(self._c, c)
+        self._fillAttribute(self._d, d)
+        pass
diff --git a/src/PythonAPI/model/construction/point.py b/src/PythonAPI/model/construction/point.py
new file mode 100644 (file)
index 0000000..db3405f
--- /dev/null
@@ -0,0 +1,70 @@
+"""Point Interface
+Author: Sergey Pokhodenko
+Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+"""
+
+from model.roots import Interface
+
+
+def addPoint(part, *args):
+    """Add an Point feature to the Part and return Point.
+
+    .. function:: addPoint(part, x, y, z)
+
+    Args:
+        part (ModelAPI_Document): part document
+        x (double): X coordinate for the point
+        y (double): Y coordinate for the point
+        z (double): Z coordinate for the point
+
+    Returns:
+        Point: point object
+    """
+    assert(args)
+    feature = part.addFeature("Point")
+    return Point(feature, *args)
+
+
+class Point(Interface):
+    """Interface class for Point feature.
+
+    .. function:: Point(feature)
+
+        Create interface for the feature without initialization.
+
+    .. function:: Point(feature, x, y, z)
+
+        Create interface for the feature and initialize the feature with arguments.
+    """
+
+    def __init__(self, feature, *args):
+        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
+        Interface.__init__(self, feature)
+        assert(self._feature.getKind() == "Point")
+
+        self._x = self._feature.data().real("x")
+        self._y = self._feature.data().real("y")
+        self._z = self._feature.data().real("z")
+
+        assert(self._x)
+        assert(self._y)
+        assert(self._z)
+
+        if not args:
+            return
+
+        assert(len(args) == 3)
+        self.setPoint(*args)
+
+        self.execute()
+        pass
+
+    def setPoint(self, x, y, z):
+        """Modify base attribute of the feature.
+
+        See __init__.
+        """
+        self._fillAttribute(self._x, x)
+        self._fillAttribute(self._y, y)
+        self._fillAttribute(self._z, z)
+        pass
diff --git a/src/PythonAPI/model/errors.py b/src/PythonAPI/model/errors.py
new file mode 100644 (file)
index 0000000..e10ec92
--- /dev/null
@@ -0,0 +1,22 @@
+# Package exceptions
+
+class ModelError(Exception):
+    """Base class for exceptions in this package."""
+    pass
+
+class WrongNumberOfArguments(ModelError):
+    """Exception raised when a wrong number of arguments is given."""
+    pass
+
+class FeatureInputInvalid(ModelError):
+    """Exception raised if a feature input is invalid."""
+    pass
+
+    #Attributes:
+        #expr -- input expression in which the error occurred
+        #msg  -- explanation of the error
+    #"""
+
+    #def __init__(self, expr, msg):
+        #self.expr = expr
+        #self.msg = msg
diff --git a/src/PythonAPI/model/exchange/__init__.py b/src/PythonAPI/model/exchange/__init__.py
new file mode 100644 (file)
index 0000000..71b17bb
--- /dev/null
@@ -0,0 +1,4 @@
+"""Package for Exchange plugin for the Parametric Geometry API of the Modeler.
+"""
+
+from exchange import addImport, exportToFile
\ No newline at end of file
diff --git a/src/PythonAPI/model/exchange/exchange.py b/src/PythonAPI/model/exchange/exchange.py
new file mode 100644 (file)
index 0000000..c884451
--- /dev/null
@@ -0,0 +1,142 @@
+"""Import Interface
+Author: Sergey Pokhodenko
+Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+"""
+
+from model.roots import Interface
+
+
+def addImport(part, *args):
+    """Add an Import feature to the Part.
+
+    .. function:: addImport(part, file_path)
+
+    Args:
+        part (ModelAPI_Document): part document
+        file_path (string): path to the imported file
+
+    Returns:
+        Import: import object
+    """
+    assert(args)
+    feature = part.addFeature("Import")
+    return Import(feature, *args)
+
+
+class Import(Interface):
+    """Interface class for Import feature.
+
+    .. function:: Import(feature)
+
+        Create interface for the feature without initialization.
+
+    .. function:: Import(feature, file_path)
+
+        Create interface for the feature and initialize the feature with arguments.
+    """
+
+    def __init__(self, feature, *args):
+        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
+        Interface.__init__(self, feature)
+        assert(self._feature.getKind() == "Import")
+
+        self._file_path = self._feature.data().string("file_path")
+
+        assert(self._file_path)
+
+        if not args:
+            return
+
+        assert(len(args) == 1)
+        self.setFilePath(args[0])
+
+        self.execute()
+        pass
+
+    def setFilePath(self, file_path):
+        """Modify file path attribute of the feature.
+
+        See __init__.
+        """
+        self._fillAttribute(self._file_path, file_path)
+        pass
+
+
+def exportToFile(part, *args):
+    """Perform export from the Part to file.
+
+    .. function:: exportToFile(part, file_path, file_format, selection_list)
+
+    Args:
+        part (ModelAPI_Document): part document
+        file_path (string): path to the exported file
+        file_format (string): format of to the exported file
+        selection_list (list of Selection): objects to export
+
+    Returns:
+        Export: export object
+    """
+    assert(args)
+    feature = part.addFeature("Export")
+    return Export(feature, *args)
+
+
+class Export(Interface):
+    """Interface class for Export feature.
+
+    .. function:: Export(feature)
+
+        Create interface for the feature without initialization.
+
+    .. function:: Export(feature, file_path, file_format, selection_list)
+
+        Create interface for the feature and initialize the feature with arguments.
+    """
+
+    def __init__(self, feature, *args):
+        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
+        Interface.__init__(self, feature)
+        assert(self._feature.getKind() == "Export")
+
+        self._file_path = self._feature.data().string("file_path")
+        self._file_format = self._feature.data().string("file_format")
+        self._objects = self._feature.data().selectionList("selection_list")
+
+        assert(self._file_path)
+        assert(self._file_format)
+        assert(self._objects)
+
+        if not args:
+            return
+
+        assert(len(args) == 3)
+        self.setFilePath(args[0])
+        self.setFileFormat(args[1])
+        self.setObjects(args[2])
+
+        self.execute()
+        pass
+
+    def setFilePath(self, file_path):
+        """Modify file path attribute of the feature.
+
+        See __init__.
+        """
+        self._fillAttribute(self._file_path, file_path)
+        pass
+
+    def setFileFormat(self, file_format):
+        """Modify file path attribute of the feature.
+
+        See __init__.
+        """
+        self._fillAttribute(self._file_format, file_format)
+        pass
+
+    def setObjects(self, objects):
+        """Modify file path attribute of the feature.
+
+        See __init__.
+        """
+        self._fillAttribute(self._objects, object)
+        pass
diff --git a/src/PythonAPI/model/features/__init__.py b/src/PythonAPI/model/features/__init__.py
new file mode 100644 (file)
index 0000000..108d089
--- /dev/null
@@ -0,0 +1,20 @@
+"""Package for Features plugin for the Parametric Geometry API of the Modeler.
+"""
+
+from boolean import addAddition, addSubtraction, addIntersection
+
+from partition import addPartition
+
+from extrusion import addExtrusion
+from extrusion_boolean import addExtrusionCut, addExtrusionFuse
+from extrusion_sketch import addExtrusionSketch
+
+from revolution import addRevolution
+from revolution_boolean import addRevolutionCut, addRevolutionFuse
+from revolution_sketch import addRevolutionSketch
+
+from placement import addPlacement
+from rotation import addRotation
+from translation import addTranslation
+
+from group import addGroup
diff --git a/src/PythonAPI/model/features/boolean.py b/src/PythonAPI/model/features/boolean.py
new file mode 100644 (file)
index 0000000..489c428
--- /dev/null
@@ -0,0 +1,146 @@
+"""Boolean operations Interface
+Author: Daniel Brunier-Coulin with contribution by Sergey Pokhodenko
+Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+"""
+
+from GeomAlgoAPI import GeomAlgoAPI_Boolean
+
+from model.roots import Interface
+
+
+def addAddition(part, *args):
+    """Perform addition in the Part.
+
+    .. function:: addAddition(part, main_objects, tool_objects)
+
+        This operation adds tools to the given objects.
+
+    Args:
+        part (ModelAPI_Document): part document
+        main_objects (list of :class:`model.Selection`): main objects
+        tool_objects (list of :class:`model.Selection`): tool_objects objects
+
+    Returns:
+        Boolean: boolean object
+    """
+    assert(args)
+    main_objects, tool_objects = args
+    feature = part.addFeature("Boolean")
+    return Boolean(
+        feature, main_objects, tool_objects, GeomAlgoAPI_Boolean.BOOL_FUSE)
+
+
+def addSubtraction(part, *args):
+    """Perform subtraction in the Part.
+
+    .. function:: addSubtraction(part, main_objects, tool_objects)
+
+        This operation subtracts tools from the given objects.
+
+    Args:
+        part (ModelAPI_Document): part document
+        main_objects (list of :class:`model.Selection`): main objects
+        tool_objects (list of :class:`model.Selection`): tool_objects objects
+
+    Returns:
+        Boolean: boolean object
+    """
+    assert(args)
+    main_objects, tool_objects = args
+    feature = part.addFeature("Boolean")
+    return Boolean(
+        feature, main_objects, tool_objects, GeomAlgoAPI_Boolean.BOOL_CUT)
+
+
+def addIntersection(part, *args):
+    """Perform intersection in the Part.
+
+    .. function:: addIntersection(part, main_objects, tool_objects)
+
+        This operation intersects tools with the given objects.
+
+    Args:
+        part (ModelAPI_Document): part document
+        main_objects (list of :class:`model.Selection`): main objects
+        tool_objects (list of :class:`model.Selection`): tool_objects objects
+
+    Returns:
+        Boolean: boolean object
+    """
+    assert(args)
+    main_objects, tool_objects = args
+    feature = part.addFeature("Boolean")
+    return Boolean(
+        feature, main_objects, tool_objects, GeomAlgoAPI_Boolean.BOOL_COMMON)
+
+
+class Boolean(Interface):
+    """Interface class for Boolean features.
+
+    .. function:: Boolean(feature)
+
+        Create interface for the feature without initialization.
+
+    .. function:: Boolean(feature, main_objects, tool_objects, bool_type)
+
+        Create interface for the feature and initialize the feature with arguments.
+    """
+
+    def __init__(self, feature, *args):
+        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
+        Interface.__init__(self, feature)
+        assert(self._feature.getKind() == "Boolean")
+
+        self._main_objects = self._feature.selectionList("main_objects")
+        self._tool_objects = self._feature.selectionList("tool_objects")
+        self._bool_type = self._feature.integer("bool_type")
+
+        assert(self._main_objects)
+        assert(self._tool_objects)
+        assert(self._bool_type)
+
+        if not args:
+            return
+
+        assert(len(args) == 3)
+        main_objects, tool_objects, bool_type = args
+
+        self.setMainObjects(main_objects)
+        self.setToolObjects(tool_objects)
+        self.setBoolType(bool_type)
+
+        self.execute()
+        pass
+
+    def setMainObjects(self, main_objects):
+        """Modify main_objects attribute of the feature.
+
+        Args:
+            main_objects (list of :class:`model.Selection`): main objects
+        """
+        self._fillAttribute(self._main_objects, main_objects)
+        pass
+
+    def setToolObjects(self, tool_objects):
+        """Modify tool_objects attribute of the feature.
+
+        Args:
+            tool_objects (list of :class:`model.Selection`): tool objects
+        """
+        self._fillAttribute(self._tool_objects, tool_objects)
+        pass
+
+    def setBoolType(self, bool_type):
+        """Modify bool_type attribute of the feature.
+
+        Args:
+            bool_type (integer): type of operation
+
+        Available types:
+
+        * GeomAlgoAPI_Boolean.BOOL_FUSE
+        * GeomAlgoAPI_Boolean.BOOL_CUT
+        * GeomAlgoAPI_Boolean.BOOL_COMMON
+        """
+        self._fillAttribute(self._bool_type, bool_type)
+        pass
diff --git a/src/PythonAPI/model/features/extrusion.py b/src/PythonAPI/model/features/extrusion.py
new file mode 100644 (file)
index 0000000..a63b093
--- /dev/null
@@ -0,0 +1,171 @@
+"""Extrusion Interface
+Author: Daniel Brunier-Coulin with contribution by Mikhail Ponikarov
+        and Sergey Pokhodenko
+Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+"""
+
+from model.roots import Interface
+from model import Selection
+
+def addExtrusion(part, *args):
+    """Add an Extrusion feature to the Part and return Extrusion.
+
+    This function has *3 signatures*:
+
+    .. function:: addExtrusion(base, size)
+
+    Arguments:
+        base(str, Sketch or list): base object(s)
+        size(double): size of the extrusion, the side is decided by the sign
+
+    .. function:: addExtrusion(base, to_size, from_size)
+
+    Arguments:
+        base(str, Sketch or list): base object(s)
+        to_size(double): upper size of the extrusion
+        from_size(double): lower size of the extrusion
+
+    .. function:: addExtrusion(base, to_object, to_offset, from_object, from_offset)
+
+    Arguments:
+        base(str, Sketch or list): base object(s)
+        to_object(plane): upper plane
+        to_offset(double): offset from upper object
+        from_object(plane): lower plane
+        from_offset(double): offset from lower plane
+
+    In all three cases the function returns an extrusion object
+
+    Returns:
+        Extrusion: extrusion object
+    """
+    assert(args)
+    feature = part.addFeature("Extrusion")
+    return Extrusion(feature, *args)
+
+
+class Extrusion(Interface):
+    """Interface class for Extrusion feature.
+    """
+
+    def __init__(self, feature, *args):
+        """
+        Extrusion(feature) -> feature interface without initialization
+        Extrusion(feature, base, size) ->
+            feature interface initialized from arguments:
+            - base -- name, sketch or list of names and sketches
+            - size -- if positive -> to_size, if negative -> from_size
+        Extrusion(feature, base, to_size, from_size) ->
+            feature interface initialized from arguments:
+            - base -- name, sketch or list of names and sketches
+            - to_size -- upper size
+            - from_size -- lower size
+        Extrusion(feature, base, to_object, to_offset, from_object, from_offset) ->
+            feature interface initialized from arguments:
+            - base -- name, sketch or list of names and sketches
+            - to_object -- upper object (plane)
+            - to_offset -- offset from upper object
+            - from_object -- lower object (plane)
+            - from_offset -- offset from lower object
+        """
+        Interface.__init__(self, feature)
+        assert(self._feature.getKind() == "Extrusion")
+
+        self._base = self._feature.data().selectionList("base")
+        self._CreationMethod = self._feature.string("CreationMethod")
+        self._to_size = self._feature.data().real("to_size")
+        self._from_size = self._feature.data().real("from_size")
+        self._to_object = self._feature.data().selection("to_object")
+        self._to_offset = self._feature.data().real("to_offset")
+        self._from_object = self._feature.data().selection("from_object")
+        self._from_offset = self._feature.data().real("from_offset")
+
+        assert(self._base)
+        assert(self._CreationMethod)
+        assert(self._to_size)
+        assert(self._from_size)
+        assert(self._to_object)
+        assert(self._to_offset)
+        assert(self._from_object)
+        assert(self._from_offset)
+
+        if not args:
+            return
+
+        assert(len(args) in (2, 3, 5))
+        base = args[0]
+        args = args[1:]
+
+        self.setBase(base)
+
+        if len(args) == 4:
+            self.setPlanesAndOffsets(*args)
+        elif len(args) == 2:
+            self.setSizes(*args)
+        elif len(args) == 1:
+            self.setSize(args[0])
+
+        self.execute()
+        pass
+
+    def __clear(self):
+        self._CreationMethod.setValue("BySizes")
+        self._fillAttribute(self._to_size, 0)
+        self._fillAttribute(self._from_size, 0)
+        self._fillAttribute(self._to_object, None)
+        self._fillAttribute(self._to_offset, 0)
+        self._fillAttribute(self._from_object, None)
+        self._fillAttribute(self._from_offset, 0)
+        pass
+
+    def setBase(self, base):
+        """Modify base attribute of the feature.
+
+        See __init__.
+        """
+        self._fillAttribute(self._base, base)
+        pass
+
+    def setSizes(self, to_size, from_size):
+        """Modify the to_size, from_size attributes of the feature.
+
+        See __init__.
+        """
+        self.__clear()
+        self._fillAttribute(self._CreationMethod, "BySizes")
+        self._fillAttribute(self._to_size, to_size)
+        self._fillAttribute(self._from_size, from_size)
+        pass
+
+    def setSize(self, size):
+        """Modify the size of the feature.
+
+        If size is positive then initialize to_size with size.
+        If size is negative then initialize from_size with -size.
+        """
+        to_size, from_size = 0, 0
+        if size >= 0:
+            to_size = size
+        else:
+            from_size = -size
+
+        self.setSizes(to_size, from_size)
+        pass
+
+    def setPlanesAndOffsets(self, to_object, to_offset,
+                            from_object, from_offset):
+        """Modify planes and offsets attributes of the feature.
+
+        See __init__.
+        """
+        self.__clear()
+        self._CreationMethod.setValue("ByPlanesAndOffsets")
+        self._fillAttribute(self._to_object, to_object)
+        self._fillAttribute(self._to_offset, to_offset)
+        self._fillAttribute(self._from_object, from_object)
+        self._fillAttribute(self._from_offset, from_offset)
+        pass
+
+    def result(self):
+        """F.result() -> list of Selection objects"""
+        return [Selection(result, result.shape()) for result in (self.firstResult(),)]
diff --git a/src/PythonAPI/model/features/extrusion_boolean.py b/src/PythonAPI/model/features/extrusion_boolean.py
new file mode 100644 (file)
index 0000000..199d1e1
--- /dev/null
@@ -0,0 +1,162 @@
+"""ExtrusionCut and ExtrusionFuse  Interfaces
+Author: Sergey Pokhodenko
+Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+"""
+
+from .roots import CompositeBoolean
+
+
+def addExtrusionCut(part, *args):
+    """Add an ExtrusionCut feature to the Part.
+
+    .. function:: addExtrusionCut(part, sketch, sketch_selection, boolean_objects, to_size, from_size)
+
+    Args:
+        part (ModelAPI_Document): part document
+        sketch (ModelAPI_Object): sketch feature
+        sketch_selection (Selection): sketch objects
+        boolean_objects (list of Selection): boolean objects
+        to_size (double): upper size of the extrusion
+        from_size (double): lower size of the extrusion
+
+    .. function:: addExtrusionCut(part, sketch, sketch_selection, boolean_objects, to_object, to_offset, from_object, from_offset)
+
+    Args:
+        part (ModelAPI_Document): part document
+        sketch (ModelAPI_Object): sketch feature
+        sketch_selection (Selection): sketch objects
+        boolean_objects (list of Selection): boolean objects
+        to_object (Selection): upper plane
+        to_offset (double): offset from upper plane
+        from_object (Selection): lower plane
+        from_offset (double): offset from lower plane
+
+    Returns:
+        ExtrusionBoolean: extrusion boolean object
+    """
+    assert(args)
+    feature = part.addFeature("ExtrusionCut")
+    return ExtrusionBoolean(feature, *args)
+
+def addExtrusionFuse(part, *args):
+    """Add an ExtrusionFuse feature to the Part and return ExtrusionBoolean.
+
+    .. function:: addExtrusionFuse(part, sketch, sketch_selection, boolean_objects, to_size, from_size)
+
+    Args:
+        part (ModelAPI_Document): part document
+        sketch (ModelAPI_Object): sketch feature
+        sketch_selection (Selection): sketch objects
+        boolean_objects (list of Selection): boolean objects
+        to_size (double): upper size of the extrusion
+        from_size (double): lower size of the extrusion
+
+    .. function:: addExtrusionFuse(part, sketch, sketch_selection, boolean_objects, to_object, to_offset, from_object, from_offset)
+
+    Args:
+        part (ModelAPI_Document): part document
+        sketch (ModelAPI_Object): sketch feature
+        sketch_selection (Selection): sketch objects
+        boolean_objects (list of Selection): boolean objects
+        to_object (Selection): upper plane
+        to_offset (double): offset from upper plane
+        from_object (Selection): lower plane
+        from_offset (double): offset from lower plane
+
+    Returns:
+        ExtrusionBoolean: extrusion boolean object
+    """
+    assert(args)
+    feature = part.addFeature("ExtrusionFuse")
+    return ExtrusionBoolean(feature, *args)
+
+
+class ExtrusionBoolean(CompositeBoolean):
+    """Interface class for ExtrusionBoolean features.
+
+    Supported features:
+
+    * ExtrusionCut
+    * ExtrusionFuse
+
+    .. function:: ExtrusionBoolean(feature)
+
+        Create interface for the feature without initialization.
+
+    .. function:: ExtrusionBoolean(feature, sketch, sketch_selection, boolean_objects, to_size, from_size)
+
+        Create interface for the feature and initialize the feature with arguments.
+
+    .. function:: ExtrusionBoolean(feature, sketch, sketch_selection, boolean_objects, to_object, to_offset, from_object, from_offset)
+
+        Create interface for the feature and initialize the feature with arguments.
+    """
+
+    def __init__(self, feature, *args):
+        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
+        CompositeBoolean.__init__(self, feature, *args[:3])
+        args = args[3:]
+
+        self._CreationMethod = self._feature.string("CreationMethod")
+        self._to_size = self._feature.data().real("to_size")
+        self._from_size = self._feature.data().real("from_size")
+        self._to_object = self._feature.data().selection("to_object")
+        self._to_offset = self._feature.data().real("to_offset")
+        self._from_object = self._feature.data().selection("from_object")
+        self._from_offset = self._feature.data().real("from_offset")
+
+        assert(self._CreationMethod)
+        assert(self._to_size)
+        assert(self._from_size)
+        assert(self._to_object)
+        assert(self._to_offset)
+        assert(self._from_object)
+        assert(self._from_offset)
+
+        if not args:
+            return
+
+        assert(len(args) in (2, 4))
+        if len(args) == 4:
+            self.setPlanesAndOffsets(*args)
+        elif len(args) == 2:
+            self.setSizes(*args)
+
+        self.execute()
+        pass
+
+    def __clear(self):
+        self._CreationMethod.setValue("BySizes")
+        self._fillAttribute(self._to_size, 0)
+        self._fillAttribute(self._from_size, 0)
+        self._fillAttribute(self._to_object, None)
+        self._fillAttribute(self._to_offset, 0)
+        self._fillAttribute(self._from_object, None)
+        self._fillAttribute(self._from_offset, 0)
+        pass
+
+    def setSizes(self, to_size, from_size):
+        """Modify the to_size, from_size attributes of the feature.
+
+        See __init__.
+        """
+        self.__clear()
+        self._CreationMethod.setValue("BySizes")
+        self._fillAttribute(self._to_size, to_size)
+        self._fillAttribute(self._from_size, from_size)
+        pass
+
+    def setPlanesAndOffsets(self, to_object, to_offset,
+                            from_object, from_offset):
+        """Modify planes and offsets attributes of the feature.
+
+        See __init__.
+        """
+        self.__clear()
+        self._CreationMethod.setValue("ByPlanesAndOffsets")
+        self._fillAttribute(self._to_object, to_object)
+        self._fillAttribute(self._to_offset, to_offset)
+        self._fillAttribute(self._from_object, from_object)
+        self._fillAttribute(self._from_offset, from_offset)
+        pass
+
diff --git a/src/PythonAPI/model/features/extrusion_sketch.py b/src/PythonAPI/model/features/extrusion_sketch.py
new file mode 100644 (file)
index 0000000..0838948
--- /dev/null
@@ -0,0 +1,122 @@
+"""ExtrusionSketch  Interfaces
+Author: Sergey Pokhodenko
+Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+"""
+
+from .roots import CompositeSketch
+
+
+def addExtrusionSketch(part, *args):
+    """Add an ExtrusionSketch feature to the Part.
+
+    .. function:: addExtrusionSketch(part, sketch, sketch_selection, to_size, from_size)
+
+    Args:
+        part (ModelAPI_Document): part document
+        sketch (ModelAPI_Object): sketch feature
+        sketch_selection (Selection): sketch objects
+        to_size (double): upper size of the extrusion
+        from_size (double): lower size of the extrusion
+
+    .. function:: addExtrusionSketch(part, sketch, sketch_selection, to_object, to_offset, from_object, from_offset)
+
+    Args:
+        part (ModelAPI_Document): part document
+        sketch (ModelAPI_Object): sketch feature
+        sketch_selection (Selection): sketch objects
+        to_object (Selection): upper plane
+        to_offset (double): offset from upper plane
+        from_object (Selection): lower plane
+        from_offset (double): offset from lower plane
+
+    Returns:
+        ExtrusionSketch: extrusion sketch object
+    """
+    assert(args)
+    feature = part.addFeature("ExtrusionSketch")
+    return ExtrusionSketch(feature, *args)
+
+
+class ExtrusionSketch(CompositeSketch):
+    """Interface class for ExtrusionSketch feature.
+
+    .. function:: ExtrusionSketch(feature)
+
+    Create interface for the feature without initialization.
+
+    .. function:: ExtrusionSketch(feature, sketch, sketch_selection, to_size, from_size)
+
+    Create interface for the feature and initialize the feature with arguments.
+
+    .. function:: ExtrusionSketch(feature, sketch, sketch_selection, to_object, to_offset, from_object, from_offset)
+
+    Create interface for the feature and initialize the feature with arguments.
+    """
+    def __init__(self, feature, *args):
+        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
+        CompositeSketch.__init__(self, feature, *args[:2])
+        args = args[2:]
+
+        self._CreationMethod = self._feature.string("CreationMethod")
+        self._to_size = self._feature.data().real("to_size")
+        self._from_size = self._feature.data().real("from_size")
+        self._to_object = self._feature.data().selection("to_object")
+        self._to_offset = self._feature.data().real("to_offset")
+        self._from_object = self._feature.data().selection("from_object")
+        self._from_offset = self._feature.data().real("from_offset")
+
+        assert(self._CreationMethod)
+        assert(self._to_size)
+        assert(self._from_size)
+        assert(self._to_object)
+        assert(self._to_offset)
+        assert(self._from_object)
+        assert(self._from_offset)
+
+        if not args:
+            return
+
+        assert(len(args) in (2, 4))
+        if len(args) == 4:
+            self.setPlanesAndOffsets(*args)
+        elif len(args) == 2:
+            self.setSizes(*args)
+
+        self.execute()
+        pass
+
+    def __clear(self):
+        self._CreationMethod.setValue("BySizes")
+        self._fillAttribute(self._to_size, 0)
+        self._fillAttribute(self._from_size, 0)
+        self._fillAttribute(self._to_object, None)
+        self._fillAttribute(self._to_offset, 0)
+        self._fillAttribute(self._from_object, None)
+        self._fillAttribute(self._from_offset, 0)
+        pass
+
+    def setSizes(self, to_size, from_size):
+        """Modify the to_size, from_size attributes of the feature.
+
+        See __init__.
+        """
+        self.__clear()
+        self._CreationMethod.setValue("BySizes")
+        self._fillAttribute(self._to_size, to_size)
+        self._fillAttribute(self._from_size, from_size)
+        pass
+
+    def setPlanesAndOffsets(self, to_object, to_offset,
+                            from_object, from_offset):
+        """Modify planes and offsets attributes of the feature.
+
+        See __init__.
+        """
+        self.__clear()
+        self._CreationMethod.setValue("ByPlanesAndOffsets")
+        self._fillAttribute(self._to_object, to_object)
+        self._fillAttribute(self._to_offset, to_offset)
+        self._fillAttribute(self._from_object, from_object)
+        self._fillAttribute(self._from_offset, from_offset)
+        pass
+
diff --git a/src/PythonAPI/model/features/group.py b/src/PythonAPI/model/features/group.py
new file mode 100644 (file)
index 0000000..68567bd
--- /dev/null
@@ -0,0 +1,62 @@
+"""Group Interface
+Author: Sergey Pokhodenko
+Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+"""
+
+from model.roots import Interface
+
+
+def addGroup(part, *args):
+    """Add a Group feature to the Part.
+
+    .. function:: addGroup(part, group_list)
+
+    Args:
+        part (ModelAPI_Document): part document
+        group_list (list of Selection): list of objects
+
+    Returns:
+        Group: group object
+    """
+    assert(args)
+    feature = part.addFeature("Group")
+    return Group(feature, *args)
+
+
+class Group(Interface):
+    """Interface class for Group feature.
+
+    .. function:: Group(feature)
+
+        Create interface for the feature without initialization.
+
+    .. function:: Group(feature, group_list)
+
+        Create interface for the feature and initialize the feature with arguments.
+    """
+
+    def __init__(self, feature, *args):
+        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
+        Interface.__init__(self, feature)
+        assert(self._feature.getKind() == "Group")
+
+        self._group_list = self._feature.data().selectionList("group_list")
+
+        assert(self._group_list)
+
+        if not args:
+            return
+
+        assert(len(args) == 1)
+        self.setGroupList(args[0])
+
+        self.execute()
+        pass
+
+    def setGroupList(self, main_objects):
+        """Modify group_list attribute of the feature.
+
+        See __init__.
+        """
+        self._fillAttribute(self._group_list, group_list)
+        pass
diff --git a/src/PythonAPI/model/features/partition.py b/src/PythonAPI/model/features/partition.py
new file mode 100644 (file)
index 0000000..26173e0
--- /dev/null
@@ -0,0 +1,89 @@
+"""Partition Interface
+Author: Sergey Pokhodenko
+Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+"""
+
+from model.roots import Interface
+
+
+def addPartition(part, *args):
+    """Add a Partition feature to the Part.
+
+    .. function:: addPartition(part, main_objects, tool_objects, partition_combine)
+
+    Args:
+        part (ModelAPI_Document): part document
+        main_objects (list of Selection): main objects
+        tool_objects (list of Selection): tool objects
+        partition_combine (boolean):
+            If True combines all results to one. If False builds separate result for each object.
+
+    Returns:
+        Partition: partition object
+    """
+    assert(len(args) > 0 and args[0] is not None)
+    feature = part.addFeature("Partition")
+    return Partition(feature, *args)
+
+
+class Partition(Interface):
+    """Interface class for Partition feature.
+
+    .. function:: Partition(feature)
+
+        Create interface for the feature without initialization.
+
+    .. function:: Partition(feature, main_objects, tool_objects, partition_combine)
+
+        Create interface for the feature and initialize the feature with arguments.
+    """
+
+    def __init__(self, feature, *args):
+        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
+        Interface.__init__(self, feature)
+        assert(self._feature.getKind() == "Partition")
+
+        self._main_objects = self._feature.data().selectionList("main_objects")
+        self._tool_objects = self._feature.data().selectionList("tool_objects")
+        self._partition_combine = self._feature.data().boolean("partition_combine")
+
+        assert(self._main_objects)
+        assert(self._tool_objects)
+        assert(self._partition_combine)
+
+        if not args:
+            return
+
+        assert(len(args) == 3)
+        main_objects, tool_objects, partition_combine = args
+
+        self.setMainObjects(main_objects)
+        self.setToolObjects(tool_objects)
+        self.setPartitionCombine(partition_combine)
+
+        self.execute()
+        pass
+
+    def setMainObjects(self, main_objects):
+        """Modify base attribute of the feature.
+
+        See __init__.
+        """
+        self._fillAttribute(self._main_objects, main_objects)
+        pass
+
+    def setToolObjects(self, tool_objects):
+        """Modify the to_size, from_size attributes of the feature.
+
+        See __init__.
+        """
+        self._fillAttribute(self._tool_objects, tool_objects)
+        pass
+
+    def setPartitionCombine(self, partition_combine):
+        """Modify planes and offsets attributes of the feature.
+
+        See __init__.
+        """
+        self._fillAttribute(self._partition_combine, partition_combine)
+        pass
diff --git a/src/PythonAPI/model/features/placement.py b/src/PythonAPI/model/features/placement.py
new file mode 100644 (file)
index 0000000..4da0998
--- /dev/null
@@ -0,0 +1,110 @@
+"""Placement Interface
+Author: Sergey Pokhodenko
+Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+"""
+
+from model.roots import Interface
+
+
+def addPlacement(part, *args):
+    """Add a Placement feature to the Part.
+
+    .. function:: addPlacement(part, objects_list, start_shape, end_shape, reverse_direction, centering)
+
+    Args:
+        part (ModelAPI_Document): part document
+        objects_list (list of Selection): solid objects
+        start_shape (Selection): start face, edge or vertex
+        end_shape (Selection): end face, edge or vertex
+        reverse_direction (boolean): reverse placement direction
+        centering (boolean): center faces under placement
+
+    Returns:
+        Placement: placement object
+    """
+    assert(args)
+    feature = part.addFeature("Placement")
+    return Placement(feature, *args)
+
+
+class Placement(Interface):
+    """Interface class for Placement feature.
+
+    .. function:: Placement(feature)
+
+        Create interface for the feature without initialization.
+
+    .. function:: Placement(feature, objects_list, start_shape, end_shape, reverse_direction, centering)
+
+        Create interface for the feature and initialize the feature with arguments.
+    """
+
+    def __init__(self, feature, *args):
+        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
+        Interface.__init__(self, feature)
+        assert(self._feature.getKind() == "Placement")
+
+        self._objects_list = self._feature.data().selectionList("placement_objects_list")
+        self._start_shape = self._feature.data().selection("placement_start_shape")
+        self._end_shape = self._feature.data().selection("placement_end_shape")
+        self._reverse_direction = self._feature.data().boolean("placement_reverse_direction")
+        self._centering = self._feature.data().boolean("placement_centering")
+
+        assert(self._objects_list)
+        assert(self._start_shape)
+        assert(self._end_shape)
+        assert(self._reverse_direction)
+        assert(self._centering)
+
+        if not args:
+            return
+
+        assert(len(args) == 5)
+        self.setObjectList(args[0])
+        self.setStartShape(args[1])
+        self.setEndShape(args[2])
+        self.setReverseDirection(args[3])
+        self.setCentering(args[4])
+
+        self.execute()
+        pass
+
+    def setObjectList(self, objects_list):
+        """Modify placement_objects_list attribute of the feature.
+
+        See __init__.
+        """
+        self._fillAttribute(self._objects_list, objects_list)
+        pass
+
+    def setStartShape(self, start_shape):
+        """Modify start_shape attribute of the feature.
+
+        See __init__.
+        """
+        self._fillAttribute(self._start_shape, start_shape)
+        pass
+
+    def setEndShape(self, end_shape):
+        """Modify end_shape attribute of the feature.
+
+        See __init__.
+        """
+        self._fillAttribute(self._end_shape, end_shape)
+        pass
+
+    def setReverseDirection(self, reverse_direction):
+        """Modify reverse_direction attribute of the feature.
+
+        See __init__.
+        """
+        self._fillAttribute(self._reverse_direction, reverse_direction)
+        pass
+
+    def setCentering(self, centering):
+        """Modify centering attribute of the feature.
+
+        See __init__.
+        """
+        self._fillAttribute(self._centering, centering)
+        pass
diff --git a/src/PythonAPI/model/features/revolution.py b/src/PythonAPI/model/features/revolution.py
new file mode 100644 (file)
index 0000000..3ab4201
--- /dev/null
@@ -0,0 +1,149 @@
+"""Revolution Interface
+Author: Sergey Pokhodenko
+Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+"""
+
+from model.roots import Interface
+
+
+def addRevolution(part, *args):
+    """Add a Revolution feature to the Part.
+
+    .. function:: addRevolution(part, base, axis_object, to_angle, from_angle)
+
+    Args:
+        part (ModelAPI_Document): part document
+        base (list of Selection): base objects
+        axis_object (Selection): axis object
+        to_angle (double): to angle
+        from_angle (double): from angle
+
+    .. function:: addRevolution(feature, base, axis_object, to_object, to_offset, from_object, from_offset)
+
+    Args:
+        part (ModelAPI_Document): part document
+        base (list of Selection): base objects
+        axis_object (Selection): axis object
+        to_object (plane): upper plane
+        to_offset (double): offset from upper object
+        from_object (plane): lower plane
+        from_offset (double): offset from lower plane
+
+    Returns:
+        Revolution: revolution object
+    """
+    assert(len(args) > 0 and args[0] is not None)
+    feature = part.addFeature("Revolution")
+    return Revolution(feature, *args)
+
+
+class Revolution(Interface):
+    """Interface class for Revolution features.
+
+    .. function:: Revolution(feature)
+
+        Create interface for the feature without initialization.
+
+    .. function:: Revolution(feature, base, axis_object, to_angle, from_angle)
+
+        Create interface for the feature and initialize the feature with arguments.
+
+    .. function:: Revolution(feature, base, axis_object, to_object, to_offset, from_object, from_offset)
+
+        Create interface for the feature and initialize the feature with arguments.
+    """
+
+    def __init__(self, feature, *args):
+        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
+        Interface.__init__(self, feature)
+        assert(self._feature.getKind() == "Revolution")
+
+        self._base = self._feature.data().selectionList("base")
+        self._axis_object = self._feature.data().selection("axis_object")
+        self._CreationMethod = self._feature.string("CreationMethod")
+        self._to_angle = self._feature.data().real("to_angle")
+        self._from_angle = self._feature.data().real("from_angle")
+        self._to_object = self._feature.data().selection("to_object")
+        self._to_offset = self._feature.data().real("to_offset")
+        self._from_object = self._feature.data().selection("from_object")
+        self._from_offset = self._feature.data().real("from_offset")
+
+        assert(self._base)
+        assert(self._axis_object)
+        assert(self._CreationMethod)
+        assert(self._to_angle)
+        assert(self._from_angle)
+        assert(self._to_object)
+        assert(self._to_offset)
+        assert(self._from_object)
+        assert(self._from_offset)
+
+        if not args:
+            return
+
+        assert(len(args) in (4, 6))
+
+        base, axis_object = args[:2]
+        args = args[2:]
+
+        self.setBase(base)
+        self.setAxisObject(axis_object)
+
+        if len(args) == 4:
+            self.setPlanesAndOffsets(*args)
+        elif len(args) == 2:
+            self.setAngles(*args)
+
+        self.execute()
+        pass
+
+    def __clear(self):
+        self._CreationMethod.setValue("ByAngles")
+        self._fillAttribute(self._to_angle, 0)
+        self._fillAttribute(self._from_angle, 0)
+        self._fillAttribute(self._to_object, None)
+        self._fillAttribute(self._to_offset, 0)
+        self._fillAttribute(self._from_object, None)
+        self._fillAttribute(self._from_offset, 0)
+        pass
+
+    def setBase(self, base):
+        """Modify base attribute of the feature.
+
+        See __init__.
+        """
+        self._fillAttribute(self._base, base)
+        pass
+
+    def setAxisObject(self, axis_object):
+        """Modify axis_object attribute of the feature.
+
+        See __init__.
+        """
+        self._fillAttribute(self._axis_object, axis_object)
+        pass
+
+    def setAngles(self, to_angle, from_angle):
+        """Modify the to_angle, from_angle attributes of the feature.
+
+        See __init__.
+        """
+        self.__clear()
+        self._CreationMethod.setValue("ByAngles")
+        self._fillAttribute(self._to_angle, to_angle)
+        self._fillAttribute(self._from_angle, from_angle)
+        pass
+
+    def setPlanesAndOffsets(self, to_object, to_offset,
+                            from_object, from_offset):
+        """Modify planes and offsets attributes of the feature.
+
+        See __init__.
+        """
+        self.__clear()
+        self._CreationMethod.setValue("ByPlanesAndOffsets")
+        self._fillAttribute(self._to_object, to_object)
+        self._fillAttribute(self._to_offset, to_offset)
+        self._fillAttribute(self._from_object, from_object)
+        self._fillAttribute(self._from_offset, from_offset)
+        pass
diff --git a/src/PythonAPI/model/features/revolution_boolean.py b/src/PythonAPI/model/features/revolution_boolean.py
new file mode 100644 (file)
index 0000000..d83642d
--- /dev/null
@@ -0,0 +1,184 @@
+"""RevolutionCut and RevolutionFuse Interface
+Author: Sergey Pokhodenko
+Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+"""
+
+from .roots import CompositeBoolean
+
+
+def addRevolutionCut(part, *args):
+    """Add a RevolutionCut feature to the Part.
+
+    .. function:: addRevolutionCut(part, sketch, sketch_selection, boolean_objects, axis_object, to_angle, from_angle)
+
+    Args:
+        part (ModelAPI_Document): part document
+        sketch (ModelAPI_Object): sketch feature
+        sketch_selection (Selection): sketch objects
+        boolean_objects (list of Selection): boolean objects
+        axis_object (Selection): axis object
+        to_size (double): upper size of the extrusion
+        from_size (double): lower size of the extrusion
+
+    .. function:: addRevolutionCut(part, sketch, sketch_selection, boolean_objects, axis_object, to_object, to_offset, from_object, from_offset)
+
+    Args:
+        part (ModelAPI_Document): part document
+        sketch (ModelAPI_Object): sketch feature
+        sketch_selection (Selection): sketch objects
+        boolean_objects (list of Selection): boolean objects
+        axis_object (Selection): axis object
+        to_object (Selection): upper plane
+        to_offset (double): offset from upper plane
+        from_object (Selection): lower plane
+        from_offset (double): offset from lower plane
+
+    Returns:
+        RevolutionBoolean: revolution boolean object
+    """
+    assert(args)
+    feature = part.addFeature("RevolutionCut")
+    return RevolutionBoolean(feature, *args)
+
+def addRevolutionFuse(part, *args):
+    """Add a RevolutionFuse feature to the Part.
+
+    .. function:: addRevolutionFuse(part, sketch, sketch_selection, boolean_objects, axis_object, to_angle, from_angle)
+
+    Args:
+        part (ModelAPI_Document): part document
+        sketch (ModelAPI_Object): sketch feature
+        sketch_selection (Selection): sketch objects
+        boolean_objects (list of Selection): boolean objects
+        axis_object (Selection): axis object
+        to_size (double): upper size of the extrusion
+        from_size (double): lower size of the extrusion
+
+    .. function:: addRevolutionFuse(part, sketch, sketch_selection, boolean_objects, axis_object, to_object, to_offset, from_object, from_offset)
+
+    Args:
+        part (ModelAPI_Document): part document
+        sketch (ModelAPI_Object): sketch feature
+        sketch_selection (Selection): sketch objects
+        boolean_objects (list of Selection): boolean objects
+        axis_object (Selection): axis object
+        to_object (Selection): upper plane
+        to_offset (double): offset from upper plane
+        from_object (Selection): lower plane
+        from_offset (double): offset from lower plane
+
+
+    Pass all args to RevolutionFuse __init__ function.
+
+    Returns:
+        RevolutionBoolean: revolution boolean object
+    """
+    assert(args)
+    feature = part.addFeature("RevolutionFuse")
+    return RevolutionBoolean(feature, *args)
+
+
+class RevolutionBoolean(CompositeBoolean):
+    """Interface class for RevolutionBoolean features.
+
+    Supported features:
+
+    * RevolutionCut
+    * RevolutionFuse
+
+    .. function:: RevolutionBoolean(feature)
+
+        Create interface for the feature without initialization.
+
+    .. function:: RevolutionBoolean(feature, sketch, sketch_selection, boolean_objects, axis_object, to_angle, from_angle)
+
+        Create interface for the feature and initialize the feature with arguments.
+
+    .. function:: RevolutionBoolean(feature, sketch, sketch_selection, boolean_objects, axis_object, to_object, to_offset, from_object, from_offset)
+
+        Create interface for the feature and initialize the feature with arguments.
+    """
+
+    def __init__(self, feature, *args):
+        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
+        CompositeBoolean.__init__(self, feature, *args[:3])
+        args = args[3:]
+
+        self._axis_object = self._feature.data().selection("axis_object")
+        self._CreationMethod = self._feature.string("CreationMethod")
+        self._to_angle = self._feature.data().real("to_angle")
+        self._from_angle = self._feature.data().real("from_angle")
+        self._to_object = self._feature.data().selection("to_object")
+        self._to_offset = self._feature.data().real("to_offset")
+        self._from_object = self._feature.data().selection("from_object")
+        self._from_offset = self._feature.data().real("from_offset")
+
+        assert(self._axis_object)
+        assert(self._CreationMethod)
+        assert(self._to_angle)
+        assert(self._from_angle)
+        assert(self._to_object)
+        assert(self._to_offset)
+        assert(self._from_object)
+        assert(self._from_offset)
+
+        if not args:
+            return
+
+        assert(len(args) in (3, 5))
+        axis_object = args[0]
+        args = args[1:]
+
+        self.setAxisObject(axis_object)
+
+        if len(args) == 4:
+            self.setPlanesAndOffsets(*args)
+        elif len(args) == 2:
+            self.setAngles(*args)
+
+        self.execute()
+        pass
+
+    def __clear(self):
+        self._CreationMethod.setValue("ByAngles")
+        self._fillAttribute(self._to_angle, 0)
+        self._fillAttribute(self._from_angle, 0)
+        self._fillAttribute(self._to_object, None)
+        self._fillAttribute(self._to_offset, 0)
+        self._fillAttribute(self._from_object, None)
+        self._fillAttribute(self._from_offset, 0)
+        pass
+
+    def setAxisObject(self, axis_object):
+        """Modify axis_object attribute of the feature.
+
+        See __init__.
+        """
+        self._fillAttribute(self._axis_object, axis_object)
+        pass
+
+    def setAngles(self, to_angle, from_angle):
+        """Modify the to_angle, from_angle attributes of the feature.
+
+        See __init__.
+        """
+        self.__clear()
+        self._CreationMethod.setValue("ByAngles")
+        self._fillAttribute(self._to_angle, to_angle)
+        self._fillAttribute(self._from_angle, from_angle)
+        pass
+
+    def setPlanesAndOffsets(self, to_object, to_offset,
+                            from_object, from_offset):
+        """Modify planes and offsets attributes of the feature.
+
+        See __init__.
+        """
+        self.__clear()
+        self._CreationMethod.setValue("ByPlanesAndOffsets")
+        self._fillAttribute(self._to_object, to_object)
+        self._fillAttribute(self._to_offset, to_offset)
+        self._fillAttribute(self._from_object, from_object)
+        self._fillAttribute(self._from_offset, from_offset)
+        pass
+
diff --git a/src/PythonAPI/model/features/revolution_sketch.py b/src/PythonAPI/model/features/revolution_sketch.py
new file mode 100644 (file)
index 0000000..1e0c9a6
--- /dev/null
@@ -0,0 +1,140 @@
+"""RevolutionSketch Interface
+Author: Sergey Pokhodenko
+Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+"""
+
+from .roots import CompositeSketch
+
+
+def addRevolutionSketch(part, *args):
+    """Add a RevolutionSketch feature to the Part.
+
+    .. function:: addRevolutionSketch(part, sketch, sketch_selection, axis_object, to_angle, from_angle)
+
+    Args:
+        part (ModelAPI_Document): part document
+        sketch (ModelAPI_Object): sketch feature
+        sketch_selection (Selection): sketch objects
+        axis_object (Selection): axis object
+        to_size (double): upper size of the extrusion
+        from_size (double): lower size of the extrusion
+
+    .. function:: addRevolutionSketch(part, sketch, sketch_selection, axis_object, to_object, to_offset, from_object, from_offset)
+
+    Args:
+        part (ModelAPI_Document): part document
+        sketch (ModelAPI_Object): sketch feature
+        sketch_selection (Selection): sketch objects
+        axis_object (Selection): axis object
+        to_object (Selection): upper plane
+        to_offset (double): offset from upper plane
+        from_object (Selection): lower plane
+        from_offset (double): offset from lower plane
+
+    Returns:
+        RevolutionSketch: revolution sketch object
+    """
+    assert(args)
+    feature = part.addFeature("RevolutionSketch")
+    return RevolutionSketch(feature, *args)
+
+
+class RevolutionSketch(CompositeSketch):
+    """Interface class for RevolutionSketch features.
+
+    .. function:: RevolutionSketch(feature)
+
+        Create interface for the feature without initialization.
+
+    .. function:: RevolutionSketch(feature, sketch, sketch_selection, to_size, from_size)
+
+        Create interface for the feature and initialize the feature with arguments.
+
+    .. function:: RevolutionSketch(feature, sketch, sketch_selection, to_object, to_offset, from_object, from_offset)
+
+        Create interface for the feature and initialize the feature with arguments.
+    """
+
+    def __init__(self, feature, *args):
+        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
+        CompositeSketch.__init__(self, feature, *args[:2])
+        args = args[2:]
+
+        self._axis_object = self._feature.data().selection("axis_object")
+        self._CreationMethod = self._feature.string("CreationMethod")
+        self._to_angle = self._feature.data().real("to_angle")
+        self._from_angle = self._feature.data().real("from_angle")
+        self._to_object = self._feature.data().selection("to_object")
+        self._to_offset = self._feature.data().real("to_offset")
+        self._from_object = self._feature.data().selection("from_object")
+        self._from_offset = self._feature.data().real("from_offset")
+
+        assert(self._axis_object)
+        assert(self._CreationMethod)
+        assert(self._to_angle)
+        assert(self._from_angle)
+        assert(self._to_object)
+        assert(self._to_offset)
+        assert(self._from_object)
+        assert(self._from_offset)
+
+        if not args:
+            return
+
+        assert(len(args) in (3, 5))
+        axis_object = args[0]
+        args = args[1:]
+
+        self.setAxisObject(axis_object)
+
+        if len(args) == 4:
+            self.setPlanesAndOffsets(*args)
+        elif len(args) == 2:
+            self.setAngles(*args)
+
+        self.execute()
+        pass
+
+    def __clear(self):
+        self._CreationMethod.setValue("ByAngles")
+        self._fillAttribute(self._to_angle, 0)
+        self._fillAttribute(self._from_angle, 0)
+        self._fillAttribute(self._to_object, None)
+        self._fillAttribute(self._to_offset, 0)
+        self._fillAttribute(self._from_object, None)
+        self._fillAttribute(self._from_offset, 0)
+        pass
+
+    def setAxisObject(self, axis_object):
+        """Modify axis_object attribute of the feature.
+
+        See __init__.
+        """
+        self._fillAttribute(self._axis_object, axis_object)
+        pass
+
+    def setAngles(self, to_angle, from_angle):
+        """Modify the to_angle, from_angle attributes of the feature.
+
+        See __init__.
+        """
+        self.__clear()
+        self._CreationMethod.setValue("ByAngles")
+        self._fillAttribute(self._to_angle, to_angle)
+        self._fillAttribute(self._from_angle, from_angle)
+        pass
+
+    def setPlanesAndOffsets(self, to_object, to_offset,
+                            from_object, from_offset):
+        """Modify planes and offsets attributes of the feature.
+
+        See __init__.
+        """
+        self.__clear()
+        self._CreationMethod.setValue("ByPlanesAndOffsets")
+        self._fillAttribute(self._to_object, to_object)
+        self._fillAttribute(self._to_offset, to_offset)
+        self._fillAttribute(self._from_object, from_object)
+        self._fillAttribute(self._from_offset, from_offset)
+        pass
+
diff --git a/src/PythonAPI/model/features/roots.py b/src/PythonAPI/model/features/roots.py
new file mode 100644 (file)
index 0000000..2aeacfe
--- /dev/null
@@ -0,0 +1,94 @@
+
+from model.roots import Interface
+
+
+class CompositeBoolean(Interface):
+    """Interface class for CompositeBoolean features.
+
+    CompositeBoolean(feature) -> feature interface without initialization
+    CompositeBoolean(feature, sketch, sketch_selection, boolean_objects) ->
+        feature interface initialized from arguments:
+        - sketch
+        - sketch_selection
+        - boolean_objects
+    """
+
+    def __init__(self, feature, *args):
+        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
+        Interface.__init__(self, feature)
+
+        self._sketch = self._feature.reference("sketch")
+        self._sketch_selection = self._feature.selection("sketch_selection")
+        self._boolean_objects = self._feature.selectionList("boolean_objects")
+
+        assert(self._sketch)
+        assert(self._sketch_selection)
+        assert(self._boolean_objects)
+
+        if not args:
+            return
+
+        assert(len(args) == 3)
+        sketch, sketch_selection, boolean_objects = args
+
+        self.setSketch(sketch)
+        self.setSketchSelection(sketch_selection)
+        self.setBooleanObjects(boolean_objects)
+        pass
+
+    def setSketch(self, sketch):
+        """Modify sketch attribute"""
+        self._fillAttribute(self._sketch, sketch)
+        pass
+
+    def setSketchSelection(self, sketch_selection):
+        """Modify sketch_selection attribute"""
+        self._fillAttribute(self._sketch_selection, sketch_selection)
+        pass
+
+    def setBooleanObjects(self, boolean_objects):
+        """Modify boolean_objects attribute"""
+        self._fillAttribute(self._boolean_objects, boolean_objects)
+        pass
+
+
+class CompositeSketch(Interface):
+    """Interface class for CompositeSketch features.
+
+    CompositeSketch(feature) -> feature interface without initialization
+    CompositeSketch(feature, sketch, sketch_selection) ->
+        feature interface initialized from arguments:
+        - sketch
+        - sketch_selection
+    """
+
+
+    def __init__(self, feature, *args):
+        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
+        Interface.__init__(self, feature)
+
+        self._sketch = self._feature.reference("sketch")
+        self._sketch_selection = self._feature.selection("sketch_selection")
+
+        assert(self._sketch)
+        assert(self._sketch_selection)
+
+        if not args:
+            return
+
+        assert(len(args) == 2)
+        sketch, sketch_selection = args
+
+        self.setSketch(sketch)
+        self.setSketchSelection(sketch_selection)
+        pass
+
+    def setSketch(self, sketch):
+        """Modify sketch attribute"""
+        self._fillAttribute(self._sketch, sketch)
+        pass
+
+    def setSketchSelection(self, sketch_selection):
+        """Modify sketch_selection attribute"""
+        self._fillAttribute(self._sketch_selection, sketch_selection)
+        pass
diff --git a/src/PythonAPI/model/features/rotation.py b/src/PythonAPI/model/features/rotation.py
new file mode 100644 (file)
index 0000000..4ec1745
--- /dev/null
@@ -0,0 +1,86 @@
+"""Rotation Interface
+Author: Sergey Pokhodenko
+Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+"""
+
+from model.roots import Interface
+
+
+def addRotation(part, *args):
+    """Add a Rotation feature to the Part.
+
+    .. function:: addRotation(part, main_objects, axis_object, angle)
+
+    Args:
+        part (ModelAPI_Document): part document
+        main_objects (list of Selection): main objects
+        axis_object (list of Selection): axis object
+        angle (double): angle
+
+    Returns:
+        Rotation: rotation object
+    """
+    assert(args)
+    feature = part.addFeature("Rotation")
+    return Rotation(feature, *args)
+
+
+class Rotation(Interface):
+    """Interface class for Rotation features.
+
+    .. function:: Rotation(feature)
+
+        Create interface for the feature without initialization.
+
+    .. function:: Rotation(feature, main_objects, axis_object, angle)
+
+        Create interface for the feature and initialize the feature with arguments.
+    """
+
+    def __init__(self, feature, *args):
+        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
+        Interface.__init__(self, feature)
+        assert(self._feature.getKind() == "Rotation")
+
+        self._main_objects = self._feature.data().selectionList("main_objects")
+        self._axis_object = self._feature.data().selection("axis_object")
+        self._angle = self._feature.data().real("angle")
+
+        assert(self._main_objects)
+        assert(self._axis_object)
+        assert(self._angle)
+
+        if not args:
+            return
+
+        assert(len(args) == 3)
+        self.setMainObjects(args[0])
+        self.setAxisObject(args[1])
+        self.setAngle(args[2])
+
+        self.execute()
+        pass
+
+    def setMainObjects(self, main_objects):
+        """Modify main_objects attribute of the feature.
+
+        See __init__.
+        """
+        self._fillAttribute(self._main_objects, main_objects)
+        pass
+
+    def setAxisObject(self, axis_object):
+        """Modify axis_object attribute of the feature.
+
+        See __init__.
+        """
+        self._fillAttribute(self._axis_object, axis_object)
+        pass
+
+    def setAngle(self, angle):
+        """Modify angle attribute of the feature.
+
+        See __init__.
+        """
+        self._fillAttribute(self._angle, angle)
+        pass
diff --git a/src/PythonAPI/model/features/translation.py b/src/PythonAPI/model/features/translation.py
new file mode 100644 (file)
index 0000000..171c988
--- /dev/null
@@ -0,0 +1,86 @@
+"""Translation Interface
+Author: Sergey Pokhodenko
+Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+"""
+
+from model.roots import Interface
+
+
+def addTranslation(part, *args):
+    """Add a Translation feature to the Part.
+
+    .. function:: addTranslation(part, main_objects, axis_object, distance)
+
+    Args:
+        part (ModelAPI_Document): part document
+        main_objects (list of Selection): main objects
+        axis_object (Selection): axis objects
+        distance (double): distance
+
+    Returns:
+        Translation: translation object
+    """
+    assert(args)
+    feature = part.addFeature("Translation")
+    return Translation(feature, *args)
+
+
+class Translation(Interface):
+    """Interface class for Translation features.
+
+    .. function:: Translation(feature)
+
+        Create interface for the feature without initialization.
+
+    .. function:: Translation(feature, main_objects, axis_object, distance)
+
+        Create interface for the feature and initialize the feature with arguments.
+    """
+
+    def __init__(self, feature, *args):
+        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
+        Interface.__init__(self, feature)
+        assert(self._feature.getKind() == "Translation")
+
+        self._main_objects = self._feature.data().selectionList("main_objects")
+        self._axis_object = self._feature.data().selection("axis_object")
+        self._distance = self._feature.data().real("distance")
+
+        assert(self._main_objects)
+        assert(self._axis_object)
+        assert(self._distance)
+
+        if not args:
+            return
+
+        assert(len(args) == 3)
+        self.setMainObjects(args[0])
+        self.setAxisObject(args[1])
+        self.setDistance(args[2])
+
+        self.execute()
+        pass
+
+    def setMainObjects(self, main_objects):
+        """Modify main_objects attribute of the feature.
+
+        See __init__.
+        """
+        self._fillAttribute(self._main_objects, main_objects)
+        pass
+
+    def setAxisObject(self, axis_object):
+        """Modify axis_object attribute of the feature.
+
+        See __init__.
+        """
+        self._fillAttribute(self._axis_object, axis_object)
+        pass
+
+    def setDistance(self, distance):
+        """Modify distance attribute of the feature.
+
+        See __init__.
+        """
+        self._fillAttribute(self._distance, distance)
+        pass
diff --git a/src/PythonAPI/model/parameter/__init__.py b/src/PythonAPI/model/parameter/__init__.py
new file mode 100644 (file)
index 0000000..44bde3f
--- /dev/null
@@ -0,0 +1,4 @@
+"""Package for Parameter plugin for the Parametric Geometry API of the Modeler.
+"""
+
+from parameter import addParameter
\ No newline at end of file
diff --git a/src/PythonAPI/model/parameter/parameter.py b/src/PythonAPI/model/parameter/parameter.py
new file mode 100644 (file)
index 0000000..d29719c
--- /dev/null
@@ -0,0 +1,76 @@
+"""Parameter Interface
+Author: Sergey Pokhodenko
+Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+"""
+
+from model.roots import Interface
+
+
+def addParameter(part, *args):
+    """Add a Parameter feature to the Part and return Parameter.
+
+    .. function:: addParameter(part, variable, expression)
+
+    Args:
+        part (ModelAPI_Document): part document
+        variable (string): variable name
+        expression (string): Python expression
+
+    Returns:
+        Parameter: parameter object
+
+    Pass all args to Parameter __init__ function.
+    """
+    assert(args)
+    feature = part.addFeature("Parameter")
+    return Parameter(feature, *args)
+
+
+class Parameter(Interface):
+    """Interface class for Parameter feature.
+
+    .. function:: Point(feature)
+
+        Create interface for the feature without initialization.
+
+    .. function:: Point(feature, variable, expression)
+
+        Create interface for the feature and initialize the feature with arguments.
+    """
+
+    def __init__(self, feature, *args):
+        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
+        Interface.__init__(self, feature)
+        assert(self._feature.getKind() == "Parameter")
+
+        self._variable = self._feature.data().string("variable")
+        self._expression = self._feature.data().string("expression")
+
+        assert(self._variable)
+        assert(self._expression)
+
+        if not args:
+            return
+
+        assert(len(args) == 2)
+        self.setName(args[0])
+        self.setExpression(args[1])
+
+        self.execute()
+        pass
+
+    def setName(self, name):
+        """Modify variable name attribute of the feature.
+
+        See __init__.
+        """
+        self._fillAttribute(self._name, name)
+        pass
+
+    def setExpression(self, expression):
+        """Modify expression attribute of the feature.
+
+        See __init__.
+        """
+        self._fillAttribute(self._expression, expression)
+        pass
diff --git a/src/PythonAPI/model/partset/__init__.py b/src/PythonAPI/model/partset/__init__.py
new file mode 100644 (file)
index 0000000..33eed0d
--- /dev/null
@@ -0,0 +1,4 @@
+"""Package for PartSet plugin for the Parametric Geometry API of the Modeler.
+"""
+
+from part import addPart, duplicatePart, removePart
\ No newline at end of file
diff --git a/src/PythonAPI/model/partset/part.py b/src/PythonAPI/model/partset/part.py
new file mode 100644 (file)
index 0000000..7954830
--- /dev/null
@@ -0,0 +1,65 @@
+"""Part Feature Interface
+Author: Daniel Brunier-Coulin
+Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+"""
+
+import ModelAPI
+
+from model.roots import Interface
+
+
+def addPart(partset):
+    """Add a Part feature to the Part and return Part.
+
+    Args:
+        partset (ModelAPI_Document): partset document
+
+    Returns:
+        Part: part object
+    """
+    feature = partset.addFeature("Part")
+    return Part(feature)
+
+def duplicatePart(part):
+    """Create a copy of the Part.
+
+    Args:
+        part (ModelAPI_Document): part document
+
+    Returns:
+        Part: part object
+    """
+    feature = part.addFeature("Duplicate")
+    feature.execute()
+    return Part(feature)
+
+def removePart(part):
+    """Remove the Part.
+
+    Args:
+        part (ModelAPI_Document): part document
+    """
+    feature = part.addFeature("Remove")
+    feature.execute()
+
+
+class Part(Interface):
+    """Interface class for Part feature.
+
+    .. function:: Part(feature)
+
+        Create interface for the feature without initialization.
+    """
+
+    def __init__(self, feature):
+        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
+        Interface.__init__(self, feature)
+        assert(self._feature.getKind() == "Part")
+
+        self.execute()
+        pass
+
+    def document(self):
+        """Returns the Part document created by this feature."""
+        result_part = ModelAPI.modelAPI_ResultPart(self._feature.firstResult())
+        return result_part.partDoc()
diff --git a/src/PythonAPI/model/roots.py b/src/PythonAPI/model/roots.py
new file mode 100644 (file)
index 0000000..5f1c294
--- /dev/null
@@ -0,0 +1,103 @@
+"""Abstract root classes of user-defined Python features producing a Body
+Author: Daniel Brunier-Coulin
+Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+"""
+
+import ModelAPI
+
+from model import tools
+
+
+class Feature(ModelAPI.ModelAPI_Feature):
+    """Base class of user-defined Python features."""
+
+    def __init__(self):
+        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
+        ModelAPI.ModelAPI_Feature.__init__(self)
+
+    def addRealInput(self, inputid):
+        """F.addRealInput(str) -- add real attribute"""
+        self.data().addAttribute(inputid,
+                                 ModelAPI.ModelAPI_AttributeDouble_typeId())
+
+    def getRealInput(self, inputid):
+        """F.getRealInput(str) -- get real value of the attribute"""
+        return self.data().real(inputid).value()
+
+    def addResult(self, result):
+        """F.addResult(ModelAPI_Result) -- add ModelAPI_Result shape as a result"""
+        shape = result.shape()
+        body = self.document().createBody(self.data())
+        body.store(shape)
+        self.setResult(body)
+
+
+class Interface():
+    """Base class of high level Python interfaces to features."""
+
+    def __init__(self, feature):
+        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
+        self._feature = feature
+
+    def __getattr__(self, name):
+        """Process missing attributes.
+
+        Add get*() methods for access feature attributes.
+        """
+        if name.startswith("get"):
+            possible_names = [
+                "_" + name[3:],
+                "_" + tools.convert_to_underscore(name[3:]),
+                ]
+            for possible_name in possible_names:
+                if hasattr(self, possible_name):
+                    def getter():
+                        return getattr(self, possible_name)
+                    return getter
+
+        raise AttributeError()
+
+    def _fillAttribute(self, attribute, value):
+        """Fill ModelAPI_Attribute* with value."""
+        tools.fill_attribute(attribute, value)
+
+    def feature(self):
+        """Return ModelAPI_Feature."""
+        return self._feature
+
+    def getKind(self):
+        """Return the unique kind of the feature"""
+        return self._feature.getKind()
+
+    def results(self):
+        """Return current results of the feature"""
+        return self._feature.results()
+
+    def firstResult(self):
+        """Return the first result in the list of results"""
+        return self._feature.firstResult()
+
+    def lastResult(self):
+        """Return the last result in the list of results"""
+        return self._feature.lastResult()
+
+    def setRealInput(self, inputid, value):
+        """I.setRealInput(str, float) -- set real value to the attribute"""
+        self._feature.data().real(inputid).setValue(value)
+
+    def areInputValid(self):
+        """I.areInputValid() -> True or False validation result"""
+        validators = ModelAPI.ModelAPI_Session.get().validators()
+        return validators.validate(self._feature)
+
+    def execute(self):
+        """I.execute() -- validate and execute the feature.
+
+        Raises RuntimeError if validation fails.
+        """
+        if self.areInputValid():
+            self._feature.execute()
+        else:
+            raise RuntimeError("Can not execute %s: %s" %
+                               (self._feature.getKind(), self._feature.error())
+                               )
diff --git a/src/PythonAPI/model/services.py b/src/PythonAPI/model/services.py
new file mode 100644 (file)
index 0000000..962087b
--- /dev/null
@@ -0,0 +1,89 @@
+"""General purpose Interface
+Author: Daniel Brunier-Coulin
+Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+"""
+
+import ModelAPI
+import GeomAPI
+
+import geom  # To be removed when gp_Ax3 will be Pythonized
+
+
+def moduleDocument ():
+    """Return the main document (the Partset) created or open from the Modeler.
+
+    This document is unique in the application session.
+    """
+    return ModelAPI.ModelAPI_Session.get().moduleDocument()
+
+
+def activeDocument ():
+    """Return the active document.
+
+    This document can be either the main application document (i.e. the Partset) or one of documents
+    referred to by the main document (a Part).
+    """
+    return ModelAPI.ModelAPI_Session.get().activeDocument()
+
+
+def defaultPlane (name):
+    """Return one of the three planes defined by the global coordinate system.
+
+    These planes are respectively referred to by name "XOY" (Z=0), "XOZ" (Y=0) or "YOZ" (X=0).
+    """
+    # Temporary implementation before the availability of default planes.
+    o = GeomAPI.GeomAPI_Pnt(0, 0, 0)
+    if   name == "XOY":
+        n = GeomAPI.GeomAPI_Dir(0, 0, 1)
+        x = GeomAPI.GeomAPI_Dir(1, 0, 0)
+    elif name == "XOZ":
+        n = GeomAPI.GeomAPI_Dir(0, 1, 0)
+        x = GeomAPI.GeomAPI_Dir(1, 0, 0)
+    elif name == "YOZ":
+        n = GeomAPI.GeomAPI_Dir(1, 0, 0)
+        x = GeomAPI.GeomAPI_Dir(0, 1, 0)
+
+    return geom.Ax3(o, n, x)
+
+
+def begin ():
+    """Start a data structure transaction.
+
+    Make a control point for being able to discard or undo
+    all operations done during this transaction.
+    """
+    ModelAPI.ModelAPI_Session.get().startOperation()
+
+
+def end ():
+    """Commit the data structure transaction.
+
+    Make all operations done since the last control point undo-able.
+    """
+    ModelAPI.ModelAPI_Session.get().finishOperation()
+
+
+def do ():
+    """Commit the data structure transaction and start the new one.
+
+    Make all operations done since the last control point undo-able
+    and continue with the new transaction.
+    """
+    session = ModelAPI.ModelAPI_Session.get()
+    session.finishOperation()
+    session.startOperation()
+
+
+def undo ():
+    """Roll-back the data structure to the previous control point."""
+    ModelAPI.ModelAPI_Session.get().undo()
+
+
+def redo ():
+    """Restore the data structure rolled-back by the last undo."""
+    ModelAPI.ModelAPI_Session.get().redo()
+
+
+def reset ():
+    """Reset the data structure to initial state."""
+    ModelAPI.ModelAPI_Session.get().closeAll()
diff --git a/src/PythonAPI/model/sketcher/__init__.py b/src/PythonAPI/model/sketcher/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/PythonAPI/model/sketcher/arc.py b/src/PythonAPI/model/sketcher/arc.py
new file mode 100644 (file)
index 0000000..212666a
--- /dev/null
@@ -0,0 +1,95 @@
+"""Sketch circle feature interface."""
+
+from GeomDataAPI import geomDataAPI_Point2D
+from model.errors import WrongNumberOfArguments
+from model.roots import Interface
+
+class Arc(Interface):
+    """Interface to a sketch arc feature."""
+    def __init__(self, feature, *args):
+        Interface.__init__(self, feature)
+        assert(self._feature.getKind() == "SketchArc")
+
+        self._center = geomDataAPI_Point2D(
+            self._feature.data().attribute("ArcCenter")
+            )
+        self._start_point = geomDataAPI_Point2D(
+            self._feature.data().attribute("ArcStartPoint")
+            )
+        self._end_point = geomDataAPI_Point2D(
+            self._feature.data().attribute("ArcEndPoint")
+            )
+        if len(args) == 6:
+            self.__createByCoordinates(*args)
+        elif len(args) == 3:
+            self.__createByPoints(*args)
+        else:
+            raise WrongNumberOfArguments(
+                "Arc takes 3 or 6 arguments (%s given)" % len(args)
+                )
+        self.execute()
+        
+        
+    ########
+    #
+    # Getters
+    #
+    ########
+
+
+    def center(self):
+        """Return the center point."""
+        return self._center
+
+    def startPoint(self):
+        """Return the start point."""
+        return self._start_point
+
+    def endPoint(self):
+        """Return the end point."""
+        return self._end_point
+
+    def result(self):
+        """Return the arc circular line attribute."""
+        return self._feature.lastResult()
+    
+        
+    ########
+    #
+    # Set methods
+    #
+    ########
+    
+    def setCenter(self, x, y):
+        """Set arc center."""
+        self._center.setValue(x, y)
+        
+    def setStartPoint(self, x, y):
+        """Set start point."""
+        self._start_point.setValue(x, y)
+        
+    def setEndPoint(self, x, y):
+        """Set end point value."""
+        self._end_point.setValue(x, y)
+
+
+    ########
+    #
+    # Private methods
+    #
+    ########
+
+
+    def __createByCoordinates(self, center_x, center_y,
+                              start_x, start_y,
+                              end_x, end_y):
+        """Create an arc by point coordinates."""
+        self.setCenter(center_x, center_y)
+        self.setStartPoint(start_x, start_y)
+        self.setEndPoint(end_x, end_y)
+
+    def __createByPoints(self, center, start, end):
+        """Create an arc with point objects."""
+        self.setCenter(center.x(), center.y())
+        self.setStartPoint(start.x(), start.y())
+        self.setEndPoint(end.x(), end.y())
diff --git a/src/PythonAPI/model/sketcher/circle.py b/src/PythonAPI/model/sketcher/circle.py
new file mode 100644 (file)
index 0000000..a3ba89a
--- /dev/null
@@ -0,0 +1,52 @@
+"""Sketch circle feature interface."""
+
+from GeomDataAPI import geomDataAPI_Point2D
+from model.roots import Interface
+
+class Circle(Interface):
+    """Interface for circle feature data manipulation."""
+    def __init__(self, feature, *args):
+        Interface.__init__(self, feature)
+        assert(self._feature.getKind() == "SketchCircle")
+        
+        self._center = geomDataAPI_Point2D(
+            self._feature.data().attribute("CircleCenter")
+            )
+        self._radius = self._feature.data().real("CircleRadius")
+        
+        if not args:
+            return
+        
+        if len(args) != 3:
+            raise TypeError(
+                "Invalid number of arguments, 3 arguments needed  (%s given)" 
+                % len(args)
+                )
+        
+        self.setCenter(args[0], args[1])
+        self.setRadius(args[2])
+        self.execute()
+
+    def setCenter(self, x, y):
+        """Set the center of the circle."""
+        self._center.setValue(x, y)
+        
+    def setRadius(self, radius):
+        """Set the radius of the circle."""
+        self._radius.setValue(radius)
+        
+    def center(self):
+        """Return the center attribute of the circle."""
+        return self._center
+
+    def radius(self):
+        """Return the radius value.
+        
+        :return: radius
+        :rtype: double
+        """
+        return self._radius.value()
+
+    def result(self):
+        """Return the cicular line attribute."""
+        return self._feature.lastResult()
diff --git a/src/PythonAPI/model/sketcher/line.py b/src/PythonAPI/model/sketcher/line.py
new file mode 100644 (file)
index 0000000..d7bb70f
--- /dev/null
@@ -0,0 +1,71 @@
+from GeomDataAPI import geomDataAPI_Point2D
+from model.roots import Interface
+from model.errors import WrongNumberOfArguments
+
+class Line(Interface):
+    """Interface for editing of a sketch line feature."""
+    def __init__(self, feature, *args):
+        Interface.__init__(self, feature)
+        assert(self._feature.getKind() == "SketchLine")
+
+        # Initialize attributes
+        self._start_point = geomDataAPI_Point2D(
+            self._feature.data().attribute("StartPoint")
+            )
+        self._end_point = geomDataAPI_Point2D(
+            self._feature.data().attribute("EndPoint")
+            )
+
+        # If no arguments are given the attributes of the feature 
+        # are'nt initialized
+        if args is None:
+            return
+        
+        # Set attribute values and execute
+        if len(args) == 4:
+            self.__createByCoordinates(*args)
+        elif len(args) == 2:
+            self.__createByPoints(*args)
+        elif len(args) == 1:
+            self.__createByName(*args)
+        else:
+            raise WrongNumberOfArguments(
+                "Arc takes 1, 2 or 4 arguments (%s given)" % len(args)
+                )
+        self.execute()
+
+    def __createByCoordinates(self, x1, y1, x2, y2):
+        self.setStartPoint(x1, y1)
+        self.setEndPoint(x2, y2)
+
+    def __createByPoints(self, p1, p2):
+        self.setStartPoint(p1.x(), p1.y())
+        self.setEndPoint(p2.x(), p2.y())
+
+    def __createByName(self, name):
+        self._feature.data().selection("External").selectSubShape("EDGE", name)
+    
+    #######
+    #
+    # Set methods
+    #
+    #######
+    
+    def setStartPoint(self, x, y):
+        """Set the start point of the line."""
+        self._start_point.setValue(x, y)
+        
+    def setEndPoint(self, x, y):
+        """Set the end point of the line."""
+        self._end_point.setValue(x, y)
+
+    # TODO : methods below will be removed. 
+    # Kept until all tests have been updated
+    def startPointData(self):
+        return self._start_point
+
+    def endPointData(self):
+        return self._end_point
+
+    def result(self):
+        return self._feature.firstResult()
diff --git a/src/PythonAPI/model/sketcher/mirror.py b/src/PythonAPI/model/sketcher/mirror.py
new file mode 100644 (file)
index 0000000..dba62b4
--- /dev/null
@@ -0,0 +1,32 @@
+"""Sketch point feature interface."""
+
+from GeomDataAPI import geomDataAPI_Point2D
+from ModelAPI import ModelAPI_Feature
+from model.roots import Interface
+from model.errors import FeatureInputInvalid
+
+class Mirror(Interface):
+    """Interface on mirror constraint for data manipulation."""
+    def __init__(self, feature, mirror_line, *mirror_objects):
+        Interface.__init__(self, feature)
+        assert(self._feature.getKind() == "SketchConstraintMirror")
+        
+        self._feature.data().refattr("ConstraintEntityA").setObject(mirror_line)
+        self._feature.data().reflist("ConstraintEntityB").clear()
+        for object_ in mirror_objects:
+            self._feature.data().reflist("ConstraintEntityB").append(object_)
+            self._feature.data().reflist("ConstraintMirrorList").append(object_)
+        self.execute()
+
+    def mirroredObjects(self):
+        return self._feature.data().reflist("ConstraintEntityC")
+            #feature = ModelAPI_Feature(object_)
+            #if feature.getKind() == "SketchCircle":
+                #objects.append(Circle(feature))
+            #elif feature.getKind() == "SketchLine":
+                #objects.append(Line(feature))
+            #else:
+                #raise TypeError(
+                    #"%s is not a valid feature type" % feature.getKind()
+                    #)
+                
diff --git a/src/PythonAPI/model/sketcher/point.py b/src/PythonAPI/model/sketcher/point.py
new file mode 100644 (file)
index 0000000..603a623
--- /dev/null
@@ -0,0 +1,30 @@
+"""Sketch point feature interface."""
+
+from GeomDataAPI import geomDataAPI_Point2D
+from model.roots import Interface
+from model.errors import FeatureInputInvalid
+
+class Point(Interface):
+    """Interface on point feature for data manipulation."""
+    def __init__(self, feature, x, y):
+        Interface.__init__(self, feature)
+        assert(self._feature.getKind() == "SketchPoint")
+        
+        # Initialize attributes of the feature
+        self._point_data = geomDataAPI_Point2D(
+            self._feature.data().attribute("PointCoordinates")
+            )
+        self.setValue(x, y)
+        self.execute()
+
+    def setValue(self, x, y):
+        """Set point coordinates."""
+        self._point_data.setValue(x, y)
+
+    def pointData (self):
+        """Return the point data."""
+        return self._point_data
+
+    def result (self):
+        """Return the feature result."""
+        return self._point_feature.firstResult()
diff --git a/src/PythonAPI/model/sketcher/sketch.py b/src/PythonAPI/model/sketcher/sketch.py
new file mode 100644 (file)
index 0000000..aac7759
--- /dev/null
@@ -0,0 +1,441 @@
+# Author: Daniel Brunier-Coulin with contribution by Mikhail Ponikarov
+#         finalized by Renaud Nedelec and Sergey Pokhodenko
+# Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+"""Sketcher interface.
+This interface allows to add a sketch
+in a part or partset.
+The created sketch object provides all the needed methods 
+for sketch modification and constraint edition.
+
+Example of code:
+
+.. doctest:: 
+
+   >>> import model
+   >>> model.begin()
+   >>> partset = model.moduleDocument()
+   >>> part = model.addPart(partset).document()
+   >>> plane = model.defaultPlane("XOY")
+   >>> sketch = model.addSketch(part, plane)
+   >>> line = sketch.addLine(0, 0, 0, 1)
+   >>> line.endPointData().x()
+   0.0
+   >>> line.endPointData().y()
+   1.0
+"""
+
+from ModelAPI import modelAPI_ResultConstruction, featureToCompositeFeature
+from GeomDataAPI import geomDataAPI_Point, geomDataAPI_Dir
+from GeomAlgoAPI import GeomAlgoAPI_SketchBuilder, ShapeList
+
+from model.sketcher.point import Point
+from model.sketcher.line import Line
+from model.sketcher.circle import Circle
+from model.sketcher.arc import Arc
+from model.sketcher.mirror import Mirror
+from model.roots import Interface
+from model.tools import Selection
+
+
+def addSketch(document, plane):
+    """Add a sketch to a Part or PartSet.
+
+    Arguments:
+       document(ModelAPI_Document): part or partset document
+       plane(geom.Ax3): plane on wich the sketch is built
+    
+    Returns:
+       Sketch: sketch object
+    """
+    feature = featureToCompositeFeature(document.addFeature("Sketch"))
+    return Sketch(feature, plane)
+
+class Sketch(Interface):
+    """Interface class for Sketch feature."""
+    def __init__(self, feature, *args):
+        """Initialize a 2D Sketch on the given plane.
+
+        The plane can be defined either by:
+        - a 3D axis system (geom.Ax3),
+        - an existing face identified by its topological name.
+        """
+        Interface.__init__(self, feature)
+        assert(self._feature.getKind() == "Sketch")
+
+        self._origin = geomDataAPI_Point(
+            self._feature.data().attribute("Origin")
+            )
+        self._dir_x = geomDataAPI_Dir(
+            self._feature.data().attribute("DirX")
+            )
+        self._norm = geomDataAPI_Dir(
+            self._feature.data().attribute("Norm")
+            )
+        self._external = self._feature.data().selection("External")
+
+        # If no arguments are given the attributes of the feature 
+        # are not Initialized
+        if args is not None:
+            plane = args[0]
+            if isinstance(plane, str):
+                self.__sketchOnFace(plane)
+            else:
+                self.__sketchOnPlane(plane)
+
+    def __sketchOnPlane(self, plane):
+        """Create the sketch on a plane."""
+        origin = plane.location()
+        normal = plane.direction()
+        x_direction = plane.xDirection()
+        self._origin.setValue(origin.x(), origin.y(), origin.z())
+        self._norm.setValue(normal.x(), normal.y(), normal.z())
+        self._dir_x.setValue(x_direction.x(), x_direction.y(), x_direction.z())
+
+    def __sketchOnFace(self, name):
+        """Initialize the sketch on a face given by its name."""
+        self._external.selectSubShape("FACE", name)
+
+    #-------------------------------------------------------------
+    #
+    # Creation of Geometries
+    #
+    #-------------------------------------------------------------
+
+    def addPoint(self, *args):
+        """Add a point to the sketch."""
+        if not args:
+            raise TypeError("No arguments given")
+        point_feature = self._feature.addFeature("SketchPoint")
+        return Point(point_feature, *args)
+
+    def addLine(self, *args):
+        """Add a line to the sketch.
+        
+        .. function:: addLine(name)
+        Select an existing line. The line is added to the sketch with a rigid 
+        constraint (it cannot be modified by the sketch)
+        
+        Arguments:
+            name(str): name of an existing line
+        
+        .. function:: addLine(start, end)
+        Create a line by points
+        
+        Arguments:
+           start(point): start point of the line
+           end(point): end point of the line
+        
+        .. function:: addLine(start_x, start_y, end_x, end_y)
+        Create a line by coordinates
+        
+        Arguments:
+           start_x(double): start point x coordinate
+        """
+        if not args:
+            raise TypeError("No arguments given")
+        line_feature = self._feature.addFeature("SketchLine")
+        line_interface = Line(line_feature, *args)
+        # if the line is created by name add a rigid constraint
+        # to the created line
+        if len(args) == 1 and isinstance(args[0], str):
+            constraint = self._feature.addFeature("SketchConstraintRigid")
+            constraint.refattr("ConstraintEntityA").setObject(
+                line_feature.firstResult()
+                )
+        return line_interface
+
+    def addCircle(self, *args):
+        """Add a circle to this Sketch."""
+        if not args:
+            raise TypeError("No arguments given")
+        circle_feature = self._feature.addFeature("SketchCircle")
+        return Circle(circle_feature, *args)
+
+    def addArc(self, *args):
+        """Add an arc of circle to the sketch and return an arc object.
+        
+        Two different syntaxes are allowed:
+        
+        .. function:: addArc(center, start, end)
+        
+        Arguments:
+            center (point): center of the arc  
+            start (point): start point of the arc
+            end (point): end point of the arc
+        
+        .. function:: addArc(center_x, center_y, start_x, start_y, end_x, end_y)
+        
+        Same as above but with coordinates
+        
+        Returns:
+            Arc: arc object
+        Raises:
+            TypeError: if no argument is provided
+        """
+        if not args:
+            raise TypeError("No arguments given")
+        arc_feature = self._feature.addFeature("SketchArc")
+        return Arc(arc_feature, *args)
+
+    #-------------------------------------------------------------
+    #
+    # Creation of Geometrical and Dimensional Constraints
+    #
+    #-------------------------------------------------------------
+
+    def setCoincident(self, p1, p2):
+        """Set coincident the two given points and add the corresponding
+        constraint to this Sketch."""
+        # assert(p1 and p2) NOTE : if an argument is missing python
+        # will raise TypeError by itself.
+        # It seems better to check only that provided arguments are not 
+        # None
+        if p1 is None or p2 is None:
+            raise TypeError("NoneType argument given")
+        constraint = self._feature.addFeature("SketchConstraintCoincidence")
+        constraint.data().refattr("ConstraintEntityA").setAttr(p1)
+        constraint.data().refattr("ConstraintEntityB").setAttr(p2)
+        self.execute()
+        return constraint
+
+    def setParallel(self, l1, l2):
+        """Set parallel the two given lines and add the corresponding
+        constraint to this Sketch."""
+        if l1 is None or l2 is None:
+            raise TypeError("NoneType argument given")
+        constraint = self._feature.addFeature("SketchConstraintParallel")
+        constraint.data().refattr("ConstraintEntityA").setObject(l1)
+        constraint.data().refattr("ConstraintEntityB").setObject(l2)
+        self.execute()
+        return constraint
+
+    def setPerpendicular(self, l1, l2):
+        """Set perpendicular the two given lines and add the corresponding
+        constraint to this Sketch."""
+        if l1 is None or l2 is None:
+            raise TypeError("NoneType argument given")
+        constraint = self._feature.addFeature("SketchConstraintPerpendicular")
+        constraint.data().refattr("ConstraintEntityA").setObject(l1)
+        constraint.data().refattr("ConstraintEntityB").setObject(l2)
+        self.execute()
+        return constraint
+
+    def setHorizontal(self, line):
+        """Set horizontal the given line and add the corresponding
+        constraint to this Sketch."""
+        if line is None:
+            raise TypeError("NoneType argument given")
+        constraint = self._feature.addFeature("SketchConstraintHorizontal")
+        constraint.data().refattr("ConstraintEntityA").setObject(line)
+        self.execute()
+        return constraint
+
+    def setVertical(self, line):
+        """Set vertical the given line and add the corresponding
+        constraint to this Sketch."""
+        if line is None:
+            raise TypeError("NoneType argument given")
+        constraint = self._feature.addFeature("SketchConstraintVertical")
+        constraint.data().refattr("ConstraintEntityA").setObject(line)
+        self.execute()
+        return constraint
+
+    def setDistance(self, point, line, length):
+        """Set the distance between the given point and line, and add
+        the corresponding constraint to this Sketch."""
+        if point is None or line is None:
+            raise TypeError("NoneType argument given")
+        constraint = self._feature.addFeature("SketchConstraintDistance")
+        if isinstance(line, basestring):
+            # Add the edge identified by the given topological name
+            # to this Sketch
+            line = self.addLine(line).result()
+        constraint.data().refattr("ConstraintEntityA").setAttr(point)
+        constraint.data().refattr("ConstraintEntityB").setObject(line)
+        constraint.data().real("ConstraintValue").setValue(length)
+        self.execute()
+        return constraint
+
+    def setLength(self, line, length):
+        """Set the length of the given line and add the corresponding
+        constraint to this Sketch."""
+        if line is None:
+            raise TypeError("NoneType argument given")
+        constraint = self._feature.addFeature("SketchConstraintLength")
+        constraint.data().refattr("ConstraintEntityA").setObject(line)
+        constraint.data().real("ConstraintValue").setValue(length)
+        self.execute()
+        return constraint
+
+    def setRadius(self, circle, radius):
+        """Set the radius of the given circle and add the corresponding
+        constraint to this Sketch."""
+        constraint = self._feature.addFeature("SketchConstraintRadius")
+        constraint.data().refattr("ConstraintEntityA").setObject(circle)
+        constraint.data().real("ConstraintValue").setValue(radius)
+        self.execute()
+        return constraint
+
+    def setEqual(self, object_1, object_2):
+        """Set the radii of two circles or the length of two lines equal.
+
+        The corresponding constraint is added to the sketch"""
+        constraint = self._feature.addFeature("SketchConstraintEqual")
+        constraint.data().refattr("ConstraintEntityA").setObject(object_1)
+        constraint.data().refattr("ConstraintEntityB").setObject(object_2)
+        self.execute()
+        return constraint
+
+    def setAngle(self, line_1, line_2, angle):
+        """Set the angle between the given 2 lines and add the corresponding
+        constraint to the sketch."""
+        constraint = self._feature.addFeature("SketchConstraintAngle")
+        constraint.data().refattr("ConstraintEntityA").setObject(line_1)
+        constraint.data().refattr("ConstraintEntityB").setObject(line_2)
+        constraint.data().real("ConstraintValue").setValue(angle)
+        self.execute()
+        return constraint
+
+    def setTangent(self, object_1, object_2):
+        """Set a tangential continuity between two objects
+        at their coincidence point."""
+        if object_1 is None or object_2 is None:
+            raise TypeError("NoneType argument given")
+        constraint = self._feature.addFeature("SketchConstraintTangent")
+        constraint.data().refattr("ConstraintEntityA").setObject(object_1)
+        constraint.data().refattr("ConstraintEntityB").setObject(object_2)
+        self.execute()
+        return constraint
+
+    def setFillet(self, line_1, line_2, radius):
+        """Set a fillet constraint between the 2 given lines with the given
+        filleting radius."""
+        constraint = self._feature.addFeature("SketchConstraintFillet")
+        constraint.data().refattr("ConstraintEntityA").setObject(line_1)
+        constraint.data().reflist("ConstraintEntityB").clear()
+        constraint.data().reflist("ConstraintEntityB").append(line_2)
+        self.execute()
+        return constraint
+    
+    def setRigid(self, object_):
+        """Set a rigid constraint on a given object."""
+        constraint = self._feature.addFeature("SketchConstraintRigid")
+        constraint.data().refattr("ConstraintEntityA").setObject(object_)
+        self.execute()
+        return constraint
+    
+    #-------------------------------------------------------------
+    #
+    # Transformation constraints
+    #
+    #-------------------------------------------------------------
+    
+    def addMirror(self, mirror_line, sketch_objects):
+        """Add a mirror transformation of the given objects to the sketch.
+        
+        This transformation is a constraint.
+        
+        :return: interface to the constraint
+        :rtype: Mirror object
+        """
+        mirror_constraint = self._feature.addFeature("SketchConstraintMirror")
+        mirror_interface = Mirror(mirror_constraint, mirror_line, sketch_objects)
+        self.execute()
+        return mirror_interface
+        
+
+    #-------------------------------------------------------------
+    #
+    # Edition of Dimensional Constraints
+    #
+    #-------------------------------------------------------------
+
+    def setValue(self, constraint, value):
+        """Modify the value of the given dimensional constraint."""
+        constraint.data().real("ConstraintValue").setValue(value)
+
+    #-------------------------------------------------------------
+    #
+    # Macro functions combining geometry creation and constraints
+    #
+    #-------------------------------------------------------------
+
+    def addPolyline(self, *coords):
+        """Add a poly-line to this Sketch.
+
+        The end of consecutive segments are defined as coincident.
+        """
+        c0 = coords[0]
+        c1 = coords[1]
+        polyline = []
+        line_1 = self.addLine(c0, c1)
+        polyline.append(line_1)
+        # Adding and connecting next lines
+        for c2 in coords[2:]:
+            line_2 = self.addLine(c1, c2)
+            self.setCoincident(line_1.endPointData(), line_2.startPointData())
+            polyline.append(line_2)
+            c1 = c2
+            line_1 = line_2
+        return polyline
+
+    def addPolygon(self, *coords):
+        """Add a polygon to this Sketch.
+
+        The end of consecutive segments are defined as coincident.
+        """
+        pg = self.addPolyline(*coords)
+        # Closing the poly-line supposed being defined by at least 3 points
+        c0 = coords[0]
+        cn = coords[len(coords) - 1]
+        ln = self.addLine(cn, c0)
+        self.setCoincident(
+            pg[len(coords) - 2].endPointData(), ln.startPointData()
+            )
+        self.setCoincident(
+            ln.endPointData(), pg[0].startPointData()
+            )
+        pg.append(ln)
+        return pg
+
+    #-------------------------------------------------------------
+    #
+    # Getters
+    #
+    #-------------------------------------------------------------
+
+    def selectFace(self, *args):
+        """Select the geometrical entities of this Sketch on which
+        the result Face must be built.
+
+        When no entity is given, the face is based on all existing
+        geometry of this Sketch.
+        """
+        if len(args) == 0:
+            wire = modelAPI_ResultConstruction(
+                self._feature.firstResult()
+                ).shape()
+        elif len(args) == 1:
+            wire = args[0].shape()
+        else:
+            raise Exception("not yet implemented")
+        # TODO: simple version now, should be a list of selected faces
+        return [Selection(self.result(), self.buildShape(wire))]
+
+    def buildShape(self, wire):
+        """Build the result Shape of this Sketch according to the
+        selected geometrical entities."""
+        o = self._origin.pnt()
+        dx = self._dir_x.dir()
+        n = self._norm.dir()
+
+        # The faces are kept otherwise they are destroyed at exit
+        faces = ShapeList()
+        GeomAlgoAPI_SketchBuilder.createFaces(o, dx, n, wire, faces)
+        # TODO: Deal with several faces
+        return faces[0]
+
+    def result(self):
+        """Returns the result data of this Feature."""
+        return self._feature.firstResult()
diff --git a/src/PythonAPI/model/tools.py b/src/PythonAPI/model/tools.py
new file mode 100644 (file)
index 0000000..9971e4b
--- /dev/null
@@ -0,0 +1,126 @@
+"""Common tools for other modules.
+Author: Sergey Pokhodenko
+Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+"""
+
+import re
+import collections
+
+import ModelAPI
+import GeomAPI
+import GeomDataAPI
+
+# from .sketcher.sketch import Sketch
+
+
+def convert_to_underscore(name):
+    """Convert CamelCase to underscore_case."""
+    s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
+    return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
+
+
+class Selection:
+    """Class for selection.
+
+    Selection() -> empty selection
+    Selection(name, type) -> selection initialized with arguments:
+        - name -- topological name
+        - type -- type of the object
+    Selection(context, shape) -> selection initialized with arguments:
+        - context -- ModelAPI_Result object
+        - shape -- GeomAPI_Shape shape
+    """
+
+    def __init__(self, *args):
+        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
+
+        if not args:
+            self.args = (None, None)
+            return
+
+        if len(args) == 1 and isinstance(args[0], basestring):
+            self.args = args
+            return
+
+        assert(len(args) > 1 and len(args) < 4)
+        assert(isinstance(args[0], basestring) or
+               isinstance(args[0], ModelAPI.ModelAPI_Result))
+        if isinstance(args[0], basestring):
+            assert(isinstance(args[1], basestring))
+        elif isinstance(args[0], ModelAPI.ModelAPI_Result) or args[0] is None:
+            assert(isinstance(args[1], GeomAPI.GeomAPI_Shape))
+        self.args = args
+
+
+def fill_attribute(attribute, value):
+    """Set value to attribure.
+
+    This function processes complex cases.
+    ModelAPI_AttributeSelectionList can accept string, result + shape, list of
+    strings and [result + shape]...
+    ModelAPI_AttributeDouble can accept float and string
+    """
+    if (isinstance(attribute, ModelAPI.ModelAPI_AttributeBoolean) or
+        isinstance(attribute, ModelAPI.ModelAPI_AttributeDocRef) or
+        isinstance(attribute, ModelAPI.ModelAPI_AttributeInteger) or
+        isinstance(attribute, ModelAPI.ModelAPI_AttributeReference) or
+        isinstance(attribute, ModelAPI.ModelAPI_AttributeString)
+        ):
+        attribute.setValue(value)
+
+    elif isinstance(attribute, ModelAPI.ModelAPI_AttributeDouble):
+        if isinstance(value, basestring):
+            attribute.setText(value)
+        else:
+            attribute.setValue(value)
+
+    elif isinstance(attribute, ModelAPI.ModelAPI_AttributeIntArray):
+        attrubute.setSize(len(value))
+        for i in range(len(value)):
+            attrubute.setValue(i, value[i])
+
+    elif isinstance(attribute, ModelAPI.ModelAPI_AttributeRefAttr):
+        assert(isinstance(value, ModelAPI.ModelAPI_Attribute) or
+               isinstance(value, ModelAPI.ModelAPI_Object))
+        if isinstance(value, ModelAPI.ModelAPI_Attribute):
+            attrubute.setAttr(value)
+        elif isinstance(value, ModelAPI.ModelAPI_Object):
+            attrubute.setObject(value)
+
+    elif isinstance(attribute, ModelAPI.ModelAPI_AttributeRefList):
+        attribute.clear()
+        if not value:
+            return
+
+        assert(isinstance(value, collections.Iterable))
+        for item in value:
+            assert(isinstance(item, ModelAPI.ModelAPI_Object))
+            attribute.append(item)
+
+    elif isinstance(attribute, ModelAPI.ModelAPI_AttributeSelection):
+        if value is None:
+            attribute.setValue(None, None)
+            return
+
+        assert(isinstance(value, Selection))
+        attribute.setValue(*value.args)
+
+    elif isinstance(attribute, ModelAPI.ModelAPI_AttributeSelectionList):
+        attribute.clear()
+        if not value:
+            return
+
+        assert(isinstance(value, collections.Iterable))
+        for item in value:
+            assert(isinstance(item, Selection))
+            attribute.append(*item.args)
+
+    elif (isinstance(attribute, GeomDataAPI.GeomDataAPI_Dir) or
+          isinstance(attribute, GeomDataAPI.GeomDataAPI_Point) or
+          isinstance(attribute, GeomDataAPI.GeomDataAPI_Point2D)
+          ):
+        assert(isinstance(value, collections.Iterable))
+        attribute.setValue(*value)
+
+    else:
+        raise AssertionError("Wrong attribute type: %s" % type(attribute))
diff --git a/src/PythonAPI/modeler/__init__.py b/src/PythonAPI/modeler/__init__.py
deleted file mode 100644 (file)
index 8ffaa38..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-"""This package defines the Parametric Geometry API of the Modeler.
-"""
-
-# General purpose functions and abstract root classes
-
-from services  import *
-from roots     import *
-
-# Built-in features
-
-from part      import Part         as addPart
-from sketcher  import Sketch       as addSketch
-from extrusion import Extrusion    as addExtrusion
-from boolean   import Addition     as addAddition
-from boolean   import Subtraction  as addSubtraction
-from boolean   import Intersection as addIntersection
\ No newline at end of file
diff --git a/src/PythonAPI/modeler/services.py b/src/PythonAPI/modeler/services.py
deleted file mode 100644 (file)
index d463c59..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-"""General purpose Interface
-Author: Daniel Brunier-Coulin
-Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-"""
-
-from ModelAPI import *
-from GeomAPI  import *
-import geom              # To be removed when gp_Ax3 will be Pythonized
-
-
-def moduleDocument ():
-  """Returns the main document (the Partset) created or open from the Modeler.
-  This document is unique in the application session.
-  """
-  return ModelAPI_Session.get().moduleDocument()
-
-
-def activeDocument ():
-  """Returns the active document.
-  This document can be either the main application document (i.e. the Partset) or one of documents
-  referred to by the main document (a Part).
-  """
-  return ModelAPI_Session.get().activeDocument()
-
-
-def defaultPlane (name):
-  """Returns one of the three planes defined by the global coordinate system.
-  These planes are respectively referred to by name "XOY" (Z=0), "XOZ" (Y=0) or "YOZ" (X=0).
-  """
-# Temporary implementation before the availability of default planes.
-
-  o = GeomAPI_Pnt( 0, 0, 0 )
-  if   name == "XOY":
-    n = GeomAPI_Dir( 0, 0, 1)
-    x = GeomAPI_Dir( 1, 0, 0)
-  elif name == "XOZ":
-    n = GeomAPI_Dir( 0, 1, 0)
-    x = GeomAPI_Dir( 1, 0, 0)
-  elif name == "YOZ":
-    n = GeomAPI_Dir( 1, 0, 0)
-    x = GeomAPI_Dir( 0, 1, 0)
-
-  return geom.Ax3( o, n, x )
-
-
-def begin ():
-  """Starts a data structure transaction, as such making a control point for being able to discard or undo
-  all operations done during this transaction.
-  """
-  ModelAPI_Session.get().startOperation()
-
-
-def end ():
-  """Commits the data structure transaction and makes all operations done since the last control point undo-able."""
-  ModelAPI_Session.get().finishOperation()
-
-
-def do ():
-  """Commits the data structure transaction and makes all operations done since the last control point undo-able."""
-  session = ModelAPI_Session.get()
-  session.finishOperation()
-  session.startOperation()
-
-
-def undo ():
-  """Rolls-back the data structure to the previous control point."""
-  ModelAPI_Session.get().undo()
-
-
-def redo ():
-  """Restore the data structure rolled-back by the last undo."""
-  ModelAPI_Session.get().redo()
diff --git a/src/PythonAPI/pylintrc b/src/PythonAPI/pylintrc
new file mode 100644 (file)
index 0000000..d1ef322
--- /dev/null
@@ -0,0 +1,283 @@
+[MASTER]
+
+# Specify a configuration file.
+#rcfile=
+
+# Python code to execute, usually for sys.path manipulation such as
+# pygtk.require().
+#init-hook=
+
+# Profiled execution.
+profile=no
+
+# Add files or directories to the blacklist. They should be base names, not
+# paths.
+ignore=CVS
+
+# Pickle collected data for later comparisons.
+persistent=yes
+
+# List of plugins (as comma separated values of python modules names) to load,
+# usually to register additional checkers.
+load-plugins=
+
+
+[MESSAGES CONTROL]
+
+# Enable the message, report, category or checker with the given id(s). You can
+# either give multiple identifier separated by comma (,) or put this option
+# multiple time. See also the "--disable" option for examples.
+#enable=
+
+# Disable the message, report, category or checker with the given id(s). You
+# can either give multiple identifiers separated by comma (,) or put this
+# option multiple times (only on the command line, not in the configuration
+# file where it should appear only once).You can also use "--disable=all" to
+# disable everything first and then reenable specific checks. For example, if
+# you want to run only the similarities checker, you can use "--disable=all
+# --enable=similarities". If you want to run only the classes checker, but have
+# no Warning level messages displayed, use"--disable=all --enable=classes
+# --disable=W"
+#disable=
+
+
+[REPORTS]
+
+# Set the output format. Available formats are text, parseable, colorized, msvs
+# (visual studio) and html. You can also give a reporter class, eg
+# mypackage.mymodule.MyReporterClass.
+output-format=text
+
+# Put messages in a separate file for each module / package specified on the
+# command line instead of printing them on stdout. Reports (if any) will be
+# written in a file name "pylint_global.[txt|html]".
+files-output=no
+
+# Tells whether to display a full report or only the messages
+reports=yes
+
+# Python expression which should return a note less than 10 (10 is the highest
+# note). You have access to the variables errors warning, statement which
+# respectively contain the number of errors / warnings messages and the total
+# number of statements analyzed. This is used by the global evaluation report
+# (RP0004).
+evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
+
+# Add a comment according to your evaluation note. This is used by the global
+# evaluation report (RP0004).
+comment=no
+
+# Template used to display messages. This is a python new-style format string
+# used to format the message information. See doc for all details
+#msg-template=
+
+
+[TYPECHECK]
+
+# Tells whether missing members accessed in mixin class should be ignored. A
+# mixin class is detected if its name ends with "mixin" (case insensitive).
+ignore-mixin-members=yes
+
+# List of classes names for which member attributes should not be checked
+# (useful for classes with attributes dynamically set).
+ignored-classes=SQLObject
+
+# When zope mode is activated, add a predefined set of Zope acquired attributes
+# to generated-members.
+zope=no
+
+# List of members which are set dynamically and missed by pylint inference
+# system, and so shouldn't trigger E0201 when accessed. Python regular
+# expressions are accepted.
+generated-members=REQUEST,acl_users,aq_parent
+
+
+[MISCELLANEOUS]
+
+# List of note tags to take in consideration, separated by a comma.
+notes=FIXME,XXX,TODO
+
+
+[SIMILARITIES]
+
+# Minimum lines number of a similarity.
+min-similarity-lines=4
+
+# Ignore comments when computing similarities.
+ignore-comments=yes
+
+# Ignore docstrings when computing similarities.
+ignore-docstrings=yes
+
+# Ignore imports when computing similarities.
+ignore-imports=no
+
+
+[BASIC]
+
+# Required attributes for module, separated by a comma
+required-attributes=
+
+# List of builtins function names that should not be used, separated by a comma
+bad-functions=map,filter,apply,input
+
+# Regular expression which should only match correct module names
+module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
+
+# Regular expression which should only match correct module level names
+const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
+
+# Regular expression which should only match correct class names
+class-rgx=[A-Z_][a-zA-Z0-9]+$
+
+# Regular expression which should only match correct function names
+#function-rgx=[a-z_][a-z0-9_]{2,30}$
+function-rgx=[a-z][a-zA-Z0-9]*$
+
+# Regular expression which should only match correct method names
+#method-rgx=[a-z_][a-z0-9_]{2,30}$
+# __get_state__ etc. are not camel case, so we add an 'OR' to the regex
+method-rgx=[a-z][a-zA-Z0-9]*|__[a-z_]*__$
+
+# Regular expression which should only match correct instance attribute names
+attr-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression which should only match correct argument names
+argument-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression which should only match correct variable names
+variable-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression which should only match correct attribute names in class
+# bodies
+class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
+
+# Regular expression which should only match correct list comprehension /
+# generator expression variable names
+inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
+
+# Good variable names which should always be accepted, separated by a comma
+good-names=i,j,k,ex,Run,_
+
+# Bad variable names which should always be refused, separated by a comma
+bad-names=foo,bar,baz,toto,tutu,tata
+
+# Regular expression which should only match function or class names that do
+# not require a docstring.
+no-docstring-rgx=__.*__
+
+# Minimum line length for functions/classes that require docstrings, shorter
+# ones are exempt.
+docstring-min-length=-1
+
+
+[FORMAT]
+
+# Maximum number of characters on a single line.
+max-line-length=80
+
+# Regexp for a line that is allowed to be longer than the limit.
+ignore-long-lines=^\s*(# )?<?https?://\S+>?$
+
+# Allow the body of an if to be on the same line as the test if there is no
+# else.
+single-line-if-stmt=no
+
+# List of optional constructs for which whitespace checking is disabled
+no-space-check=trailing-comma,dict-separator
+
+# Maximum number of lines in a module
+max-module-lines=1000
+
+# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
+# tab).
+indent-string='    '
+
+
+[VARIABLES]
+
+# Tells whether we should check for unused import in __init__ files.
+init-import=no
+
+# A regular expression matching the beginning of the name of dummy variables
+# (i.e. not used).
+dummy-variables-rgx=_$|dummy
+
+# List of additional names supposed to be defined in builtins. Remember that
+# you should avoid to define new builtins when possible.
+additional-builtins=
+
+
+[DESIGN]
+
+# Maximum number of arguments for function / method
+max-args=5
+
+# Argument names that match this expression will be ignored. Default to name
+# with leading underscore
+ignored-argument-names=_.*
+
+# Maximum number of locals for function / method body
+max-locals=15
+
+# Maximum number of return / yield for function / method body
+max-returns=6
+
+# Maximum number of branch for function / method body
+max-branches=12
+
+# Maximum number of statements in function / method body
+max-statements=50
+
+# Maximum number of parents for a class (see R0901).
+max-parents=7
+
+# Maximum number of attributes for a class (see R0902).
+max-attributes=7
+
+# Minimum number of public methods for a class (see R0903).
+min-public-methods=2
+
+# Maximum number of public methods for a class (see R0904).
+max-public-methods=20
+
+
+[IMPORTS]
+
+# Deprecated modules which should not be used, separated by a comma
+deprecated-modules=regsub,TERMIOS,Bastion,rexec
+
+# Create a graph of every (i.e. internal and external) dependencies in the
+# given file (report RP0402 must not be disabled)
+import-graph=
+
+# Create a graph of external dependencies in the given file (report RP0402 must
+# not be disabled)
+ext-import-graph=
+
+# Create a graph of internal dependencies in the given file (report RP0402 must
+# not be disabled)
+int-import-graph=
+
+
+[CLASSES]
+
+# List of interface methods to ignore, separated by a comma. This is used for
+# instance to not check methods defines in Zope's Interface base class.
+ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
+
+# List of method names used to declare (i.e. assign) instance attributes.
+defining-attr-methods=__init__,__new__,setUp
+
+# List of valid names for the first argument in a class method.
+valid-classmethod-first-arg=cls
+
+# List of valid names for the first argument in a metaclass class method.
+valid-metaclass-classmethod-first-arg=mcs
+
+
+[EXCEPTIONS]
+
+# Exceptions that will emit a warning when being caught. Defaults to
+# "Exception"
+overgeneral-exceptions=Exception
diff --git a/src/PythonAPI/shaper.py b/src/PythonAPI/shaper.py
new file mode 100644 (file)
index 0000000..b2eb4d4
--- /dev/null
@@ -0,0 +1,7 @@
+"""This package defines the Python API of the Shaper.
+"""
+
+# Main packages
+
+import geom
+import model
index d53755595a96af63074ba78b340932aa23cc9aee..3fef980a8e2638086adb4f5c53d4310b8a042bd6 100644 (file)
@@ -6,17 +6,20 @@ from macros.box.feature      import BoxFeature
 
 
 class PythonFeaturesPlugin(ModelAPI.ModelAPI_Plugin):
-    """Implementation of features plugin"""
+    """Implementation of features plugin.
+
+    PythonFeaturesPlugin() -> plugin object
+    """
 
     def __init__(self):
-        """Constructor"""
+        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
         ModelAPI.ModelAPI_Plugin.__init__(self)
         aSession = ModelAPI.ModelAPI_Session.get()
         aSession.registerPlugin(self)
         pass
 
     def createFeature(self, theFeatureID):
-        """Create a feature by its Id"""
+        """Override ModelAPI_Plugin.createFeature()"""
         aFeature = None
 
         if theFeatureID == BoxFeature.ID():
@@ -27,6 +30,6 @@ class PythonFeaturesPlugin(ModelAPI.ModelAPI_Plugin):
 
         return aFeature
 
-### The plugin object
+# The plugin object
 plugin = PythonFeaturesPlugin()
 plugin.__disown__()
index 208c408e877dda93247641bb28d9c4ef35608f77..ca037ba1f14d813a64c592e984bfce370ec610e4 100644 (file)
@@ -3,100 +3,107 @@ Authors: Renaud Nedelec - Daniel Brunier-Coulin
 Copyright (C) 2014-20xx CEA/DEN, EDF R&D
 """
 
-import modeler
+import model
 import geom
 
 
-class BoxFeature(modeler.Feature):
-  """An example of Box feature implementation"""
+class BoxFeature(model.Feature):
+    """An example of Box feature implementation.
+
+    BoxFeature() -> Box
+    """
 
 # Initializations
 
-  def __init__(self):
-    """Constructor"""
-    modeler.Feature.__init__(self)
+    def __init__(self):
+        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
+        model.Feature.__init__(self)
+
+    @staticmethod
+    def ID():
+        """Return Id of the feature."""
+        return "Box"
 
-  @staticmethod
-  def ID():
-    """Return Id of the feature"""
-    return "Box"
+    @staticmethod
+    def WIDTH_ID():
+        """Returns ID of Width parameter."""
+        return "width"
 
-  @staticmethod
-  def WIDTH_ID():
-    """Returns ID of Width parameter"""
-    return "width"
+    @staticmethod
+    def LENGTH_ID():
+        """Returns ID of Length parameter."""
+        return "length"
 
-  @staticmethod
-  def LENGTH_ID():
-    """Returns ID of Length parameter"""
-    return "length"
+    @staticmethod
+    def HEIGHT_ID():
+        """Returns ID of Height parameter."""
+        return "height"
 
-  @staticmethod
-  def HEIGHT_ID():
-    """Returns ID of Height parameter"""
-    return "height"
+    def getKind(self):
+        """Override Feature.getKind()"""
+        return BoxFeature.ID()
 
-  def getKind(self):
-    """Returns ID of the feature"""
-    return BoxFeature.ID()
 
-       
 # Creation of the box at default size
 
-  def initAttributes(self):
-    """Initialise attributes of the feature"""
-    # Creating the input arguments of the feature
-    self.addRealInput( self.WIDTH_ID() )
-    self.addRealInput( self.LENGTH_ID() )
-    self.addRealInput( self.HEIGHT_ID() )
+    def initAttributes(self):
+        """Override Feature.initAttributes()"""
+        # Creating the input arguments of the feature
+        self.addRealInput(self.WIDTH_ID())
+        self.addRealInput(self.LENGTH_ID())
+        self.addRealInput(self.HEIGHT_ID())
 
-    # Creating the base of the box with unit values
-    mypart = modeler.activeDocument()
-    xoy    = modeler.defaultPlane("XOY")
+        # Creating the base of the box with unit values
+        mypart = model.activeDocument()
+        xoy = model.defaultPlane("XOY")
 
-    ### A base of the geometry
-    self.base = modeler.addSketch( mypart, xoy )
+        # A base of the geometry
+        self.base = model.addSketch(mypart, xoy)
 
-    p1 = geom.Pnt2d( 0, 0 )
-    p2 = geom.Pnt2d( 0, 1 )
-    p3 = geom.Pnt2d( 1, 1 )
-    p4 = geom.Pnt2d( 1, 0 )
+        p1 = geom.Pnt2d(0, 0)
+        p2 = geom.Pnt2d(0, 1)
+        p3 = geom.Pnt2d(1, 1)
+        p4 = geom.Pnt2d(1, 0)
 
-    line = self.base.addPolygon(p1, p2, p3, p4)
+        line = self.base.addPolygon(p1, p2, p3, p4)
 
-    self.base.setParallel( line[0].result(), line[2].result() )
-    self.base.setParallel( line[1].result(), line[3].result() )
-    self.base.setPerpendicular( line[0].result(), line[3].result() )
+        self.base.setParallel(line[0].result(), line[2].result())
+        self.base.setParallel(line[1].result(), line[3].result())
+        self.base.setPerpendicular(line[0].result(), line[3].result())
 
-    # Setting the size of the base with default values
-    ### Width
-    self.width  = self.base.setLength( line[0].result(), 50 )   # Keeps the constraint for edition
-    ### Length
-    self.length = self.base.setLength( line[3].result(), 50 )   # Keeps the constraint for edition
+        # Setting the size of the base with default values
+        # Width
+        self.width = self.base.setLength(line[0].result(), 50)  # Keeps the constraint for edition
+        # Length
+        self.length = self.base.setLength(line[3].result(), 50)  # Keeps the constraint for edition
 
-    # Creating the extrusion (the box) at default size
-    ### A box result
-    self.box = modeler.addExtrusion( mypart, self.base.selectFace(), 50 )
+        # Creating the extrusion (the box) at default size
+        # A box result
+        self.box = model.addExtrusion(mypart, self.base.selectFace(), 50)
 
-       
 # Edition of the box at user size
 
-  def execute(self):
-    """Compute the feature result"""
-    # Retrieving the user inputs
-    width  = self.getRealInput( self.WIDTH_ID() )
-    length = self.getRealInput( self.LENGTH_ID() )
-    height = self.getRealInput( self.HEIGHT_ID() )
-
-    # Editing the box
-    self.base.setValue( self.width,  width )
-    self.base.setValue( self.length, length )
-    self.box.setSize( height )
-
-    # Publishing the result: not needed for Macro feature
-    #self.addResult( self.box.result() )
-  
-  def isMacro(self):
-    """Returns True"""
-    # Box feature is macro: removes itself on the creation transaction finish
-    return True
+    def execute(self):
+        """F.execute() -- execute the feature"""
+        # Retrieving the user inputs
+        width = self.getRealInput(self.WIDTH_ID())
+        length = self.getRealInpuut(self.WIDTH_ID())
+        length = self.getRealInt(self.LENGTH_ID())
+        height = self.getRealInput(self.HEIGHT_ID())
+
+        # Editing the box
+        self.base.setValue(self.width, width)
+        self.base.setValue(self.length, length)
+        self.box.setSize(height)
+
+        # Publishing the result: not needed for Macro feature
+        # self.addResult( self.box.result() )
+
+    def isMacro(self):
+        """Override Feature.initAttributes().
+        F.isMacro() -> True
+
+        Box feature is macro: removes itself on the creation transaction
+        finish.
+        """
+        return True