diff --git a/.gitignore b/.gitignore index a5a208d..624a48b 100644 --- a/.gitignore +++ b/.gitignore @@ -107,4 +107,7 @@ install_plugin_cad.sh # emacs backup files ~* +*~ *# +.#* +\#*\# diff --git a/cg/blender/import_fcstd/import_cad_objects.py b/cg/blender/import_fcstd/import_cad_objects.py index 6249358..026a610 100644 --- a/cg/blender/import_fcstd/import_cad_objects.py +++ b/cg/blender/import_fcstd/import_cad_objects.py @@ -11,6 +11,7 @@ # 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. +__version__ = "0.2" import time import FreeCAD import logging @@ -22,6 +23,7 @@ import os import bpy from bpy_extras.node_shader_utils import PrincipledBSDFWrapper from import_fcstd.handler import FreeCAD_xml_handler +from import_fcstd.import_hierarchy import import_hierarchy from import_fcstd.materials import set_fem_mat from import_fcstd.is_object_solid import is_object_solid @@ -236,11 +238,16 @@ def obj_importer(filename, bobj.rotation_quaternion = (q) bobj.rotation_mode = m bobj.scale = (scale, scale, scale) - if obj.Name in guidata: - # !!! - # one material for the whole object - for fem_mat in doc.Objects: - set_fem_mat(obj, bobj, fem_mat) + + if obj.Name in guidata: + # !!! + # one material for the whole object + for fem_mat in doc.Objects: + set_fem_mat(obj, bobj, fem_mat) + + obj_parent = obj.getParentGeoFeatureGroup() + if obj_parent: + import_hierarchy(obj, bobj, scale) fcstd_collection.objects.link(bobj) if select: diff --git a/cg/blender/import_fcstd/import_hierarchy.py b/cg/blender/import_fcstd/import_hierarchy.py new file mode 100644 index 0000000..5ec54eb --- /dev/null +++ b/cg/blender/import_fcstd/import_hierarchy.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2023 Ilia Kurochkin +# +# 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. +# Collecting all parents and reconstruct this hierarhy in bledner. +import logging +import bpy + +logger = logging.getLogger(__name__) +logging.basicConfig(level=logging.INFO) + + +def import_hierarchy(fc_obj, b_obj, scale): + """FreeCAD object, Blender object, scene scale""" + obj_parent = fc_obj.getParentGeoFeatureGroup() + obj_child_name = None + while obj_parent: + if bpy.context.scene.objects.get(obj_parent.Label): + empty = bpy.data.objects[obj_parent.Label] + else: + bpy.ops.object.empty_add( + type='CUBE', radius=0.01, align='WORLD', + location=(0, 0, 0), rotation=(0, 0, 0)) + empty = bpy.data.objects['Empty'] + empty.name = obj_parent.Label + placement = obj_parent.Placement + empty.location = placement.Base.multiply(scale) + rm = empty.rotation_mode + if placement.Rotation.Angle: + empty.rotation_mode = 'QUATERNION' + q = (placement.Rotation.Q[3],)+placement.Rotation.Q[:3] + empty.rotation_quaternion = (q) + empty.rotation_mode = rm + if b_obj.parent: + bpy.data.objects[obj_child_name].parent = empty + else: + b_obj.parent = empty + obj_child_name = obj_parent.Label + obj_parent = obj_parent.getParentGeoFeatureGroup() + empty.select_set(False) + logger.debug('Add parent %s to object %s', empty.name, b_obj.name) diff --git a/cg/blender/import_fcstd/is_object_solid.py b/cg/blender/import_fcstd/is_object_solid.py index 12e93ee..10ee07a 100644 --- a/cg/blender/import_fcstd/is_object_solid.py +++ b/cg/blender/import_fcstd/is_object_solid.py @@ -24,10 +24,4 @@ def is_object_solid(obj): 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 + return obj.Shape.isClosed() diff --git a/cg/blender/remesh/__init__.py b/cg/blender/remesh/__init__.py index d5bf2b3..ded2629 100644 --- a/cg/blender/remesh/__init__.py +++ b/cg/blender/remesh/__init__.py @@ -19,10 +19,13 @@ logging.basicConfig(level=logging.INFO) def asset_setup(transforms=True, sharpness=True, shading=True): """ asset setup pipeline """ for ob in bpy.context.scene.objects: - #deselect all but just one object and make it active + if not ob.type == 'MESH': + continue bpy.ops.object.select_all(action='DESELECT') ob.select_set(state=True) bpy.context.view_layer.objects.active = ob + # apply scale + apply_transforms(ob, location=False, rotation=False, scale=True) if transforms: # remove doubles diff --git a/cg/pipeline/freecad_to_asset.py b/cg/pipeline/freecad_to_asset.py index 4652d09..ffddd79 100644 --- a/cg/pipeline/freecad_to_asset.py +++ b/cg/pipeline/freecad_to_asset.py @@ -37,16 +37,6 @@ def freecad_asset_pipeline(fcstd_path, cleanup_orphan_data() obj_importer(fcstd_path, tessellation) - # apply scale to all objects - obs = bpy.context.selected_objects - for ob in obs: - bpy.ops.object.select_all(action='DESELECT') - ob.select_set(state=True) - bpy.context.view_layer.objects.active = ob - apply_transforms(ob, location=False, rotation=False, scale=True) - for ob in obs: - ob.select_set(state=True) - if json_path is not None: for point in os.listdir(json_path): if point.endswith('.json'):