diff --git a/VirtualSatelliteCAD/Init.py b/VirtualSatelliteCAD/Init.py
index 1e61532..f4074cb 100644
--- a/VirtualSatelliteCAD/Init.py
+++ b/VirtualSatelliteCAD/Init.py
@@ -24,9 +24,11 @@
# SPDX-License-Identifier: LGPL-3.0-or-later
#
import FreeCAD
-from os.path import isdir
+import os
import sys
+MOD_DIR = os.path.join(FreeCAD.ConfigGet("UserAppData"), "Mod")
+APPDATA_DIR = os.path.join(MOD_DIR, "VirtualSatelliteCAD")
# FreeCAD seems to load modules differently once they are stored in the User Home directory.
# We try to load the whole folder if it exists
@@ -37,7 +39,7 @@
Log("See if the directory " + freecad_user_mod + "exists...")
-if isdir(freecad_user_mod):
+if os.path.isdir(freecad_user_mod):
Log("Directory Exists... Check if it is already on the path...")
if (freecad_user_mod in sys.path):
Log("Directory is already on the path...")
@@ -45,5 +47,11 @@
Log("Directory will be appended to system path...")
sys.path.append(freecad_user_mod)
+# Create an appdata directory
+if not os.path.isdir(MOD_DIR):
+ os.mkdir(MOD_DIR)
+if not os.path.isdir(APPDATA_DIR):
+ os.mkdir(APPDATA_DIR)
+
# Finally register the unit test for being executed with all other FreeCAD tests
FreeCAD.__unit_test__ += ["TestVirtualSatelliteApp"]
diff --git a/VirtualSatelliteCAD/InitGui.py b/VirtualSatelliteCAD/InitGui.py
index ff4ccea..9dc35be 100644
--- a/VirtualSatelliteCAD/InitGui.py
+++ b/VirtualSatelliteCAD/InitGui.py
@@ -45,10 +45,10 @@ def Initialize(self):
import commands.command_export # NOQA @UnusedImport
from commands.command_definitions import COMMAND_ID_EXPORT_2_VIRTUAL_SATELLITE
from commands.command_definitions import COMMAND_ID_IMPORT_2_FREECAD
- self.appendToolbar('VirtualSatelliteMod', [COMMAND_ID_EXPORT_2_VIRTUAL_SATELLITE])
- self.appendMenu('VirtualSatelliteMod', [COMMAND_ID_EXPORT_2_VIRTUAL_SATELLITE])
self.appendToolbar('VirtualSatelliteMod', [COMMAND_ID_IMPORT_2_FREECAD])
self.appendMenu('VirtualSatelliteMod', [COMMAND_ID_IMPORT_2_FREECAD])
+ self.appendToolbar('VirtualSatelliteMod', [COMMAND_ID_EXPORT_2_VIRTUAL_SATELLITE])
+ self.appendMenu('VirtualSatelliteMod', [COMMAND_ID_EXPORT_2_VIRTUAL_SATELLITE])
def GetClassName(self):
# Required method by FreeCAD framework
diff --git a/VirtualSatelliteCAD/Resources/Tests/VisCube2.json b/VirtualSatelliteCAD/Resources/Tests/VisCube2.json
new file mode 100644
index 0000000..bf4ca17
--- /dev/null
+++ b/VirtualSatelliteCAD/Resources/Tests/VisCube2.json
@@ -0,0 +1,158 @@
+{
+ "Products": {
+ "children": [{
+ "posX": 0.0,
+ "posY": 0.0,
+ "posZ": 1.0,
+ "rotX": 0.0,
+ "children": [],
+ "rotZ": 0.0,
+ "rotY": 0.0,
+ "name": "Top",
+ "uuid": "cc14e2c7-9d7e-4cf2-8d6d-9b8cf5e96d56",
+ "partUuid": "cc14e2c7-9d7e-4cf2-8d6d-9b8cf5e96d56",
+ "partName": "Top"
+ }, {
+ "posX": 0.0,
+ "posY": 0.0,
+ "posZ": 0.0,
+ "rotX": 0.0,
+ "children": [],
+ "rotZ": 0.0,
+ "rotY": 0.0,
+ "name": "Bottom",
+ "uuid": "61db0622-6fef-4f12-932d-a00fdb9d0848",
+ "partUuid": "00f430a6-6311-4a33-961b-41ded4cf57d5",
+ "partName": "Plate"
+ }, {
+ "posX": 0.5,
+ "posY": 0.0,
+ "posZ": 0.5,
+ "rotX": 0.0,
+ "children": [],
+ "rotZ": 0.0,
+ "rotY": 1.5707963267948966,
+ "name": "Front",
+ "uuid": "e6af9d3f-8ad6-4488-b3d0-d35549be9a1e",
+ "partUuid": "e6af9d3f-8ad6-4488-b3d0-d35549be9a1e",
+ "partName": "Front"
+ }, {
+ "posX": -0.5,
+ "posY": 0.0,
+ "posZ": 0.5,
+ "rotX": 0.0,
+ "children": [],
+ "rotZ": 0.0,
+ "rotY": 1.5707963267948966,
+ "name": "Back",
+ "uuid": "a3c9c547-8fd3-40d5-97a1-a3f9a3a9c337",
+ "partUuid": "a3c9c547-8fd3-40d5-97a1-a3f9a3a9c337",
+ "partName": "Back"
+ }, {
+ "posX": 0.0,
+ "posY": 0.0,
+ "posZ": 0.5,
+ "rotX": 0.0,
+ "children": [{
+ "posX": 0.0,
+ "posY": 0.5,
+ "posZ": 0.0,
+ "rotX": 1.5707963267948966,
+ "children": [],
+ "rotZ": 0.0,
+ "rotY": 0.0,
+ "name": "Left",
+ "uuid": "615985c0-73fd-48db-8f8b-e11b7cbb2ee8",
+ "partUuid": "615985c0-73fd-48db-8f8b-e11b7cbb2ee8",
+ "partName": "Left"
+ }, {
+ "posX": 0.0,
+ "posY": -0.5,
+ "posZ": 0.0,
+ "rotX": 1.5707963267948966,
+ "children": [],
+ "rotZ": 0.0,
+ "rotY": 0.0,
+ "name": "Right",
+ "uuid": "882a0b35-7da8-4555-903d-fd6b5cbec392",
+ "partUuid": "882a0b35-7da8-4555-903d-fd6b5cbec392",
+ "partName": "Right"
+ }
+ ],
+ "rotZ": 0.0,
+ "rotY": 0.0,
+ "name": "BeamStructure",
+ "uuid": "2afb23c9-f458-4bdb-a4e7-fc863364644f",
+ "partUuid": "2afb23c9-f458-4bdb-a4e7-fc863364644f",
+ "partName": "BeamStructure"
+ }
+ ],
+ "name": "SpaceCube",
+ "uuid": "a3533e02-125c-4066-bffe-d046d8d8342a"
+ },
+ "Parts": [{
+ "color": 16744448,
+ "shape": "CYLINDER",
+ "name": "BeamStructure",
+ "lengthY": 1.0,
+ "lengthX": 1.0,
+ "radius": 0.05,
+ "uuid": "2afb23c9-f458-4bdb-a4e7-fc863364644f",
+ "lengthZ": 1.0
+ }, {
+ "color": 8388608,
+ "shape": "BOX",
+ "name": "Right",
+ "lengthY": 1.0,
+ "lengthX": 1.0,
+ "radius": 0.05,
+ "uuid": "882a0b35-7da8-4555-903d-fd6b5cbec392",
+ "lengthZ": 0.02
+ }, {
+ "color": 32832,
+ "shape": "BOX",
+ "name": "Front",
+ "lengthY": 1.0,
+ "lengthX": 1.0,
+ "radius": 0.05,
+ "uuid": "e6af9d3f-8ad6-4488-b3d0-d35549be9a1e",
+ "lengthZ": 0.02
+ }, {
+ "color": 16711680,
+ "shape": "BOX",
+ "name": "Left",
+ "lengthY": 1.0,
+ "lengthX": 1.0,
+ "radius": 0.05,
+ "uuid": "615985c0-73fd-48db-8f8b-e11b7cbb2ee8",
+ "lengthZ": 0.02
+ }, {
+ "color": 65280,
+ "shape": "BOX",
+ "name": "Plate",
+ "lengthY": 1.0,
+ "lengthX": 1.0,
+ "radius": 0.05,
+ "uuid": "00f430a6-6311-4a33-961b-41ded4cf57d5",
+ "lengthZ": 0.02
+ }, {
+ "color": 16776960,
+ "shape": "BOX",
+ "name": "Back",
+ "lengthY": 1.0,
+ "lengthX": 1.0,
+ "radius": 0.05,
+ "uuid": "a3c9c547-8fd3-40d5-97a1-a3f9a3a9c337",
+ "lengthZ": 0.02
+ }, {
+ "color": 32768,
+ "shape": "BOX",
+ "name": "Top",
+ "lengthY": 1.0,
+ "lengthX": 1.0,
+ "radius": 0.05,
+ "uuid": "cc14e2c7-9d7e-4cf2-8d6d-9b8cf5e96d56",
+ "lengthZ": 0.02
+ }
+ ]
+}
\ No newline at end of file
diff --git a/VirtualSatelliteCAD/Resources/Tests/VisCube2_update.json b/VirtualSatelliteCAD/Resources/Tests/VisCube2_update.json
new file mode 100644
index 0000000..082262e
--- /dev/null
+++ b/VirtualSatelliteCAD/Resources/Tests/VisCube2_update.json
@@ -0,0 +1,31 @@
+{
+ "Products": {
+ "children": [{
+ "posX": 0.0,
+ "posY": 0.0,
+ "posZ": 1.0,
+ "rotX": 0.0,
+ "children": [],
+ "rotZ": 0.0,
+ "rotY": 0.0,
+ "name": "Top",
+ "uuid": "cc14e2c7-9d7e-4cf2-8d6d-9b8cf5e96d56",
+ "partUuid": "cc14e2c7-9d7e-4cf2-8d6d-9b8cf5e96d57",
+ "partName": "Top2"
+ }
+ ],
+ "name": "SpaceCube",
+ "uuid": "a3533e02-125c-4066-bffe-d046d8d8342a"
+ },
+ "Parts": [{
+ "color": 32768,
+ "shape": "BOX",
+ "name": "Top2",
+ "lengthY": 1.0,
+ "lengthX": 1.0,
+ "radius": 0.05,
+ "uuid": "cc14e2c7-9d7e-4cf2-8d6d-9b8cf5e96d57",
+ "lengthZ": 0.02
+ }
+ ]
+}
\ No newline at end of file
diff --git a/VirtualSatelliteCAD/TestVirtualSatelliteApp.py b/VirtualSatelliteCAD/TestVirtualSatelliteApp.py
index 8ebab03..abf8191 100644
--- a/VirtualSatelliteCAD/TestVirtualSatelliteApp.py
+++ b/VirtualSatelliteCAD/TestVirtualSatelliteApp.py
@@ -36,4 +36,5 @@
from test.json_io.products.test_json_product import TestJsonProduct # NOQA
from test.json_io.products.test_json_product_assembly import TestJsonProductAssembly # NOQA
from test.json_io.products.test_json_product_child import TestJsonProductChild # NOQA
+from test.json_io.products.test_json_product_assembly_tree_traverser import TestJsonProductAssemblyTreeTraverser # NOQA
from test.freecad.test_actice_document import TestActiveDocument # NOQA
diff --git a/VirtualSatelliteCAD/commands/command_export.py b/VirtualSatelliteCAD/commands/command_export.py
index 24ccddd..5f94ffd 100644
--- a/VirtualSatelliteCAD/commands/command_export.py
+++ b/VirtualSatelliteCAD/commands/command_export.py
@@ -26,21 +26,21 @@
import FreeCAD
import FreeCADGui
-from module.environment import Environment, ICON_IMPORT
+from module.environment import Environment, ICON_EXPORT
from commands.command_definitions import COMMAND_ID_EXPORT_2_VIRTUAL_SATELLITE
class CommandExport:
def Activated(self):
- FreeCAD.Console.PrintMessage("Calling the importer\n")
+ FreeCAD.Console.PrintMessage("Calling the exporter\n")
def IsActive(self):
return True
def GetResources(self):
- return {'Pixmap': Environment().get_icon_path(ICON_IMPORT),
- 'MenuText': 'Import from Virtual Satellite',
- 'ToolTip': 'Open the dialog for the Virtual Satellite json import.'}
+ return {'Pixmap': Environment().get_icon_path(ICON_EXPORT),
+ 'MenuText': 'Export from Virtual Satellite',
+ 'ToolTip': 'Open the dialog for the Virtual Satellite json export.'}
FreeCADGui.addCommand(COMMAND_ID_EXPORT_2_VIRTUAL_SATELLITE, CommandExport()) # @UndefinedVariable
diff --git a/VirtualSatelliteCAD/commands/command_import.py b/VirtualSatelliteCAD/commands/command_import.py
index 1dc2713..62bdc40 100644
--- a/VirtualSatelliteCAD/commands/command_import.py
+++ b/VirtualSatelliteCAD/commands/command_import.py
@@ -28,19 +28,46 @@
import FreeCADGui
from module.environment import Environment, ICON_IMPORT
from commands.command_definitions import COMMAND_ID_IMPORT_2_FREECAD
+from PySide2.QtWidgets import QFileDialog
+from json_io.json_importer import JsonImporter
+import os
+import json
+Log = FreeCAD.Console.PrintMessage
-class CommandExport:
+
+class CommandImport:
def Activated(self):
- FreeCAD.Console.PrintMessage("Calling the json_io\n")
+ Log("Calling the importer\n")
+
+ # call pyqt dialog: returns (filename, filter)
+ filename = QFileDialog.getOpenFileName(
+ None, # ui parent
+ "Open JSON file", # dialog caption
+ Environment.get_appdata_module_path(),
+ "JSON(*.json)")[0] # filter
+
+ if filename != '':
+ (f"Selected file '{filename}'\n")
+
+ with open(filename, 'r') as f:
+ try:
+ json_object = json.load(f)
+ except ValueError as error:
+ Log(f"ERROR: Invalid JSON found: '{error}'\n")
+ Log("Please provide a valid JSON\n")
+ return
+
+ json_importer = JsonImporter(Environment.get_appdata_module_path() + os.sep)
+ json_importer.full_import(json_object)
def IsActive(self):
return True
def GetResources(self):
return {'Pixmap': Environment().get_icon_path(ICON_IMPORT),
- 'MenuText': 'Export to Virtual Satellite',
- 'ToolTip': 'Open the dialog for the Virtual Satellite json export.'}
+ 'MenuText': 'Import to Virtual Satellite',
+ 'ToolTip': 'Open the dialog for the Virtual Satellite json import.'}
-FreeCADGui.addCommand(COMMAND_ID_IMPORT_2_FREECAD, CommandExport()) # @UndefinedVariable
+FreeCADGui.addCommand(COMMAND_ID_IMPORT_2_FREECAD, CommandImport()) # @UndefinedVariable
diff --git a/VirtualSatelliteCAD/freecad/active_document.py b/VirtualSatelliteCAD/freecad/active_document.py
index a49d343..1cf324b 100644
--- a/VirtualSatelliteCAD/freecad/active_document.py
+++ b/VirtualSatelliteCAD/freecad/active_document.py
@@ -70,6 +70,14 @@ def open_set_and_get_document(self, file_name_without_extension):
return self
+ def clear_if_open_document(self, file_name_without_extension):
+ documents = list(App.listDocuments().keys())
+
+ if documents.count(file_name_without_extension) != 0:
+ Log('Delete and recreate new FreeCAD file...\n')
+ App.closeDocument(file_name_without_extension)
+ App.newDocument(file_name_without_extension)
+
def set_active_documents(self, file_name_without_extension):
App.setActiveDocument(file_name_without_extension)
diff --git a/VirtualSatelliteCAD/json_io/json_definitions.py b/VirtualSatelliteCAD/json_io/json_definitions.py
index baf6832..2eca28b 100644
--- a/VirtualSatelliteCAD/json_io/json_definitions.py
+++ b/VirtualSatelliteCAD/json_io/json_definitions.py
@@ -30,6 +30,9 @@
RAD_TO_DEG = 180.0 / math.pi
+JSON_PARTS = "Parts"
+JSON_PRODUCTS = "Products"
+
JSON_ELEMENT_COLOR = "color"
JSON_ELEMENT_SHAPE = "shape"
@@ -64,6 +67,9 @@
JSON_ELEMNT_CHILDREN = "children"
+PART_IDENTIFIER = "part_"
+PRODUCT_IDENTIFIER = "assembly_"
+
def _get_combined_name_uuid(name, uuid):
return str(name + "_" + uuid.replace("-", "_"))
diff --git a/VirtualSatelliteCAD/json_io/json_importer.py b/VirtualSatelliteCAD/json_io/json_importer.py
index 281f94e..f31ba9e 100644
--- a/VirtualSatelliteCAD/json_io/json_importer.py
+++ b/VirtualSatelliteCAD/json_io/json_importer.py
@@ -28,7 +28,8 @@
import FreeCADGui
from freecad.active_document import ActiveDocument
from json_io.parts.json_part_factory import JsonPartFactory
-from json_io.json_definitions import get_part_name_uuid
+from json_io.products.json_product_assembly_tree_traverser import JsonProductAssemblyTreeTraverser
+from json_io.json_definitions import get_part_name_uuid, JSON_PRODUCTS, JSON_PARTS, PART_IDENTIFIER
App = FreeCAD
Gui = FreeCADGui
@@ -40,22 +41,24 @@
class JsonImporter(object):
'''
- classdocs
+ Provides functionality to import a JSON created by Virtual Satellite into FreeCAD
'''
- def __init__(self, working_ouput_directory):
- self.working_output_directory = working_ouput_directory
+ def __init__(self, working_output_directory):
+ self.working_output_directory = working_output_directory
def create_or_update_part(self, json_object):
Log("Creating or Updating a part...\n")
json_part = JsonPartFactory().create_from_json(json_object)
+ part_file_name = ""
+
if json_part is not None:
# Use the name to create the part document
# should be careful in case the name already exists.
# thus it is combined with the uuid. not really nice
# but definitely efficient
- part_file_name = get_part_name_uuid(json_object)
+ part_file_name = PART_IDENTIFIER + get_part_name_uuid(json_object)
active_document = ActiveDocument(self.working_output_directory).open_set_and_get_document(part_file_name)
@@ -65,3 +68,24 @@ def create_or_update_part(self, json_object):
Log("Saved part to file: " + part_file_name + "\n")
else:
Log("Visualization shape is most likely NONE, therefore no file is created\n")
+
+ return part_file_name
+
+ def full_import(self, json_object):
+ '''
+ Import a whole json file's products and parts into a FreeCAD document
+ '''
+ Log(f"Calling the importer'\n")
+
+ json_parts = json_object[JSON_PARTS]
+
+ part_file_names = []
+ for part in json_parts:
+ part_file_names.append(self.create_or_update_part(part))
+
+ traverser = JsonProductAssemblyTreeTraverser(self.working_output_directory)
+ json_product, active_document = traverser.traverse_and_parse_from_json(json_object[JSON_PRODUCTS])
+
+ Log(f"Import successful\n")
+
+ return part_file_names, json_product, active_document
diff --git a/VirtualSatelliteCAD/json_io/json_spread_sheet.py b/VirtualSatelliteCAD/json_io/json_spread_sheet.py
index 600630d..fe7626e 100644
--- a/VirtualSatelliteCAD/json_io/json_spread_sheet.py
+++ b/VirtualSatelliteCAD/json_io/json_spread_sheet.py
@@ -67,14 +67,18 @@ def write_to_freecad(self, active_document):
sheet_line = FREECAD_PART_SHEET_ATTRIBUTE_START_LINE
for json_part_attribute_name in list(self._json_part_or_product.attributes.keys()):
- json_part_attribute_value = str(getattr(self._json_part_or_product, json_part_attribute_name))
- json_part_attribute_unit = self._json_part_or_product.attributes[json_part_attribute_name]
-
- sheet.set("A" + str(sheet_line), json_part_attribute_name)
- sheet.set("B" + str(sheet_line), json_part_attribute_value)
- sheet.set("C" + str(sheet_line), json_part_attribute_unit)
-
- sheet_line += 1
+ # TODO: added this try catch because some children would not have part_name and attribute (because they are assemblies)
+ try:
+ json_part_attribute_value = str(getattr(self._json_part_or_product, json_part_attribute_name))
+ json_part_attribute_unit = self._json_part_or_product.attributes[json_part_attribute_name]
+
+ sheet.set("A" + str(sheet_line), json_part_attribute_name)
+ sheet.set("B" + str(sheet_line), json_part_attribute_value)
+ sheet.set("C" + str(sheet_line), json_part_attribute_unit)
+
+ sheet_line += 1
+ except AttributeError as e:
+ print(e)
# Recompute the sheet, so that all properties are correctly written
# if not recomputed accessing the properties will result in none objects
diff --git a/VirtualSatelliteCAD/json_io/parts/json_part.py b/VirtualSatelliteCAD/json_io/parts/json_part.py
index d0305e2..70192e6 100644
--- a/VirtualSatelliteCAD/json_io/parts/json_part.py
+++ b/VirtualSatelliteCAD/json_io/parts/json_part.py
@@ -27,7 +27,7 @@
from json_io.json_definitions import JSON_ELEMENT_NAME, JSON_ELEMENT_SHAPE,\
JSON_ELEMENT_UUID, JSON_ELEMENT_LENGTH_X, JSON_ELEMENT_LENGTH_Y,\
JSON_ELEMENT_LENGTH_Z, JSON_ELEMENT_RADIUS, JSON_ELEMENT_COLOR, M_TO_MM,\
- _get_combined_name_uuid
+ _get_combined_name_uuid, PART_IDENTIFIER
from json_io.json_spread_sheet import JsonSpreadSheet
@@ -138,4 +138,4 @@ def get_shape_type(self):
return shape_type
def get_unique_name(self):
- return _get_combined_name_uuid(self.name, self.uuid)
+ return PART_IDENTIFIER + _get_combined_name_uuid(self.name, self.uuid)
diff --git a/VirtualSatelliteCAD/json_io/products/json_product.py b/VirtualSatelliteCAD/json_io/products/json_product.py
index b456e9c..61033e5 100644
--- a/VirtualSatelliteCAD/json_io/products/json_product.py
+++ b/VirtualSatelliteCAD/json_io/products/json_product.py
@@ -28,7 +28,7 @@
JSON_ELEMENT_POS_Y, JSON_ELEMENT_POS_X,\
JSON_ELEMENT_POS_Z, JSON_ELEMENT_ROT_X, JSON_ELEMENT_ROT_Y,\
JSON_ELEMENT_ROT_Z, JSON_ELEMENT_PART_UUID, JSON_ELEMENT_PART_NAME, M_TO_MM,\
- RAD_TO_DEG, _get_combined_name_uuid, JSON_ELEMNT_CHILDREN
+ RAD_TO_DEG, _get_combined_name_uuid, JSON_ELEMNT_CHILDREN, PART_IDENTIFIER
from json_io.json_spread_sheet import JsonSpreadSheet
from A2plus.a2p_importpart import importPartFromFile
from freecad.active_document import VECTOR_X, VECTOR_Y, VECTOR_Z, VECTOR_ZERO
@@ -58,6 +58,9 @@ def __init__(self):
self.rot_y = 0.0
self.rot_z = 0.0
+ self.name = None
+ self.uuid = None
+
def _parse_name_and_uuid_from_json(self, json_object):
self.name = str(json_object[JSON_ELEMENT_NAME])
self.uuid = str(json_object[JSON_ELEMENT_UUID]).replace("-", "_")
@@ -97,19 +100,24 @@ def _create_or_update_freecad_part(self, active_document):
This method imports the part referenced by the product.
The referenced part will be placed under the product part name into
the assembly. E.g. A BasePlate will be added as BasePlateBottom to the
- assembly. In case the object already exists, nothing special will happen.
+ assembly. In case the object already exists, it will be recreated.
'''
import_part_file_name = self.get_part_unique_name()
import_part_name_in_product = self.get_unique_name()
import_part_full_path = active_document.get_file_full_path(import_part_file_name)
+ import_part_ref = active_document.app_active_document.getObjectsByLabel(import_part_name_in_product)
+
+ # print(f"Called with '{import_part_name_in_product}'")
+ # TODO: CRUD
+ # If the part doesn't exists (the returned list is not empty) update (delete and recreate) it
+ if import_part_ref:
+ active_document.app_active_document.removeObject(import_part_ref[0].Name)
+
imported_product_part = importPartFromFile(
active_document.app_active_document,
import_part_full_path)
imported_product_part.Label = import_part_name_in_product
- def _set_freecad_name_and_color(self, active_document):
- pass
-
def _set_freecad_position_and_rotation(self, active_document):
product_part_name = self.get_unique_name()
@@ -122,7 +130,7 @@ def _set_freecad_position_and_rotation(self, active_document):
vector_rotation_y = active_document.app.Rotation(VECTOR_Y, self.rot_y)
vector_rotation_z = active_document.app.Rotation(VECTOR_Z, self.rot_z)
- placement = product_part.Placement
+ placement = product_part.Placement # Placement()
placement_translation = active_document.app.Placement(
vector_translation,
@@ -167,7 +175,7 @@ def get_part_unique_name(self):
'''
Returns the unique name of the referenced part
'''
- return _get_combined_name_uuid(self.part_name, self.part_uuid)
+ return PART_IDENTIFIER + _get_combined_name_uuid(self.part_name, self.part_uuid)
def is_part_reference(self):
'''
@@ -178,3 +186,22 @@ def is_part_reference(self):
has_part_name = hasattr(self, "part_name")
return has_part_uuid and has_part_name
+
+ def has_equal_values(self, other):
+ """
+ Compares values with another AJsonProduct
+ """
+ if(isinstance(other, AJsonProduct)):
+ return (
+ self.pos_x == other.pos_x and
+ self.pos_y == other.pos_y and
+ self.pos_z == other.pos_z and
+
+ self.rot_x == other.rot_x and
+ self.rot_y == other.rot_y and
+ self.rot_z == other.rot_z and
+
+ self.name == other.name and
+ self.uuid == other.uuid)
+
+ return NotImplemented
diff --git a/VirtualSatelliteCAD/json_io/products/json_product_assembly.py b/VirtualSatelliteCAD/json_io/products/json_product_assembly.py
index 426d984..fdca5d5 100644
--- a/VirtualSatelliteCAD/json_io/products/json_product_assembly.py
+++ b/VirtualSatelliteCAD/json_io/products/json_product_assembly.py
@@ -25,7 +25,7 @@
#
from json_io.products.json_product import AJsonProduct
-from json_io.json_definitions import JSON_ELEMNT_CHILDREN
+from json_io.json_definitions import JSON_ELEMNT_CHILDREN, PRODUCT_IDENTIFIER, _get_combined_name_uuid
from json_io.products.json_product_child import JsonProductChild
@@ -70,6 +70,7 @@ class without implementation. Additionally this method starts parsing
self.children = []
for json_object_child in json_object_children:
json_product_child = JsonProductChild().parse_from_json(json_object_child)
+ # json_product_child.propagate_pos_and_rot_from_parent(self)
self.children.append(json_product_child)
# Don't hand back an assembly if there are no children
@@ -89,3 +90,6 @@ def write_to_freecad(self, active_document):
# part or a product
for child in self.children:
child.write_to_freecad(active_document)
+
+ def get_product_unique_name(self):
+ return PRODUCT_IDENTIFIER + _get_combined_name_uuid(self.name, self.uuid)
diff --git a/VirtualSatelliteCAD/json_io/products/json_product_assembly_tree_traverser.py b/VirtualSatelliteCAD/json_io/products/json_product_assembly_tree_traverser.py
new file mode 100644
index 0000000..b78f02a
--- /dev/null
+++ b/VirtualSatelliteCAD/json_io/products/json_product_assembly_tree_traverser.py
@@ -0,0 +1,88 @@
+# -*- coding: utf-8 -*-
+#
+# Virtual Satellite 4 - FreeCAD module
+#
+# Copyright (C) 2019 by
+#
+# DLR (German Aerospace Center),
+# Software for Space Systems and interactive Visualization
+# Braunschweig, Germany
+#
+# This program 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 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see .
+#
+# SPDX-License-Identifier: LGPL-3.0-or-later
+
+from json_io.products.json_product_assembly import JsonProductAssembly
+from json_io.json_definitions import JSON_ELEMNT_CHILDREN, JSON_ELEMENT_NAME
+from freecad.active_document import ActiveDocument
+import FreeCAD
+Log = FreeCAD.Console.PrintLog
+
+
+class JsonProductAssemblyTreeTraverser(object):
+ '''
+ This class provides functionality to traverse a product tree to parse the product assemblies in the right order
+ '''
+
+ def __init__(self, working_output_directory):
+ self._lst_of_depths = []
+ self.working_output_directory = working_output_directory
+
+ def traverse(self, json_object, depth=0):
+ """
+ Recursive traverse the tree and create a list containing the found depths,
+ that for each depth contains a list of found assembly (NOT child) nodes at that depth
+ """
+
+ # only look for products that have children
+ if(JSON_ELEMNT_CHILDREN in json_object and json_object[JSON_ELEMNT_CHILDREN] != []):
+
+ # if the current depth has no list in the _lst_of_depths, add it
+ if(len(self._lst_of_depths) < depth + 1):
+ self._lst_of_depths.append([])
+ Log(f"Added depth {depth} to _lst_of_depths\n")
+
+ # append found assembly to the list
+ self._lst_of_depths[depth].append(json_object)
+ Log(f"Found assembly '{json_object[JSON_ELEMENT_NAME]}' at {depth}\n")
+
+ # recursive call on all children
+ for child in json_object[JSON_ELEMNT_CHILDREN]:
+ self.traverse(child, depth+1)
+
+ def parse_from_json(self):
+ """
+ Iterate through the list created by traversing the tree in reverse and parse the found product assemblies
+ """
+ json_product, active_document = None, None
+
+ # parse in reverse order
+ for depth in reversed(self._lst_of_depths):
+ for assembly in depth:
+ Log(f"Parsing '{assembly[JSON_ELEMENT_NAME]}'\n")
+
+ json_product = JsonProductAssembly().parse_from_json(assembly)
+ active_document = ActiveDocument(self.working_output_directory).open_set_and_get_document(json_product.get_product_unique_name())
+ json_product.write_to_freecad(active_document)
+ active_document.save_and_close_active_document(json_product.get_product_unique_name())
+
+ # the last json_product is the root of the assembly, open it again for the UI
+ if(json_product is not None):
+ active_document = ActiveDocument(self.working_output_directory).open_set_and_get_document(json_product.get_product_unique_name())
+
+ return json_product, active_document
+
+ def traverse_and_parse_from_json(self, json_object):
+ self.traverse(json_object)
+ return self.parse_from_json()
diff --git a/VirtualSatelliteCAD/json_io/products/json_product_child.py b/VirtualSatelliteCAD/json_io/products/json_product_child.py
index 56583ad..13e5994 100644
--- a/VirtualSatelliteCAD/json_io/products/json_product_child.py
+++ b/VirtualSatelliteCAD/json_io/products/json_product_child.py
@@ -26,6 +26,7 @@
from json_io.products.json_product import AJsonProduct
from json_io.json_definitions import _get_combined_name_uuid
+from json_io.json_definitions import PART_IDENTIFIER, PRODUCT_IDENTIFIER
class JsonProductChild(AJsonProduct):
@@ -37,6 +38,6 @@ def get_part_unique_name(self):
In this case the file name of the product has to be returned
'''
if self.has_children:
- return _get_combined_name_uuid(self.name, self.uuid)
+ return PRODUCT_IDENTIFIER + _get_combined_name_uuid(self.name, self.uuid)
else:
- return _get_combined_name_uuid(self.part_name, self.part_uuid)
+ return PART_IDENTIFIER + _get_combined_name_uuid(self.part_name, self.part_uuid)
diff --git a/VirtualSatelliteCAD/module/environment.py b/VirtualSatelliteCAD/module/environment.py
index dadf9b7..4fe05d1 100644
--- a/VirtualSatelliteCAD/module/environment.py
+++ b/VirtualSatelliteCAD/module/environment.py
@@ -39,7 +39,7 @@
class Environment:
'''
This class helps to understand the environment where the module is executed in.
- E.g. knwoing which is the directory of the module and so on
+ E.g. knowing which is the directory of the module and so on
'''
@classmethod
@@ -90,3 +90,11 @@ def get_test_resource_path(cls, test_resource_name):
'''
path = os.path.join(cls.get_tests_resource_path(), test_resource_name)
return path
+
+ # TODO: Update user file handling
+ @classmethod
+ def get_appdata_module_path(cls):
+ '''
+ This method hands back the module path of the local Appdata directory.
+ '''
+ return Init.APPDATA_DIR
diff --git a/VirtualSatelliteCAD/test/json_io/parts/test_json_part.py b/VirtualSatelliteCAD/test/json_io/parts/test_json_part.py
index 7ebe2bc..e5d2335 100644
--- a/VirtualSatelliteCAD/test/json_io/parts/test_json_part.py
+++ b/VirtualSatelliteCAD/test/json_io/parts/test_json_part.py
@@ -32,6 +32,7 @@
import FreeCAD
import FreeCADGui
from test.json_io.test_json_data import TEST_JSON_PART_BOX
+from json_io.json_definitions import PART_IDENTIFIER
App = FreeCAD
Gui = FreeCADGui
@@ -105,4 +106,4 @@ def test_get_part_unique_name(self):
json_part = AJsonPart()
json_part.parse_from_json(json_object)
- self.assertEquals(json_part.get_unique_name(), "Beam_6201a731_d703_43f8_ab37_6a0581dfe022", "Correct unique name")
+ self.assertEquals(json_part.get_unique_name(), PART_IDENTIFIER + "Beam_6201a731_d703_43f8_ab37_6a0581dfe022", "Correct unique name")
diff --git a/VirtualSatelliteCAD/test/json_io/products/test_json_product.py b/VirtualSatelliteCAD/test/json_io/products/test_json_product.py
index ef880d1..4f3961b 100644
--- a/VirtualSatelliteCAD/test/json_io/products/test_json_product.py
+++ b/VirtualSatelliteCAD/test/json_io/products/test_json_product.py
@@ -31,6 +31,7 @@
import FreeCADGui
from json_io.products.json_product import AJsonProduct
from test.json_io.test_json_data import TEST_JSON_PRODUCT_WITHOUT_CHILDREN
+from json_io.json_definitions import PART_IDENTIFIER
App = FreeCAD
@@ -76,7 +77,7 @@ def test_get_unique_names(self):
json_product = AJsonProduct().parse_from_json(json_object)
self.assertEquals(json_product.get_unique_name(), "BasePlateBottom_e8794f3d_86ec_44c5_9618_8b7170c45484", "Correct unique name")
- self.assertEquals(json_product.get_part_unique_name(), "BasePlate_3d3708fd_5c6c_4af9_b710_d68778466084", "Correct unique name")
+ self.assertEquals(json_product.get_part_unique_name(), PART_IDENTIFIER + "BasePlate_3d3708fd_5c6c_4af9_b710_d68778466084", "Correct unique name")
def test_is_part_reference(self):
json_data = """{
diff --git a/VirtualSatelliteCAD/test/json_io/products/test_json_product_assembly.py b/VirtualSatelliteCAD/test/json_io/products/test_json_product_assembly.py
index 4fcee99..b94431a 100644
--- a/VirtualSatelliteCAD/test/json_io/products/test_json_product_assembly.py
+++ b/VirtualSatelliteCAD/test/json_io/products/test_json_product_assembly.py
@@ -32,8 +32,8 @@
from json_io.products.json_product_assembly import JsonProductAssembly
from freecad.active_document import ActiveDocument
from test.json_io.test_json_data import TEST_JSON_PRODUCT_WITH_CHILDREN,\
- TEST_JSON_PRODUCT_WITHOUT_CHILDREN
-
+ TEST_JSON_PRODUCT_WITHOUT_CHILDREN, TEST_JSON_PRODUCT_WITH_CHILDREN_WITH_CHILD
+from json_io.json_definitions import JSON_ELEMNT_CHILDREN, PRODUCT_IDENTIFIER
App = FreeCAD
Gui = FreeCADGui
@@ -79,6 +79,23 @@ def test_parse_with_children(self):
self.assertEqual(json_product_child_1.name, "BasePlateBottom2", "Parsed correct child")
self.assertEqual(json_product_child_2.name, "BasePlateTop", "Parsed correct child")
+ # Check that position and rotation from parent are propagated correctly
+ self.assertEqual(json_product_child_1.pos_x, 0, "Property is correctly set")
+ self.assertEqual(json_product_child_1.pos_y, 0, "Property is correctly set")
+ self.assertEqual(json_product_child_1.pos_z, 0, "Property is correctly set")
+
+ self.assertEqual(json_product_child_1.rot_x, 0.0, "Property is correctly set")
+ self.assertEqual(json_product_child_1.rot_y, 0.0, "Property is correctly set")
+ self.assertEqual(json_product_child_1.rot_z, 0.0, "Property is correctly set")
+
+ self.assertEqual(json_product_child_2.pos_x, 0, "Property is correctly set")
+ self.assertEqual(json_product_child_2.pos_y, 0, "Property is correctly set")
+ self.assertEqual(json_product_child_2.pos_z, 500.0, "Property is correctly set")
+
+ self.assertEqual(json_product_child_2.rot_x, 0.0, "Property is correctly set")
+ self.assertEqual(json_product_child_2.rot_y, 0.0, "Property is correctly set")
+ self.assertEqual(json_product_child_2.rot_z, 0.0, "Property is correctly set")
+
def test_parse_with_no_children(self):
json_data = TEST_JSON_PRODUCT_WITHOUT_CHILDREN
@@ -93,7 +110,6 @@ def test_create_part_product_assembly_with_root_part(self):
active_document = ActiveDocument(self._WORKING_DIRECTORY).open_set_and_get_document("ProductAssemblyRootPart")
json_object = json.loads(self.json_data)
json_product = JsonProductAssembly().parse_from_json(json_object)
- active_document.save_as("ProductAssemblyRootPart")
json_product.write_to_freecad(active_document)
@@ -115,3 +131,53 @@ def test_create_part_product_assembly_with_root_part(self):
product_child2_part_name = json_product.children[1].get_unique_name()
product_object = active_document.app_active_document.getObjectsByLabel(product_child2_part_name)[0]
self.assertIsNotNone(product_object, "Found an object under the given part name")
+
+ def test_create_part_product_subassembly_with_root_part(self):
+ json_data = TEST_JSON_PRODUCT_WITH_CHILDREN_WITH_CHILD
+ self.create_Test_Part()
+
+ active_document = ActiveDocument(self._WORKING_DIRECTORY).open_set_and_get_document("ProductSubassemblyRootPart")
+
+ json_object = json.loads(json_data)
+
+ subassembly = json_object[JSON_ELEMNT_CHILDREN][0]
+ json_product = JsonProductAssembly().parse_from_json(subassembly)
+
+ json_product.write_to_freecad(active_document)
+ active_document.save_as("ProductSubassemblyRootPart")
+
+ self.assertEquals(len(json_product.children), 1, "correct amount of children")
+ self.assertEquals(len(active_document.app_active_document.RootObjects), 4, "Found correct amount of root objects 2 objects plus 2 sheets")
+
+ product_part_name = json_product.get_unique_name()
+ product_object = active_document.app_active_document.getObjectsByLabel(product_part_name)[0]
+ self.assertIsNotNone(product_object, "Found an object under the given part name")
+
+ product_child1_part_name = json_product.children[0].get_unique_name()
+ product_object = active_document.app_active_document.getObjectsByLabel(product_child1_part_name)[0]
+ self.assertIsNotNone(product_object, "Found an object under the given part name")
+
+ def test_create_part_product_assembly_and_subassembly_with_root_part_manual(self):
+ json_data = TEST_JSON_PRODUCT_WITH_CHILDREN_WITH_CHILD
+ self.create_Test_Part()
+
+ json_object = json.loads(json_data)
+
+ subassembly = json_object[JSON_ELEMNT_CHILDREN][0]
+
+ active_document = ActiveDocument(self._WORKING_DIRECTORY).open_set_and_get_document(
+ PRODUCT_IDENTIFIER + "BasePlateBottom2_e8794f3d_86ec_44c5_9618_8b7170c45484")
+
+ json_product = JsonProductAssembly().parse_from_json(subassembly)
+ json_product.write_to_freecad(active_document)
+ active_document.save_as(PRODUCT_IDENTIFIER + "BasePlateBottom2_e8794f3d_86ec_44c5_9618_8b7170c45484")
+
+ self.assertEquals(len(active_document.app_active_document.RootObjects), 4, "Found correct amount of root objects 2 objects plus 2 sheets")
+
+ active_document = ActiveDocument(self._WORKING_DIRECTORY).open_set_and_get_document("ProductAssemblyAndSubassemblyRootPart")
+
+ json_product = JsonProductAssembly().parse_from_json(json_object)
+ json_product.write_to_freecad(active_document)
+ active_document.save_as("ProductAssemblyAndSubassemblyRootPart")
+
+ self.assertEquals(len(active_document.app_active_document.RootObjects), 6, "Found correct amount of root objects 3 objects plus 3 sheets")
diff --git a/VirtualSatelliteCAD/test/json_io/products/test_json_product_assembly_tree_traverser.py b/VirtualSatelliteCAD/test/json_io/products/test_json_product_assembly_tree_traverser.py
new file mode 100644
index 0000000..ec593c9
--- /dev/null
+++ b/VirtualSatelliteCAD/test/json_io/products/test_json_product_assembly_tree_traverser.py
@@ -0,0 +1,149 @@
+#
+# DLR (German Aerospace Center),
+# Software for Space Systems and interactive Visualization
+# Braunschweig, Germany
+#
+# This program 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 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see .
+#
+# SPDX-License-Identifier: LGPL-3.0-or-later
+#
+from test.test_setup import AWorkingDirectoryTest
+from test.json_io.test_json_data import TEST_JSON_PRODUCT_WITH_CHILDREN_WITH_CHILD, TEST_JSON_PRODUCT_WITHOUT_CHILDREN, \
+ TEST_JSON_PRODUCT_WITH_CHILDREN_WITH_CHILD_SUBASSEMBLY_IS_NO_PART, TEST_JSON_PRODUCT_SUBASSEMBLY_WITH_SAME_PART
+import json
+from json_io.products.json_product_assembly_tree_traverser import JsonProductAssemblyTreeTraverser
+from json_io.json_definitions import JSON_ELEMENT_NAME, PRODUCT_IDENTIFIER
+from freecad.active_document import ActiveDocument
+import glob
+import os
+
+
+class TestJsonProductAssemblyTreeTraverser(AWorkingDirectoryTest):
+
+ @classmethod
+ def setUpClass(cls):
+ cls.setUpDirectory("ProductAssemblyTreeTraverser/")
+ cls._WORKING_DIRECTORY = cls.getDirectoryFullPath()
+
+ def tearDown(self):
+ super().tearDown()
+
+ def clearWorkingDirectory(self):
+ filelist = glob.glob(os.path.join(self._WORKING_DIRECTORY, "*"))
+ for f in filelist:
+ os.remove(f)
+
+ def test_traverse_json(self):
+ json_data = TEST_JSON_PRODUCT_WITH_CHILDREN_WITH_CHILD
+ self.create_Test_Part()
+
+ json_object = json.loads(json_data)
+
+ traverser = JsonProductAssemblyTreeTraverser(self._WORKING_DIRECTORY)
+ traverser.traverse(json_object)
+ lst_of_depths = traverser._lst_of_depths
+
+ self.assertEqual(len(lst_of_depths), 2, "Found the right amount of 2 depths")
+ self.assertEqual(len(lst_of_depths[0]), 1, "Found the right amount of 1 assembly at depth 0")
+ self.assertEqual(len(lst_of_depths[1]), 1, "Found the right amount of 1 assembly at depth 1")
+ self.assertEqual(lst_of_depths[0][0][JSON_ELEMENT_NAME], "BasePlateBottom1", "Found the right element at depth 0")
+ self.assertEqual(lst_of_depths[1][0][JSON_ELEMENT_NAME], "BasePlateBottom2", "Found the right element at depth 1")
+
+ def test_parse_json_from_tree_without_traversing(self):
+
+ traverser = JsonProductAssemblyTreeTraverser(self._WORKING_DIRECTORY)
+ self.assertIsNone(traverser.parse_from_json()[0], "Parsing no read in json object will result in 'None'")
+
+ def test_traverse_and_parse_json_tree(self):
+ json_data = TEST_JSON_PRODUCT_WITH_CHILDREN_WITH_CHILD
+ self.create_Test_Part()
+
+ json_object = json.loads(json_data)
+
+ traverser = JsonProductAssemblyTreeTraverser(self._WORKING_DIRECTORY)
+ traverser.traverse(json_object)
+ lst_of_depths = traverser._lst_of_depths
+
+ self.assertEqual(len(lst_of_depths), 2, "Found the right amount of 2 assemblies")
+
+ traverser.parse_from_json()
+
+ # this should have similar results to test_create_part_product_assembly_and_subassembly_with_root_part_manual in TestJsonProductAssembly
+ active_document = ActiveDocument(self._WORKING_DIRECTORY).open_set_and_get_document(
+ PRODUCT_IDENTIFIER + "BasePlateBottom2_e8794f3d_86ec_44c5_9618_8b7170c45484")
+ self.assertEquals(len(active_document.app_active_document.RootObjects), 4, "Found correct amount of root objects 2 objects plus 2 sheets")
+
+ active_document = ActiveDocument(self._WORKING_DIRECTORY).open_set_and_get_document(
+ PRODUCT_IDENTIFIER + "BasePlateBottom1_e8794f3d_86ec_44c5_9618_8b7170c45484")
+ self.assertEquals(len(active_document.app_active_document.RootObjects), 6, "Found correct amount of root objects 3 objects plus 3 sheets")
+
+ def test_traverse_and_parse_json_tree_subassembly_no_part(self):
+ self.clearWorkingDirectory()
+ json_data = TEST_JSON_PRODUCT_WITH_CHILDREN_WITH_CHILD_SUBASSEMBLY_IS_NO_PART
+ self.create_Test_Part()
+
+ json_object = json.loads(json_data)
+
+ traverser = JsonProductAssemblyTreeTraverser(self._WORKING_DIRECTORY)
+ traverser.traverse(json_object)
+ lst_of_depths = traverser._lst_of_depths
+
+ self.assertEqual(len(lst_of_depths), 2, "Found the right amount of 2 assemblies")
+
+ traverser.parse_from_json()
+
+ # in this test case the product assembly "BasePlateBottom2" only has a child and not a part reference
+ active_document = ActiveDocument(self._WORKING_DIRECTORY).open_set_and_get_document(
+ PRODUCT_IDENTIFIER + "BasePlateBottom2_e8794f3d_86ec_44c5_9618_8b7170c45484")
+ self.assertEquals(len(active_document.app_active_document.RootObjects), 2, "Found correct amount of root objects 1 objects plus 1 sheets")
+
+ active_document = ActiveDocument(self._WORKING_DIRECTORY).open_set_and_get_document(
+ PRODUCT_IDENTIFIER + "BasePlateBottom1_e8794f3d_86ec_44c5_9618_8b7170c45484")
+ self.assertEquals(len(active_document.app_active_document.RootObjects), 6, "Found correct amount of root objects 3 objects plus 3 sheets")
+
+ def test_traverse_and_parse_json_tree_subassembly_same_part(self):
+ self.clearWorkingDirectory()
+ json_data = TEST_JSON_PRODUCT_SUBASSEMBLY_WITH_SAME_PART
+ self.create_Test_Part()
+
+ json_object = json.loads(json_data)
+
+ traverser = JsonProductAssemblyTreeTraverser(self._WORKING_DIRECTORY)
+ traverser.traverse(json_object)
+ lst_of_depths = traverser._lst_of_depths
+
+ self.assertEqual(len(lst_of_depths), 2, "Found the right amount of 2 assemblies")
+
+ traverser.parse_from_json()
+
+ # in this test case the product assembly "BasePlate" refers a part "BasePlate" with the same name and uuid
+ active_document = ActiveDocument(self._WORKING_DIRECTORY).open_set_and_get_document(
+ PRODUCT_IDENTIFIER + "BasePlate_3d3708fd_5c6c_4af9_b710_d68778466084")
+ self.assertEquals(len(active_document.app_active_document.RootObjects), 4, "Found correct amount of root objects 2 objects plus 2 sheets")
+
+ # the root assembly should only have a part and the product assembly "BasePlate"
+ active_document = ActiveDocument(self._WORKING_DIRECTORY).open_set_and_get_document(
+ PRODUCT_IDENTIFIER + "BasePlateBottom1_e8794f3d_86ec_44c5_9618_8b7170c45484")
+ self.assertEquals(len(active_document.app_active_document.RootObjects), 4, "Found correct amount of root objects 2 objects plus 2 sheets")
+
+ def test_traverse_and_parse_json_tree_rootassembly_without_children(self):
+ json_data = TEST_JSON_PRODUCT_WITHOUT_CHILDREN
+ self.create_Test_Part()
+
+ json_object = json.loads(json_data)
+
+ traverser = JsonProductAssemblyTreeTraverser(self._WORKING_DIRECTORY)
+ traverser.traverse_and_parse_from_json(json_object)
+
+ self.assertIsNone(traverser.parse_from_json()[0], "Parsing a json object without children")
diff --git a/VirtualSatelliteCAD/test/json_io/products/test_json_product_child.py b/VirtualSatelliteCAD/test/json_io/products/test_json_product_child.py
index 7be5aed..2f2dbc4 100644
--- a/VirtualSatelliteCAD/test/json_io/products/test_json_product_child.py
+++ b/VirtualSatelliteCAD/test/json_io/products/test_json_product_child.py
@@ -31,7 +31,7 @@
import FreeCADGui
from json_io.products.json_product_child import JsonProductChild
from freecad.active_document import ActiveDocument
-from json_io.json_definitions import get_product_name_uuid
+from json_io.json_definitions import get_product_name_uuid, PART_IDENTIFIER, PRODUCT_IDENTIFIER
from test.json_io.test_json_data import TEST_JSON_PRODUCT_WITHOUT_CHILDREN,\
TEST_JSON_PRODUCT_WITH_ONE_CHILD
@@ -73,14 +73,16 @@ def test_parse(self):
self.assertAlmostEqual(json_product.rot_z, 60, 5, "Property is correctly set")
self.assertFalse(json_product.has_children, "Current product has no children")
- self.assertEquals(json_product.get_part_unique_name(), "BasePlate_3d3708fd_5c6c_4af9_b710_d68778466084", "No children thus references the part")
+ self.assertEquals(json_product.get_part_unique_name(),
+ PART_IDENTIFIER + "BasePlate_3d3708fd_5c6c_4af9_b710_d68778466084", "No children thus references the part")
def test_parse_with_children(self):
json_object = json.loads(self.json_data_with_child)
json_product = JsonProductChild().parse_from_json(json_object)
self.assertTrue(json_product.has_children, "Current product has children")
- self.assertEquals(json_product.get_part_unique_name(), "BasePlateBottom_e8794f3d_86ec_44c5_9618_8b7170c45484", "No children thus references the part")
+ self.assertEquals(json_product.get_part_unique_name(),
+ PRODUCT_IDENTIFIER + "BasePlateBottom_e8794f3d_86ec_44c5_9618_8b7170c45484", "No children thus references the part")
def test_create_part_product_child(self):
self.create_Test_Part()
diff --git a/VirtualSatelliteCAD/test/json_io/test_json_data.py b/VirtualSatelliteCAD/test/json_io/test_json_data.py
index 22c4375..15e9637 100644
--- a/VirtualSatelliteCAD/test/json_io/test_json_data.py
+++ b/VirtualSatelliteCAD/test/json_io/test_json_data.py
@@ -97,9 +97,9 @@
"uuid": "e8794f3d-86ec-44c5-9618-8b7170c45484",
"partUuid": "3d3708fd-5c6c-4af9-b710-d68778466084",
"partName": "BasePlate",
- "posX": 10.0,
- "posY": 15.0,
- "posZ": 20.0,
+ "posX": 1.0,
+ "posY": 2.0,
+ "posZ": 3.0,
"rotX": 0.349,
"rotY": 0.698,
"rotZ": 1.046,
@@ -136,6 +136,165 @@
}
"""
+TEST_JSON_PRODUCT_WITH_CHILDREN_WITH_CHILD = """{
+ "name": "BasePlateBottom1",
+ "uuid": "e8794f3d-86ec-44c5-9618-8b7170c45484",
+ "partUuid": "3d3708fd-5c6c-4af9-b710-d68778466084",
+ "partName": "BasePlate",
+ "posX": 1.0,
+ "posY": 2.0,
+ "posZ": 3.0,
+ "rotX": 0.349,
+ "rotY": 0.698,
+ "rotZ": 1.046,
+ "children": [
+ {
+ "posX": 0.0,
+ "posY": 0.0,
+ "posZ": 0.0,
+ "rotX": 0.0,
+ "children": [
+ {
+ "posX": 0.5,
+ "posY": 0.5,
+ "posZ": 0.5,
+ "rotX": 0.0,
+ "children": [
+ ],
+ "rotZ": 0.0,
+ "rotY": 0.0,
+ "name": "BasePlateBottom3",
+ "uuid": "e8794f3d-86ec-44c5-9618-8b7170c45485",
+ "partUuid": "3d3708fd-5c6c-4af9-b710-d68778466084",
+ "partName": "BasePlate"
+ }
+ ],
+ "rotZ": 0.3490659,
+ "rotY": 0.0,
+ "name": "BasePlateBottom2",
+ "uuid": "e8794f3d-86ec-44c5-9618-8b7170c45484",
+ "partUuid": "3d3708fd-5c6c-4af9-b710-d68778466084",
+ "partName": "BasePlate"
+ },
+ {
+ "posX": 0.0,
+ "posY": 0.0,
+ "posZ": 0.5,
+ "rotX": 0.0,
+ "children": [
+ ],
+ "rotZ": 0.0,
+ "rotY": 0.0,
+ "name": "BasePlateTop",
+ "uuid": "a199e3bd-3bc1-426d-8321-e9bd829339b3",
+ "partUuid": "3d3708fd-5c6c-4af9-b710-d68778466084",
+ "partName": "BasePlate"
+ }
+ ]
+ }
+ """
+
+TEST_JSON_PRODUCT_WITH_CHILDREN_WITH_CHILD_SUBASSEMBLY_IS_NO_PART = """{
+ "name": "BasePlateBottom1",
+ "uuid": "e8794f3d-86ec-44c5-9618-8b7170c45484",
+ "partUuid": "3d3708fd-5c6c-4af9-b710-d68778466084",
+ "partName": "BasePlate",
+ "posX": 1.0,
+ "posY": 2.0,
+ "posZ": 3.0,
+ "rotX": 0.349,
+ "rotY": 0.698,
+ "rotZ": 1.046,
+ "children": [
+ {
+ "posX": 0.0,
+ "posY": 0.0,
+ "posZ": 0.0,
+ "rotX": 0.0,
+ "children": [
+ {
+ "posX": 0.5,
+ "posY": 0.5,
+ "posZ": 0.5,
+ "rotX": 0.0,
+ "children": [
+ ],
+ "rotZ": 0.0,
+ "rotY": 0.0,
+ "name": "BasePlateBottom3",
+ "uuid": "e8794f3d-86ec-44c5-9618-8b7170c45485",
+ "partUuid": "3d3708fd-5c6c-4af9-b710-d68778466084",
+ "partName": "BasePlate"
+ }
+ ],
+ "rotZ": 0.3490659,
+ "rotY": 0.0,
+ "name": "BasePlateBottom2",
+ "uuid": "e8794f3d-86ec-44c5-9618-8b7170c45484"
+ },
+ {
+ "posX": 0.0,
+ "posY": 0.0,
+ "posZ": 0.5,
+ "rotX": 0.0,
+ "children": [
+ ],
+ "rotZ": 0.0,
+ "rotY": 0.0,
+ "name": "BasePlateTop",
+ "uuid": "a199e3bd-3bc1-426d-8321-e9bd829339b3",
+ "partUuid": "3d3708fd-5c6c-4af9-b710-d68778466084",
+ "partName": "BasePlate"
+ }
+ ]
+ }
+ """
+
+TEST_JSON_PRODUCT_SUBASSEMBLY_WITH_SAME_PART = """{
+ "name": "BasePlateBottom1",
+ "uuid": "e8794f3d-86ec-44c5-9618-8b7170c45484",
+ "partUuid": "3d3708fd-5c6c-4af9-b710-d68778466084",
+ "partName": "BasePlate",
+ "posX": 1.0,
+ "posY": 2.0,
+ "posZ": 3.0,
+ "rotX": 0.349,
+ "rotY": 0.698,
+ "rotZ": 1.046,
+ "children": [
+ {
+ "posX": 0.0,
+ "posY": 0.0,
+ "posZ": 0.0,
+ "rotX": 0.0,
+ "children": [
+ {
+ "posX": 0.5,
+ "posY": 0.5,
+ "posZ": 0.5,
+ "rotX": 0.0,
+ "children": [
+ ],
+ "rotZ": 0.0,
+ "rotY": 0.0,
+ "name": "BasePlateBottom3",
+ "uuid": "e8794f3d-86ec-44c5-9618-8b7170c45485",
+ "partUuid": "3d3708fd-5c6c-4af9-b710-d68778466084",
+ "partName": "BasePlate"
+ }
+ ],
+ "rotZ": 0.3490659,
+ "rotY": 0.0,
+ "name": "BasePlate",
+ "uuid": "3d3708fd-5c6c-4af9-b710-d68778466084",
+ "partUuid": "3d3708fd-5c6c-4af9-b710-d68778466084",
+ "partName": "BasePlate"
+ }
+ ]
+ }
+ """
+
+
TEST_JSON_PRODUCT_WITHOUT_CHILDREN = """{
"name": "BasePlateBottom",
"uuid": "e8794f3d-86ec-44c5-9618-8b7170c45484",
@@ -181,3 +340,162 @@
]
}
"""
+TEST_JSON_FULL_VISCUBE = """{
+ "Products": {
+ "children": [{
+ "posX": 0.0,
+ "posY": 0.0,
+ "posZ": 1.0,
+ "rotX": 0.0,
+ "children": [],
+ "rotZ": 0.0,
+ "rotY": 0.0,
+ "name": "Top",
+ "uuid": "cc14e2c7-9d7e-4cf2-8d6d-9b8cf5e96d56",
+ "partUuid": "cc14e2c7-9d7e-4cf2-8d6d-9b8cf5e96d56",
+ "partName": "Top"
+ }, {
+ "posX": 0.0,
+ "posY": 0.0,
+ "posZ": 0.0,
+ "rotX": 0.0,
+ "children": [],
+ "rotZ": 0.0,
+ "rotY": 0.0,
+ "name": "Bottom",
+ "uuid": "61db0622-6fef-4f12-932d-a00fdb9d0848",
+ "partUuid": "00f430a6-6311-4a33-961b-41ded4cf57d5",
+ "partName": "Plate"
+ }, {
+ "posX": 0.5,
+ "posY": 0.0,
+ "posZ": 0.5,
+ "rotX": 0.0,
+ "children": [],
+ "rotZ": 0.0,
+ "rotY": 1.5707963267948966,
+ "name": "Front",
+ "uuid": "e6af9d3f-8ad6-4488-b3d0-d35549be9a1e",
+ "partUuid": "e6af9d3f-8ad6-4488-b3d0-d35549be9a1e",
+ "partName": "Front"
+ }, {
+ "posX": -0.5,
+ "posY": 0.0,
+ "posZ": 0.5,
+ "rotX": 0.0,
+ "children": [],
+ "rotZ": 0.0,
+ "rotY": 1.5707963267948966,
+ "name": "Back",
+ "uuid": "a3c9c547-8fd3-40d5-97a1-a3f9a3a9c337",
+ "partUuid": "a3c9c547-8fd3-40d5-97a1-a3f9a3a9c337",
+ "partName": "Back"
+ }, {
+ "posX": 0.0,
+ "posY": 0.0,
+ "posZ": 0.5,
+ "rotX": 0.0,
+ "children": [{
+ "posX": 0.0,
+ "posY": 0.5,
+ "posZ": 0.0,
+ "rotX": 1.5707963267948966,
+ "children": [],
+ "rotZ": 0.0,
+ "rotY": 0.0,
+ "name": "Left",
+ "uuid": "615985c0-73fd-48db-8f8b-e11b7cbb2ee8",
+ "partUuid": "615985c0-73fd-48db-8f8b-e11b7cbb2ee8",
+ "partName": "Left"
+ }, {
+ "posX": 0.0,
+ "posY": -0.5,
+ "posZ": 0.0,
+ "rotX": 1.5707963267948966,
+ "children": [],
+ "rotZ": 0.0,
+ "rotY": 0.0,
+ "name": "Right",
+ "uuid": "882a0b35-7da8-4555-903d-fd6b5cbec392",
+ "partUuid": "882a0b35-7da8-4555-903d-fd6b5cbec392",
+ "partName": "Right"
+ }
+ ],
+ "rotZ": 0.0,
+ "rotY": 0.0,
+ "name": "BeamStructure",
+ "uuid": "2afb23c9-f458-4bdb-a4e7-fc863364644f",
+ "partUuid": "2afb23c9-f458-4bdb-a4e7-fc863364644f",
+ "partName": "BeamStructure"
+ }
+ ],
+ "name": "SpaceCube",
+ "uuid": "a3533e02-125c-4066-bffe-d046d8d8342a"
+ },
+ "Parts": [{
+ "color": 16744448,
+ "shape": "CYLINDER",
+ "name": "BeamStructure",
+ "lengthY": 1.0,
+ "lengthX": 1.0,
+ "radius": 0.05,
+ "uuid": "2afb23c9-f458-4bdb-a4e7-fc863364644f",
+ "lengthZ": 1.0
+ }, {
+ "color": 8388608,
+ "shape": "BOX",
+ "name": "Right",
+ "lengthY": 1.0,
+ "lengthX": 1.0,
+ "radius": 0.05,
+ "uuid": "882a0b35-7da8-4555-903d-fd6b5cbec392",
+ "lengthZ": 0.02
+ }, {
+ "color": 32832,
+ "shape": "BOX",
+ "name": "Front",
+ "lengthY": 1.0,
+ "lengthX": 1.0,
+ "radius": 0.05,
+ "uuid": "e6af9d3f-8ad6-4488-b3d0-d35549be9a1e",
+ "lengthZ": 0.02
+ }, {
+ "color": 16711680,
+ "shape": "BOX",
+ "name": "Left",
+ "lengthY": 1.0,
+ "lengthX": 1.0,
+ "radius": 0.05,
+ "uuid": "615985c0-73fd-48db-8f8b-e11b7cbb2ee8",
+ "lengthZ": 0.02
+ }, {
+ "color": 65280,
+ "shape": "BOX",
+ "name": "Plate",
+ "lengthY": 1.0,
+ "lengthX": 1.0,
+ "radius": 0.05,
+ "uuid": "00f430a6-6311-4a33-961b-41ded4cf57d5",
+ "lengthZ": 0.02
+ }, {
+ "color": 16776960,
+ "shape": "BOX",
+ "name": "Back",
+ "lengthY": 1.0,
+ "lengthX": 1.0,
+ "radius": 0.05,
+ "uuid": "a3c9c547-8fd3-40d5-97a1-a3f9a3a9c337",
+ "lengthZ": 0.02
+ }, {
+ "color": 32768,
+ "shape": "BOX",
+ "name": "Top",
+ "lengthY": 1.0,
+ "lengthX": 1.0,
+ "radius": 0.05,
+ "uuid": "cc14e2c7-9d7e-4cf2-8d6d-9b8cf5e96d56",
+ "lengthZ": 0.02
+ }
+ ]
+ }
+ """
diff --git a/VirtualSatelliteCAD/test/json_io/test_json_importer.py b/VirtualSatelliteCAD/test/json_io/test_json_importer.py
index 469a5ba..c95c1d4 100644
--- a/VirtualSatelliteCAD/test/json_io/test_json_importer.py
+++ b/VirtualSatelliteCAD/test/json_io/test_json_importer.py
@@ -32,9 +32,11 @@
import FreeCAD
import FreeCADGui
from test.test_setup import AWorkingDirectoryTest
-from freecad.active_document import FREECAD_FILE_EXTENSION
+from freecad.active_document import FREECAD_FILE_EXTENSION, ActiveDocument
from module.environment import Environment
-from json_io.json_definitions import JSON_ELEMENT_STL_PATH
+from json_io.json_definitions import JSON_ELEMENT_STL_PATH, PART_IDENTIFIER, PRODUCT_IDENTIFIER
+import unittest
+from test.json_io.test_json_data import TEST_JSON_FULL_VISCUBE
App = FreeCAD
Gui = FreeCADGui
@@ -71,7 +73,7 @@ def test_create_part(self):
json_importer.create_or_update_part(json_object)
# Check the file got created
- test_file_name = self._WORKING_DIRECTORY + "Beam_6201a731_d703_43f8_ab37_6a0581dfe022" + FREECAD_FILE_EXTENSION
+ test_file_name = self._WORKING_DIRECTORY + PART_IDENTIFIER + "Beam_6201a731_d703_43f8_ab37_6a0581dfe022" + FREECAD_FILE_EXTENSION
self.assertTrue(os.path.isfile(test_file_name), "File exists on drive")
App.open(test_file_name)
@@ -126,7 +128,7 @@ def test_create_part_update_uuid(self):
json_importer.create_or_update_part(json_object)
# Check the file got created
- test_file_name = self._WORKING_DIRECTORY + "Beam_6201a731_d703_43f8_ab37_6a0581dfe022" + FREECAD_FILE_EXTENSION
+ test_file_name = self._WORKING_DIRECTORY + PART_IDENTIFIER + "Beam_6201a731_d703_43f8_ab37_6a0581dfe022" + FREECAD_FILE_EXTENSION
self.assertTrue(os.path.isfile(test_file_name), "File exists on drive")
App.open(test_file_name)
@@ -149,7 +151,7 @@ def test_create_part_update_uuid(self):
json_importer.create_or_update_part(json_object)
# Check the file got created
- test_file_name = self._WORKING_DIRECTORY + "Beam_6201a731_d703_43f8_ab37_6a0666dfe022" + FREECAD_FILE_EXTENSION
+ test_file_name = self._WORKING_DIRECTORY + PART_IDENTIFIER + "Beam_6201a731_d703_43f8_ab37_6a0666dfe022" + FREECAD_FILE_EXTENSION
App.open(test_file_name)
self.assertEquals(len(App.ActiveDocument.RootObjects), TEST_ALLOWED_AMOUNT_OF_PART_OBJECTS, "Correct amount of objects in file")
@@ -176,7 +178,7 @@ def test_create_part_update_value(self):
json_importer.create_or_update_part(json_object)
# Check the file got created
- test_file_name = self._WORKING_DIRECTORY + "Beam_6201a731_d703_43f8_ab37_6a0581dfe022" + FREECAD_FILE_EXTENSION
+ test_file_name = self._WORKING_DIRECTORY + PART_IDENTIFIER + "Beam_6201a731_d703_43f8_ab37_6a0581dfe022" + FREECAD_FILE_EXTENSION
self.assertTrue(os.path.isfile(test_file_name), "File exists on drive")
App.open(test_file_name)
@@ -200,7 +202,7 @@ def test_create_part_update_value(self):
json_importer.create_or_update_part(json_object)
# Check the file got created
- test_file_name = self._WORKING_DIRECTORY + "Beam_6201a731_d703_43f8_ab37_6a0581dfe022" + FREECAD_FILE_EXTENSION
+ test_file_name = self._WORKING_DIRECTORY + PART_IDENTIFIER + "Beam_6201a731_d703_43f8_ab37_6a0581dfe022" + FREECAD_FILE_EXTENSION
self.assertTrue(os.path.isfile(test_file_name), "File exists on drive")
App.open(test_file_name)
@@ -232,12 +234,12 @@ def test_create_part_change_shape(self):
json_importer.create_or_update_part(json_object)
# Check the file got created
- test_file_name = self._WORKING_DIRECTORY + "Beam_6201a731_d703_43f8_ab37_6a7171dfe022" + FREECAD_FILE_EXTENSION
+ test_file_name = self._WORKING_DIRECTORY + PART_IDENTIFIER + "Beam_6201a731_d703_43f8_ab37_6a7171dfe022" + FREECAD_FILE_EXTENSION
App.open(test_file_name)
# Check that there is the correct object inside
self.assertIsNotNone(App.ActiveDocument.getObject("Box"), "Got correct object")
- App.closeDocument("Beam_6201a731_d703_43f8_ab37_6a7171dfe022")
+ App.closeDocument(PART_IDENTIFIER + "Beam_6201a731_d703_43f8_ab37_6a7171dfe022")
# Now start cyling the objects
json_object["shape"] = "CYLINDER"
@@ -247,7 +249,7 @@ def test_create_part_change_shape(self):
App.open(test_file_name)
self.assertIsNone(App.ActiveDocument.getObject("Box"), "Removed previous object")
self.assertIsNotNone(App.ActiveDocument.getObject("Cylinder"), "Got correct object")
- App.closeDocument("Beam_6201a731_d703_43f8_ab37_6a7171dfe022")
+ App.closeDocument(PART_IDENTIFIER + "Beam_6201a731_d703_43f8_ab37_6a7171dfe022")
# Next object
json_object["shape"] = "SPHERE"
@@ -257,7 +259,7 @@ def test_create_part_change_shape(self):
App.open(test_file_name)
self.assertIsNone(App.ActiveDocument.getObject("Cylinder"), "Removed previous object")
self.assertIsNotNone(App.ActiveDocument.getObject("Sphere"), "Got correct object")
- App.closeDocument("Beam_6201a731_d703_43f8_ab37_6a7171dfe022")
+ App.closeDocument(PART_IDENTIFIER + "Beam_6201a731_d703_43f8_ab37_6a7171dfe022")
# Next object
json_object["shape"] = "GEOMETRY"
@@ -267,7 +269,7 @@ def test_create_part_change_shape(self):
App.open(test_file_name)
self.assertIsNone(App.ActiveDocument.getObject("Sphere"), "Removed previous object")
self.assertIsNotNone(App.ActiveDocument.getObject("Geometry"), "Got correct object")
- App.closeDocument("Beam_6201a731_d703_43f8_ab37_6a7171dfe022")
+ App.closeDocument(PART_IDENTIFIER + "Beam_6201a731_d703_43f8_ab37_6a7171dfe022")
# Next object
json_object["shape"] = "CONE"
@@ -277,4 +279,112 @@ def test_create_part_change_shape(self):
App.open(test_file_name)
self.assertIsNone(App.ActiveDocument.getObject("Geometry"), "Removed previous object")
self.assertIsNotNone(App.ActiveDocument.getObject("Cone"), "Got correct object")
- App.closeDocument("Beam_6201a731_d703_43f8_ab37_6a7171dfe022")
+ App.closeDocument(PART_IDENTIFIER + "Beam_6201a731_d703_43f8_ab37_6a7171dfe022")
+
+ def test_full_import(self):
+ """
+ Full JSON import test
+ """
+
+ json_importer = JsonImporter(self._WORKING_DIRECTORY)
+ json_object = json.loads(TEST_JSON_FULL_VISCUBE)
+ part_file_names, json_product, active_document = json_importer.full_import(json_object)
+
+ # =========================
+ # Check parts
+
+ # Check that the right number of parts was found
+ self.assertEqual(len(part_file_names), 7, "Found 7 files")
+
+ # Check each part
+ for part_file_name in part_file_names:
+ test_file_name = self._WORKING_DIRECTORY + part_file_name + FREECAD_FILE_EXTENSION
+
+ # Check the file got created
+ self.assertTrue(os.path.isfile(test_file_name), "File exists on drive")
+
+ # =========================
+ # Check product
+
+ # Check that the right number of children and root objects got created
+ self.assertEquals(len(json_product.children), 5, "Correct amount of children")
+ self.assertEquals(len(active_document.app_active_document.RootObjects), 10, "Found correct amount of root objects 5 plus 5 sheets")
+
+ active_document = ActiveDocument(self._WORKING_DIRECTORY).open_set_and_get_document(
+ PRODUCT_IDENTIFIER + "BeamStructure_2afb23c9_f458_4bdb_a4e7_fc863364644f")
+ self.assertEquals(len(active_document.app_active_document.RootObjects), 6, "Found correct amount of root objects 3 objects plus 3 sheets")
+
+ @unittest.SkipTest
+ def test_full_import_again(self):
+ """
+ Importing the same file again should not result in changes
+ """
+
+ json_test_resource_path = Environment.get_test_resource_path("VisCube2.json")
+ json_importer = JsonImporter(self._WORKING_DIRECTORY)
+
+ # =========================
+ # First import
+ part_file_names, json_product, active_document = json_importer.full_import(json_test_resource_path)
+
+ # Check that the right number of parts was found
+ self.assertEqual(len(part_file_names), 7, "Found 7 files")
+
+ # Check that the right number of children and root objects got created
+ self.assertEqual(len(json_product.children), 5, "Correct amount of children")
+ self.assertEqual(len(active_document.app_active_document.RootObjects), 14, "Found correct amount of root objects 7 plus 7 sheets")
+
+ # =========================
+ # Second import
+ part_file_names2, json_product2, active_document2 = json_importer.full_import(json_test_resource_path)
+
+ # Check that the right number of parts was found
+ self.assertEqual(len(part_file_names2), 7, "Found 7 files")
+
+ # Check that the right number of children and root objects got created
+ self.assertEqual(len(json_product2.children), 5, "Correct amount of children")
+ self.assertEqual(len(active_document2.app_active_document.RootObjects), 14, "Found correct amount of root objects 7 plus 7 sheets")
+
+ # =========================
+ # Check equality
+ self.assertEquals(part_file_names, part_file_names2)
+
+ for i, child1 in enumerate(json_product.children):
+ child2 = json_product2.children[i]
+ child1.has_equal_values(child2)
+
+ @unittest.SkipTest
+ def test_full_import_again_with_changes(self):
+ """
+ If two files with the same name get imported: we assume that the VirSat side used CRUD, that means:
+ - new parts/products could be created, so add them
+ - old parts/products could be replaced/updated, so use the new information
+ - old parts/products could be deleted, so delete all not updated files
+ -> this means instead of merging, simply the information of the old files get replaced by the newer one
+ """
+
+ json_importer = JsonImporter(self._WORKING_DIRECTORY)
+
+ # =========================
+ # First import
+ json_test_resource_path = Environment.get_test_resource_path("VisCube2.json")
+ part_file_names, json_product, active_document = json_importer.full_import(json_test_resource_path)
+
+ # Check that the right number of parts was found
+ self.assertEqual(len(part_file_names), 7, "Found 7 files")
+
+ # Check that the right number of children and root objects got created
+ self.assertEqual(len(json_product.children), 5, "Correct amount of children")
+ self.assertEqual(len(active_document.app_active_document.RootObjects), 14, "Found correct amount of root objects 7 plus 7 sheets")
+
+ # =========================
+ # Second import
+ json_test_resource_path2 = Environment.get_test_resource_path("VisCube2_update.json")
+ part_file_names2, json_product2, active_document2 = json_importer.full_import(json_test_resource_path2)
+
+ # Check that the right number of parts was found
+ self.assertEqual(len(part_file_names2), 1, "Found 1 files")
+
+ # Check that the right number of children and root objects got created
+ self.assertEquals(len(json_product2.children), 1, "Correct amount of children")
+ self.assertEquals(len(active_document2.app_active_document.RootObjects), 2, "Found correct amount of root objects 1 plus 1 sheets")