diff --git a/.gitignore b/.gitignore
index 624a48b..3390209 100644
--- a/.gitignore
+++ b/.gitignore
@@ -104,6 +104,7 @@ ENV/
*.blend1
install_plugin_cad.sh
.vscode
+.DS_Store
# emacs backup files
~*
diff --git a/cg/freecad/Frames/Frames.py b/cg/freecad/Frames/Frames.py
index 4b8ccd4..ea46662 100644
--- a/cg/freecad/Frames/Frames.py
+++ b/cg/freecad/Frames/Frames.py
@@ -13,7 +13,7 @@
# License along with this library. If not, see .
import FreeCAD
import Tools
-from usecases.asm4parser_usecase import Asm4StructureParseUseCase
+from scenarios.robossembler_freecad_export_scenario import RobossemblerFreeCadExportScenario
if FreeCAD.GuiUp:
import FreeCADGui
@@ -311,8 +311,9 @@ Tools.spawnClassCommand("FrameCommand",
{"Pixmap": str(os.path.join(icondir, "frame.svg")),
"MenuText": "Make a free frame",
"ToolTip": "Make a freestanding reference frame."})
+
Tools.spawnClassCommand("ASM4StructureParsing",
- Asm4StructureParseUseCase().initParse,
+ RobossemblerFreeCadExportScenario().call,
{"Pixmap": str(os.path.join(icondir, "assembly4.svg")),
"MenuText": "Make a ASM4 parsing",
"ToolTip": "Make a ASM4 1"})
diff --git a/cg/freecad/Frames/helper/fs.py b/cg/freecad/Frames/helper/fs.py
new file mode 100644
index 0000000..9068e9a
--- /dev/null
+++ b/cg/freecad/Frames/helper/fs.py
@@ -0,0 +1,14 @@
+import os
+import json
+
+
+class FS:
+ def readJSON(path: str):
+ return json.loads((open(path)).read())
+
+ def writeFile(data, filePath, fileName):
+ file_to_open = filePath + fileName
+
+ f = open(file_to_open, 'w', )
+
+ f.write(data)
diff --git a/cg/freecad/Frames/helper/is_solid.py b/cg/freecad/Frames/helper/is_solid.py
new file mode 100644
index 0000000..431c814
--- /dev/null
+++ b/cg/freecad/Frames/helper/is_solid.py
@@ -0,0 +1,18 @@
+import FreeCAD
+
+
+def is_object_solid(obj):
+ """If obj is solid return True"""
+ if not isinstance(obj, FreeCAD.DocumentObject):
+ return False
+
+ if not hasattr(obj, 'Shape'):
+ return False
+
+ if not hasattr(obj.Shape, 'Solids'):
+ return False
+
+ if len(obj.Shape.Solids) == 0:
+ return False
+
+ return True
diff --git a/cg/freecad/Frames/model/files_generator.py b/cg/freecad/Frames/model/files_generator.py
new file mode 100644
index 0000000..8b234b6
--- /dev/null
+++ b/cg/freecad/Frames/model/files_generator.py
@@ -0,0 +1,12 @@
+from enum import Enum
+
+
+class FilesGenerator(Enum):
+ DETAIL = 'detail.json'
+ ASSEMBLY = 'assembly.json'
+
+
+class FolderGenerator(Enum):
+ MESHES = 'meshes'
+ ASSETS = 'assets'
+ SDF = 'sdf'
diff --git a/cg/freecad/Frames/model/geometry_part.py b/cg/freecad/Frames/model/geometry_part.py
new file mode 100644
index 0000000..f63f055
--- /dev/null
+++ b/cg/freecad/Frames/model/geometry_part.py
@@ -0,0 +1,86 @@
+from typing import Any, TypeVar, Type, cast
+
+
+T = TypeVar("T")
+
+
+def from_float(x: Any) -> float:
+ assert isinstance(x, (float, int)) and not isinstance(x, bool)
+ return float(x)
+
+
+def to_float(x: Any) -> float:
+ assert isinstance(x, float)
+ return x
+
+
+def to_class(c: Type[T], x: Any) -> dict:
+ assert isinstance(x, c)
+ return cast(Any, x).to_dict()
+
+
+class Axis:
+ x: float
+ y: float
+ z: float
+
+ def __init__(self, x: float, y: float, z: float) -> None:
+ self.x = x
+ self.y = y
+ self.z = z
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'Axis':
+ assert isinstance(obj, dict)
+ x = from_float(obj.get("x"))
+ y = from_float(obj.get("y"))
+ z = from_float(obj.get("z"))
+ return Axis(x, y, z)
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ result["x"] = to_float(self.x)
+ result["y"] = to_float(self.y)
+ result["z"] = to_float(self.z)
+ return result
+
+
+class GeometryPart:
+ euler: Axis
+ position: Axis
+ rotation: Axis
+ center: Axis
+
+ def __init__(self, euler: Axis, position: Axis, rotation: Axis, center: Axis) -> None:
+ self.euler = euler
+ self.position = position
+ self.rotation = rotation
+ self.center = center
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'GeometryPart':
+ assert isinstance(obj, dict)
+ euler = Axis.from_dict(obj.get("euler"))
+ position = Axis.from_dict(obj.get("position"))
+ rotation = Axis.from_dict(obj.get("rotation"))
+ center = Axis.from_dict(obj.get("center"))
+ return GeometryPart(euler, position, rotation, center)
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ result["euler"] = to_class(Axis, self.euler)
+ result["position"] = to_class(Axis, self.position)
+ result["rotation"] = to_class(Axis, self.rotation)
+ result["center"] = to_class(Axis, self.center)
+ return result
+
+ def toJson(self) -> str:
+ return str(self.to_dict()).replace('\'', '"')
+
+
+def geometry_part_from_dict(s: Any) -> GeometryPart:
+ return GeometryPart.from_dict(s)
+
+
+def geometry_part_to_dict(x: GeometryPart) -> Any:
+ return to_class(GeometryPart, x)
diff --git a/cg/freecad/Frames/model/sdf_geometry_model.py b/cg/freecad/Frames/model/sdf_geometry_model.py
new file mode 100644
index 0000000..dca815d
--- /dev/null
+++ b/cg/freecad/Frames/model/sdf_geometry_model.py
@@ -0,0 +1,107 @@
+import json
+
+
+def from_str(x):
+ assert isinstance(x, str)
+ return x
+
+
+def from_none(x):
+ assert x is None
+ return x
+
+
+def from_union(fs, x):
+ for f in fs:
+ try:
+ return f(x)
+ except:
+ pass
+ assert False
+
+
+def to_class(c, x):
+ assert isinstance(x, c)
+ return x.to_dict()
+
+
+class SdfGeometryModel:
+ def __init__(self, name, ixx, ixy, ixz, iyy, izz, massSDF, posX, posY, posZ, eulerX, eulerY, eulerZ, iyz, stl, friction):
+ self.name = name
+ self.ixx = ixx
+ self.ixy = ixy
+ self.ixz = ixz
+ self.iyy = iyy
+ self.izz = izz
+ self.massSDF = massSDF
+ self.posX = posX
+ self.posY = posY
+ self.posZ = posZ
+ self.eulerX = eulerX
+ self.eulerY = eulerY
+ self.eulerZ = eulerZ
+ self.iyz = iyz
+ self.stl = stl
+ self.friction = friction
+
+ @staticmethod
+ def from_dict(obj):
+ assert isinstance(obj, dict)
+ name = from_union([from_str, from_none], obj.get("name"))
+ ixx = from_union([from_str, from_none], obj.get("ixx"))
+ ixy = from_union([from_str, from_none], obj.get("ixy"))
+ ixz = from_union([from_str, from_none], obj.get("ixz"))
+ iyy = from_union([from_str, from_none], obj.get("iyy"))
+ izz = from_union([from_str, from_none], obj.get("izz"))
+ massSDF = from_union([from_str, from_none], obj.get("massSDF"))
+ posX = from_union([from_str, from_none], obj.get("posX"))
+ posY = from_union([from_str, from_none], obj.get("posY"))
+ posZ = from_union([from_str, from_none], obj.get("posZ"))
+ eulerX = from_union([from_str, from_none], obj.get("eulerX"))
+ eulerY = from_union([from_str, from_none], obj.get("eulerY"))
+ eulerZ = from_union([from_str, from_none], obj.get("eulerZ"))
+ iyz = from_union([from_str, from_none], obj.get("iyz"))
+ stl = from_union([from_str, from_none], obj.get("stl") )
+ friction = from_union([from_str, from_none], obj.get("friction"))
+ return SdfGeometryModel(name, ixx, ixy, ixz, iyy, izz, massSDF, posX, posY, posZ, eulerX, eulerY, eulerZ, iyz,stl,friction)
+
+ def to_dict(self):
+ result = {}
+ if self.name is not None:
+ result["name"] = from_union([from_str, from_none], self.name)
+ if self.ixx is not None:
+ result["ixx"] = from_union([from_str, from_none], self.ixx)
+ if self.ixy is not None:
+ result["ixy"] = from_union([from_str, from_none], self.ixy)
+ if self.ixz is not None:
+ result["ixz"] = from_union([from_str, from_none], self.ixz)
+ if self.iyy is not None:
+ result["iyy"] = from_union([from_str, from_none], self.iyy)
+ if self.izz is not None:
+ result["izz"] = from_union([from_str, from_none], self.izz)
+ if self.massSDF is not None:
+ result["massSDF"] = from_union([from_str, from_none], self.massSDF)
+ if self.posX is not None:
+ result["posX"] = from_union([from_str, from_none], self.posX)
+ if self.posY is not None:
+ result["posY"] = from_union([from_str, from_none], self.posY)
+ if self.posZ is not None:
+ result["posZ"] = from_union([from_str, from_none], self.posZ)
+ if self.eulerX is not None:
+ result["eulerX"] = from_union([from_str, from_none], self.eulerX)
+ if self.eulerY is not None:
+ result["eulerY"] = from_union([from_str, from_none], self.eulerY)
+ if self.eulerZ is not None:
+ result["eulerZ"] = from_union([from_str, from_none], self.eulerZ)
+ if self.iyz is not None:
+ result["iyz"] = from_union([from_str, from_none], self.iyz)
+ if self.stl is not None:
+ result["stl"] = from_union([from_str, from_none], self.stl)
+ if self.friction is not None:
+ result["friction"] = from_union([from_str, from_none], self.eulerZ)
+ return result
+
+ def toJSON(self) -> str:
+ return str(self.to_dict()).replace('\'', '"')
+
+
\ No newline at end of file
diff --git a/cg/freecad/Frames/scenarios/robossembler_freecad_export_scenario.py b/cg/freecad/Frames/scenarios/robossembler_freecad_export_scenario.py
new file mode 100644
index 0000000..4868a93
--- /dev/null
+++ b/cg/freecad/Frames/scenarios/robossembler_freecad_export_scenario.py
@@ -0,0 +1,70 @@
+import FreeCAD
+from usecases.export_usecase import ExportUseCase
+from usecases.get_sdf_geometry_usecase import SdfGeometryUseCase
+from usecases.assembly_parse_usecase import AssemblyParseUseCase
+from usecases.geometry_usecase import GeometryUseCase
+from model.geometry_part import GeometryPart
+from model.files_generator import FolderGenerator
+from helper.fs import FS
+from PySide import QtGui
+import os
+import ImportGui
+import shutil
+
+
+class RobossemblerFreeCadExportScenario:
+
+ def call(self):
+
+ path = self.qtGuiFeature()
+ if path == None:
+ return
+ self.systemHelper(path)
+
+ def qtGuiFeature(self):
+ if FreeCAD.ActiveDocument == None:
+ FreeCAD.Console.PrintError("No active document")
+
+ p = QtGui.QFileDialog.getExistingDirectoryUrl()
+ path = p.path()
+
+ if path == '':
+ return None
+ return path
+
+ def systemHelper(self, path: str):
+
+ root_label = FreeCAD.ActiveDocument.RootObjects[0].Label
+ directory = path + '/' + root_label
+
+ if not os.path.exists(directory):
+ os.makedirs(directory)
+
+ __objs__ = FreeCAD.ActiveDocument.RootObjects
+
+ os.makedirs(directory + '/' + FolderGenerator.ASSETS.value)
+ os.makedirs(directory + '/' + FolderGenerator.SDF.value)
+ os.makedirs(directory + '/' + FolderGenerator.SDF.value + '/' + FolderGenerator.MESHES.value)
+ f = open(directory + "/step-structure.json", "w")
+ f.write(AssemblyParseUseCase().toJson())
+ f.close()
+ self.geometry(directory)
+
+ ImportGui.export(__objs__, directory + '/' + 'assembly.step')
+
+ shutil.make_archive(directory, 'zip', directory)
+
+ shutil.rmtree(directory)
+ return True
+
+ def geometry(self, outPutsPath: str):
+ meshesExportUseCase = ExportUseCase.call(outPutsPath)
+ for el in SdfGeometryUseCase.call(meshesExportUseCase):
+ FS.writeFile(el.toJSON(), outPutsPath +
+ '/' + FolderGenerator.ASSETS.value + '/', el.name + '.json',)
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cg/freecad/Frames/usecases/asm4parser_usecase.py b/cg/freecad/Frames/usecases/asm4parser_usecase.py
deleted file mode 100644
index f732d1b..0000000
--- a/cg/freecad/Frames/usecases/asm4parser_usecase.py
+++ /dev/null
@@ -1,53 +0,0 @@
-import FreeCAD as App
-
-class Asm4StructureParseUseCase:
- _parts = []
- _label = []
-
- def getSubPartsLabel(self, group):
- groupLabel = []
- for el in group:
- if str(el) == '':
- groupLabel.append(el.Label)
- return groupLabel
-
- def parseLabel(self, nextGroup, label, level=2, nextGroupParse=0):
- if nextGroup.__len__() == nextGroupParse:
- return
- else:
- groupParts = []
-
- for el in nextGroup:
- if str(el) == '':
- groupParts.append(el)
-
- for el in groupParts:
- if str(el) == '':
- label.append({
- "level": level,
- "attachedTo": el.AttachedTo.split('#'),
- "label": el.Label,
- "axis": self.getSubPartsLabel(el.Group)
- })
-
- def initParse(self):
-
- model = App.ActiveDocument.RootObjects[1]
- self._label.append({
- "level": 1,
- "attachedTo": "Parent Assembly",
- "label": model.Label,
- "axis": self.getSubPartsLabel(model.Group)
- })
- for parent in model.Group:
- if str(parent) == '':
- self._label.append({
- "level": 1,
- "attachedTo": parent.AttachedTo.split('#'),
- "label": parent.Label,
- "axis": self.getSubPartsLabel(parent.Group)
- })
- print(self._label)
-
-
-
\ No newline at end of file
diff --git a/cg/freecad/Frames/usecases/assembly_parse_usecase.py b/cg/freecad/Frames/usecases/assembly_parse_usecase.py
new file mode 100644
index 0000000..b1cd291
--- /dev/null
+++ b/cg/freecad/Frames/usecases/assembly_parse_usecase.py
@@ -0,0 +1,42 @@
+import FreeCAD as App
+from helper.is_solid import is_object_solid
+
+
+class AssemblyParseUseCase:
+ _parts = []
+ _asm = []
+
+ def __init__(self) -> None:
+ self.initParse()
+ pass
+
+
+
+ def initParse(self):
+ for el in App.ActiveDocument.Objects:
+ if(is_object_solid(el)):
+ self._asm.append(el.Label)
+
+ def toJson(self):
+ return str(self._asm).replace('\'', "\"")
+
+ def getSubPartsLink(self, group):
+ groupLink = {}
+ for el in group:
+ if (is_object_solid(el)):
+ if str(el.Shape).find('Solid') != -1:
+ if groupLink.get(el.Label) == None:
+ groupLink[el.Label] = []
+ for i in el.Group:
+
+ if str(i).find('Pad') != -1:
+ groupLink[el.Label].append(i)
+ if groupLink.__len__() == 0:
+ return None
+ return groupLink
+
+ def getLinkedProperty(self):
+ return self._asm
+
+
+
diff --git a/cg/freecad/Frames/usecases/export_usecase.py b/cg/freecad/Frames/usecases/export_usecase.py
new file mode 100644
index 0000000..519982a
--- /dev/null
+++ b/cg/freecad/Frames/usecases/export_usecase.py
@@ -0,0 +1,16 @@
+import importDAE
+import FreeCAD as App
+from model.files_generator import FolderGenerator
+from helper.is_solid import is_object_solid
+
+
+class ExportUseCase:
+ def call(path):
+ meshes = {}
+ for el in App.ActiveDocument.Objects:
+ if (is_object_solid(el)):
+ importDAE.export([el], path + '/' + FolderGenerator.SDF.value +
+ '/' + FolderGenerator.MESHES.value + '/' + el.Label + '.dae')
+ meshes[el.Label] = '/' + FolderGenerator.MESHES.value + \
+ '/' + el.Label + '.dae'
+ return meshes
diff --git a/cg/freecad/Frames/usecases/geometry_usecase.py b/cg/freecad/Frames/usecases/geometry_usecase.py
new file mode 100644
index 0000000..d4df666
--- /dev/null
+++ b/cg/freecad/Frames/usecases/geometry_usecase.py
@@ -0,0 +1,54 @@
+
+import FreeCAD as App
+from helper.is_solid import is_object_solid
+
+
+class GeometryUseCase:
+ def call() -> dict:
+ labels = []
+ for el in App.ActiveDocument.Objects:
+
+ if is_object_solid(el):
+ labels.append(el.Label)
+
+ geometry = {
+ "euler": {
+ "x": None,
+ "y": None,
+ "z": None
+ },
+ "position": {
+ "x": None,
+ "y": None,
+ "z": None
+ },
+ "rotation": {
+ "x": None,
+ "y": None,
+ "z": None
+ },
+ "center": {
+ "x": None,
+ "y": None,
+ "z": None
+ },
+
+ }
+
+ boundBox = el.Shape.BoundBox
+ geometry["center"]["x"] = boundBox.Center.x
+ geometry["center"]["y"] = boundBox.Center.y
+ geometry["center"]["z"] = boundBox.Center.z
+ geometry["position"]['x'] = boundBox.XMax
+ geometry["position"]['y'] = boundBox.YMax
+ geometry["position"]['z'] = boundBox.ZMax
+ rotation = el.Placement.Rotation
+ geometry["rotation"]['x'] = rotation.Axis.z
+ geometry["rotation"]['y'] = rotation.Axis.y
+ geometry["rotation"]['z'] = rotation.Axis.z
+ euler = el.Placement.Rotation.toEuler()
+ geometry["euler"]['x'] = euler[0]
+ geometry["euler"]['y'] = euler[1]
+ geometry["euler"]['z'] = euler[2]
+
+ return {"geometry": geometry, "labels": labels, "label": el.Label}
diff --git a/cg/freecad/Frames/usecases/get_sdf_geometry_usecase.py b/cg/freecad/Frames/usecases/get_sdf_geometry_usecase.py
new file mode 100644
index 0000000..d3c6ee3
--- /dev/null
+++ b/cg/freecad/Frames/usecases/get_sdf_geometry_usecase.py
@@ -0,0 +1,63 @@
+import FreeCAD as App
+from model.sdf_geometry_model import SdfGeometryModel
+
+from helper.is_solid import is_object_solid
+
+
+class SdfGeometryUseCase:
+ def call(stlPaths:dict) -> list[SdfGeometryModel]:
+ materialSolid = {}
+ for el in App.ActiveDocument.Objects:
+ if str(el) == '':
+ friction = el.Material.get('SlidingFriction')
+ for i in el.References:
+ materialSolid[i[0].Label] = friction
+ geometry = []
+ for el in App.ActiveDocument.Objects:
+ if is_object_solid(el):
+ com = el.Shape.CenterOfMass
+ mass = el.Shape.Mass
+ inertia = el.Shape.MatrixOfInertia
+ pos = el.Shape.Placement
+ inertia = el.Shape.MatrixOfInertia
+ name = el.Label
+ ixx = str(inertia.A11 / 1000000)
+ ixy = str(inertia.A12 / 1000000)
+ ixz = str(inertia.A13 / 1000000)
+ iyy = str(inertia.A22 / 1000000)
+ iyz = str(inertia.A23 / 1000000)
+ izz = str(inertia.A33 / 1000000)
+ massSDF = str(mass / 1000000)
+ posX = str(pos.Base[0] / 1000000)
+ posY = str(pos.Base[1] / 1000000)
+ posZ = str(pos.Base[2] / 1000000)
+ eulerX = str(pos.Rotation.toEuler()[0])
+ eulerY = str(pos.Rotation.toEuler()[1])
+ eulerZ = str(pos.Rotation.toEuler()[2])
+
+ geometry.append(
+ SdfGeometryModel(
+ stl=stlPaths.get(el.Label),
+ name=name,
+ ixx=ixx,
+ ixz=ixz,
+ ixy=ixy,
+ iyy=iyy,
+ iyz=iyz,
+ izz=izz,
+ massSDF=massSDF,
+ posX=posX,
+ posY=posY,
+ posZ=posZ,
+ eulerX=eulerX,
+ eulerY=eulerY,
+ eulerZ=eulerZ,
+ friction=materialSolid.get(el.Label) or '',
+ )
+ )
+ return geometry
+
+
+
+
+
diff --git a/pddl/helper/fs.py b/pddl/helper/fs.py
index 0c60e01..1bd3dbe 100644
--- a/pddl/helper/fs.py
+++ b/pddl/helper/fs.py
@@ -12,6 +12,8 @@ class FS:
f = open(file_to_open, 'w', )
f.write(data)
+ def readFile(path):
+ return open(path).read()
def readFile(path:str):
return open(path).read()
diff --git a/pddl/main.py b/pddl/main.py
index 68ff3a9..8541124 100644
--- a/pddl/main.py
+++ b/pddl/main.py
@@ -2,25 +2,23 @@ import argparse
from helper.fs import FS
from src.model.asm4_structure import Asm4Structure
-from src.usecases.asm4_to_assembly_use_case import Asm4ToAssemblyUseCase
from src.usecases.assembly_to_pddl_use_case import AssemblyToPddlUseCase
-
+# python3 main.py --stepStructurePath /Users/idontsudo/robo/Cube3/step-structure.json --outPath /Users/idontsudo/robo/Cube3/pddl/
if __name__ == "__main__":
parser = argparse.ArgumentParser()
- parser.add_argument('--asm4Path', help='asm4 json FreeCad')
+ parser.add_argument('--stepStructurePath', help='json step by FreeCad')
parser.add_argument('--outPath', help='save pddl path')
args = parser.parse_args()
- if args.asm4Path == None or args.outPath == None:
+ if args.stepStructurePath == None or args.outPath == None:
parser.print_help()
- data = FS.readJSON(args.asm4Path)
- asm4 = Asm4Structure.parse(data)
- asm4usecase = Asm4ToAssemblyUseCase().call(asm4)
- assemblyToPddlUseCase = AssemblyToPddlUseCase.call(assembly=asm4usecase['asm'],rootLabel=asm4usecase['rootLabel'])
+ data = FS.readJSON(args.stepStructurePath)
+
+ assemblyToPddlUseCase = AssemblyToPddlUseCase.call(assembly=data,rootLabel=data[0])
FS.writeFile(assemblyToPddlUseCase['problem'] ,args.outPath, 'problem.pddl')
FS.writeFile(assemblyToPddlUseCase['domain'] ,args.outPath, 'domain.pddl')
diff --git a/pddl/mocks/asm4-mock.json b/pddl/mocks/asm4-mock.json
deleted file mode 100644
index 3178ba2..0000000
--- a/pddl/mocks/asm4-mock.json
+++ /dev/null
@@ -1,86 +0,0 @@
-[
- {
- "level": 1,
- "attachedTo": "Parent Assembly",
- "label": "Model",
- "axis": [
- "LCS_Origin"
- ]
- },
- {
- "level": 1,
- "attachedTo": [
- "Parent Assembly",
- "LCS_Origin"
- ],
- "label": "CubePart001",
- "axis": [
- "LCS_0"
- ]
- },
- {
- "level": 1,
- "attachedTo": [
- "CubePart001",
- "LCS_0"
- ],
- "label": "CubePart002",
- "axis": [
- "LCS_0"
- ]
- },
- {
- "level": 1,
- "attachedTo": [
- "CubePart001",
- "LCS_0"
- ],
- "label": "CubePart003",
- "axis": [
- "LCS_0"
- ]
- },
- {
- "level": 1,
- "attachedTo": [
- ""
- ],
- "label": "CubePart004",
- "axis": [
- "LCS_0"
- ]
- },
- {
- "level": 1,
- "attachedTo": [
- "CubePart001",
- "LCS_0"
- ],
- "label": "CubePart005",
- "axis": [
- "LCS_0"
- ]
- },
- {
- "level": 1,
- "attachedTo": [
- "CubePart005",
- "LCS_0"
- ],
- "label": "CubePart006",
- "axis": [
- "LCS_0"
- ]
- },
- {
- "level": 1,
- "attachedTo": [
- "CubePart006",
- "LCS_0"
- ],
- "label": "CubePart007",
- "axis": [
- "LCS_0"
- ]
- }
-]
\ No newline at end of file
diff --git a/pddl/mocks/step-mock.json b/pddl/mocks/step-mock.json
new file mode 100644
index 0000000..361aade
--- /dev/null
+++ b/pddl/mocks/step-mock.json
@@ -0,0 +1 @@
+["Cube3", "Cube1", "Cube2"]
\ No newline at end of file
diff --git a/pddl/src/usecases/asm4_to_assembly_use_case.py b/pddl/src/usecases/asm4_to_assembly_use_case.py
deleted file mode 100644
index a1b0ecd..0000000
--- a/pddl/src/usecases/asm4_to_assembly_use_case.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from src.model.asm4_structure import Asm4Structure
-from typing import List
-
-
-
-class Asm4ToAssemblyUseCase:
- _asm4Assembly = []
- def call(self,asm4:List[Asm4Structure] ):
- rootPart = asm4[0]
- self._asm4Assembly.append(rootPart.label)
- for el in asm4[1:asm4.__len__()]:
- self.parse(lead=el)
- return {'asm':self._asm4Assembly[1:self._asm4Assembly.__len__()],'rootLabel':rootPart.label}
- def parse(self,lead:Asm4Structure ):
- if lead.attached_to[0] == 'Parent Assembly':
- self._asm4Assembly.append(lead.label)
- for i in self._asm4Assembly:
- if i == lead.attached_to[0]:
- self._asm4Assembly.append(lead.label)
\ No newline at end of file
diff --git a/pddl/src/usecases/assembly_to_pddl_use_case.py b/pddl/src/usecases/assembly_to_pddl_use_case.py
index 3d66f47..7583043 100644
--- a/pddl/src/usecases/assembly_to_pddl_use_case.py
+++ b/pddl/src/usecases/assembly_to_pddl_use_case.py
@@ -7,6 +7,7 @@ import os
class AssemblyToPddlUseCase:
def call(assembly: List[str], rootLabel: str):
+ print(assembly)
partType = UserType("part")
assemblyType = UserType('assembly')
@@ -36,8 +37,8 @@ class AssemblyToPddlUseCase:
goal = Fluent(rootLabel)
problem.add_goal(connected(objectsPartPddl[objectsPartPddl.__len__(
) - 1], objectsAsmToPddl[objectsAsmToPddl.__len__() - 1]),)
-
return {
"problem": unified_planning.io.PDDLWriter(problem).get_problem(),
'domain': FS.readFile(os.path.dirname(os.path.realpath(__file__)) + '/../../mocks' + '/domain.txt'),
}
+
diff --git a/pddl/unit.test.py b/pddl/unit.test.py
index c883c48..df08c98 100644
--- a/pddl/unit.test.py
+++ b/pddl/unit.test.py
@@ -1,5 +1,4 @@
import unittest
-from src.usecases.asm4_to_assembly_use_case import Asm4ToAssemblyUseCase
from src.usecases.assembly_to_pddl_use_case import AssemblyToPddlUseCase
from src.model.asm4_structure import Asm4Structure
@@ -7,17 +6,16 @@ from helper.fs import FS
import os
-mock = FS.readJSON(os.path.dirname(os.path.realpath(__file__)) + '/mocks/asm4-mock.json')
+mock = FS.readJSON(os.path.dirname(os.path.realpath(__file__)) + '/mocks/step-mock.json')
-asm4 = Asm4Structure.parse(mock)
-
+
-asm4usecase = Asm4ToAssemblyUseCase().call(asm4)
-assemblyToPddl = AssemblyToPddlUseCase.call(assembly=asm4usecase['asm'],rootLabel=asm4usecase['rootLabel'])
+assemblyToPddl = AssemblyToPddlUseCase.call(assembly=mock,rootLabel=mock[0])
class TestStringMethods(unittest.TestCase):
def test_problem(self):
+ print(assemblyToPddl["problem"])
self.assertIsInstance(assemblyToPddl["problem"], str)
def test_domain(self):
self.assertIsInstance(assemblyToPddl["domain"], str)
diff --git a/sdf/helper/fs.py b/sdf/helper/fs.py
new file mode 100644
index 0000000..a529801
--- /dev/null
+++ b/sdf/helper/fs.py
@@ -0,0 +1,23 @@
+import os
+import json
+
+
+class FS:
+ def readJSON(path: str):
+ return json.loads((open(path)).read())
+
+ def writeFile(data, filePath, fileName):
+
+ file_to_open = filePath + fileName
+
+ f = open(file_to_open, 'w', )
+
+ f.write(data)
+ def readFile(path:str):
+ return open(path).read()
+
+ def readFilesTypeFolder(pathFolder: str, fileType = '.json'):
+ filesJson = list(
+ filter(lambda x: x[-fileType.__len__():] == fileType, os.listdir(pathFolder)))
+ return filesJson
+
diff --git a/sdf/main.py b/sdf/main.py
new file mode 100644
index 0000000..e4ee14f
--- /dev/null
+++ b/sdf/main.py
@@ -0,0 +1,71 @@
+import argparse
+import shutil
+from distutils.dir_util import copy_tree
+import asyncio
+from helper.fs import FS
+from src.usecases.generate_world import SdfGenerateWorldUseCase
+from src.model.sdf_geometry import SdfGeometryModel
+from src.usecases.sdf_sub_assembly_usecase import SdfSubAssemblyUseCase
+
+import os
+import typing
+import xmlformatter
+
+
+
+# python3 main.py --generationFolder /Users/idontsudo/robo/Cube3/ --outPath /Users/idontsudo/robo/ --world true
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--generationFolder', help='FreeCad generation folder')
+ parser.add_argument('--outPath', help='save SDF path')
+ parser.add_argument('--world', help='adding sdf world')
+
+ args = parser.parse_args()
+
+ if args.generationFolder == None or args.outPath == None:
+ parser.print_help()
+ outPath = args.outPath
+
+ geometryFiles = FS.readFilesTypeFolder(args.generationFolder + '/assets/')
+ assemblyStructure = FS.readJSON(
+ args.generationFolder + '/step-structure.json')
+
+ sdfGeometryModels: list[SdfGeometryModel] = []
+ for el in geometryFiles:
+ sdfGeometryModels.append(SdfGeometryModel.from_dict(
+ FS.readJSON(args.generationFolder + '/assets/' + el)))
+ sdfSubAssemblyUseCase = SdfSubAssemblyUseCase().call(
+ sdfGeometryModels, assemblyStructure,)
+
+ if os.path.exists(outPath + 'sdf-generation/'):
+ shutil.rmtree(path=outPath + 'sdf-generation/')
+
+ copy_tree(args.generationFolder + 'sdf/', outPath + 'sdf-generation/')
+ dirPath = outPath + 'sdf-generation/'
+ for el in sdfGeometryModels:
+ path = dirPath + el.name + '/'
+ os.makedirs(path)
+ FS.writeFile(data=el.toSDF(), filePath=path,
+ fileName='/model' + '.sdf')
+ FS.writeFile(data=FS.readFile(os.path.dirname(os.path.realpath(__file__))
+ + '/mocks/sdf/model.config'), filePath=path, fileName='/model' + '.config')
+
+
+ if(args.world == None):
+ for key, v in sdfSubAssemblyUseCase.items():
+ FS.writeFile(data=v['assembly'], filePath=dirPath,
+ fileName='/' + key + '.sdf')
+
+ else:
+ for key, v in sdfSubAssemblyUseCase.items():
+ FS.writeFile(data=SdfGenerateWorldUseCase.call(v['assembly']), filePath=dirPath,
+ fileName='/' + key + '.sdf')
+ formatter = xmlformatter.Formatter(indent="1", indent_char="\t", encoding_output="ISO-8859-1", preserve=["literal"])
+
+ files = FS.readFilesTypeFolder(outPath + 'sdf-generation/', fileType= '.sdf')
+ for el in files:
+
+ FS.writeFile(data=str(formatter.format_file(outPath + 'sdf-generation/' + el) , 'utf-8'), filePath=outPath + 'sdf-generation/', fileName=el)
+
+
+
diff --git a/sdf/mocks/Cube1.json b/sdf/mocks/Cube1.json
new file mode 100644
index 0000000..6952409
--- /dev/null
+++ b/sdf/mocks/Cube1.json
@@ -0,0 +1,18 @@
+{
+ "name": "Cube1",
+ "ixx": "16.66666666666667",
+ "ixy": "0.0",
+ "ixz": "0.0",
+ "iyy": "16.66666666666667",
+ "izz": "16.66666666666667",
+ "massSDF": "0.9999999999999998",
+ "posX": "0.0",
+ "posY": "-0.015",
+ "posZ": "0.0",
+ "eulerX": "0.0",
+ "eulerY": "0.0",
+ "eulerZ": "0.0",
+ "iyz": "0.0",
+ "stl": "/meshes/Cube1.stl",
+ "link": "1554"
+}
\ No newline at end of file
diff --git a/sdf/mocks/Cube2.json b/sdf/mocks/Cube2.json
new file mode 100644
index 0000000..66d8705
--- /dev/null
+++ b/sdf/mocks/Cube2.json
@@ -0,0 +1,18 @@
+{
+ "name": "Cube2",
+ "ixx": "16.66666666666667",
+ "ixy": "0.0",
+ "ixz": "-3.637978807091713e-15",
+ "iyy": "16.66666666666667",
+ "izz": "16.66666666666667",
+ "massSDF": "0.9999999999999998",
+ "posX": "0.0",
+ "posY": "-0.009",
+ "posZ": "0.01",
+ "eulerX": "0.0",
+ "eulerY": "0.0",
+ "eulerZ": "0.0",
+ "iyz": "-3.637978807091713e-15",
+ "stl": "/meshes/Cube2.stl",
+ "link": "8838"
+}
\ No newline at end of file
diff --git a/sdf/mocks/sdf/include.sdf b/sdf/mocks/sdf/include.sdf
new file mode 100644
index 0000000..089a39e
--- /dev/null
+++ b/sdf/mocks/sdf/include.sdf
@@ -0,0 +1,4 @@
+
+ {name}
+ {uri}
+
\ No newline at end of file
diff --git a/sdf/mocks/sdf/include_pose.sdf b/sdf/mocks/sdf/include_pose.sdf
new file mode 100644
index 0000000..ad43ee8
--- /dev/null
+++ b/sdf/mocks/sdf/include_pose.sdf
@@ -0,0 +1,5 @@
+
+ {name}
+ {uri}
+ {posX} {posY} {posZ} {eulerX} {eulerY} {eulerZ}
+
\ No newline at end of file
diff --git a/sdf/mocks/sdf/joint_fixed.sdf b/sdf/mocks/sdf/joint_fixed.sdf
new file mode 100644
index 0000000..8e8a45c
--- /dev/null
+++ b/sdf/mocks/sdf/joint_fixed.sdf
@@ -0,0 +1,7 @@
+
+ base_link
+ {child}::{child}
+ {posX} {posY} {posZ} {eulerX} {eulerY} {eulerZ}
+
+
+
\ No newline at end of file
diff --git a/sdf/mocks/sdf/link.sdf b/sdf/mocks/sdf/link.sdf
new file mode 100644
index 0000000..0b2f09d
--- /dev/null
+++ b/sdf/mocks/sdf/link.sdf
@@ -0,0 +1,36 @@
+
+ {posX} {posY} {posZ} {eulerX} {eulerY} {eulerZ}
+
+ {posX} {posY} {posZ} {eulerX} {eulerY} {eulerZ}
+
+ {ixx}
+ {ixy}
+ {ixz}
+ {iyy}
+ {iyz}
+ {izz}
+
+ {massSDF}
+
+
+
+
+ model:/{stl}
+
+
+
+
+
+
+ model:/{stl}
+
+
+
+
+
+ {friction}
+
+
+
+
+
\ No newline at end of file
diff --git a/sdf/mocks/sdf/model.config b/sdf/mocks/sdf/model.config
new file mode 100644
index 0000000..ca79d61
--- /dev/null
+++ b/sdf/mocks/sdf/model.config
@@ -0,0 +1,5 @@
+
+
+
+ model.sdf
+
\ No newline at end of file
diff --git a/sdf/mocks/sdf/model.sdf b/sdf/mocks/sdf/model.sdf
new file mode 100644
index 0000000..2b19966
--- /dev/null
+++ b/sdf/mocks/sdf/model.sdf
@@ -0,0 +1,27 @@
+
+
+
+
+ 0
+
+
+ model:/{stl}
+
+
+
+
+
+ model:/{stl}
+
+
+
+
+
+ {friction}
+
+
+
+
+
+
+
diff --git a/sdf/mocks/sdf/world.sdf b/sdf/mocks/sdf/world.sdf
new file mode 100644
index 0000000..4014b10
--- /dev/null
+++ b/sdf/mocks/sdf/world.sdf
@@ -0,0 +1,71 @@
+
+
+
+ 0.001
+ 1
+ 1000
+
+
+
+
+
+ 0 0 -9.8
+ 6e-06 2.3e-05 -4.2e-05
+
+
+ 0.4 0.4 0.4 1
+ 0.7 0.7 0.7 1
+ true
+
+
+ true
+
+
+
+
+ 0 0 1
+ 100 100
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0 0 1
+ 100 100
+
+
+
+ 0.8 0.8 0.8 1
+ 0.8 0.8 0.8 1
+ 0.8 0.8 0.8 1
+
+
+ 0 0 0 0 -0 0
+
+ 0 0 0 0 -0 0
+ 1
+
+ 1
+ 0
+ 0
+ 1
+ 0
+ 1
+
+
+ false
+
+ 0 0 0 0 -0 0
+ false
+
+
+
+
diff --git a/sdf/requirements.txt b/sdf/requirements.txt
new file mode 100644
index 0000000..1352d5e
--- /dev/null
+++ b/sdf/requirements.txt
@@ -0,0 +1 @@
+argparse
diff --git a/sdf/src/model/sdf_geometry.py b/sdf/src/model/sdf_geometry.py
new file mode 100644
index 0000000..866a7ff
--- /dev/null
+++ b/sdf/src/model/sdf_geometry.py
@@ -0,0 +1,161 @@
+import os
+from helper.fs import FS
+
+from src.model.sdf_join import SdfJoin
+import typing
+import uuid
+
+
+def from_str(x):
+ assert isinstance(x, str)
+ return x
+
+
+def from_none(x):
+ assert x is None
+ return x
+
+
+def from_union(fs, x):
+ for f in fs:
+ try:
+ return f(x)
+ except:
+ pass
+ assert False
+
+
+def to_class(c, x):
+ assert isinstance(x, c)
+ return x.to_dict()
+
+
+class SdfGeometryModel:
+ def __init__(self, name, ixx, ixy, ixz, iyy, izz, massSDF, posX, posY, posZ, eulerX, eulerY, eulerZ, iyz, stl, link, friction):
+ self.name = name
+ self.ixx = ixx
+ self.ixy = ixy
+ self.ixz = ixz
+ self.iyy = iyy
+ self.izz = izz
+ self.massSDF = massSDF
+ self.posX = posX
+ self.posY = posY
+ self.posZ = posZ
+ self.eulerX = eulerX
+ self.eulerY = eulerY
+ self.eulerZ = eulerZ
+ self.iyz = iyz
+ self.stl = stl
+ self.link = link
+ self.friction = friction
+
+ @staticmethod
+ def from_dict(obj):
+ assert isinstance(obj, dict)
+ name = from_union([from_str, from_none], obj.get("name"))
+ ixx = from_union([from_str, from_none], obj.get("ixx"))
+ ixy = from_union([from_str, from_none], obj.get("ixy"))
+ ixz = from_union([from_str, from_none], obj.get("ixz"))
+ iyy = from_union([from_str, from_none], obj.get("iyy"))
+ izz = from_union([from_str, from_none], obj.get("izz"))
+ massSDF = from_union([from_str, from_none], obj.get("massSDF"))
+ posX = from_union([from_str, from_none], obj.get("posX"))
+ posY = from_union([from_str, from_none], obj.get("posY"))
+ posZ = from_union([from_str, from_none], obj.get("posZ"))
+ eulerX = from_union([from_str, from_none], obj.get("eulerX"))
+ eulerY = from_union([from_str, from_none], obj.get("eulerY"))
+ eulerZ = from_union([from_str, from_none], obj.get("eulerZ"))
+ iyz = from_union([from_str, from_none], obj.get("iyz"))
+ stl = from_union([from_str, from_none], obj.get("stl"))
+ link = from_union([from_str, from_none], obj.get('link'))
+ friction = from_union([from_str, from_none], obj.get("friction"))
+
+ return SdfGeometryModel(name, ixx, ixy, ixz, iyy, izz, massSDF, posX, posY, posZ, eulerX, eulerY, eulerZ, iyz, stl, link, friction)
+
+ def to_dict(self):
+ result = {}
+ if self.name is not None:
+ result["name"] = from_union([from_str, from_none], self.name)
+ if self.ixx is not None:
+ result["ixx"] = from_union([from_str, from_none], self.ixx)
+ if self.ixy is not None:
+ result["ixy"] = from_union([from_str, from_none], self.ixy)
+ if self.ixz is not None:
+ result["ixz"] = from_union([from_str, from_none], self.ixz)
+ if self.iyy is not None:
+ result["iyy"] = from_union([from_str, from_none], self.iyy)
+ if self.izz is not None:
+ result["izz"] = from_union([from_str, from_none], self.izz)
+ if self.massSDF is not None:
+ result["massSDF"] = from_union([from_str, from_none], self.massSDF)
+ if self.posX is not None:
+ result["posX"] = from_union([from_str, from_none], self.posX)
+ if self.posY is not None:
+ result["posY"] = from_union([from_str, from_none], self.posY)
+ if self.posZ is not None:
+ result["posZ"] = from_union([from_str, from_none], self.posZ)
+ if self.eulerX is not None:
+ result["eulerX"] = from_union([from_str, from_none], self.eulerX)
+ if self.eulerY is not None:
+ result["eulerY"] = from_union([from_str, from_none], self.eulerY)
+ if self.eulerZ is not None:
+ result["eulerZ"] = from_union([from_str, from_none], self.eulerZ)
+ if self.iyz is not None:
+ result["iyz"] = from_union([from_str, from_none], self.iyz)
+ if self.stl is not None:
+ result["stl"] = from_union([from_str, from_none], self.stl)
+ if self.link is not None:
+ result['link'] = from_union([from_str, from_none], self.link)
+ if self.friction is not None:
+ result["friction"] = from_union([from_str, from_none], self.eulerZ)
+ return result
+
+ def toJSON(self) -> str:
+ return str(self.to_dict()).replace('\'', '"')
+
+ def toSDF(self):
+ return FS.readFile(os.path.dirname(os.path.realpath(__file__))
+ + '/../../mocks/sdf/model.sdf').replace('{name}', self.name,).replace('{posX}', self.posX).replace('{posY}', self.posY).replace('{posZ}', self.posZ).replace('{eulerX}', self.eulerX).replace('{eulerY}', self.eulerY).replace('{eulerZ}', self.eulerZ).replace('{ixx}', self.ixx).replace('{ixy}', self.ixy).replace('{ixz}', self.ixz).replace('{iyy}', self.iyy).replace('{iyz}', self.iyz).replace('{izz}', self.izz).replace('{massSDF}', self.massSDF,).replace('{stl}', self.stl).replace('{friction}',self.friction)
+
+ def toSdfLink(self):
+
+ return FS.readFile(os.path.dirname(os.path.realpath(__file__))
+ + '/../../mocks/sdf/link.sdf').replace('{name}', self.name,).replace('{posX}', self.posX).replace('{posY}', self.posY).replace('{posZ}', self.posZ).replace('{eulerX}', self.eulerX).replace('{eulerY}', self.eulerY).replace('{eulerZ}', self.eulerZ).replace('{ixx}', self.ixx).replace('{ixy}', self.ixy).replace('{ixz}', self.ixz).replace('{iyy}', self.iyy).replace('{iyz}', self.iyz).replace('{izz}', self.izz).replace('{massSDF}', self.massSDF,).replace('{stl}', self.stl).replace('{friction}',self.friction)
+ def includeLink(self, pose = False):
+ if(pose == False):
+ return FS.readFile(os.path.dirname(os.path.realpath(__file__))
+ + '/../../mocks/sdf/include.sdf').replace('{name}', self.name).replace('{uri}', '/' + self.name)
+ return FS.readFile(os.path.dirname(os.path.realpath(__file__))
+ + '/../../mocks/sdf/include_pose.sdf').replace('{name}', self.name).replace('{uri}', '/' + self.name).replace('{posX}', self.posX).replace('{posY}', self.posY).replace('{posZ}', self.posZ).replace('{eulerX}', self.eulerX).replace('{eulerY}', self.eulerY).replace('{eulerZ}', self.eulerZ).replace('{ixx}', self.ixx).replace('{ixy}', self.ixy).replace('{ixz}', self.ixz).replace('{iyy}', self.iyy).replace('{iyz}', self.iyz).replace('{izz}', self.izz)
+
+ def generateSDFatJoinFixed(self, sdfModels: list['SdfGeometryModel']):
+ sdf = '\n\n'
+ sdf+= ' \n'
+ sdf += " 0 0 0 0 0 0\n"
+ sdf+= " \n"
+
+ link = sdf + self.includeLink(pose=True)
+ if sdfModels.__len__() == 0:
+ return link
+ endTagLinkInc = link.__len__()
+ beginSDF = link[0: endTagLinkInc]
+
+
+ sdfJoin = beginSDF + '\n'
+
+ for el in sdfModels:
+ if el.name != self.name:
+ sdfJoin += el.includeLink(pose=True) + '\n'
+
+ endSDF = link[endTagLinkInc:link.__len__()]
+
+ for el in sdfModels:
+ if el.name != self.name:
+ sdfJoin += SdfJoin(name=str(uuid.uuid4()),
+ parent=self.name, child=el.name,modelAt=el).toSDF() + '\n'
+
+ sdfJoin += endSDF
+ sdfJoin += ''
+ return sdfJoin
+
\ No newline at end of file
diff --git a/sdf/src/model/sdf_join.py b/sdf/src/model/sdf_join.py
new file mode 100644
index 0000000..2e38208
--- /dev/null
+++ b/sdf/src/model/sdf_join.py
@@ -0,0 +1,16 @@
+from helper.fs import FS
+import os
+
+
+
+class SdfJoin:
+
+ def __init__(self, name, parent, modelAt, child) -> None:
+ self.name = name
+ self.parent = parent
+ self.child = child
+ self.modelAt = modelAt
+ pass
+
+ def toSDF(self):
+ return (FS.readFile(os.path.dirname(os.path.realpath(__file__)) + '/../../mocks/sdf/joint_fixed.sdf')).replace('{name}', self.name,).replace('{parent}', self.parent).replace('{child}', self.child).replace('{posX}', self.modelAt.posX).replace('{posY}', self.modelAt.posY).replace('{posZ}', self.modelAt.posZ).replace('{eulerX}', self.modelAt.eulerX).replace('{eulerY}', self.modelAt.eulerY).replace('{eulerZ}', self.modelAt.eulerZ).replace('{ixx}', self.modelAt.ixx).replace('{ixy}', self.modelAt.ixy).replace('{ixz}', self.modelAt.ixz).replace('{iyy}', self.modelAt.iyy).replace('{iyz}', self.modelAt.iyz).replace('{izz}', self.modelAt.izz)
diff --git a/sdf/src/usecases/generate_world.py b/sdf/src/usecases/generate_world.py
new file mode 100644
index 0000000..96b842e
--- /dev/null
+++ b/sdf/src/usecases/generate_world.py
@@ -0,0 +1,12 @@
+import os
+from helper.fs import FS
+
+class SdfGenerateWorldUseCase:
+ def call(assembly:str) -> str:
+ world = FS.readFile(os.path.dirname(os.path.realpath(__file__))
+ + '/../../mocks/sdf/world.sdf')
+ beginWorld = world[0:world.find('=3.10',
packages=setuptools.find_packages(),
-)
+)
\ No newline at end of file