Salome HOME
Merge remote-tracking branch 'origin/cbr/export_to_geom_via_xao'
authorChristophe Bourcier <christophe.bourcier@cea.fr>
Tue, 5 Dec 2017 07:37:33 +0000 (08:37 +0100)
committerChristophe Bourcier <christophe.bourcier@cea.fr>
Tue, 5 Dec 2017 14:22:41 +0000 (15:22 +0100)
15 files changed:
src/ConnectorAPI/CMakeLists.txt
src/ConnectorAPI/Test/CMakeLists.txt [new file with mode: 0755]
src/ConnectorAPI/Test/CTestTestfileInstall.cmake [new file with mode: 0644]
src/ConnectorAPI/Test/TestExportToGEOM.py
src/ConnectorAPI/Test/TestExportToGEOMAllGroupsAndFields.py [new file with mode: 0644]
src/ConnectorAPI/Test/testme.py [new file with mode: 0755]
src/ConnectorAPI/Test/tests.set [new file with mode: 0644]
src/ConnectorPlugin/ConnectorPlugin_ExportFeature.py
src/ExchangeAPI/ExchangeAPI_Export.cpp
src/ExchangeAPI/ExchangeAPI_Export.h
src/ExchangePlugin/ExchangePlugin_ExportFeature.cpp
src/ExchangePlugin/ExchangePlugin_ExportFeature.h
src/ExchangePlugin/Test/Data/export_ref.xao
src/ExchangePlugin/Test/TestExport.py
src/PythonAPI/model/dump/DumpAssistant.py

index 67c29091a713dae4df895b1b29294a669a3980e3..99f15351a6a1cf4bd93b4e31f59562950f0a4c4e 100644 (file)
@@ -88,9 +88,6 @@ INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/ConnectorAPI.py DESTINATION ${SHAPER_I
 
 # Tests
 IF(${HAVE_SALOME})
-  INCLUDE(UnitTest)
-
-  ADD_UNIT_TESTS(
-    TestExportToGEOM.py
-  )
+  ENABLE_TESTING()
+  ADD_SUBDIRECTORY(Test)
 ENDIF(${HAVE_SALOME})
diff --git a/src/ConnectorAPI/Test/CMakeLists.txt b/src/ConnectorAPI/Test/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..1506027
--- /dev/null
@@ -0,0 +1,59 @@
+# Copyright (C) 2013-2016  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+INCLUDE(tests.set)
+
+SET(COMPONENT_NAME SHAPER)
+
+SET(SALOME_SHAPER_INSTALL_TESTS "${SHAPER_INSTALL_PYTHON_FILES}/test")
+SET(TEST_INSTALL_DIRECTORY ${SALOME_SHAPER_INSTALL_TESTS})
+
+# make test
+SET(SALOME_INSTALL_LIBS "lib/salome")
+# Adding KERNEL and GUI libraries to environment so that Salome launches correctly
+if (WIN32)
+  SALOME_ACCUMULATE_ENVIRONMENT(PATH NOCHECK ${KERNEL_ROOT_DIR}/${SALOME_INSTALL_LIBS})
+  SALOME_ACCUMULATE_ENVIRONMENT(PATH NOCHECK ${GUI_ROOT_DIR}/${SALOME_INSTALL_LIBS})
+else()
+  SALOME_ACCUMULATE_ENVIRONMENT(LD_LIBRARY_PATH NOCHECK ${KERNEL_ROOT_DIR}/${SALOME_INSTALL_LIBS})
+  SALOME_ACCUMULATE_ENVIRONMENT(LD_LIBRARY_PATH NOCHECK ${GUI_ROOT_DIR}/${SALOME_INSTALL_LIBS})
+endif()
+SALOME_GENERATE_TESTS_ENVIRONMENT(tests_env)
+
+
+# -B ${CMAKE_SOURCE_DIR}/doc/salome/examples/testme.py
+FOREACH(tfile ${TEST_NAMES})
+  SET(TEST_NAME ${COMPONENT_NAME}_${tfile})
+  ADD_TEST(NAME ${TEST_NAME}
+           COMMAND ${PYTHON_EXECUTABLE} -B ${CMAKE_CURRENT_SOURCE_DIR}/testme.py ${CMAKE_CURRENT_SOURCE_DIR}/${tfile}.py)
+  SET_TESTS_PROPERTIES(${TEST_NAME} PROPERTIES ENVIRONMENT "${tests_env}")
+  SET_TESTS_PROPERTIES(${TEST_NAME} PROPERTIES LABELS "${COMPONENT_NAME}")
+ENDFOREACH()
+
+# salome test
+FOREACH(tfile ${TEST_NAMES})
+  INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${tfile}.py
+          DESTINATION ${TEST_INSTALL_DIRECTORY})
+ENDFOREACH()
+
+INSTALL(FILES CTestTestfileInstall.cmake
+  DESTINATION ${TEST_INSTALL_DIRECTORY}
+  RENAME CTestTestfile.cmake)
+
+INSTALL(FILES tests.set DESTINATION ${TEST_INSTALL_DIRECTORY})
\ No newline at end of file
diff --git a/src/ConnectorAPI/Test/CTestTestfileInstall.cmake b/src/ConnectorAPI/Test/CTestTestfileInstall.cmake
new file mode 100644 (file)
index 0000000..92cde25
--- /dev/null
@@ -0,0 +1,31 @@
+# Copyright (C) 2016  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+INCLUDE(tests.set)
+
+SET(COMPONENT_NAME SHAPER)
+SET(SALOME_TEST_DRIVER "$ENV{KERNEL_ROOT_DIR}/bin/salome/appliskel/salome_test_driver.py")
+SET(TIMEOUT        300)
+
+
+FOREACH(tfile ${TEST_NAMES} ${EXAMPLE_NAMES})
+  SET(TEST_NAME ${COMPONENT_NAME}_${tfile})
+  ADD_TEST(${TEST_NAME} python ${SALOME_TEST_DRIVER} ${TIMEOUT} ${tfile}.py)
+  SET_TESTS_PROPERTIES(${TEST_NAME} PROPERTIES LABELS "${COMPONENT_NAME}")
+ENDFOREACH()
index 90539fff4538db143ce5a578c12b91afb138d48d..ad6c8bd7a15261101da152999767b68db7086757 100644 (file)
 ## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
 ##
 
+import salome
 from salome.shaper import model
 
