FreeCAD: Workbench Refactor
This commit is contained in:
parent
037827669a
commit
a58dcdafb1
386 changed files with 997 additions and 64533 deletions
187
freecad_workbench/freecad_to_json.py
Normal file
187
freecad_workbench/freecad_to_json.py
Normal file
|
@ -0,0 +1,187 @@
|
|||
# coding: utf-8
|
||||
# Copyright (C) 2023 Ilia Kurochkin <brothermechanic@yandex.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU 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.
|
||||
'''
|
||||
DESCRIPTION.
|
||||
- Reads a FreeCAD .FCStd file.
|
||||
- Set tesselation parts to mesh.
|
||||
- Return scene as JSON dictionary.
|
||||
'''
|
||||
__version__ = '0.1'
|
||||
import json
|
||||
import FreeCAD
|
||||
import Part
|
||||
import Mesh
|
||||
import MeshPart
|
||||
import logging
|
||||
import math
|
||||
from utils.is_object_solid import is_object_solid
|
||||
from utils.processor import process_file
|
||||
from utils.custom_parser import CustomArgumentParser
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def freecad_to_json(**kwargs):
|
||||
''' Reads a FreeCAD .FCStd file and return json assembly. '''
|
||||
|
||||
scene = {}
|
||||
js_objs = {}
|
||||
|
||||
doc = FreeCAD.open(kwargs['fcstd_path'])
|
||||
docname = doc.Name
|
||||
|
||||
# collect all materials
|
||||
fem_mats = []
|
||||
for fem_mat in doc.Objects:
|
||||
if fem_mat.isDerivedFrom('App::MaterialObjectPython'):
|
||||
fem_mats.append(fem_mat)
|
||||
|
||||
for obj in doc.Objects:
|
||||
js_obj = {}
|
||||
|
||||
if kwargs['skiphidden']:
|
||||
if not obj.Visibility:
|
||||
continue
|
||||
|
||||
if obj.isDerivedFrom('PartDesign::CoordinateSystem'):
|
||||
js_obj['type'] = 'LCS'
|
||||
|
||||
elif obj.isDerivedFrom('Part::Feature'):
|
||||
js_obj['type'] = 'PART'
|
||||
# filter for nonsolids
|
||||
|
||||
if is_object_solid(obj) or hasattr(obj, kwargs['property_forse_nonsolid']):
|
||||
# create mesh from shape
|
||||
shape = obj.Shape
|
||||
shape = obj.Shape.copy()
|
||||
shape.Placement = obj.Placement.inverse().multiply(shape.Placement)
|
||||
meshfromshape = doc.addObject('Mesh::Feature', 'Mesh')
|
||||
if kwargs['tesselation_method'] == 'Standard':
|
||||
meshfromshape.Mesh = MeshPart.meshFromShape(
|
||||
Shape=shape,
|
||||
LinearDeflection=kwargs['linear_deflection'],
|
||||
AngularDeflection=math.radians(kwargs['angular_deflection']),
|
||||
Relative=False)
|
||||
elif kwargs['tesselation_method'] == 'FEM':
|
||||
meshfromshape.Mesh = MeshPart.meshFromShape(
|
||||
Shape=shape,
|
||||
MaxLength=kwargs['fem_size'])
|
||||
else:
|
||||
raise TypeError('Wrong tesselation method! '
|
||||
'Standard and FEM methods are supported only!')
|
||||
|
||||
t = meshfromshape.Mesh.Topology
|
||||
verts = [[v.x, v.y, v.z] for v in t[0]]
|
||||
faces = t[1]
|
||||
js_obj['mesh'] = (verts, faces)
|
||||
|
||||
# one material for the whole object
|
||||
for fem_mat in fem_mats:
|
||||
for ref in fem_mat.References:
|
||||
if ref[0].Label == obj.Label:
|
||||
js_obj['material'] = fem_mat.Material
|
||||
|
||||
# skip for other object's types
|
||||
else:
|
||||
continue
|
||||
|
||||
js_obj['fc_location'] = tuple(obj.Placement.Base)
|
||||
js_obj['fc_rotation'] = obj.Placement.Rotation.Q
|
||||
|
||||
# construct assembly hierarchy
|
||||
obj_parent = obj.getParentGeoFeatureGroup()
|
||||
obj_child_name = None
|
||||
parents = {}
|
||||
deep_index = 0
|
||||
while obj_parent:
|
||||
parent = {}
|
||||
parent['fc_location'] = tuple(obj_parent.Placement.Base)
|
||||
parent['fc_rotation'] = obj_parent.Placement.Rotation.Q
|
||||
obj_child_name = obj_parent.Label
|
||||
obj_parent = obj_parent.getParentGeoFeatureGroup()
|
||||
if obj_parent:
|
||||
parent['parent'] = obj_parent.Label
|
||||
else:
|
||||
parent['parent'] = None
|
||||
parents[obj_child_name] = parent
|
||||
parent['deep_index'] = deep_index
|
||||
deep_index += 1
|
||||
js_obj['hierarchy'] = parents
|
||||
|
||||
js_objs[obj.Label] = js_obj
|
||||
|
||||
FreeCAD.closeDocument(docname)
|
||||
|
||||
scene[kwargs['fcstd_path']] = js_objs
|
||||
|
||||
logger.info('Passed %s objects without errors', len(js_objs))
|
||||
|
||||
print(json.dumps(scene))
|
||||
|
||||
|
||||
# to run script via FreeCADCmd
|
||||
parser = CustomArgumentParser()
|
||||
parser.add_argument(
|
||||
'--fcstd_path',
|
||||
type=str,
|
||||
help='Path to source FreeCAD scene',
|
||||
required=True
|
||||
)
|
||||
parser.add_argument(
|
||||
'--tesselation_method',
|
||||
type=str,
|
||||
help='Select tesselation method: Standard or FEM.',
|
||||
default='Standard',
|
||||
required=False
|
||||
)
|
||||
parser.add_argument(
|
||||
'--linear_deflection',
|
||||
type=float,
|
||||
help='Max linear distance error',
|
||||
default=0.1,
|
||||
required=False
|
||||
)
|
||||
parser.add_argument(
|
||||
'--angular_deflection',
|
||||
type=float,
|
||||
help='Max angular distance error',
|
||||
default=20.0,
|
||||
required=False
|
||||
)
|
||||
parser.add_argument(
|
||||
'--fem_size',
|
||||
type=float,
|
||||
help='For FEM method only! Finite element size in mm',
|
||||
default=50.0,
|
||||
required=False
|
||||
)
|
||||
parser.add_argument(
|
||||
'--skiphidden',
|
||||
type=bool,
|
||||
help='Skip processing for hidden FreeCAD objects',
|
||||
default=True,
|
||||
required=False
|
||||
)
|
||||
parser.add_argument(
|
||||
'--property_forse_nonsolid',
|
||||
type=str,
|
||||
help='FreeCAD property to enable processing for nonsolid objects',
|
||||
default='Robossembler_NonSolid',
|
||||
required=False
|
||||
)
|
||||
|
||||
fc_kwargs = vars(parser.parse_known_args()[0])
|
||||
|
||||
freecad_to_json(**fc_kwargs)
|
||||
|
||||
logger.info('FreeCAD scene passed!')
|
Loading…
Add table
Add a link
Reference in a new issue