IO: Option to import each DXF file on a new collection or new scene #105289

Merged
Sebastian Sille merged 2 commits from :dxf-patch-import-scene-coll into main 2024-04-23 14:12:02 +02:00
2 changed files with 94 additions and 32 deletions

View File

@ -4,10 +4,10 @@
import bpy import bpy
import os import os
from bpy.props import StringProperty, BoolProperty, EnumProperty, IntProperty, FloatProperty from bpy.props import StringProperty, BoolProperty, EnumProperty, IntProperty, FloatProperty, CollectionProperty
from .dxfimport.do import Do, Indicator from .dxfimport.do import Do, Indicator
from .transverse_mercator import TransverseMercator from .transverse_mercator import TransverseMercator
from pathlib import Path
try: try:
from pyproj import Proj, transform from pyproj import Proj, transform
@ -83,6 +83,7 @@ T_CreateNewScene = False
T_Recenter = False T_Recenter = False
T_ThicknessBevel = True T_ThicknessBevel = True
T_import_atts = True T_import_atts = True
T_Collection = False
RELEASE_TEST = False RELEASE_TEST = False
DEBUG = False DEBUG = False
@ -93,14 +94,14 @@ def is_ref_scene(scene):
def read(report, filename, obj_merge=BY_LAYER, import_text=True, import_light=True, export_acis=True, merge_lines=True, def read(report, filename, obj_merge=BY_LAYER, import_text=True, import_light=True, export_acis=True, merge_lines=True,
do_bbox=True, block_rep=LINKED_OBJECTS, new_scene=None, recenter=False, projDXF=None, projSCN=None, do_bbox=True, block_rep=LINKED_OBJECTS, new_scene=None, new_collection=None, recenter=False, projDXF=None, projSCN=None,
thicknessWidth=True, but_group_by_att=True, dxf_unit_scale=1.0): thicknessWidth=True, but_group_by_att=True, dxf_unit_scale=1.0):
# import dxf and export nurbs types to sat/sab files # import dxf and export nurbs types to sat/sab files
# because that's how autocad stores nurbs types in a dxf... # because that's how autocad stores nurbs types in a dxf...
do = Do(filename, obj_merge, import_text, import_light, export_acis, merge_lines, do_bbox, block_rep, recenter, do = Do(filename, obj_merge, import_text, import_light, export_acis, merge_lines, do_bbox, block_rep, recenter,
projDXF, projSCN, thicknessWidth, but_group_by_att, dxf_unit_scale) projDXF, projSCN, thicknessWidth, but_group_by_att, dxf_unit_scale)
errors = do.entities(os.path.basename(filename).replace(".dxf", ""), new_scene) errors = do.entities(Path(filename.name).stem, new_scene, new_collection)
# display errors # display errors
for error in errors: for error in errors:
@ -192,6 +193,15 @@ class IMPORT_OT_dxf(bpy.types.Operator):
filename_ext = ".dxf" filename_ext = ".dxf"
files: CollectionProperty(
type=bpy.types.OperatorFileListElement,
options={'HIDDEN', 'SKIP_SAVE'}
)
directory: StringProperty(
subtype='DIR_PATH'
)
filter_glob: StringProperty( filter_glob: StringProperty(
default="*.dxf", default="*.dxf",
options={'HIDDEN'}, options={'HIDDEN'},
@ -256,7 +266,23 @@ class IMPORT_OT_dxf(bpy.types.Operator):
default=T_Bbox default=T_Bbox
) )
scene_options: EnumProperty(
name="Scene",
description="Select the import method",
items=[('CURRENT_SCENE', "Current", "All DXF files in the current scene."),
('NEW_SCENE', "New", "Each DXF file in a new scene."),
('NEW_UNIQUE_SCENE', "Unique", "All DXF files in a new collection.")],
default='CURRENT_SCENE',
)
collection_options: EnumProperty(
name="Collection",
description="Select the import method",
items=[('CURRENT_COLLECTION', "Current", "All DXF files in the current scene collection."),
('NEW_COLLECTION', "New", "Each DXF file in a new collection."),
('SCENE_COLLECTION', "Scene", "All DXF files in the scene collection.")],
default='CURRENT_COLLECTION',
)
block_options: EnumProperty( block_options: EnumProperty(
name="Blocks As", name="Blocks As",
@ -368,6 +394,12 @@ class IMPORT_OT_dxf(bpy.types.Operator):
layout = self.layout layout = self.layout
scene = context.scene scene = context.scene
# Import options
layout.label(text="Import Options:")
box = layout.box()
box.prop(self, "scene_options")
box.prop(self, "collection_options")
# merge options # merge options
layout.label(text="Merge Options:") layout.label(text="Merge Options:")
box = layout.box() box = layout.box()
@ -401,7 +433,6 @@ class IMPORT_OT_dxf(bpy.types.Operator):
layout.label(text="View Options:") layout.label(text="View Options:")
box = layout.box() box = layout.box()
box.prop(self, "outliner_groups") box.prop(self, "outliner_groups")
box.prop(self, "create_new_scene")
sub = box.row() sub = box.row()
sub.enabled = _recenter_allowed(self) sub.enabled = _recenter_allowed(self)
sub.prop(self, "recenter") sub.prop(self, "recenter")
@ -515,13 +546,39 @@ class IMPORT_OT_dxf(bpy.types.Operator):
proj_dxf = Indicator(self.dxf_indi) proj_dxf = Indicator(self.dxf_indi)
proj_scn = TransverseMercator(lat=self.merc_scene_lat, lon=self.merc_scene_lon) proj_scn = TransverseMercator(lat=self.merc_scene_lat, lon=self.merc_scene_lon)
scene = bpy.context.scene
if self.create_new_scene:
scene = bpy.data.scenes.new(Path(file.name).stem)
for file in self.files:
match self.scene_options:
case 'NEW_SCENE':
scene = bpy.data.scenes.new(Path(file.name).stem)
case 'NEW_UNIQUE_SCENE':
scene_name="DXF Import"
if bpy.data.scenes.get(scene_name): scene=bpy.data.scenes[scene_name]
else: scene = bpy.data.scenes.new(scene_name)
case _:
scene = bpy.context.scene
match self.collection_options:
case 'NEW_COLLECTION':
collection = bpy.data.collections.new(Path(file.name).stem)
scene.collection.children.link(collection)
case 'SCENE_COLLECTION':
collection = scene.collection
case _:
collection = bpy.context.collection
if collection.name not in scene.collection.children: scene.collection.children.link(collection)
if RELEASE_TEST: if RELEASE_TEST:
# for release testing # for release testing
from . import test from . import test
test.test() test.test()
else: else:
read(self.report, self.filepath, merge_options, self.import_text, self.import_light, self.export_acis, read(self.report, Path(self.directory, file.name), merge_options, self.import_text, self.import_light, self.export_acis,
self.merge_lines, self.do_bbox, block_map[self.block_options], scene, self.recenter, self.merge_lines, self.do_bbox, block_map[self.block_options], scene, collection, self.recenter,
proj_dxf, proj_scn, self.represent_thickness_and_width, self.import_atts, dxf_unit_scale) proj_dxf, proj_scn, self.represent_thickness_and_width, self.import_atts, dxf_unit_scale)
if self.outliner_groups: if self.outliner_groups:

View File

@ -78,7 +78,7 @@ class Do:
__slots__ = ( __slots__ = (
"dwg", "combination", "known_blocks", "import_text", "import_light", "export_acis", "merge_lines", "dwg", "combination", "known_blocks", "import_text", "import_light", "export_acis", "merge_lines",
"do_bounding_boxes", "acis_files", "errors", "block_representation", "recenter", "did_group_instance", "do_bounding_boxes", "acis_files", "errors", "block_representation", "recenter", "did_group_instance",
"objects_before", "pDXF", "pScene", "thickness_and_width", "but_group_by_att", "current_scene", "objects_before", "pDXF", "pScene", "thickness_and_width", "but_group_by_att", "current_scene", "current_collection",
"dxf_unit_scale" "dxf_unit_scale"
) )
@ -104,6 +104,7 @@ class Do:
self.thickness_and_width = thicknessWidth self.thickness_and_width = thicknessWidth
self.but_group_by_att = but_group_by_att self.but_group_by_att = but_group_by_att
self.current_scene = None self.current_scene = None
self.current_collection = None
self.dxf_unit_scale = dxf_unit_scale self.dxf_unit_scale = dxf_unit_scale
def proj(self, co, elevation=0): def proj(self, co, elevation=0):
@ -707,7 +708,7 @@ class Do:
o = bpy.data.objects.new("Point", None) o = bpy.data.objects.new("Point", None)
o.location = self.proj(en.point) o.location = self.proj(en.point)
self._extrusion(o, en) self._extrusion(o, en)
scene.collection.objects.link(o) self.current_collection.objects.link(o)
group = self._get_group(en.layer) group = self._get_group(en.layer)
group.objects.link(o) group.objects.link(o)
@ -735,7 +736,7 @@ class Do:
o.location = self.proj(en.position) o.location = self.proj(en.position)
dir = self.proj(en.target) - self.proj(en.position) dir = self.proj(en.target) - self.proj(en.position)
o.rotation_quaternion = dir.rotation_difference(Vector((0, 0, -1))) o.rotation_quaternion = dir.rotation_difference(Vector((0, 0, -1)))
scene.collection.objects.link(o) self.current_collection.objects.link(o)
return o return o
def mtext(self, en, scene, name): def mtext(self, en, scene, name):
@ -818,7 +819,7 @@ class Do:
if inserts is not None: if inserts is not None:
inserts.append(new_insert) inserts.append(new_insert)
new_insert.parent = parent new_insert.parent = parent
scene.collection.objects.link(new_insert) self.current_collection.objects.link(new_insert)
if name is None: if name is None:
name = entity.name name = entity.name
@ -850,7 +851,7 @@ class Do:
if len(insert.children) > 0: if len(insert.children) > 0:
i_copy = bpy.data.objects.new(insert.name, None) i_copy = bpy.data.objects.new(insert.name, None)
i_copy.matrix_basis = insert.matrix_basis i_copy.matrix_basis = insert.matrix_basis
scene.collection.objects.link(i_copy) self.current_collection.objects.link(i_copy)
group.objects.link(i_copy) group.objects.link(i_copy)
kids = insert.children[:] kids = insert.children[:]
for child in kids: for child in kids:
@ -864,10 +865,10 @@ class Do:
if len(objects) > 1 or len(insert_bounding_boxes) > 0: if len(objects) > 1 or len(insert_bounding_boxes) > 0:
if self.do_bounding_boxes: if self.do_bounding_boxes:
o = self._object_bbox(objects + insert_bounding_boxes, name, recursion_level == 0) o = self._object_bbox(objects + insert_bounding_boxes, name, recursion_level == 0)
scene.collection.objects.link(o) self.current_collection.objects.link(o)
else: else:
o = bpy.data.objects.new(name, None) o = bpy.data.objects.new(name, None)
scene.collection.objects.link(o) self.current_collection.objects.link(o)
if len(objects) > 0: if len(objects) > 0:
for obj in objects: for obj in objects:
obj.parent = o obj.parent = o
@ -877,13 +878,13 @@ class Do:
else: else:
# strange case but possible according to the testfiles # strange case but possible according to the testfiles
o = bpy.data.objects.new(name, None) o = bpy.data.objects.new(name, None)
scene.collection.objects.link(o) self.current_collection.objects.link(o)
# unlink bounding boxes of inserts # unlink bounding boxes of inserts
for ib in insert_bounding_boxes: for ib in insert_bounding_boxes:
if ib.name in group.objects: if ib.name in group.objects:
group.objects.unlink(ib) group.objects.unlink(ib)
scene.collection.objects.unlink(ib) self.current_collection.objects.unlink(ib)
# parent inserts to this block before any transformation on the block is being applied # parent inserts to this block before any transformation on the block is being applied
for obj in inserts: for obj in inserts:
@ -902,11 +903,11 @@ class Do:
for known_object in known_objects: for known_object in known_objects:
oc = known_object.copy() oc = known_object.copy()
scene.collection.objects.link(oc) self.current_collection.objects.link(oc)
objects.append(oc) objects.append(oc)
o = known_o.copy() o = known_o.copy()
scene.collection.objects.link(o) self.current_collection.objects.link(o)
_recursive_copy_inserts(o, known_inserts, inserts, group, invisible) _recursive_copy_inserts(o, known_inserts, inserts, group, invisible)
@ -996,7 +997,7 @@ class Do:
if invisible is not None: if invisible is not None:
o.hide_viewport = invisible o.hide_viewport = invisible
o.location = self.proj(entity.basepoint) o.location = self.proj(entity.basepoint)
scene.collection.objects.link(o) self.current_collection.objects.link(o)
# block_scene.view_layers[0].update() # block_scene.view_layers[0].update()
return o return o
@ -1074,7 +1075,7 @@ class Do:
# Blender custom property # Blender custom property
o[a.tag] = a.text o[a.tag] = a.text
attname = entity.name + "_" + a.tag attname = entity.name + "_" + a.tag
scene.collection.objects.link(self.text(a, scene, attname)) self.current_collection.objects.link(self.text(a, scene, attname))
return o return o
@ -1157,7 +1158,7 @@ class Do:
bevel = bpy.data.objects.new("BEVEL", bevd) bevel = bpy.data.objects.new("BEVEL", bevd)
obj.data.bevel_object = bevel obj.data.bevel_object = bevel
scene.collection.objects.link(bevel) self.current_collection.objects.link(bevel)
# CURVE TAPER # CURVE TAPER
if has_varying_width and len(ew) == 1: if has_varying_width and len(ew) == 1:
@ -1179,7 +1180,7 @@ class Do:
taper = bpy.data.objects.new("TAPER", tapd) taper = bpy.data.objects.new("TAPER", tapd)
obj.data.taper_object = taper obj.data.taper_object = taper
scene.collection.objects.link(taper) self.current_collection.objects.link(taper)
# THICKNESS FOR CURVES HAVING A WIDTH # THICKNESS FOR CURVES HAVING A WIDTH
if th != 0: if th != 0:
@ -1217,7 +1218,7 @@ class Do:
bm.to_mesh(d) bm.to_mesh(d)
o = bpy.data.objects.new(name, d) o = bpy.data.objects.new(name, d)
scene.collection.objects.link(o) self.current_collection.objects.link(o)
return o return o
def object_mesh(self, entities, scene, name): def object_mesh(self, entities, scene, name):
@ -1374,7 +1375,7 @@ class Do:
if type(o) == bpy.types.Object: if type(o) == bpy.types.Object:
if o.name not in scene.objects: if o.name not in scene.objects:
scene.collection.objects.link(o) self.current_collection.objects.link(o)
if o.name not in group.objects: if o.name not in group.objects:
group.objects.link(o) group.objects.link(o)
@ -1447,7 +1448,7 @@ class Do:
bm.to_mesh(m) bm.to_mesh(m)
o = bpy.data.objects.new(blockname, m) o = bpy.data.objects.new(blockname, m)
o.location = location o.location = location
scene.collection.objects.link(o) self.current_collection.objects.link(o)
self._nest_block(o, blockname, blgroup, scene) self._nest_block(o, blockname, blgroup, scene)
o.instance_type = "FACES" o.instance_type = "FACES"
@ -1457,7 +1458,7 @@ class Do:
def _nest_block(self, parent, name, blgroup, scene): def _nest_block(self, parent, name, blgroup, scene):
b = self.dwg.blocks[name] b = self.dwg.blocks[name]
e = bpy.data.objects.new(name, None) e = bpy.data.objects.new(name, None)
scene.collection.objects.link(e) self.current_collection.objects.link(e)
#e.location = parent.location #e.location = parent.location
e.parent = parent e.parent = parent
for TYPE, grouped in groupsort.by_dxftype(b): for TYPE, grouped in groupsort.by_dxftype(b):
@ -1593,14 +1594,18 @@ class Do:
return objects return objects
def entities(self, name, scene=None): def entities(self, name, scene=None, collection=None):
""" """
Iterates over all DXF entities according to the options set by user. Iterates over all DXF entities according to the options set by user.
""" """
if scene is None: if scene is None:
scene = bpy.context.scene scene = bpy.context.scene
if collection is None:
collection = scene.collection
self.current_scene = scene self.current_scene = scene
self.current_collection = collection
if self.recenter: if self.recenter:
self.objects_before += scene.objects[:] self.objects_before += scene.objects[:]