-model.begin()
-partSet = model.moduleDocument()
-Part_1 = model.addPart(partSet)
-Part_1_doc = Part_1.document()
-Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
-SketchLine_1 = Sketch_1.addLine(0, 0, 0, 50)
-SketchLine_2 = Sketch_1.addLine(0, 50, 50, 50)
-SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
-SketchLine_3 = Sketch_1.addLine(50, 50, 50, 0)
-SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
-SketchLine_4 = Sketch_1.addLine(50, 0, 0, 0)
-SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
-SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
-SketchConstraintRigid_1 = Sketch_1.setFixed(SketchLine_1.startPoint())
-SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_1.result())
-SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_4.result(), 50)
-SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_1.result(), 50)
-SketchConstraintParallel_1 = Sketch_1.setParallel(SketchLine_1.result(), SketchLine_3.result())
-SketchConstraintParallel_2 = Sketch_1.setParallel(SketchLine_2.result(), SketchLine_4.result())
-SketchConstraintPerpendicular_1 = Sketch_1.setPerpendicular(SketchLine_1.result(), SketchLine_4.result())
-model.do()
-Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2r-SketchLine_3r-SketchLine_4r")], model.selection(), 50, 0)
-model.end()
-
-model.exportToGEOM(Part_1_doc)
+from salome.geom import geomBuilder
+
+import os
+import tempfile
+
+salome.salome_init(0,1)
+geompy = geomBuilder.New(salome.myStudy)
+
+## Get the last object published in the GEOM section of the object browser
+def getLastGEOMShape():
+  sb = salome.myStudy.NewBuilder()
+  comp = salome.myStudy.FindComponent("GEOM")
+  obj = None
+  if comp:
+    iterator = salome.myStudy.NewChildIterator( comp )
+    sobj = None
+    while iterator.More():
+      sobj = iterator.Value()
+      iterator.Next()
+    if sobj:
+      obj = sobj.GetObject()
+  else:
+    raise Exception("GEOM component not found.")
+  return obj
+
+## Get the sub-object i of an object in the object browser
+# Numerotation starts at 1
+def getSubObject(obj, i):
+  ok, sub_sobj = salome.ObjectToSObject(obj).FindSubObject(i)
+  if not ok:
+    raise Exception("No child found at %i for %s"%(i, obj.GetName()))
+  sub_obj = sub_sobj.GetObject()
+  return sub_obj
+
+def dumpShaper(fileName):
+  model.begin()
+  dump=model.moduleDocument().addFeature("Dump")
+  dump.string("file_path").setValue(fileName)
+  dump.string("file_format").setValue("py")
+  model.do()
+  model.end()
+  pass
+
+def getTmpFileName(ext):
+  tempdir = tempfile.gettempdir()
+  tmp_file = tempfile.NamedTemporaryFile(suffix=".%s"%ext, prefix='shaper_', dir=tempdir, delete=False)
+  tmp_filename = tmp_file.name
+  return tmp_filename
+
+# Create 2 boxes
+# Create a group of faces
+# Create a field of faces
+# exportToGEOM
+# Check the result
+# Check the dump
+def testSeveralExportsToGEOM():
+
+  model.begin()
+  partSet = model.moduleDocument()
+  Part_1 = model.addPart(partSet)
+  Part_1_doc = Part_1.document()
+  Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+  Box_2 = model.addBox(Part_1_doc, 20, 20, 20)
+  Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), -10)
+  Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Translation_1_1"), model.selection("SOLID", "Box_2_1")])
+  Group_1 = model.addGroup(Part_1_doc, [model.selection("FACE", "Partition_1_1_1/Modified_Face_1_1"), model.selection("FACE", "Box_2_1/Top")])
+  model.do()
+  model.end()
+
+  # First export to GEOM
+  model.exportToGEOM(Part_1_doc)
+
+  # Check that the GEOM object has 1 compsolid and 2 solids
+  geomObject_1 = getLastGEOMShape()
+  assert geompy.NumberOfSubShapes(geomObject_1, geompy.ShapeType["COMPSOLID"]) == 1
+  assert geompy.NumberOfSolids(geomObject_1) == 2
+
+  # Check that the group has 2 faces
+  geomGroup_1 = getSubObject(geomObject_1, 1)
+  assert geompy.NumberOfFaces(geomGroup_1) == 2
+
+  # Add a third box
+  Box_3 = model.addBox(Part_1_doc, 10, 10, 10)
+  Translation_2 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_3_1")], model.selection("EDGE", "PartSet/OX"), 20)
+
+  # Second export to GEOM
+  model.exportToGEOM(Part_1_doc)
+
+  # Check that the GEOM object has 3 solids
+  geomObject_2 = getLastGEOMShape()
+  assert geompy.NumberOfSolids(geomObject_2) == 3
+
+  # Dump the salome study (only CORBA modules, SHAPER dump is not in it)
+  tempdir = tempfile.gettempdir()
+  dumpFileGeomBase = "dump_test_geom"
+  dumpFileGeom = os.path.join(tempdir, "%s.py"%dumpFileGeomBase)
+  salome.myStudy.DumpStudy(tempdir, dumpFileGeomBase, True, False)
+
+  # Dump SHAPER
+  dumpFileShaper = os.path.join(tempdir, "dump_test_shaper.py")
+  dumpShaper(dumpFileShaper)
+
+  # Load SHAPER dump
+  execfile(dumpFileShaper)
+
+  # Load GEOM dump
+  execfile(dumpFileGeom)
+
+  # Clean files
+  files = [dumpFileGeom, dumpFileShaper]
+  for f in files:
+    os.remove(f)
+
+  pass
+
+
+
+if __name__ == '__main__':
+  testSeveralExportsToGEOM()
\ No newline at end of file
diff --git a/src/ConnectorAPI/Test/TestExportToGEOMAllGroupsAndFields.py b/src/ConnectorAPI/Test/TestExportToGEOMAllGroupsAndFields.py
new file mode 100644 (file)
index 0000000..e52df8c
--- /dev/null
@@ -0,0 +1,186 @@
+# -*- coding: utf-8 -*-
+
+import os
+import tempfile
+
+import sys
+import salome
+
+salome.salome_init()
+theStudy = salome.myStudy
+
+from salome.shaper import model
+
+from salome.geom import geomBuilder
+geompy = geomBuilder.New(salome.myStudy)
+
+## Get the last object published in the GEOM section of the object browser
+def getLastGEOMShape():
+  sb = salome.myStudy.NewBuilder()
+  comp = salome.myStudy.FindComponent("GEOM")
+  obj = None
+  if comp:
+    iterator = salome.myStudy.NewChildIterator( comp )
+    sobj = None
+    while iterator.More():
+      sobj = iterator.Value()
+      iterator.Next()
+    if sobj:
+      obj = sobj.GetObject()
+  else:
+    raise Exception("GEOM component not found.")
+  return obj
+
+## Get the sub-object i of an object in the object browser
+# Numerotation starts at 1
+def getSubObject(obj, i):
+  ok, sub_sobj = salome.ObjectToSObject(obj).FindSubObject(i)
+  if not ok:
+    raise Exception("No child found at %i for %s"%(i, obj.GetName()))
+  sub_obj = sub_sobj.GetObject()
+  return sub_obj
+
+def dumpShaper(fileName):
+  model.begin()
+  dump=model.moduleDocument().addFeature("Dump")
+  dump.string("file_path").setValue(fileName)
+  dump.string("file_format").setValue("py")
+  model.do()
+  model.end()
+  pass
+
+def getTmpFileName(ext):
+  tempdir = tempfile.gettempdir()
+  tmp_file = tempfile.NamedTemporaryFile(suffix=".%s"%ext, prefix='shaper_', dir=tempdir, delete=False)
+  tmp_filename = tmp_file.name
+  return tmp_filename
+
+def testGroupsAndFieldsExportToGEOM():
+  model.begin()
+  partSet = model.moduleDocument()
+  Part_1 = model.addPart(partSet)
+  Part_1_doc = Part_1.document()
+  Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+  Box_2 = model.addBox(Part_1_doc, 20, 20, 20)
+  Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), -10)
+  Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Translation_1_1"), model.selection("SOLID", "Box_2_1")])
+  Box_3 = model.addBox(Part_1_doc, 10, 10, 10)
+  Translation_2 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_3_1")], model.selection("EDGE", "PartSet/OX"), 20)
+  Group_1 = model.addGroup(Part_1_doc, [model.selection("FACE", "Partition_1_1_1/Modified_Face_1_1"), model.selection("FACE", "Box_2_1/Top"), model.selection("FACE", "Translation_2_1/Translated_Face_1")])
+  Group_1.result().setName("faces_top")
+  Group_2 = model.addGroup(Part_1_doc, [model.selection("EDGE", "Partition_1_1_1/Modified_Face_1_4&Partition_1_1_1/Modified_Face_1_2"), model.selection("EDGE", "Partition_1_1_2/Modified_Face_2_2&Partition_1_1_2/Modified_Face_2_1"), model.selection("EDGE", "Translation_2_1/Translated_Face_4&Translation_2_1/Translated_Face_2")])
+  Group_2.result().setName("edges_x")
+  Group_3 = model.addGroup(Part_1_doc, [model.selection("VERTEX", "Translation_1_1/Translated_Face_6&Partition_1_1_1/Modified_Face_1_4&Partition_1_1_1/Modified_Face_1_2"), model.selection("VERTEX", "Translation_2_1/Translated_Face_5&Translation_2_1/Translated_Face_4&Translation_2_1/Translated_Face_2"), model.selection("VERTEX", "Translation_2_1/Translated_Face_5&Translation_2_1/Translated_Face_3&Translation_2_1/Translated_Face_2"), model.selection("VERTEX", "Translation_1_1/Translated_Face_6&Partition_1_1_1/Modified_Face_1_3&Partition_1_1_1/Modified_Face_1_2"), model.selection("VERTEX", "Partition_1_1_2/Modified_Face_2_3&Partition_1_1_2/Modified_Face_2_1&Box_2_1/Right"), model.selection("VERTEX", "Partition_1_1_2/Modified_Face_2_1&Box_2_1/Front&Box_2_1/Right"), model.selection("VERTEX", "Partition_1_1_1/Modified_Face_1_3&Partition_1_1_1/Modified_Face_1_2&Partition_1_1_2/Modified_Face_2_4"), model.selection("VERTEX", "Translation_2_1/Translated_Face_6&Translation_2_1/Translated_Face_3&Translation_2_1/Translated_Face_2")])
+  Group_3.result().setName("vertices_bottom")
+  Group_4 = model.addGroup(Part_1_doc, [model.selection("SOLID", "Partition_1_1_1"), model.selection("SOLID", "Translation_2_1")])
+  Group_4.result().setName("solids_small")
+  Field_1 = model.addField(Part_1_doc, 1, "DOUBLE", 1, ["Comp 1"], [model.selection("SOLID", "Partition_1_1_1"), model.selection("SOLID", "Partition_1_1_2"), model.selection("SOLID", "Translation_2_1")])
+  Field_1.result().setName("Field_solids")
+  Field_1.addStep(0, 0, [[0], [1], [2], [3]])
+  Field_2 = model.addField(Part_1_doc, 1, "DOUBLE", 1, ["Comp 1"], [model.selection("FACE", "Partition_1_1_1/Modified_Face_1_2"), model.selection("FACE", "Partition_1_1_2/Modified_Face_2_1"), model.selection("FACE", "Translation_2_1/Translated_Face_2"), model.selection("FACE", "Partition_1_1_1/Modified_Face_1_1"), model.selection("FACE", "Box_2_1/Top"), model.selection("FACE", "Translation_2_1/Translated_Face_1")])
+  Field_2.result().setName("Field_faces")
+  Field_2.addStep(0, 0, [[0], [1], [1], [1], [2], [2], [2]])
+  Field_3 = model.addField(Part_1_doc, 1, "DOUBLE", 1, ["Comp 1"], [model.selection("EDGE", "Partition_1_1_1/Modified_Face_1_4&Partition_1_1_1/Modified_Face_1_2"), model.selection("EDGE", "Partition_1_1_2/Modified_Face_2_2&Partition_1_1_2/Modified_Face_2_1"), model.selection("EDGE", "Translation_2_1/Translated_Face_4&Translation_2_1/Translated_Face_2"), model.selection("EDGE", "Translation_1_1/Translated_Face_6&Partition_1_1_1/Modified_Face_1_2"), model.selection("EDGE", "Translation_2_1/Translated_Face_5&Translation_2_1/Translated_Face_2"), model.selection("EDGE", "Translation_2_1/Translated_Face_5&Translation_2_1/Translated_Face_1"), model.selection("EDGE", "Translation_1_1/Translated_Face_6&Partition_1_1_1/Modified_Face_1_1"), model.selection("EDGE", "Partition_1_1_2/Modified_Face_2_3&Box_2_1/Top"), model.selection("EDGE", "Box_2_1/Front&Box_2_1/Top"), model.selection("EDGE", "Partition_1_1_2/Modified_Face_2_2&Box_2_1/Top"), model.selection("EDGE", "Box_2_1/Top&Box_2_1/Right")])
+  Field_3.result().setName("Field_edges")
+  Field_3.addStep(0, 0, [[0], [1], [1], [1], [2], [2], [2], [2], [3], [3], [3], [3]])
+  Field_4 = model.addField(Part_1_doc, 1, "DOUBLE", 1, ["Comp 1"], [model.selection("VERTEX", "Translation_1_1/Translated_Face_6&Partition_1_1_1/Modified_Face_1_4&Partition_1_1_1/Modified_Face_1_2"), model.selection("VERTEX", "Translation_1_1/Translated_Face_6&Partition_1_1_1/Modified_Face_1_3&Partition_1_1_1/Modified_Face_1_2"), model.selection("VERTEX", "Translation_2_1/Translated_Face_5&Translation_2_1/Translated_Face_4&Translation_2_1/Translated_Face_2"), model.selection("VERTEX", "Translation_2_1/Translated_Face_5&Translation_2_1/Translated_Face_3&Translation_2_1/Translated_Face_2"), model.selection("VERTEX", "Translation_2_1/Translated_Face_6&Translation_2_1/Translated_Face_3&Translation_2_1/Translated_Face_2"), model.selection("VERTEX", "Partition_1_1_2/Modified_Face_2_1&Box_2_1/Front&Box_2_1/Right"), model.selection("VERTEX", "Partition_1_1_2/Modified_Face_2_3&Partition_1_1_2/Modified_Face_2_1&Box_2_1/Right"), model.selection("VERTEX", "Partition_1_1_1/Modified_Face_1_3&Partition_1_1_1/Modified_Face_1_2&Partition_1_1_2/Modified_Face_2_4"), model.selection("VERTEX", "Translation_1_1/Translated_Face_6&Partition_1_1_1/Modified_Face_1_1&Partition_1_1_1/Modified_Face_1_3"), model.selection("VERTEX", "Translation_1_1/Translated_Face_6&Partition_1_1_1/Modified_Face_1_4&Partition_1_1_1/Modified_Face_1_1"), model.selection("VERTEX", "Translation_2_1/Translated_Face_5&Translation_2_1/Translated_Face_4&Translation_2_1/Translated_Face_1"), model.selection("VERTEX", "Translation_2_1/Translated_Face_5&Translation_2_1/Translated_Face_3&Translation_2_1/Translated_Face_1"), model.selection("VERTEX", "Partition_1_1_2/Modified_Face_2_2&Partition_1_1_2/Modified_Face_2_3&Box_2_1/Top"), model.selection("VERTEX", "Partition_1_1_2/Modified_Face_2_3&Box_2_1/Top&Box_2_1/Right"), model.selection("VERTEX", "Partition_1_1_2/Modified_Face_2_2&Box_2_1/Front&Box_2_1/Top"), model.selection("VERTEX", "Box_2_1/Front&Box_2_1/Top&Box_2_1/Right")])
+  Field_4.result().setName("Field_vertices")
+  Field_4.addStep(0, 0, [[0], [1], [1], [1], [1], [1], [1], [1], [1], [2], [2], [2], [2], [3], [3], [3], [3]])
+  model.exportToGEOM(Part_1_doc)
+  model.do()
+  model.end()
+
+# check the groups content by the coordinates of a point on its sub-shapes
+def checkGroupByCoords(group, coords, tolerance=1e-7):
+  for coord in coords:
+    p = geompy.MakeVertex(*coord)
+    assert geompy.MinDistance(group, p) < tolerance
+  pass
+
+## Check the result imported in GEOM
+def checkResultInGEOM():
+  geomObject_1 = getLastGEOMShape()
+
+  group_1_GEOM = getSubObject(geomObject_1, 1)
+  assert group_1_GEOM.GetName() == 'faces_top'
+  assert geompy.NumberOfFaces(group_1_GEOM) == 3
+
+  # coordinates of the barycenters of the faces of Group_1
+  coords_1 = [[-5, 5, 10], [10, 10, 20], [25, 5, 10]]
+  checkGroupByCoords(group_1_GEOM, coords_1)
+
+  group_2_GEOM = getSubObject(geomObject_1, 2)
+  assert group_2_GEOM.GetName() == 'edges_x'
+  assert geompy.NumberOfEdges(group_2_GEOM) == 3
+
+  # coordinates of the barycenters of the edges of Group_2
+  coords_2 = [[-5, 0, 0], [10, 0, 0], [25, 0, 0]]
+  checkGroupByCoords(group_2_GEOM, coords_2)
+
+  group_3_GEOM = getSubObject(geomObject_1, 3)
+  assert group_3_GEOM.GetName() == 'vertices_bottom'
+  assert geompy.NumberOfSubShapes(group_3_GEOM, geompy.ShapeType["VERTEX"]) == 8
+
+  # coordinates of the points of of Group_3
+  coords_3 = [[-10, 0, 0], [-10, 10, 0], [0, 10, 0], [0, 20, 0], [20, 20, 0], [20, 10, 0], [30, 10, 0], [30, 0, 0]]
+  checkGroupByCoords(group_3_GEOM, coords_3)
+
+  group_4_GEOM = getSubObject(geomObject_1, 4)
+  assert group_4_GEOM.GetName() == 'solids_small'
+  assert geompy.NumberOfSolids(group_4_GEOM) == 2
+
+  # coordinates of the barycenters of the solids of Group_4
+  coords_4 = [[-5, 5, 5], [25, 5, 5]]
+  checkGroupByCoords(group_4_GEOM, coords_4)
+
+  field_1_GEOM = getSubObject(geomObject_1, 5)
+  assert field_1_GEOM.GetName() == 'Field_solids'
+  assert field_1_GEOM.GetStep(0).GetValues() == [1.0, 2.0, 3.0]
+
+  field_2_GEOM = getSubObject(geomObject_1, 6)
+  assert field_2_GEOM.GetName() == 'Field_faces'
+  assert field_2_GEOM.GetStep(0).GetValues() == [0.0, 0.0, 2.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0]
+
+  field_3_GEOM = getSubObject(geomObject_1, 7)
+  assert field_3_GEOM.GetName() == 'Field_edges'
+  assert field_3_GEOM.GetStep(0).GetValues() == [0.0, 2.0, 0.0, 2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 3.0, 3.0, 0.0, 0.0, 0.0, 0.0, 3.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 2.0, 1.0, 0.0, 0.0, 0.0]
+
+  field_4_GEOM = getSubObject(geomObject_1, 8)
+  assert field_4_GEOM.GetName() == 'Field_vertices'
+  assert field_4_GEOM.GetStep(0).GetValues() == [2.0, 1.0, 2.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 3.0, 3.0, 3.0, 1.0, 1.0, 3.0, 0.0, 0.0, 0.0, 1.0, 2.0, 1.0, 2.0, 1.0]
+
+  pass
+
+def checkDump():
+  # Dump the salome study (only CORBA modules, SHAPER dump is not in it)
+  tempdir = tempfile.gettempdir()
+  dumpFileGeomBase = "dump_test_geom"
+  dumpFileGeom = os.path.join(tempdir, "%s.py"%dumpFileGeomBase)
+  salome.myStudy.DumpStudy(tempdir, dumpFileGeomBase, True, False)
+
+  # Dump SHAPER
+  dumpFileShaper = os.path.join(tempdir, "dump_test_shaper.py")
+  dumpShaper(dumpFileShaper)
+
+  # Load SHAPER dump
+  execfile(dumpFileShaper)
+
+  # Load GEOM dump
+  execfile(dumpFileGeom)
+
+  # Clean files
+  files = [dumpFileGeom, dumpFileShaper]
+  for f in files:
+    os.remove(f)
+
+  pass
+
+if __name__ == '__main__':
+  # create 3 boxes with groups and fields
+  testGroupsAndFieldsExportToGEOM()
+  # check the result in GEOM
+  checkResultInGEOM()
+  # check that dump produces no error and can be reloaded
+  checkDump()
+  # check the result of the dump
+  checkResultInGEOM()
diff --git a/src/ConnectorAPI/Test/testme.py b/src/ConnectorAPI/Test/testme.py
new file mode 100755 (executable)
index 0000000..4a6e17a
--- /dev/null
@@ -0,0 +1,56 @@
+# Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+#!/usr/bin/env python
+
+import unittest, sys, os
+
+class SalomeSession(object):
+    def __init__(self, script):
+        import runSalome
+        run_script = "runSalome.py"
+        if sys.platform == 'win32':
+            module_dir = os.getenv("KERNEL_ROOT_DIR")
+            if module_dir: run_script = os.path.join(module_dir, "bin", "salome", run_script)
+            pass
+        sys.argv  = [run_script]
+        sys.argv += ["--terminal"]
+        sys.argv += ["--modules=SHAPER,GEOM"]
+        sys.argv += ["%s" % script]
+        if sys.platform == 'win32':
+            main_module_path = sys.modules['__main__'].__file__
+            sys.modules['__main__'].__file__ = ''
+        clt, d = runSalome.main()
+        if sys.platform == 'win32':
+            sys.modules['__main__'].__file__ = main_module_path
+        return
+
+    def __del__(self):
+        port = os.getenv('NSPORT')
+        import killSalomeWithPort
+        killSalomeWithPort.killMyPort(port)
+        return
+    pass
+
+class MyTest(unittest.TestCase):
+    def testFunction(self):
+        SalomeSession(sys.argv[1])
+    pass
+
+unittest.main(argv=sys.argv[:1])
diff --git a/src/ConnectorAPI/Test/tests.set b/src/ConnectorAPI/Test/tests.set
new file mode 100644 (file)
index 0000000..c3126a3
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright (C) 2016  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+SET(TEST_NAMES
+  TestExportToGEOM
+  TestExportToGEOMAllGroupsAndFields
+)
index aaaab43c631fe3001dfbc0d59cb897eb52e910a0..b5d42602bdee9680dcb9dabfbe213faf69c10096 100644 (file)
 ## @package Plugins
 #  ExportFeature class definition
 
