Add PDDL, 3D-assets & SDF-URDF generator from Blender Scene Config
This commit is contained in:
parent
b77687ea14
commit
e305d486f2
41 changed files with 2793 additions and 664 deletions
116
insertion_vector_predicate/.gitignore
vendored
Normal file
116
insertion_vector_predicate/.gitignore
vendored
Normal file
|
@ -0,0 +1,116 @@
|
|||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
env/
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
.hypothesis/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# dotenv
|
||||
.env
|
||||
|
||||
# virtualenv
|
||||
.venv
|
||||
venv/
|
||||
ENV/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
|
||||
# blender backup files
|
||||
*.blend1
|
||||
install_plugin_cad.sh
|
||||
.vscode
|
||||
.DS_Store
|
||||
|
||||
# emacs backup files
|
||||
~*
|
||||
*~
|
||||
*#
|
||||
.#*
|
||||
\#*\#
|
||||
out/
|
||||
/env.json
|
19
insertion_vector_predicate/README.md
Normal file
19
insertion_vector_predicate/README.md
Normal file
|
@ -0,0 +1,19 @@
|
|||
# Start dev
|
||||
create env.json
|
||||
|
||||
```json
|
||||
{
|
||||
"cadDoc":"CAD_DOC_PATH_REPLACE",
|
||||
"sequences":"SEQUENCES_PATH_REPLACE",
|
||||
"aspDir":"ASP_DIR_REPLACE"
|
||||
}
|
||||
```
|
||||
# Command generation assets
|
||||
freecad generate.py
|
||||
|
||||
# Command generation insertion vectors
|
||||
|
||||
git submodule update --init
|
||||
conda env create -f assembly/environment.yml
|
||||
conda activate assembly
|
||||
python3 main.py
|
205
insertion_vector_predicate/generate.py
Normal file
205
insertion_vector_predicate/generate.py
Normal file
|
@ -0,0 +1,205 @@
|
|||
|
||||
|
||||
from typing import List
|
||||
import FreeCAD as App
|
||||
import Part
|
||||
import Mesh
|
||||
import Part
|
||||
import MeshPart
|
||||
import os
|
||||
import json
|
||||
import FreeCADGui as Gui
|
||||
|
||||
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', encoding='utf-8',
|
||||
errors='ignore')
|
||||
f.write(data)
|
||||
f.close()
|
||||
def createFolder(path: str):
|
||||
if (not os.path.exists(path)):
|
||||
return os.mkdir(path)
|
||||
|
||||
|
||||
|
||||
class SimpleCopyPartModel:
|
||||
id = None
|
||||
copyLink = None
|
||||
label = None
|
||||
part = None
|
||||
|
||||
def getPart(self):
|
||||
return self.part
|
||||
|
||||
def __init__(self, part) -> None:
|
||||
try:
|
||||
from random import randrange
|
||||
self.id = str(randrange(1000000))
|
||||
childObj = part
|
||||
print(part)
|
||||
__shape = Part.getShape(
|
||||
childObj, '', needSubElement=False, refine=False)
|
||||
obj = App.ActiveDocument.addObject('Part::Feature', self.id)
|
||||
obj.Shape = __shape
|
||||
self.part = obj
|
||||
self.label = obj.Label
|
||||
App.ActiveDocument.recompute()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
def remove(self):
|
||||
App.ActiveDocument.removeObject(self.label)
|
||||
|
||||
class MeshPartModel:
|
||||
id = None
|
||||
mesh = None
|
||||
|
||||
def __init__(self, part) -> None:
|
||||
try:
|
||||
from random import randrange
|
||||
self.id = 'mesh' + str(randrange(1000000))
|
||||
document = App.ActiveDocument
|
||||
mesh = document.addObject("Mesh::Feature", self.id)
|
||||
shape = Part.getShape(part, "")
|
||||
mesh.Mesh = MeshPart.meshFromShape(
|
||||
Shape=shape, LinearDeflection=20, AngularDeflection=0.1, Relative=False)
|
||||
mesh.Label = self.id
|
||||
self.mesh = mesh
|
||||
except Exception as e:
|
||||
print(e)
|
||||
pass
|
||||
|
||||
def remove(self):
|
||||
try:
|
||||
App.ActiveDocument.removeObject(self.mesh.Label)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
|
||||
class JoinMeshModel:
|
||||
id = None
|
||||
mesh = None
|
||||
|
||||
def __init__(self, meshesPartModels: list['MeshPartModel']) -> None:
|
||||
meshes = []
|
||||
from random import randrange
|
||||
for el in meshesPartModels:
|
||||
meshes.append(el.mesh.Mesh)
|
||||
|
||||
self.id = 'MergedMesh' + str(randrange(1000000))
|
||||
doc = App.ActiveDocument
|
||||
merged_mesh = Mesh.Mesh()
|
||||
for el in meshes:
|
||||
merged_mesh.addMesh(el)
|
||||
|
||||
new_obj = doc.addObject("Mesh::Feature", self.id)
|
||||
new_obj.Mesh = merged_mesh
|
||||
new_obj.ViewObject.DisplayMode = "Flat Lines"
|
||||
self.mesh = new_obj
|
||||
|
||||
def remove(self):
|
||||
try:
|
||||
App.ActiveDocument.removeObject(self.id)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
class ExportAssemblyThemAllUseCase:
|
||||
|
||||
def call(self, path:str, assemblys:list[str]):
|
||||
assembly = assemblys
|
||||
asmStructure = {}
|
||||
inc = 0
|
||||
for el in assembly:
|
||||
if (inc != 0):
|
||||
asmStructure[inc] = {
|
||||
"child": el,
|
||||
"parents": assembly[0:inc]
|
||||
}
|
||||
inc += 1
|
||||
objectsFreeCad = App.ActiveDocument.Objects
|
||||
asmSolids = {}
|
||||
for k, v in asmStructure.items():
|
||||
assemblyParentList = v['parents']
|
||||
assemblyChild = v['child']
|
||||
for el in assemblyParentList:
|
||||
for solid in objectsFreeCad:
|
||||
if (el == solid.Label):
|
||||
if (asmSolids.get(k) is None):
|
||||
|
||||
asmSolids[k] = {'parents': [], 'child': list(
|
||||
filter(lambda x: x.Label == assemblyChild, objectsFreeCad))[0]}
|
||||
|
||||
asmSolids[k]['parents'].append(solid)
|
||||
|
||||
inc = 0
|
||||
for k, v in asmSolids.items():
|
||||
geometry = {"0": [], "1": []}
|
||||
if (k != 0):
|
||||
App.activeDocument().addObject("Part::Compound", "Compound")
|
||||
|
||||
copyLinks = list(
|
||||
map(lambda el: SimpleCopyPartModel(el), v['parents']))
|
||||
|
||||
if copyLinks != None:
|
||||
App.activeDocument().Compound.Links = list(
|
||||
map(lambda el: el.getPart(), copyLinks))
|
||||
|
||||
object = App.activeDocument().getObject('Compound')
|
||||
boundBox = object.Shape.BoundBox
|
||||
geometry['0'].append(boundBox.XMax)
|
||||
geometry['0'].append(boundBox.YMax)
|
||||
geometry['0'].append(boundBox.ZMax)
|
||||
|
||||
boundBoxChild = v['child'].Shape.BoundBox
|
||||
geometry['1'].append(boundBoxChild.XMax)
|
||||
geometry['1'].append(boundBoxChild.YMax)
|
||||
geometry['1'].append(boundBoxChild.ZMax)
|
||||
meshParents = []
|
||||
|
||||
for el in v['parents']:
|
||||
meshParents.append(MeshPartModel(el))
|
||||
joinMesh = JoinMeshModel(meshParents)
|
||||
for el in meshParents:
|
||||
el.remove()
|
||||
import importOBJ
|
||||
importOBJ.export(joinMesh.mesh, path + str(1) + '.obj')
|
||||
joinMesh.remove()
|
||||
importOBJ.export(v['child'], path + str(0) + '.obj')
|
||||
FS.writeFile(json.dumps(geometry), path, 'translation.json')
|
||||
|
||||
App.ActiveDocument.removeObject("Compound")
|
||||
for el in copyLinks:
|
||||
el.remove()
|
||||
App.activeDocument().recompute()
|
||||
inc += 1
|
||||
|
||||
def main():
|
||||
|
||||
env = FS.readJSON('./env.json')
|
||||
env.get('cadDoc')
|
||||
aspDir = env.get('aspDir')
|
||||
sequences = FS.readJSON(env.get('sequences')).get('sequences')
|
||||
App.openDocument(env.get('cadDoc'))
|
||||
for sequencyNumber in range(len(sequences)):
|
||||
FS.createFolder(aspDir + 'assemblys/')
|
||||
mainFolder = aspDir + 'assemblys/' + str(sequencyNumber) + '/'
|
||||
FS.createFolder(mainFolder)
|
||||
for subSequenceNumber in range(len(sequences[sequencyNumber])):
|
||||
if(subSequenceNumber != 0):
|
||||
subFolder = aspDir + 'assemblys/' + \
|
||||
str(sequencyNumber) + '/' + str(subSequenceNumber) + '/'
|
||||
|
||||
FS.createFolder(subFolder)
|
||||
ExportAssemblyThemAllUseCase().call(path=subFolder,assemblys=sequences[sequencyNumber][0:subSequenceNumber+1])
|
||||
|
||||
App.closeDocument(App.ActiveDocument.Name)
|
||||
freecadQTWindow = Gui.getMainWindow()
|
||||
freecadQTWindow.close()
|
||||
main()
|
|
@ -1,4 +1,14 @@
|
|||
# Алгоритм генерации графа с помощью вычисления векторов вставки при разборке изделия
|
||||
import os
|
||||
import sys
|
||||
|
||||
project_base_dir = os.path.abspath(os.path.join(
|
||||
os.path.dirname(os.path.abspath(__file__)), './')) + '/assembly/'
|
||||
|
||||
|
||||
sys.path.append(project_base_dir)
|
||||
sys.path.append(project_base_dir + '/baselines/')
|
||||
sys.path.append(project_base_dir + '/assets/')
|
||||
|
||||
from scipy.spatial.transform import Rotation
|
||||
import shutil
|
||||
from spatialmath import *
|
||||
|
@ -9,18 +19,32 @@ from assembly.baselines.run_joint_plan import PyPlanner
|
|||
from assembly.assets.subdivide import subdivide_to_size
|
||||
import numpy as np
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
import trimesh
|
||||
|
||||
import re
|
||||
def merge_meshes(meshes):
|
||||
# Создание пустого меша
|
||||
merged_mesh = trimesh.Trimesh()
|
||||
|
||||
# Объединение каждого меша в один
|
||||
for mesh in meshes:
|
||||
merged_mesh = trimesh.util.concatenate(
|
||||
[merged_mesh, trimesh.load(mesh)])
|
||||
i = True
|
||||
while i:
|
||||
if merged_mesh.fill_holes():
|
||||
i = False
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return merged_mesh
|
||||
|
||||
|
||||
os.environ['OMP_NUM_THREADS'] = '1'
|
||||
|
||||
project_base_dir = os.path.abspath(os.path.join(
|
||||
os.path.dirname(os.path.abspath(__file__)), './')) + '/assembly/'
|
||||
|
||||
|
||||
sys.path.append(project_base_dir)
|
||||
sys.path.append(project_base_dir + '/baselines/')
|
||||
sys.path.append(project_base_dir + '/assets/')
|
||||
|
||||
|
||||
|
||||
class FS:
|
||||
def readJSON(path: str):
|
||||
|
@ -43,6 +67,10 @@ class FS:
|
|||
def readFolder(pathFolder: str):
|
||||
return list(map(lambda el: pathFolder + '/' + el, os.listdir(pathFolder)))
|
||||
|
||||
def createFolder(path: str):
|
||||
if (not os.path.exists(path)):
|
||||
return os.mkdir(path)
|
||||
|
||||
|
||||
def listGetFirstValue(iterable, default=False, pred=None):
|
||||
return next(filter(pred, iterable), default)
|
||||
|
@ -56,31 +84,44 @@ def filterModels(filterModels, filterModelsDescription):
|
|||
return models
|
||||
|
||||
|
||||
# mesh1 = trimesh.load('/Users/idontsudo/framework/asp/out/sdf-generation/meshes/Cube.obj')
|
||||
# mesh2 = trimesh.load('/Users/idontsudo/framework/asp/out/sdf-generation/meshes/Cube001.obj')
|
||||
|
||||
|
||||
# # Объединение мешей
|
||||
# merged_mesh = merge_meshes([mesh1, mesh2])
|
||||
|
||||
# # Сохранение объединенного меша в файл
|
||||
# merged_mesh.export('merged.obj')
|
||||
def main():
|
||||
from argparse import ArgumentParser
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument('--asp-path', type=str, required=True)
|
||||
args = parser.parse_args()
|
||||
aspDir = args.asp_dir
|
||||
# from argparse import ArgumentParser
|
||||
# parser = ArgumentParser()
|
||||
# parser.add_argument('--asp-path', type=str, required=True)
|
||||
# args = parser.parse_args()
|
||||
# aspDir = args.asp_dir
|
||||
|
||||
# # Коректировка пути до папки с генерацией ASP
|
||||
# if (aspDir == None):
|
||||
# args.print_helper()
|
||||
# if (aspDir[aspDir.__len__() - 1] != '/'):
|
||||
# aspDir += '/'
|
||||
aspDir = '/home/idontsudo/framework/asp/out/'
|
||||
sequences = FS.readJSON(aspDir + 'sequences.json').get('sequences')
|
||||
|
||||
# Коректировка пути до папки с генерацией ASP
|
||||
if (aspDir == None):
|
||||
args.print_helper()
|
||||
if (aspDir[aspDir.__len__() - 1] != '/'):
|
||||
aspDir += '/'
|
||||
# Получение списка папок с .obj обьектами
|
||||
assembles = FS.readFolder(aspDir + 'assembly')
|
||||
assemblyDirNormalize = []
|
||||
for el in assembles:
|
||||
try:
|
||||
# Пост обработка .obj обьектов
|
||||
process_mesh(source_dir=el, target_dir=el +
|
||||
'/process/', subdivide=el, verbose=True)
|
||||
assemblyDirNormalize.append(el + '/process/')
|
||||
except Exception as e:
|
||||
print('ERRROR:')
|
||||
print(e)
|
||||
for el in FS.readFolder(aspDir + 'assemblys'):
|
||||
for e in FS.readFolder(el):
|
||||
try:
|
||||
# Пост обработка .obj обьектов
|
||||
process_mesh(source_dir=e, target_dir=e +
|
||||
'/process/', subdivide=e, verbose=True)
|
||||
assemblyDirNormalize.append(e + '/process/')
|
||||
except Exception as e:
|
||||
print('ERRROR:')
|
||||
print(e)
|
||||
|
||||
|
||||
print(assemblyDirNormalize)
|
||||
for el in assemblyDirNormalize:
|
||||
asset_folder = os.path.join(project_base_dir, aspDir)
|
||||
assembly_dir = os.path.join(asset_folder, el)
|
||||
|
@ -113,13 +154,13 @@ def main():
|
|||
try:
|
||||
planner = PyPlanner(assembly_dir, 'process', still_ids=[1],)
|
||||
status, t_plan, path = planner.plan(
|
||||
planner_name=args.planner,
|
||||
step_size=args.step_size,
|
||||
max_time=args.max_time,
|
||||
seed=args.seed,
|
||||
planner_name='rrt',
|
||||
step_size=None,
|
||||
max_time=None,
|
||||
seed=1,
|
||||
return_path=True,
|
||||
simplify=args.simplify,
|
||||
render=args.render
|
||||
simplify=False,
|
||||
render=False
|
||||
)
|
||||
|
||||
print(f'Status: {status}, planning time: {t_plan}')
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
spatialmath
|
||||
scipy
|
||||
scipy
|
||||
uuid
|
Loading…
Add table
Add a link
Reference in a new issue