-import EventsAPI
 import ModelAPI
-import GeomAPI
-import GeomAlgoAPI
+import ExchangeAPI
 
 import salome
 from salome.geom import geomBuilder
 
-def getObjectIndex(theName):
-    aStudy = salome.myStudy
-    aId = 0
-    aObj = aStudy.FindObjectByName(theName, "GEOM")
-    while len(aObj) != 0:
-        aId = aId + 1
-        aName = theName + '_' + str(aId)
-        aObj = aStudy.FindObjectByName(aName, "GEOM")
-    return aId
+from salome.shaper import model
+
+import os
+
+def getTmpFileName(ext):
+    import tempfile
+    tempdir = tempfile.gettempdir()
+    tmp_file = tempfile.NamedTemporaryFile(suffix=".%s"%ext, prefix='shaper_', dir=tempdir, delete=False)
+    tmp_filename = tmp_file.name
+    return tmp_filename
 
 ## @ingroup Plugins
 #  Feature to export all shapes and groups into the GEOM module
@@ -46,10 +45,7 @@ class ExportFeature(ModelAPI.ModelAPI_Feature):
     ## The constructor.
     def __init__(self):
         ModelAPI.ModelAPI_Feature.__init__(self)
-        ## Shape that will be exported (the compound if there are several exported bodies)
-        self.shape = None
-        ## BRep representation of the exported shape (a stream that will be sent to GEOM and converted to GEOM object)
-        self.brep = None
+        pass
 
     @staticmethod
     ## Export kind. Static.
@@ -60,7 +56,7 @@ class ExportFeature(ModelAPI.ModelAPI_Feature):
     def getKind(self):
         return ExportFeature.ID()
 
-    ## This feature is action: has no property pannel and executes immideately.
+    ## This feature is action: has no property pannel and executes immediately.
     def isAction(self):
         return True
 
@@ -68,222 +64,35 @@ class ExportFeature(ModelAPI.ModelAPI_Feature):
     def initAttributes(self):
       pass
 
-    ## Exports all bodies
-    def exportBodies(self):
-        global ShapeIndex
-        kResultBodyType = "Bodies"
-        aPartSize = self.Part.size(kResultBodyType)
-        if aPartSize == 0:
-            EventsAPI.Events_InfoMessage("ExportFeature","No results in the active document").send()
+    ## Export the results, groups and fields via XAO
+    def exportViaXAO(self):
+        tmpXAOFile = getTmpFileName("xao")
+        self.tmpXAOFile = tmpXAOFile
+        #print "Export to %s"%tmpXAOFile
+        exportXAO = ExchangeAPI.exportToXAO(self.Part, tmpXAOFile, "automatic_shaper_export_to_XAO")
+        if not os.path.exists(tmpXAOFile) or os.stat(tmpXAOFile).st_size == 0:
+            exportXAO.feature().setError("Error in exportToXAO. No XAO file has been created.")
             return
-
-        anObjList = [self.Part.object(kResultBodyType, idx) for idx in xrange(aPartSize)]
-        aShapesList = GeomAlgoAPI.ShapeList()
-        aName = ""
-        for idx, anObject in enumerate(anObjList):
-            aResult = ModelAPI.modelAPI_Result(anObject)
-            aBodyResult = ModelAPI.modelAPI_ResultBody(aResult)
-            if not aBodyResult:
-                continue
-            aShape = aBodyResult.shape()
-            if aShape is not None and not aShape.isNull():
-              aShapesList.append(aShape)
-              if len(aShapesList) == 1:
-                aName = aBodyResult.data().name()
-
-        # issue 1045: create compound if there are more than one shape
-        if len(aShapesList) > 1:
-          self.shape = GeomAlgoAPI.GeomAlgoAPI_CompoundBuilder.compound(aShapesList)
-          aName = "ShaperResults"
-        elif len(aShapesList) == 1:
-          self.shape = aShapesList[0]
-
-        # so, only one shape is always in the result
-        aDump = self.shape.getShapeStream()
-        # Load shape to SALOME Geom
-        aBrep = self.geompy.RestoreShape(aDump)
-
-        # Make unique name
-        aId = getObjectIndex(aName)
-        if aId != 0:
-            aName = aName + '_' + str(aId)
-
-        self.geompy.addToStudy(aBrep, aName)
-        self.brep = aBrep
-
-    ## Exports all groups
-    def exportGroups(self):
-        # iterate all features to find groups
-        aFeaturesNum = self.Part.size("Features")
-        groupIndex = 0
-        for anIndex in range(0, aFeaturesNum):
-            aFeature = self.Part.object("Features", anIndex)
-            aSelectionList = aFeature.data().selectionList("group_list")
-            # if a group has been found
-            if aSelectionList:
-                aFeature = ModelAPI.objectToFeature(aFeature)
-                if aFeature.firstResult() is not None:
-                  aName = aFeature.firstResult().data().name()
-                groupIndex = groupIndex + 1
-                self.createGroupFromList(aSelectionList, aName)
-
-    ## Returns a type of the shape in the old GEOM representation
-    def shapeType(self, shape):
-        if shape.isVertex():
-            return "VERTEX"
-        elif shape.isEdge():
-            return "EDGE"
-        elif shape.isFace():
-            return "FACE"
-
-        return "SOLID"
-
-    ## Creates a group by given list of selected objects and the name
-    #  @param theSelectionList: list of selected objects
-    #  @param theGroupName: name of the group to create
-    def createGroupFromList(self, theSelectionList, theGroupName):
-        # iterate on all selected entities of the group
-        # and get the corresponding ID
-        aSelectionNum = theSelectionList.size()
-        Ids = []
-        groupType = ""
-        for aSelIndex in range(0, aSelectionNum):
-            aSelection = theSelectionList.value(aSelIndex)
-            # issue 1326: bodies that are already concealed did not exported, so groups should not be invalid
-            aContext =  ModelAPI.modelAPI_Result(aSelection.context())
-            # chcking of concealment removed because of #1799, remark #13 "aContext.isConcealed()"
-            if aContext is None or aContext.isDisabled():
-                continue
-
-            anID = GeomAlgoAPI.GeomAlgoAPI_CompoundBuilder.id(self.shape, aSelection.value())
-            if anID == 0:
-                #it may be a compound of objects if movement of the group to the end
-                # splits the original element to several (issue 1146)
-                anExp = GeomAPI.GeomAPI_ShapeExplorer(aSelection.value(), GeomAPI.GeomAPI_Shape.SHAPE)
-                while anExp.more():
-                    anID = GeomAlgoAPI.GeomAlgoAPI_CompoundBuilder.id(self.shape, anExp.current())
-                    if anID != 0:
-                        Ids.append(anID)
-                        groupType = self.shapeType(anExp.current())
-                    anExp.next()
-            else:
-                Ids.append(anID)
-                groupType = self.shapeType(aSelection.value())
-
-        if len(Ids) <> 0:
-          aGroup = self.geompy.CreateGroup(self.brep, self.geompy.ShapeType[groupType])
-          self.geompy.UnionIDs(aGroup,Ids)
-          self.geompy.addToStudyInFather(self.brep, aGroup, theGroupName)
-
-    ## Exports all fields
-    def exportFields(self):
-        # iterate all features to find fields
-        aFeaturesNum = self.Part.size("Features")
-        fieldIndex = 0
-        for anIndex in range(0, aFeaturesNum):
-            aFeature = self.Part.object("Features", anIndex)
-            aSelectionList = aFeature.data().selectionList("selected")
-            # if a field has been found
-            if aSelectionList:
-                aFeature = ModelAPI.objectToFeature(aFeature)
-                if aFeature.firstResult() is not None:
-                  aName = aFeature.firstResult().data().name()
-                fieldIndex = fieldIndex + 1
-                self.createFieldFromFeature(aFeature, aName)
-
-    ## Returns a type of the shape type in the old GEOM representation
-    def selectionDim(self, theSelectionType):
-        selType=theSelectionType.lower() # more or less independed approach
-        if selType== "vertex":
-            return 0
-        if selType== "edge":
-            return 1
-        if selType== "face":
-            return 2
-        if selType== "solid":
-            return 3
-        return -1
-
-    ## Returns a type of the shape type in the GeomAPI_Shape representation
-    def geomAPISelectionDim(self, theSelectionType):
-        selType=theSelectionType.lower() # more or less independed approach
-        if selType== "vertex":
-            return GeomAPI.GeomAPI_Shape.VERTEX
-        if selType== "edge":
-            return GeomAPI.GeomAPI_Shape.EDGE
-        if selType== "face":
-            return GeomAPI.GeomAPI_Shape.FACE
-        if selType== "solid":
-            return GeomAPI.GeomAPI_Shape.SOLID
-        return GeomAPI.GeomAPI_Shape.SHAPE
-
-    ## Creates a field by the field feature and the name
-    #  @param theField: the field feature
-    #  @param theFieldName: name of the field to create
-    def createFieldFromFeature(self, theField, theFieldName):
-        # iterate on all selected entities of the field
-        # and get the corresponding ID
-        aTables = theField.tables("values")
-        aSelection = theField.selectionList("selected")
-
-        # set component names
-        aComps = theField.stringArray("components_names")
-        aCompNames = []
-        aCompNum = aComps.size()
-        for aCompIndex in range(0, aCompNum):
-          aCompNames.append(aComps.value(aCompIndex))
-
-        #if len(Ids) <> 0:
-        aDim = self.selectionDim(aSelection.selectionType())
-        aResField = self.geompy.CreateField(self.brep, theFieldName, aTables.type(), aDim, aCompNames)
-        #self.geompy.UnionIDs(theField,Ids)
-        self.geompy.addToStudyInFather(self.brep, aResField, theFieldName)
-
-        # set default values to all not filled sub-shapes (fields in GEOM support only full set of subs)
-        Ids={}
-        anExp = GeomAPI.GeomAPI_ShapeExplorer(self.shape, self.geomAPISelectionDim(aSelection.selectionType()))
-        while anExp.more():
-          anID = GeomAlgoAPI.GeomAlgoAPI_CompoundBuilder.id(self.shape, anExp.current())
-          if anID != 0:
-            Ids[anID]=anExp.current()
-          anExp.next()
-
-        SelectedIds={}
-        for aSelIndex in range(aSelection.size()):
-          selShape = aSelection.value(aSelIndex).value()
-          # searching for this shape in Ids
-          for a in Ids.items():
-            if (a[1].isSame(selShape)):
-              SelectedIds[a[0]] = aSelIndex
-
-        # values here are in the same order as in field
-        listOfValues = Ids.items()
-        listOfValues.sort()
-        # set steps
-        aStepsNum = aTables.tables()
-        for aStepIndex in range(0, aStepsNum):
-          aStamp = theField.intArray("stamps").value(aStepIndex)
-          aValues = []
-          for aValId in listOfValues:
-            aRow = 0 # default value if not from selection
-            if SelectedIds.has_key(aValId[0]): # take the value from the table
-              aRow = SelectedIds[aValId[0]] + 1 # plus one to avoid default string
-            aCols = aTables.columns()
-            for aCol in range(0, aCols):
-              aVal = aTables.valueStr(aRow, aCol, aStepIndex)
-              if aTables.type() == 0: # bool
-                if aVal == "True":
-                  aVal = True
-                else:
-                  aVal = False
-              elif aTables.type() == 1: # int
-                aVal = int(aVal)
-              elif aTables.type() == 2: # double
-                aVal = float(aVal)
-              aValues.append(aVal)
-          aStep = aResField.addStep(aStepIndex + 1, aStamp, aValues)
-          if aStep:
-            self.geompy.addToStudyInFather( aResField, aStep, aStep.GetName() )
+        imported, shape, subShapes, groups, fields = self.geompy.ImportXAO(tmpXAOFile)
+        self.geompy.addToStudy( shape, shape.GetName() )
+        # add sub-shapes and groups to the object browser
+        for obj in subShapes + groups:
+            name = obj.GetName()
+            self.geompy.addToStudyInFather(shape, obj, name)
+        # add fields to the object browser
+        for field in fields:
+            name = field.GetName()
+            self.geompy.addToStudyInFather(shape, field, name)
+            # add steps to the object browser
+            steps = field.getSteps()
+            for i_step in steps:
+                step = field.getStep(i_step)
+                i_stamp = step.GetStamp()
+                step_name = "Step %i %i"%(i_step, i_stamp)
+                self.geompy.addToStudyInFather( field, step, step_name )
+        # Remove the temporary file
+        os.remove(tmpXAOFile)
+        pass
 
     ## Exports all shapes and groups into the GEOM module.
     def execute(self):
@@ -296,8 +105,6 @@ class ExportFeature(ModelAPI.ModelAPI_Feature):
         salome.salome_init(0,1)
         self.geompy = geomBuilder.New(salome.myStudy)
 
-        # Export bodies and groups
-        self.exportBodies()
-        self.exportGroups()
-        self.exportFields()
+        self.exportViaXAO()
+
         pass
index 9a49e0b64fe7eeffcfe2032889765248fdace722..71666dca3b28ca86cf1970627ddaff1ee5155172 100644 (file)
 
 #include "ExchangeAPI_Export.h"
 //--------------------------------------------------------------------------------------
+#include <ModelAPI_Document.h>
+#include <ModelAPI_Feature.h>
 #include <ModelHighAPI_Tools.h>
+#include <ModelHighAPI_Dumper.h>
+#include <ModelHighAPI_Services.h>
 //--------------------------------------------------------------------------------------
-void exportToFile(const std::shared_ptr<ModelAPI_Document> & thePart,
+
+ExchangeAPI_Export::ExchangeAPI_Export(const std::shared_ptr<ModelAPI_Feature>& theFeature)
+: ModelHighAPI_Interface(theFeature)
+{
+  initialize();
+}
+
+/// Constructor with values for XAO export.
+ExchangeAPI_Export::ExchangeAPI_Export(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                              const std::string & theFilePath,
+                              const std::string & theAuthor,
+                              const std::string & theGeometryName)
+: ModelHighAPI_Interface(theFeature)
+{
+  initialize();
+  fillAttribute("XAO", theFeature->string(ExchangePlugin_ExportFeature::EXPORT_TYPE_ID()));
+  fillAttribute(theFilePath, theFeature->string(ExchangePlugin_ExportFeature::XAO_FILE_PATH_ID()));
+  fillAttribute(theAuthor, theFeature->string(ExchangePlugin_ExportFeature::XAO_AUTHOR_ID()));
+  fillAttribute(theGeometryName,
+                theFeature->string(ExchangePlugin_ExportFeature::XAO_GEOMETRY_NAME_ID()));
+  fillAttribute("XAO", theFeature->string(ExchangePlugin_ExportFeature::FILE_FORMAT_ID()));
+  execute();
+  apply(); // finish operation to make sure the export is done on the current state of the history
+}
+
+/// Constructor with values for export in other formats than XAO.
+ExchangeAPI_Export::ExchangeAPI_Export(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                              const std::string & theFilePath,
+                              const std::list<ModelHighAPI_Selection> & theSelectionList,
+                              const std::string & theFileFormat)
+: ModelHighAPI_Interface(theFeature)
+{
+  initialize();
+  fillAttribute("Regular", theFeature->string(ExchangePlugin_ExportFeature::EXPORT_TYPE_ID()));
+  fillAttribute(theFilePath, theFeature->string(ExchangePlugin_ExportFeature::FILE_PATH_ID()));
+  fillAttribute(theSelectionList,
+                theFeature->selectionList(ExchangePlugin_ExportFeature::SELECTION_LIST_ID()));
+  fillAttribute(theFileFormat, theFeature->string(ExchangePlugin_ExportFeature::FILE_FORMAT_ID()));
+  execute();
+  apply(); // finish operation to make sure the export is done on the current state of the history
+}
+
+ExchangeAPI_Export::~ExchangeAPI_Export()
+{
+}
+
+
+void ExchangeAPI_Export::dump(ModelHighAPI_Dumper& theDumper) const
+{
+
+  FeaturePtr aBase = feature();
+  const std::string& aDocName = theDumper.name(aBase->document());
+
+  theDumper << aBase << " = model.";
+
+  std::string exportType = aBase->string(ExchangePlugin_ExportFeature::EXPORT_TYPE_ID())->value();
+
+  if (exportType == "XAO") {
+    std::string tmpXAOFile = aBase->string(ExchangePlugin_ExportFeature::XAO_FILE_PATH_ID())->value();
+    theDumper << "exportToXAO(" << aDocName << ", '" << tmpXAOFile << "'" ;
+    std::string theAuthor = aBase->string(ExchangePlugin_ExportFeature::XAO_AUTHOR_ID())->value();
+    if (not theAuthor.empty())
+      theDumper << ", '" << theAuthor << "'";
+    std::string theGeometryName = aBase->string(ExchangePlugin_ExportFeature::XAO_GEOMETRY_NAME_ID())->value();
+    if (not theGeometryName.empty())
+      theDumper << ", '" << theGeometryName << "'";
+    theDumper << ")" << std::endl;
+  }
+  else {
+      theDumper << "exportToFile(" << aDocName << ", " <<
+          aBase->string(ExchangePlugin_ExportFeature::FILE_PATH_ID()) << ", " <<
+          aBase->selectionList(ExchangePlugin_ExportFeature::SELECTION_LIST_ID()) ;
+      std::string theFileFormat = aBase->string(ExchangePlugin_ExportFeature::FILE_FORMAT_ID())->value();
+      if (not theFileFormat.empty())
+        theDumper << ", '" << theFileFormat << "'";
+      theDumper << ")" << std::endl;
+  }
+}
+
+ExportPtr exportToFile(const std::shared_ptr<ModelAPI_Document> & thePart,
                   const std::string & theFilePath,
                   const std::list<ModelHighAPI_Selection> & theSelectionList,
                   const std::string & theFileFormat)
 {
+  apply(); // finish previous operation to make sure all previous operations are done
   std::shared_ptr<ModelAPI_Feature> aFeature =
     thePart->addFeature(ExchangePlugin_ExportFeature::ID());
-  fillAttribute("Regular", aFeature->string(ExchangePlugin_ExportFeature::EXPORT_TYPE_ID()));
-  fillAttribute(theFilePath, aFeature->string(ExchangePlugin_ExportFeature::FILE_PATH_ID()));
-  fillAttribute(theSelectionList,
-                aFeature->selectionList(ExchangePlugin_ExportFeature::SELECTION_LIST_ID()));
-  fillAttribute(theFileFormat, aFeature->string(ExchangePlugin_ExportFeature::FILE_FORMAT_ID()));
-  aFeature->execute();
+  return ExportPtr(new ExchangeAPI_Export(aFeature, theFilePath, theSelectionList, theFileFormat));
 }
 
-void exportToXAO(const std::shared_ptr<ModelAPI_Document> & thePart,
+ExportPtr exportToXAO(const std::shared_ptr<ModelAPI_Document> & thePart,
                  const std::string & theFilePath,
                  const std::string & theAuthor,
                  const std::string & theGeometryName)
 {
+  apply(); // finish previous operation to make sure all previous operations are done
   std::shared_ptr<ModelAPI_Feature> aFeature =
     thePart->addFeature(ExchangePlugin_ExportFeature::ID());
-  fillAttribute("XAO", aFeature->string(ExchangePlugin_ExportFeature::EXPORT_TYPE_ID()));
-  fillAttribute(theFilePath, aFeature->string(ExchangePlugin_ExportFeature::XAO_FILE_PATH_ID()));
-  fillAttribute(theAuthor, aFeature->string(ExchangePlugin_ExportFeature::XAO_AUTHOR_ID()));
-  fillAttribute(theGeometryName,
-                aFeature->string(ExchangePlugin_ExportFeature::XAO_GEOMETRY_NAME_ID()));
-  fillAttribute("XAO", aFeature->string(ExchangePlugin_ExportFeature::FILE_FORMAT_ID()));
-  aFeature->execute();
+  return ExportPtr(new ExchangeAPI_Export(aFeature, theFilePath, theAuthor, theGeometryName));
 }
 
 //--------------------------------------------------------------------------------------
index f10bf831c137ebd011efffdc12c14d1435cfea1f..a4b314836c0775554452e820a61094bf348f6b7f 100644 (file)
 //--------------------------------------------------------------------------------------
 class ModelHighAPI_Selection;
 //--------------------------------------------------------------------------------------
+
+
+/// \class ExchangeAPI_Export
+/// \ingroup CPPHighAPI
+/// \brief Interface for Export feature.
+class ExchangeAPI_Export: public ModelHighAPI_Interface
+{
+public:
+  /// Constructor without values.
+  EXCHANGEAPI_EXPORT
+  explicit ExchangeAPI_Export(const std::shared_ptr<ModelAPI_Feature>& theFeature);
+
+  /// Constructor with values for XAO export.
+  EXCHANGEAPI_EXPORT
+  explicit ExchangeAPI_Export(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                              const std::string & theFilePath,
+                              const std::string & theAuthor = std::string(),
+                              const std::string & theGeometryName = std::string());
+
+  /// Constructor with values for export in other formats than XAO.
+  EXCHANGEAPI_EXPORT
+  explicit ExchangeAPI_Export(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                              const std::string & theFilePath,
+                              const std::list<ModelHighAPI_Selection> & theSelectionList,
+                              const std::string & theFileFormat = std::string());
+
+  /// Destructor.
+  EXCHANGEAPI_EXPORT
+  virtual ~ExchangeAPI_Export();
+
+  INTERFACE_7(ExchangePlugin_ExportFeature::ID(),
+             exportType, ExchangePlugin_ExportFeature::EXPORT_TYPE_ID(),
+             ModelAPI_AttributeString, /** ExportType */,
+             filePath, ExchangePlugin_ExportFeature::FILE_PATH_ID(),
+             ModelAPI_AttributeString, /** file path */,
+             xaoFilePath, ExchangePlugin_ExportFeature::XAO_FILE_PATH_ID(),
+             ModelAPI_AttributeString, /** xao_file_path */,
+             fileFormat, ExchangePlugin_ExportFeature::FILE_FORMAT_ID(),
+             ModelAPI_AttributeString, /** file format */,
+             selectionList, ExchangePlugin_ExportFeature::SELECTION_LIST_ID(),
+             ModelAPI_AttributeString, /** selection list */,
+             xaoAuthor, ExchangePlugin_ExportFeature::XAO_AUTHOR_ID(),
+             ModelAPI_AttributeString, /** xao author */,
+             xaoGeometryName, ExchangePlugin_ExportFeature::XAO_GEOMETRY_NAME_ID(),
+             ModelAPI_AttributeString, /** xao geometry name */)
+
+  /// Dump wrapped feature
+  EXCHANGEAPI_EXPORT
+  virtual void dump(ModelHighAPI_Dumper& theDumper) const;
+};
+
+/// Pointer on Export object
+typedef std::shared_ptr<ExchangeAPI_Export> ExportPtr;
+
 /**\ingroup CPPHighAPI
  * \brief Export to file
  */
 EXCHANGEAPI_EXPORT
-void exportToFile(const std::shared_ptr<ModelAPI_Document> & thePart,
+ExportPtr exportToFile(const std::shared_ptr<ModelAPI_Document> & thePart,
                   const std::string & theFilePath,
                   const std::list<ModelHighAPI_Selection> & theSelectionList,
                   const std::string & theFileFormat = std::string());
@@ -47,7 +101,7 @@ void exportToFile(const std::shared_ptr<ModelAPI_Document> & thePart,
  * \brief Export XAO
  */
 EXCHANGEAPI_EXPORT
-void exportToXAO(const std::shared_ptr<ModelAPI_Document> & thePart,
+ExportPtr exportToXAO(const std::shared_ptr<ModelAPI_Document> & thePart,
                  const std::string & theFilePath,
                  const std::string & theAuthor = std::string(),
                  const std::string & theGeometryName = std::string());
index 0c78b27e19d564ea586603b39054585ecea74786..8b7f59638cf9edba2b1703e94b083a35d36b98f1 100644 (file)
@@ -225,6 +225,7 @@ void ExchangePlugin_ExportFeature::exportXAO(const std::string& theFileName)
 
   // make shape for export from all results
   std::list<GeomShapePtr> aShapes;
+  std::list<ResultBodyPtr> aResults;
   int aBodyCount = document()->size(ModelAPI_ResultBody::group());
   for (int aBodyIndex = 0; aBodyIndex < aBodyCount; ++aBodyIndex) {
     ResultBodyPtr aResultBody =
@@ -233,6 +234,7 @@ void ExchangePlugin_ExportFeature::exportXAO(const std::string& theFileName)
     if (!aResultBody.get())
       continue;
     aShapes.push_back(aResultBody->shape());
+    aResults.push_back(aResultBody);
   }
   GeomShapePtr aShape = (aShapes.size() == 1)
       ? *aShapes.begin()
@@ -246,8 +248,13 @@ void ExchangePlugin_ExportFeature::exportXAO(const std::string& theFileName)
   }
 
   // geometry name
-
   std::string aGeometryName = string(ExchangePlugin_ExportFeature::XAO_GEOMETRY_NAME_ID())->value();
+  if (aGeometryName.empty() and aBodyCount == 1){
+    // get the name from the first result
+    ResultBodyPtr aResultBody = *aResults.begin();
+    aGeometryName = aResultBody->data()->name();
+  }
+
   aXao.getGeometry()->setName(aGeometryName);
 
   // groups
@@ -276,7 +283,12 @@ void ExchangePlugin_ExportFeature::exportXAO(const std::string& theFileName)
       AttributeSelectionPtr aSelection = aSelectionList->value(aSelectionIndex);
 
       // complex conversion of reference id to element index
-      int aReferenceID = aSelection->Id();
+      // gives bad id in case the selection is done from python script
+      // => using GeomAlgoAPI_CompoundBuilder::id instead
+      // int aReferenceID_old = aSelection->Id();
+
+      int aReferenceID = GeomAlgoAPI_CompoundBuilder::id(aShape, aSelection->value());
+
       std::string aReferenceString = XAO::XaoUtils::intToString(aReferenceID);
       int anElementID =
         aXao.getGeometry()->getElementIndexByReference(aGroupDimension, aReferenceString);
@@ -335,7 +347,12 @@ void ExchangePlugin_ExportFeature::exportXAO(const std::string& theFileName)
             AttributeSelectionPtr aSelection = aSelectionList->value(aRow - 1);
 
             // complex conversion of reference id to element index
-            int aReferenceID = aSelection->Id();
+            // gives bad id in case the selection is done from python script
+            // => using GeomAlgoAPI_CompoundBuilder::id instead
+            //int aReferenceID_old = aSelection->Id();
+
+            int aReferenceID = GeomAlgoAPI_CompoundBuilder::id(aShape, aSelection->value());
+
             std::string aReferenceString = XAO::XaoUtils::intToString(aReferenceID);
             anElementID =
               aXao.getGeometry()->getElementIndexByReference(aFieldDimension, aReferenceString);
index 754198869b2ad4dec31224c4b724968bd8bb7315..f0866181c1e63d5c22a2b05ae1f5965a91a4419f 100644 (file)
@@ -105,12 +105,17 @@ public:
   /// Computes or recomputes the results
   EXCHANGEPLUGIN_EXPORT virtual void execute();
 
-  /// Reimplemented from ModelAPI_Feature::isMacro(). Returns true.
-  EXCHANGEPLUGIN_EXPORT virtual bool isMacro() const { return true; }
+  /// Reimplemented from ModelAPI_Feature::isMacro(). Returns false.
+  // Not a macro. Otherwise, the feature will be deleted after being executed
+  EXCHANGEPLUGIN_EXPORT virtual bool isMacro() const { return false; }
 
   /// Reimplemented from ModelAPI_Feature::isPreviewNeeded(). Returns false.
   EXCHANGEPLUGIN_EXPORT virtual bool isPreviewNeeded() const { return false; }
 
+  /// Do not put in history.
+  /// Since it is not a macro, it is not deleted, but we don't want to see it.
+  bool isInHistory()  { return false; }
+
 protected:
   /// Performs export of the file
   EXCHANGEPLUGIN_EXPORT void exportFile(const std::string& theFileName,
index 0848d67148e91dbc26008ec41a0fc4aea8a26b8c..566bbdf0576e2d1af5d5c7464a496b2ee97b90b7 100644 (file)
@@ -413,5 +413,40 @@ So
       <element index="1"/>
     </group>
   </groups>
-  <fields count="0"/>
+  <fields count="1">
+    <field name="Field_1" type="double" dimension="face">
+      <components count="2">
+        <component column="0" name="temperatue"/>
+        <component column="1" name="porosity"/>
+      </components>
+      <steps count="1">
+        <step number="0" stamp="10">
+          <element index="0">
+            <value component="0">2</value>
+            <value component="1">5</value>
+          </element>
+          <element index="1">
+            <value component="0">3</value>
+            <value component="1">6</value>
+          </element>
+          <element index="2">
+            <value component="0">1</value>
+            <value component="1">4</value>
+          </element>
+          <element index="3">
+            <value component="0">1</value>
+            <value component="1">4</value>
+          </element>
+          <element index="4">
+            <value component="0">1</value>
+            <value component="1">4</value>
+          </element>
+          <element index="5">
+            <value component="0">1</value>
+            <value component="1">4</value>
+          </element>
+        </step>
+      </steps>
+    </field>
+  </fields>
 </XAO>
index d3f88a729dca44ca2232a419da8f9b39f04fad4f..696a2b0c270eafc0885326dca553db00e133ea42 100644 (file)
@@ -144,8 +144,8 @@ def testExportXAO():
     aSession.finishOperation()
 
     # Check exported file
-#    import filecmp
-#    assert filecmp.cmp("Data/export.xao", "Data/export_ref.xao")
+    import filecmp
+    assert filecmp.cmp("Data/export.xao", "Data/export_ref.xao")
 
 if __name__ == '__main__':
 #=========================================================================
index 0cdebfdfefe8b2e29eaf0b65026fc2cd59e74297..5cb8cd081073ef6cbde2bd33ef13cf4d6015f446 100644 (file)
@@ -61,8 +61,9 @@ class DumpAssistant(ModelHighAPI.ModelHighAPI_Dumper):
         aFeatureKind = theFeature.getKind()
         if aFeatureKind in self.myFeatures:
             # Dump only feature created by user (in history).
+            # Also dump Export features (hard-coded here in order not to change the data model).
             # For all other features, just keep their name.
-            if theForce or theFeature.isInHistory():
+            if theForce or theFeature.isInHistory() or aFeatureKind=="Export":
                 self.myFeatures[aFeatureKind](theFeature).dump(self)
             else:
                 self.name(theFeature)