diff options
25 files changed, 2324 insertions, 2415 deletions
diff --git a/archipack/__init__.py b/archipack/__init__.py index 8b87585b..74f4f761 100644 --- a/archipack/__init__.py +++ b/archipack/__init__.py @@ -31,8 +31,8 @@ bl_info = { 'author': 's-leger', 'license': 'GPL', 'deps': '', - 'version': (1, 2, 8), - 'blender': (2, 7, 8), + 'version': (1, 2, 81), + 'blender': (2, 80, 0), 'location': 'View3D > Tools > Create > Archipack', 'warning': '', 'wiki_url': 'https://github.com/s-leger/archipack/wiki', @@ -46,7 +46,6 @@ import os if "bpy" in locals(): import importlib as imp - imp.reload(archipack_progressbar) imp.reload(archipack_material) imp.reload(archipack_snap) imp.reload(archipack_manipulator) @@ -65,7 +64,6 @@ if "bpy" in locals(): # print("archipack: reload ready") else: - from . import archipack_progressbar from . import archipack_material from . import archipack_snap from . import archipack_manipulator @@ -81,8 +79,7 @@ else: from . import archipack_truss from . import archipack_floor from . import archipack_rendering - - # print("archipack: ready") + print("archipack: ready") # noinspection PyUnresolvedReferences import bpy @@ -105,82 +102,110 @@ icons_collection = {} # Addon preferences # ---------------------------------------------------- -def update_panel(self, context): - try: - bpy.utils.unregister_class(TOOLS_PT_Archipack_Tools) - bpy.utils.unregister_class(TOOLS_PT_Archipack_Create) - except: - pass - prefs = context.user_preferences.addons[__name__].preferences - TOOLS_PT_Archipack_Tools.bl_category = prefs.tools_category - bpy.utils.register_class(TOOLS_PT_Archipack_Tools) - TOOLS_PT_Archipack_Create.bl_category = prefs.create_category - bpy.utils.register_class(TOOLS_PT_Archipack_Create) - class Archipack_Pref(AddonPreferences): bl_idname = __name__ - tools_category = StringProperty( - name="Tools", - description="Choose a name for the category of the Tools panel", - default="Tools", - update=update_panel - ) - create_category = StringProperty( - name="Create", - description="Choose a name for the category of the Create panel", - default="Create", - update=update_panel - ) - create_submenu = BoolProperty( + create_submenu : BoolProperty( name="Use Sub-menu", description="Put Achipack's object into a sub menu (shift+a)", default=True ) - max_style_draw_tool = BoolProperty( + max_style_draw_tool : BoolProperty( name="Draw a wall use 3dsmax style", description="Reverse clic / release & drag cycle for Draw a wall", default=True ) # Arrow sizes (world units) - arrow_size = FloatProperty( + arrow_size : FloatProperty( name="Arrow", description="Manipulators arrow size (blender units)", default=0.05 ) # Handle area size (pixels) - handle_size = IntProperty( + handle_size : IntProperty( name="Handle", description="Manipulators handle sensitive area size (pixels)", min=2, default=10 ) - matlib_path = StringProperty( + constant_handle_size: BoolProperty( + name="Constant handle size", + description="When checked, handle size on scree remains constant (handle size pixels)", + default=False + ) + text_size: IntProperty( + name="Manipulators", + description="Manipulator font size (pixels)", + min=2, + default=14 + ) + handle_colour_selected: FloatVectorProperty( + name="Selected handle colour", + description="Handle color when selected", + subtype='COLOR_GAMMA', + default=(0.0, 0.0, 0.7, 1.0), + size=4, + min=0, max=1 + ) + handle_colour_inactive: FloatVectorProperty( + name="Inactive handle colour", + description="Handle color when disabled", + subtype='COLOR_GAMMA', + default=(0.3, 0.3, 0.3, 1.0), + size=4, + min=0, max=1 + ) + handle_colour_normal: FloatVectorProperty( + name="Handle colour normal", + description="Base handle color when not selected", + subtype='COLOR_GAMMA', + default=(1.0, 1.0, 1.0, 1.0), + size=4, + min=0, max=1 + ) + handle_colour_hover: FloatVectorProperty( + name="Handle colour hover", + description="Handle color when mouse hover", + subtype='COLOR_GAMMA', + default=(1.0, 1.0, 0.0, 1.0), + size=4, + min=0, max=1 + ) + handle_colour_active: FloatVectorProperty( + name="Handle colour active", + description="Handle colour when moving", + subtype='COLOR_GAMMA', + default=(1.0, 0.0, 0.0, 1.0), + size=4, + min=0, max=1 + ) + matlib_path : StringProperty( name="Folder path", description="absolute path to material library folder", - default="" + default="", + subtype="DIR_PATH" ) # Font sizes and basic colour scheme - feedback_size_main = IntProperty( + feedback_size_main : IntProperty( name="Main", description="Main title font size (pixels)", min=2, default=16 ) - feedback_size_title = IntProperty( + feedback_size_title : IntProperty( name="Title", description="Tool name font size (pixels)", min=2, default=14 ) - feedback_size_shortcut = IntProperty( + feedback_size_shortcut : IntProperty( name="Shortcut", description="Shortcuts font size (pixels)", min=2, default=11 ) - feedback_shortcut_area = FloatVectorProperty( + feedback_shortcut_area : FloatVectorProperty( name="Background Shortcut", description="Shortcut area background color", subtype='COLOR_GAMMA', @@ -188,7 +213,7 @@ class Archipack_Pref(AddonPreferences): size=4, min=0, max=1 ) - feedback_title_area = FloatVectorProperty( + feedback_title_area : FloatVectorProperty( name="Background Main", description="Title area background color", subtype='COLOR_GAMMA', @@ -196,7 +221,7 @@ class Archipack_Pref(AddonPreferences): size=4, min=0, max=1 ) - feedback_colour_main = FloatVectorProperty( + feedback_colour_main : FloatVectorProperty( name="Font Main", description="Title color", subtype='COLOR_GAMMA', @@ -204,7 +229,7 @@ class Archipack_Pref(AddonPreferences): size=4, min=0, max=1 ) - feedback_colour_key = FloatVectorProperty( + feedback_colour_key : FloatVectorProperty( name="Font Shortcut key", description="KEY label color", subtype='COLOR_GAMMA', @@ -212,7 +237,7 @@ class Archipack_Pref(AddonPreferences): size=4, min=0, max=1 ) - feedback_colour_shortcut = FloatVectorProperty( + feedback_colour_shortcut : FloatVectorProperty( name="Font Shortcut hint", description="Shortcuts text color", subtype='COLOR_GAMMA', @@ -226,21 +251,22 @@ class Archipack_Pref(AddonPreferences): box = layout.box() row = box.row() col = row.column() - col.label(text="Tab Category:") - col.prop(self, "tools_category") - col.prop(self, "create_category") - col.prop(self, "create_submenu") - box = layout.box() - box.label("Features") - box.prop(self, "max_style_draw_tool") + col.label(text="Setup actions") + col.prop(self, "matlib_path", text="Material library") + box.label(text="Render presets Thumbnails") + box.operator("archipack.render_thumbs", icon='ERROR') box = layout.box() row = box.row() col = row.column() - col.label(text="Material library:") - col.prop(self, "matlib_path") + col.label(text="Add menu:") + col.prop(self, "create_submenu") + + box = layout.box() + box.label(text="Features") + box.prop(self, "max_style_draw_tool") box = layout.box() row = box.row() - split = row.split(percentage=0.5) + split = row.split(factor=0.5) col = split.column() col.label(text="Colors:") row = col.row(align=True) @@ -253,6 +279,16 @@ class Archipack_Pref(AddonPreferences): row.prop(self, "feedback_colour_key") row = col.row(align=True) row.prop(self, "feedback_colour_shortcut") + row = col.row(align=True) + row.prop(self, "handle_colour_normal") + row = col.row(align=True) + row.prop(self, "handle_colour_hover") + row = col.row(align=True) + row.prop(self, "handle_colour_active") + row = col.row(align=True) + row.prop(self, "handle_colour_selected") + row = col.row(align=True) + row.prop(self, "handle_colour_inactive") col = split.column() col.label(text="Font size:") col.prop(self, "feedback_size_main") @@ -261,7 +297,8 @@ class Archipack_Pref(AddonPreferences): col.label(text="Manipulators:") col.prop(self, "arrow_size") col.prop(self, "handle_size") - # layout.operator("archipack.render_thumbs") + col.prop(self, "text_size") + col.prop(self, "constant_handle_size") # ---------------------------------------------------- # Archipack panels @@ -273,7 +310,7 @@ class TOOLS_PT_Archipack_Tools(Panel): bl_idname = "TOOLS_PT_Archipack_Tools" bl_space_type = "VIEW_3D" bl_region_type = "TOOLS" - bl_category = "Tools" + # bl_category = "Tools" bl_context = "objectmode" @classmethod @@ -284,23 +321,16 @@ class TOOLS_PT_Archipack_Tools(Panel): wm = context.window_manager layout = self.layout box = layout.box() - box.label("Auto boolean") + box.label(text="Auto boolean") box.operator("archipack.auto_boolean", text="AutoBoolean", icon='AUTO').mode = 'HYBRID' - box = layout.box() - box.label("Rendering") - box.prop(wm.archipack, 'render_type', text="") - box.operator("archipack.render", icon='RENDER_STILL') - box = layout.box() - box.label("Render presets Thumbnails") - box.operator("archipack.render_thumbs", icon='ERROR') class TOOLS_PT_Archipack_Create(Panel): - bl_label = "Add Archipack" + bl_label = "Archipack" bl_idname = "TOOLS_PT_Archipack_Create" bl_space_type = "VIEW_3D" bl_region_type = "TOOLS" - bl_category = "Create" + # bl_category = "Create" bl_context = "objectmode" @classmethod @@ -314,7 +344,7 @@ class TOOLS_PT_Archipack_Create(Panel): layout = self.layout row = layout.row(align=True) box = row.box() - box.label("Objects") + box.label(text="Objects") row = box.row(align=True) row.operator("archipack.window_preset_menu", text="Window", @@ -454,25 +484,6 @@ def menu_func(self, context): draw_menu(self, context) -# ---------------------------------------------------- -# Datablock to store global addon variables -# ---------------------------------------------------- - - -class archipack_data(PropertyGroup): - render_type = EnumProperty( - items=( - ('1', "Draw over", "Draw over last rendered image"), - ('2', "OpenGL", ""), - ('3', "Animation OpenGL", ""), - ('4', "Image", "Render image and draw over"), - ('5', "Animation", "Draw on each frame") - ), - name="Render type", - description="Render method" - ) - - def register(): global icons_collection icons = previews.new() @@ -481,8 +492,6 @@ def register(): name, ext = os.path.splitext(icon) icons.load(name, os.path.join(icons_dir, icon), 'IMAGE') icons_collection["main"] = icons - - archipack_progressbar.register() archipack_material.register() archipack_snap.register() archipack_manipulator.register() @@ -498,11 +507,9 @@ def register(): archipack_truss.register() archipack_floor.register() archipack_rendering.register() - - bpy.utils.register_class(archipack_data) - WindowManager.archipack = PointerProperty(type=archipack_data) bpy.utils.register_class(Archipack_Pref) - update_panel(None, bpy.context) + bpy.utils.register_class(TOOLS_PT_Archipack_Tools) + bpy.utils.register_class(TOOLS_PT_Archipack_Create) bpy.utils.register_class(ARCHIPACK_MT_create) bpy.types.VIEW3D_MT_mesh_add.append(menu_func) @@ -515,7 +522,6 @@ def unregister(): bpy.utils.unregister_class(TOOLS_PT_Archipack_Tools) bpy.utils.unregister_class(TOOLS_PT_Archipack_Create) bpy.utils.unregister_class(Archipack_Pref) - archipack_progressbar.unregister() archipack_material.unregister() archipack_snap.unregister() archipack_manipulator.unregister() @@ -532,9 +538,6 @@ def unregister(): archipack_floor.unregister() archipack_rendering.unregister() - bpy.utils.unregister_class(archipack_data) - del WindowManager.archipack - for icons in icons_collection.values(): previews.remove(icons) icons_collection.clear() diff --git a/archipack/archipack_2d.py b/archipack/archipack_2d.py index 0078ae3c..e286e730 100644 --- a/archipack/archipack_2d.py +++ b/archipack/archipack_2d.py @@ -253,10 +253,10 @@ class Line(Projection): t: param t of intersection on current line """ c = line.cross_z - d = self.v * c + d = self.v.dot(c) if d == 0: return False, 0, 0 - t = (c * (line.p - self.p)) / d + t = c.dot(line.p - self.p) / d return True, self.lerp(t), t def intersect_ext(self, line): @@ -264,13 +264,13 @@ class Line(Projection): same as intersect, but return param t on both lines """ c = line.cross_z - d = self.v * c + d = self.v.dot(c) if d == 0: return False, 0, 0, 0 dp = line.p - self.p c2 = self.cross_z - u = (c * dp) / d - v = (c2 * dp) / d + u = c.dot(dp) / d + v = c2.dot(dp) / d return u > 0 and v > 0 and u < 1 and v < 1, self.lerp(u), u, v def point_sur_segment(self, pt): @@ -284,7 +284,7 @@ class Line(Projection): if dl == 0: return dp.length < 0.00001, 0, 0 d = (self.v.x * dp.y - self.v.y * dp.x) / dl - t = (self.v * dp) / (dl * dl) + t = self.v.dot(dp) / (dl * dl) return t > 0 and t < 1, d, t def steps(self, len): @@ -328,7 +328,7 @@ class Line(Projection): self.v = Matrix([ [ca, -sa], [sa, ca] - ]) * self.v + ]) @ self.v return self def scale(self, length): @@ -354,8 +354,8 @@ class Line(Projection): x, y, z = p spline.points[i].co = (x, y, 0, 1) curve_obj = bpy.data.objects.new('LINE', curve) - context.scene.objects.link(curve_obj) - curve_obj.select = True + context.scene.collection.objects.link(curve_obj) + curve_obj.select_set(state=True) def make_offset(self, offset, last=None): """ @@ -399,13 +399,13 @@ class Line(Projection): # intersect line / line # 1 line -> 2 line c = line.cross_z - d = last.v * c + d = last.v.dot(c) if d == 0: return line v = line.p - last.p - t = (c * v) / d + t = c.dot(v) / d c2 = last.cross_z - u = (c2 * v) / d + u = c2.dot(v) / d # intersect past this segment end # or before last segment start # print("u:%s t:%s" % (u, t)) @@ -431,9 +431,9 @@ class Circle(Projection): def intersect(self, line): v = line.p - self.c - A = line.v * line.v - B = 2 * v * line.v - C = v * v - self.r2 + A = line.v.dot(line.v) + B = 2 * v.dot(line.v) + C = v.dot(v) - self.r2 d = B * B - 4 * A * C if A <= 0.0000001 or d < 0: # dosent intersect, find closest point of line @@ -549,7 +549,7 @@ class Arc(Circle): u = self.p0 - self.p1 v = p0 - self.p1 scale, rM = self.scale_rot_matrix(u, v) - self.c = self.p1 + rM * (self.c - self.p1) + self.c = self.p1 + rM @ (self.c - self.p1) self.r *= scale self.r2 = self.r * self.r dp = p0 - self.c @@ -566,7 +566,7 @@ class Arc(Circle): v = p1 - p0 scale, rM = self.scale_rot_matrix(u, v) - self.c = p0 + rM * (self.c - p0) + self.c = p0 + rM @ (self.c - p0) self.r *= scale self.r2 = self.r * self.r dp = p0 - self.c @@ -730,7 +730,7 @@ class Arc(Circle): [sa, ca] ]) p0 = self.p0 - self.c = p0 + rM * (self.c - p0) + self.c = p0 + rM @ (self.c - p0) dp = p0 - self.c self.a0 = atan2(dp.y, dp.x) return self @@ -842,8 +842,8 @@ class Arc(Circle): x, y = p spline.points[i].co = (x, y, 0, 1) curve_obj = bpy.data.objects.new('ARC', curve) - context.scene.objects.link(curve_obj) - curve_obj.select = True + context.scene.collection.objects.link(curve_obj) + curve_obj.select_set(state=True) class Line3d(Line): diff --git a/archipack/archipack_autoboolean.py b/archipack/archipack_autoboolean.py index 10b8c5ce..ad0e28d8 100644 --- a/archipack/archipack_autoboolean.py +++ b/archipack/archipack_autoboolean.py @@ -38,12 +38,11 @@ class ArchipackBoolManager(): - mixed: merge holes with boolean and use result on wall may be slow, but is robust """ - def __init__(self, mode, solver_mode='CARVE'): + def __init__(self, mode): """ mode in 'ROBUST', 'INTERACTIVE', 'HYBRID' """ self.mode = mode - self.solver_mode = solver_mode # internal variables self.itM = None self.min_x = 0 @@ -69,7 +68,7 @@ class ArchipackBoolManager(): self.min_z + 0.5 * (self.max_z - self.min_z))) def _contains(self, pt): - p = self.itM * pt + p = self.itM @ pt return (p.x >= self.min_x and p.x <= self.max_x and p.y >= self.min_y and p.y <= self.max_y and p.z >= self.min_z and p.z <= self.max_z) @@ -108,7 +107,7 @@ class ArchipackBoolManager(): hole.display_type = 'WIRE' hole.hide_render = True hole.hide_select = True - hole.select = True + hole.select_set(state=True) hole.cycles_visibility.camera = False hole.cycles_visibility.diffuse = False hole.cycles_visibility.glossy = False @@ -135,7 +134,7 @@ class ArchipackBoolManager(): if d is not None: if (self.itM is not None and ( self._contains(o.location) or - self._contains(o.matrix_world * Vector((0, 0, 0.5 * d.z)))) + self._contains(o.matrix_world @ Vector((0, 0, 0.5 * d.z)))) ): if self.mode != 'ROBUST': hole = d.interactive_hole(context, o) @@ -172,7 +171,7 @@ class ArchipackBoolManager(): sort hole from center to borders by distance from center may improve nested booleans """ - center = wall.matrix_world * self.center + center = wall.matrix_world @ self.center holes = [(o, (o.matrix_world.translation - center).length) for o in holes] self.quicksort(holes) return [o[0] for o in holes] @@ -181,17 +180,12 @@ class ArchipackBoolManager(): # print("difference %s" % (hole.name)) m = basis.modifiers.new('AutoBoolean', 'BOOLEAN') m.operation = 'DIFFERENCE' - if solver is None: - m.solver = self.solver_mode - else: - m.solver = solver m.object = hole def union(self, basis, hole): # print("union %s" % (hole.name)) m = basis.modifiers.new('AutoMerge', 'BOOLEAN') m.operation = 'UNION' - m.solver = self.solver_mode m.object = hole def remove_modif_and_object(self, context, o, to_delete): @@ -202,7 +196,7 @@ class ArchipackBoolManager(): m.object = None o.modifiers.remove(m) if h is not None: - context.scene.objects.unlink(h) + context.scene.collection.objects.unlink(h) bpy.data.objects.remove(h, do_unlink=True) # Mixed @@ -210,7 +204,7 @@ class ArchipackBoolManager(): # print("create_merge_basis") h = bpy.data.meshes.new("AutoBoolean") hole_obj = bpy.data.objects.new("AutoBoolean", h) - context.scene.objects.link(hole_obj) + context.scene.collection.objects.link(hole_obj) hole_obj['archipack_hybridhole'] = True if wall.parent is not None: hole_obj.parent = wall.parent @@ -254,7 +248,6 @@ class ArchipackBoolManager(): m = wall.modifiers.get("AutoMixedBoolean") if m is None: m = wall.modifiers.new('AutoMixedBoolean', 'BOOLEAN') - m.solver = self.solver_mode m.operation = 'DIFFERENCE' if m.object is None: @@ -306,7 +299,7 @@ class ArchipackBoolManager(): to_delete.append([m, h]) # remove modifier and holes not found in new list self.remove_modif_and_object(context, hole_obj, to_delete) - context.scene.objects.unlink(hole_obj) + # context.scene.collection.objects.unlink(hole_obj) bpy.data.objects.remove(hole_obj, do_unlink=True) to_delete = [] @@ -388,12 +381,12 @@ class ArchipackBoolManager(): # to support "revival" of applied modifiers m = wall.modifiers.get("Wall") if m is None: - wall.select = True - context.scene.objects.active = wall + wall.select_set(state=True) + context.view_layer.objects.active = wall wall.data.archipack_wall2[0].update(context) bpy.ops.object.select_all(action='DESELECT') - context.scene.objects.active = None + context.view_layer.objects.active = None childs = [] holes = [] # get wall bounds to find what's inside @@ -429,19 +422,19 @@ class ArchipackBoolManager(): # parenting childs to wall reference point if wall.parent is None: x, y, z = wall.bound_box[0] - context.scene.cursor_location = wall.matrix_world * Vector((x, y, z)) + context.scene.cursor_location = wall.matrix_world @ Vector((x, y, z)) # fix issue #9 - context.scene.objects.active = wall + context.view_layer.objects.active = wall bpy.ops.archipack.reference_point() else: - wall.parent.select = True - context.scene.objects.active = wall.parent + wall.parent.select_set(state=True) + context.view_layer.objects.active = wall.parent - wall.select = True + wall.select_set(state=True) for o in childs: if 'archipack_robusthole' in o: o.hide_select = False - o.select = True + o.select_set(state=True) bpy.ops.archipack.parent_to_reference() @@ -499,7 +492,6 @@ class ArchipackBoolManager(): if m is None: m = wall.modifiers.new('AutoMixedBoolean', 'BOOLEAN') m.operation = 'DIFFERENCE' - m.solver = self.solver_mode if m.object is None: hole_obj = self.create_merge_basis(context, wall) @@ -513,21 +505,21 @@ class ArchipackBoolManager(): # parenting childs to wall reference point if wall.parent is None: x, y, z = wall.bound_box[0] - context.scene.cursor_location = wall.matrix_world * Vector((x, y, z)) + context.scene.cursor_location = wall.matrix_world @ Vector((x, y, z)) # fix issue #9 - context.scene.objects.active = wall + context.view_layer.objects.active = wall bpy.ops.archipack.reference_point() else: - context.scene.objects.active = wall.parent + context.view_layer.objects.active = wall.parent if hole_obj is not None: - hole_obj.select = True + hole_obj.select_set(state=True) - wall.select = True - o.select = True + wall.select_set(state=True) + o.select_set(state=True) bpy.ops.archipack.parent_to_reference() - wall.select = True - context.scene.objects.active = wall + wall.select_set(state=True) + context.view_layer.objects.active = wall if "archipack_wall2" in wall.data: d = wall.data.archipack_wall2[0] g = d.get_generator() @@ -545,7 +537,7 @@ class ARCHIPACK_OT_single_boolean(Operator): bl_description = "Add single boolean for doors and windows" bl_category = 'Archipack' bl_options = {'REGISTER', 'UNDO'} - mode = EnumProperty( + mode : EnumProperty( name="Mode", items=( ('INTERACTIVE', 'INTERACTIVE', 'Interactive, fast but may fail', 0), @@ -554,7 +546,7 @@ class ARCHIPACK_OT_single_boolean(Operator): ), default='HYBRID' ) - solver_mode = EnumProperty( + solver_mode : EnumProperty( name="Solver", items=( ('CARVE', 'CARVE', 'Slow but robust (could be slow in hybrid mode with many holes)', 0), @@ -583,14 +575,14 @@ class ARCHIPACK_OT_single_boolean(Operator): def execute(self, context): if context.mode == "OBJECT": wall = context.active_object - manager = ArchipackBoolManager(mode=self.mode, solver_mode=self.solver_mode) + manager = ArchipackBoolManager(mode=self.mode) for o in context.selected_objects: if o != wall: manager.singleboolean(context, wall, o) + o.select_set(state=False) break - o.select = False - wall.select = True - context.scene.objects.active = wall + wall.select_set(state=True) + context.view_layer.objects.active = wall return {'FINISHED'} else: self.report({'WARNING'}, "Archipack: Option only valid in Object mode") @@ -603,7 +595,7 @@ class ARCHIPACK_OT_auto_boolean(Operator): bl_description = "Automatic boolean for doors and windows" bl_category = 'Archipack' bl_options = {'REGISTER', 'UNDO'} - mode = EnumProperty( + mode : EnumProperty( name="Mode", items=( ('INTERACTIVE', 'INTERACTIVE', 'Interactive, fast but may fail', 0), @@ -612,14 +604,6 @@ class ARCHIPACK_OT_auto_boolean(Operator): ), default='HYBRID' ) - solver_mode = EnumProperty( - name="Solver", - items=( - ('CARVE', 'CARVE', 'Slow but robust (could be slow in hybrid mode with many holes)', 0), - ('BMESH', 'BMESH', 'Fast but more prone to errors', 1) - ), - default='BMESH' - ) def draw(self, context): layout = self.layout @@ -629,22 +613,22 @@ class ARCHIPACK_OT_auto_boolean(Operator): def execute(self, context): if context.mode == "OBJECT": - manager = ArchipackBoolManager(mode=self.mode, solver_mode=self.solver_mode) - active = context.scene.objects.active + manager = ArchipackBoolManager(mode=self.mode) + active = context.view_layer.objects.active walls = [wall for wall in context.selected_objects if not manager.filter_wall(wall)] bpy.ops.object.select_all(action='DESELECT') for wall in walls: manager.autoboolean(context, wall) bpy.ops.object.select_all(action='DESELECT') - wall.select = True - context.scene.objects.active = wall + wall.select_set(state=True) + context.view_layer.objects.active = wall if wall.data is not None and 'archipack_wall2' in wall.data: bpy.ops.archipack.wall2_manipulate('EXEC_DEFAULT') # reselect walls bpy.ops.object.select_all(action='DESELECT') for wall in walls: - wall.select = True - context.scene.objects.active = active + wall.select_set(state=True) + context.view_layer.objects.active = active return {'FINISHED'} else: self.report({'WARNING'}, "Archipack: Option only valid in Object mode") @@ -668,13 +652,13 @@ class ARCHIPACK_OT_generate_hole(Operator): self.report({'WARNING'}, "Archipack: active object must be a door, a window or a roof") return {'CANCELLED'} bpy.ops.object.select_all(action='DESELECT') - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o hole = manager._generate_hole(context, o) manager.prepare_hole(hole) - hole.select = False - o.select = True - context.scene.objects.active = o + hole.select_set(state=False) + o.select_set(state=True) + context.view_layer.objects.active = o return {'FINISHED'} else: self.report({'WARNING'}, "Archipack: Option only valid in Object mode") diff --git a/archipack/archipack_cutter.py b/archipack/archipack_cutter.py index 2ce37d4c..d46dd58f 100644 --- a/archipack/archipack_cutter.py +++ b/archipack/archipack_cutter.py @@ -160,7 +160,7 @@ class CutterGenerator(): """ move shape fromTM into toTM coordsys """ - dp = (toTM.inverted() * fromTM.translation).to_2d() + dp = (toTM.inverted() @ fromTM.translation).to_2d() da = toTM.row[1].to_2d().angle_signed(fromTM.row[1].to_2d()) ca = cos(da) sa = sin(da) @@ -169,7 +169,7 @@ class CutterGenerator(): [sa, ca] ]) for s in self.segs: - tp = (rM * s.p0) - s.p0 + dp + tp = (rM @ s.p0) - s.p0 + dp s.rotate(da) s.translate(tp) @@ -519,7 +519,7 @@ class CutAbleGenerator(): f.calc_center_median().to_2d(), segs=segs)] if len(f_geom) > 0: - bmesh.ops.delete(bm, geom=f_geom, context=5) + bmesh.ops.delete(bm, geom=f_geom, context='FACES') def cut_boundary(self, bm, cutable, offset={'DEFAULT': 0}): o_keys = offset.keys() @@ -545,7 +545,7 @@ class CutAbleGenerator(): f_geom = [f for f in bm.faces if not cutable.inside(f.calc_center_median().to_2d())] if len(f_geom) > 0: - bmesh.ops.delete(bm, geom=f_geom, context=5) + bmesh.ops.delete(bm, geom=f_geom, context='FACES') def update_hole(self, context): @@ -562,14 +562,14 @@ class ArchipackCutterPart(): Childs MUST define -type EnumProperty """ - length = FloatProperty( + length : FloatProperty( name="Length", min=0.01, max=1000.0, default=2.0, update=update_hole ) - a0 = FloatProperty( + a0 : FloatProperty( name="Angle", min=-2 * pi, max=2 * pi, @@ -577,7 +577,7 @@ class ArchipackCutterPart(): subtype='ANGLE', unit='ROTATION', update=update_hole ) - offset = FloatProperty( + offset : FloatProperty( name="Offset", min=0, default=0, @@ -617,28 +617,28 @@ def update_manipulators(self, context): class ArchipackCutter(): - n_parts = IntProperty( + n_parts : IntProperty( name="Parts", min=1, default=1, update=update_manipulators ) - z = FloatProperty( + z : FloatProperty( name="dumb z", description="Dumb z for manipulator placeholder", default=0.01, options={'SKIP_SAVE'} ) - user_defined_path = StringProperty( + user_defined_path : StringProperty( name="User defined", update=update_path ) - user_defined_resolution = IntProperty( + user_defined_resolution : IntProperty( name="Resolution", min=1, max=128, default=12, update=update_path ) - operation = EnumProperty( + operation : EnumProperty( items=( ('DIFFERENCE', 'Difference', 'Cut inside part', 0), ('INTERSECTION', 'Intersection', 'Keep inside part', 1) @@ -646,16 +646,16 @@ class ArchipackCutter(): default='DIFFERENCE', update=update_operation ) - auto_update = BoolProperty( + auto_update : BoolProperty( options={'SKIP_SAVE'}, default=True, update=update_manipulators ) # UI layout related - parts_expand = BoolProperty( + parts_expand : BoolProperty( default=False ) - closed = BoolProperty( + closed : BoolProperty( description="keep closed to be wall snap manipulator compatible", options={'SKIP_SAVE'}, default=True @@ -731,18 +731,18 @@ class ArchipackCutter(): # since this can lower points count by a resolution factor # use normalized to handle non linear t if resolution == 0: - pts.append(wM * p0.co.to_3d()) + pts.append(wM @ p0.co.to_3d()) else: v = (p1.co - p0.co).normalized() d1 = (p0.handle_right - p0.co).normalized() d2 = (p1.co - p1.handle_left).normalized() if d1 == v and d2 == v: - pts.append(wM * p0.co.to_3d()) + pts.append(wM @ p0.co.to_3d()) else: - seg = interpolate_bezier(wM * p0.co, - wM * p0.handle_right, - wM * p1.handle_left, - wM * p1.co, + seg = interpolate_bezier(wM @ p0.co, + wM @ p0.handle_right, + wM @ p1.handle_left, + wM @ p1.co, resolution + 1) for i in range(resolution): pts.append(seg[i].to_3d()) @@ -768,7 +768,7 @@ class ArchipackCutter(): def from_spline(self, context, wM, resolution, spline): pts = [] if spline.type == 'POLY': - pts = [wM * p.co.to_3d() for p in spline.points] + pts = [wM @ p.co.to_3d() for p in spline.points] if spline.use_cyclic_u: pts.append(pts[0]) elif spline.type == 'BEZIER': @@ -783,21 +783,16 @@ class ArchipackCutter(): self.interpolate_bezier(pts, wM, p0, p1, resolution) pts.append(pts[0]) else: - pts.append(wM * points[-1].co) + pts.append(wM @ points[-1].co) if self.is_cw(pts) == (self.operation == 'INTERSECTION'): pts = list(reversed(pts)) - pt = wM.inverted() * pts[0] + pt = wM.inverted() @ pts[0] # pretranslate o = self.find_in_selection(context, self.auto_update) - o.matrix_world = wM * Matrix([ - [1, 0, 0, pt.x], - [0, 1, 0, pt.y], - [0, 0, 1, pt.z], - [0, 0, 0, 1] - ]) + o.matrix_world = wM @ Matrix.Translation(pt) self.auto_update = False self.from_points(pts) self.auto_update = True @@ -912,7 +907,7 @@ class ArchipackCutter(): def manipulable_setup(self, context): self.manipulable_disable(context) - o = context.active_object + o = context.object n_parts = self.n_parts + 1 diff --git a/archipack/archipack_door.py b/archipack/archipack_door.py index 3e85cf31..9c63082b 100644 --- a/archipack/archipack_door.py +++ b/archipack/archipack_door.py @@ -40,7 +40,7 @@ from .panel import Panel as DoorPanel from .archipack_handle import create_handle, door_handle_horizontal_01 from .archipack_manipulator import Manipulable from .archipack_preset import ArchipackPreset, PresetMenuOperator -from .archipack_object import ArchipackObject, ArchipackCreateTool, ArchpackDrawTool +from .archipack_object import ArchipackObject, ArchipackCreateTool, ArchipackDrawTool from .archipack_gl import FeedbackPanel from .archipack_keymaps import Keymaps @@ -60,83 +60,83 @@ def update_childs(self, context): class archipack_door_panel(ArchipackObject, PropertyGroup): - x = FloatProperty( + x : FloatProperty( name='Width', min=0.25, default=100.0, precision=2, unit='LENGTH', subtype='DISTANCE', description='Width' ) - y = FloatProperty( + y : FloatProperty( name='Depth', min=0.001, default=0.02, precision=2, unit='LENGTH', subtype='DISTANCE', description='depth' ) - z = FloatProperty( + z : FloatProperty( name='Height', min=0.1, default=2.0, precision=2, unit='LENGTH', subtype='DISTANCE', description='height' ) - direction = IntProperty( + direction : IntProperty( name="Direction", min=0, max=1, description="open direction" ) - model = IntProperty( + model : IntProperty( name="Model", min=0, max=3, default=0, description="Model" ) - chanfer = FloatProperty( + chanfer : FloatProperty( name='Bevel', min=0.001, default=0.005, precision=3, unit='LENGTH', subtype='DISTANCE', description='chanfer' ) - panel_spacing = FloatProperty( + panel_spacing : FloatProperty( name='Spacing', min=0.001, default=0.1, precision=2, unit='LENGTH', subtype='DISTANCE', description='distance between panels' ) - panel_bottom = FloatProperty( + panel_bottom : FloatProperty( name='Bottom', min=0.0, default=0.0, precision=2, unit='LENGTH', subtype='DISTANCE', description='distance from bottom' ) - panel_border = FloatProperty( + panel_border : FloatProperty( name='Border', min=0.001, default=0.2, precision=2, unit='LENGTH', subtype='DISTANCE', description='distance from border' ) - panels_x = IntProperty( + panels_x : IntProperty( name="# h", min=1, max=50, default=1, description="panels h" ) - panels_y = IntProperty( + panels_y : IntProperty( name="# v", min=1, max=50, default=1, description="panels v" ) - panels_distrib = EnumProperty( + panels_distrib : EnumProperty( name='distribution', items=( ('REGULAR', 'Regular', '', 0), @@ -144,7 +144,7 @@ class archipack_door_panel(ArchipackObject, PropertyGroup): ), default='REGULAR' ) - handle = EnumProperty( + handle : EnumProperty( name='Shape', items=( ('NONE', 'No handle', '', 0), @@ -559,7 +559,7 @@ class archipack_door_panel(ArchipackObject, PropertyGroup): def remove_handle(self, context, o): handle = self.find_handle(o) if handle is not None: - context.scene.objects.unlink(handle) + context.scene.collection.objects.unlink(handle) bpy.data.objects.remove(handle, do_unlink=True) def update(self, context): @@ -584,7 +584,7 @@ class ARCHIPACK_PT_door_panel(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'UI' # bl_context = 'object' - bl_category = 'ArchiPack' + bl_category = 'Archipack' @classmethod def poll(cls, context): @@ -606,82 +606,82 @@ class ARCHIPACK_OT_door_panel(Operator): bl_description = "Door model 1" bl_category = 'Archipack' bl_options = {'REGISTER', 'UNDO'} - x = FloatProperty( + x : FloatProperty( name='Width', min=0.1, default=0.80, precision=2, unit='LENGTH', subtype='DISTANCE', description='Width' ) - z = FloatProperty( + z : FloatProperty( name='Height', min=0.1, default=2.0, precision=2, unit='LENGTH', subtype='DISTANCE', description='height' ) - y = FloatProperty( + y : FloatProperty( name='Depth', min=0.001, default=0.02, precision=2, unit='LENGTH', subtype='DISTANCE', description='Depth' ) - direction = IntProperty( + direction : IntProperty( name="Direction", min=0, max=1, description="open direction" ) - model = IntProperty( + model : IntProperty( name="Model", min=0, max=3, description="panel type" ) - chanfer = FloatProperty( + chanfer : FloatProperty( name='Bevel', min=0.001, default=0.005, precision=3, unit='LENGTH', subtype='DISTANCE', description='chanfer' ) - panel_spacing = FloatProperty( + panel_spacing : FloatProperty( name='Spacing', min=0.001, default=0.1, precision=2, unit='LENGTH', subtype='DISTANCE', description='distance between panels' ) - panel_bottom = FloatProperty( + panel_bottom : FloatProperty( name='Bottom', min=0.0, default=0.0, precision=2, unit='LENGTH', subtype='DISTANCE', description='distance from bottom' ) - panel_border = FloatProperty( + panel_border : FloatProperty( name='Border', min=0.001, default=0.2, precision=2, unit='LENGTH', subtype='DISTANCE', description='distance from border' ) - panels_x = IntProperty( + panels_x : IntProperty( name="# h", min=1, max=50, default=1, description="panels h" ) - panels_y = IntProperty( + panels_y : IntProperty( name="# v", min=1, max=50, default=1, description="panels v" ) - panels_distrib = EnumProperty( + panels_distrib : EnumProperty( name='Distribution', items=( ('REGULAR', 'Regular', '', 0), @@ -689,7 +689,7 @@ class ARCHIPACK_OT_door_panel(Operator): ), default='REGULAR' ) - handle = EnumProperty( + handle : EnumProperty( name='Shape', items=( ('NONE', 'No handle', '', 0), @@ -697,14 +697,14 @@ class ARCHIPACK_OT_door_panel(Operator): ), default='BOTH' ) - material = StringProperty( + material : StringProperty( default="" ) def draw(self, context): layout = self.layout row = layout.row() - row.label("Use Properties panel (N) to define parms", icon='INFO') + row.label(text="Use Properties panel (N) to define parms", icon='INFO') def create(self, context): """ @@ -727,7 +727,7 @@ class ARCHIPACK_OT_door_panel(Operator): d.panels_x = self.panels_x d.panels_y = self.panels_y d.handle = self.handle - context.scene.objects.link(o) + context.scene.collection.objects.link(o) o.lock_location[0] = True o.lock_location[1] = True o.lock_location[2] = True @@ -736,8 +736,8 @@ class ARCHIPACK_OT_door_panel(Operator): o.lock_scale[0] = True o.lock_scale[1] = True o.lock_scale[2] = True - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o m = o.archipack_material.add() m.category = "door" m.material = self.material @@ -751,8 +751,8 @@ class ARCHIPACK_OT_door_panel(Operator): if context.mode == "OBJECT": bpy.ops.object.select_all(action="DESELECT") o = self.create(context) - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o return {'FINISHED'} else: self.report({'WARNING'}, "Archipack: Option only valid in Object mode") @@ -769,14 +769,14 @@ class ARCHIPACK_OT_select_parent(Operator): def draw(self, context): layout = self.layout row = layout.row() - row.label("Use Properties panel (N) to define parms", icon='INFO') + row.label(text="Use Properties panel (N) to define parms", icon='INFO') def execute(self, context): if context.mode == "OBJECT": if context.active_object is not None and context.active_object.parent is not None: bpy.ops.object.select_all(action="DESELECT") - context.active_object.parent.select = True - context.scene.objects.active = context.active_object.parent + context.active_object.parent.select_set(state=True) + context.view_layer.objects.active = context.active_object.parent return {'FINISHED'} else: self.report({'WARNING'}, "Archipack: Option only valid in Object mode") @@ -789,117 +789,117 @@ class archipack_door(ArchipackObject, Manipulable, PropertyGroup): parent parametric object create/remove/update her own childs """ - x = FloatProperty( + x : FloatProperty( name='Width', min=0.25, default=100.0, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='Width', update=update, ) - y = FloatProperty( + y : FloatProperty( name='Depth', min=0.1, default=0.20, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='Depth', update=update, ) - z = FloatProperty( + z : FloatProperty( name='Height', min=0.1, default=2.0, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='height', update=update, ) - frame_x = FloatProperty( + frame_x : FloatProperty( name='Width', min=0, default=0.1, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='frame width', update=update, ) - frame_y = FloatProperty( + frame_y : FloatProperty( name='Depth', default=0.03, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='frame depth', update=update, ) - direction = IntProperty( + direction : IntProperty( name="Direction", min=0, max=1, description="open direction", update=update, ) - door_y = FloatProperty( + door_y : FloatProperty( name='Depth', min=0.001, default=0.02, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='depth', update=update, ) - door_offset = FloatProperty( + door_offset : FloatProperty( name='Offset', min=0, default=0, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='offset', update=update, ) - model = IntProperty( + model : IntProperty( name="Model", min=0, max=3, default=0, description="Model", update=update, ) - n_panels = IntProperty( + n_panels : IntProperty( name="Panels", min=1, max=2, default=1, description="number of panels", update=update ) - chanfer = FloatProperty( + chanfer : FloatProperty( name='Bevel', min=0.001, default=0.005, precision=3, step=0.01, unit='LENGTH', subtype='DISTANCE', description='chanfer', update=update_childs, ) - panel_spacing = FloatProperty( + panel_spacing : FloatProperty( name='Spacing', min=0.001, default=0.1, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='distance between panels', update=update_childs, ) - panel_bottom = FloatProperty( + panel_bottom : FloatProperty( name='Bottom', min=0.0, default=0.0, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='distance from bottom', update=update_childs, ) - panel_border = FloatProperty( + panel_border : FloatProperty( name='Border', min=0.001, default=0.2, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='distance from border', update=update_childs, ) - panels_x = IntProperty( + panels_x : IntProperty( name="# h", min=1, max=50, default=1, description="panels h", update=update_childs, ) - panels_y = IntProperty( + panels_y : IntProperty( name="# v", min=1, max=50, default=1, description="panels v", update=update_childs, ) - panels_distrib = EnumProperty( + panels_distrib : EnumProperty( name='Distribution', items=( ('REGULAR', 'Regular', '', 0), @@ -907,7 +907,7 @@ class archipack_door(ArchipackObject, Manipulable, PropertyGroup): ), default='REGULAR', update=update_childs, ) - handle = EnumProperty( + handle : EnumProperty( name='Handle', items=( ('NONE', 'No handle', '', 0), @@ -915,19 +915,19 @@ class archipack_door(ArchipackObject, Manipulable, PropertyGroup): ), default='BOTH', update=update_childs, ) - hole_margin = FloatProperty( + hole_margin : FloatProperty( name='Hole margin', min=0.0, default=0.1, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='how much hole surround wall' ) - flip = BoolProperty( + flip : BoolProperty( default=False, update=update, description='flip outside and outside material of hole' ) - auto_update = BoolProperty( + auto_update : BoolProperty( options={'SKIP_SAVE'}, default=True, update=update @@ -1032,13 +1032,13 @@ class archipack_door(ArchipackObject, Manipulable, PropertyGroup): if archipack_door_panel.filter(child): self.remove_handle(context, child) to_remove -= 1 - context.scene.objects.unlink(child) + context.scene.collection.objects.unlink(child) bpy.data.objects.remove(child, do_unlink=True) def remove_handle(self, context, o): handle = self.find_handle(o) if handle is not None: - context.scene.objects.unlink(handle) + context.scene.collection.objects.unlink(handle) bpy.data.objects.remove(handle, do_unlink=True) def create_childs(self, context, o): @@ -1112,7 +1112,7 @@ class archipack_door(ArchipackObject, Manipulable, PropertyGroup): id = c_names.index(c.data.name) except: self.remove_handle(context, c) - context.scene.objects.unlink(c) + context.scene.collection.objects.unlink(c) bpy.data.objects.remove(c, do_unlink=True) # children ordering may not be the same, so get the right l_childs order @@ -1130,7 +1130,7 @@ class archipack_door(ArchipackObject, Manipulable, PropertyGroup): for i, child in enumerate(childs): if order[i] < 0: p = bpy.data.objects.new("DoorPanel", child.data) - context.scene.objects.link(p) + context.scene.collection.objects.link(p) p.lock_location[0] = True p.lock_location[1] = True p.lock_location[2] = True @@ -1158,7 +1158,7 @@ class archipack_door(ArchipackObject, Manipulable, PropertyGroup): # MaterialUtils.add_handle_materials(h) h.location = handle.location.copy() elif h is not None: - context.scene.objects.unlink(h) + context.scene.collection.objects.unlink(h) bpy.data.objects.remove(h, do_unlink=True) def _synch_hole(self, context, linked, hole): @@ -1166,7 +1166,7 @@ class archipack_door(ArchipackObject, Manipulable, PropertyGroup): if l_hole is None: l_hole = bpy.data.objects.new("hole", hole.data) l_hole['archipack_hole'] = True - context.scene.objects.link(l_hole) + context.scene.collection.objects.link(l_hole) l_hole.parent = linked l_hole.matrix_world = linked.matrix_world.copy() l_hole.location = hole.location.copy() @@ -1178,8 +1178,8 @@ class archipack_door(ArchipackObject, Manipulable, PropertyGroup): synch childs nodes of linked objects """ bpy.ops.object.select_all(action='DESELECT') - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o childs = self.get_childs_panels(context, o) hole = self.find_hole(o) bpy.ops.object.select_linked(type='OBDATA') @@ -1253,8 +1253,8 @@ class archipack_door(ArchipackObject, Manipulable, PropertyGroup): child.matrix_world = o.matrix_world.copy() else: child = childs[child_n - 1] - child.select = True - context.scene.objects.active = child + child.select_set(state=True) + context.view_layer.objects.active = child props = archipack_door_panel.datablock(child) if props is not None: props.x = x @@ -1314,7 +1314,7 @@ class archipack_door(ArchipackObject, Manipulable, PropertyGroup): if hole_obj is None: m = bpy.data.meshes.new("hole") hole_obj = bpy.data.objects.new("hole", m) - context.scene.objects.link(hole_obj) + context.scene.collection.objects.link(hole_obj) hole_obj['archipack_hole'] = True hole_obj.parent = o hole_obj.matrix_world = o.matrix_world.copy() @@ -1339,19 +1339,19 @@ class archipack_door(ArchipackObject, Manipulable, PropertyGroup): m = bpy.data.meshes.new("hole") o = bpy.data.objects.new("hole", m) o['archipack_robusthole'] = True - context.scene.objects.link(o) + context.scene.collection.objects.link(o) v = Vector((0, 0, 0)) offset = Vector((0, -0.001, 0)) size = Vector((self.x + 2 * self.frame_x, self.z + self.frame_x + 0.001, self.y)) verts = hole.vertices(16, offset, v, v, size, v, 0, 0, shape_z=None, path_type='RECTANGLE') - verts = [tM * Vector(v) for v in verts] + verts = [tM @ Vector(v) for v in verts] faces = hole.faces(16, path_type='RECTANGLE') matids = hole.mat(16, 0, 1, path_type='RECTANGLE') uvs = hole.uv(16, v, v, size, v, 0, 0, 0, 0, path_type='RECTANGLE') bmed.buildmesh(context, o, verts, faces, matids=matids, uvs=uvs) - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o return o @@ -1360,7 +1360,7 @@ class ARCHIPACK_PT_door(Panel): bl_label = "Door" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' - bl_category = 'ArchiPack' + bl_category = 'Archipack' @classmethod def poll(cls, context): @@ -1371,7 +1371,7 @@ class ARCHIPACK_PT_door(Panel): if not archipack_door.filter(o): return layout = self.layout - layout.operator('archipack.door_manipulate', icon='HAND') + layout.operator('archipack.door_manipulate', icon='VIEW_PAN') props = archipack_door.datablock(o) row = layout.row(align=True) row.operator('archipack.door', text="Refresh", icon='FILE_REFRESH').mode = 'REFRESH' @@ -1382,8 +1382,8 @@ class ARCHIPACK_PT_door(Panel): # box.label(text="Styles") row = box.row(align=True) row.operator("archipack.door_preset_menu", text=bpy.types.ARCHIPACK_OT_door_preset_menu.bl_label) - row.operator("archipack.door_preset", text="", icon='ZOOMIN') - row.operator("archipack.door_preset", text="", icon='ZOOMOUT').remove_active = True + row.operator("archipack.door_preset", text="", icon='ADD') + row.operator("archipack.door_preset", text="", icon='REMOVE').remove_active = True row = layout.row() box = row.box() box.label(text="Size") @@ -1434,82 +1434,82 @@ class ARCHIPACK_OT_door(ArchipackCreateTool, Operator): bl_description = "Door" bl_category = 'Archipack' bl_options = {'REGISTER', 'UNDO'} - x = FloatProperty( + x : FloatProperty( name='width', min=0.1, default=0.80, precision=2, unit='LENGTH', subtype='DISTANCE', description='Width' ) - y = FloatProperty( + y : FloatProperty( name='depth', min=0.1, default=0.20, precision=2, unit='LENGTH', subtype='DISTANCE', description='Depth' ) - z = FloatProperty( + z : FloatProperty( name='height', min=0.1, default=2.0, precision=2, unit='LENGTH', subtype='DISTANCE', description='height' ) - direction = IntProperty( + direction : IntProperty( name="direction", min=0, max=1, description="open direction" ) - n_panels = IntProperty( + n_panels : IntProperty( name="panels", min=1, max=2, default=1, description="number of panels" ) - chanfer = FloatProperty( + chanfer : FloatProperty( name='chanfer', min=0.001, default=0.005, precision=3, unit='LENGTH', subtype='DISTANCE', description='chanfer' ) - panel_spacing = FloatProperty( + panel_spacing : FloatProperty( name='spacing', min=0.001, default=0.1, precision=2, unit='LENGTH', subtype='DISTANCE', description='distance between panels' ) - panel_bottom = FloatProperty( + panel_bottom : FloatProperty( name='bottom', default=0.0, precision=2, unit='LENGTH', subtype='DISTANCE', description='distance from bottom' ) - panel_border = FloatProperty( + panel_border : FloatProperty( name='border', min=0.001, default=0.2, precision=2, unit='LENGTH', subtype='DISTANCE', description='distance from border' ) - panels_x = IntProperty( + panels_x : IntProperty( name="panels h", min=1, max=50, default=1, description="panels h" ) - panels_y = IntProperty( + panels_y : IntProperty( name="panels v", min=1, max=50, default=1, description="panels v" ) - panels_distrib = EnumProperty( + panels_distrib : EnumProperty( name='distribution', items=( ('REGULAR', 'Regular', '', 0), @@ -1517,7 +1517,7 @@ class ARCHIPACK_OT_door(ArchipackCreateTool, Operator): ), default='REGULAR' ) - handle = EnumProperty( + handle : EnumProperty( name='Shape', items=( ('NONE', 'No handle', '', 0), @@ -1525,7 +1525,7 @@ class ARCHIPACK_OT_door(ArchipackCreateTool, Operator): ), default='BOTH' ) - mode = EnumProperty( + mode : EnumProperty( items=( ('CREATE', 'Create', '', 0), ('DELETE', 'Delete', '', 1), @@ -1556,13 +1556,13 @@ class ARCHIPACK_OT_door(ArchipackCreateTool, Operator): d.panels_x = self.panels_x d.panels_y = self.panels_y d.handle = self.handle - context.scene.objects.link(o) - o.select = True - context.scene.objects.active = o + context.scene.collection.objects.link(o) + o.select_set(state=True) + context.view_layer.objects.active = o self.add_material(o) self.load_preset(d) - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o return o def delete(self, context): @@ -1571,16 +1571,16 @@ class ARCHIPACK_OT_door(ArchipackCreateTool, Operator): bpy.ops.archipack.disable_manipulate() for child in o.children: if 'archipack_hole' in child: - context.scene.objects.unlink(child) + context.scene.collection.objects.unlink(child) bpy.data.objects.remove(child, do_unlink=True) elif child.data is not None and 'archipack_door_panel' in child.data: for handle in child.children: if 'archipack_handle' in handle: - context.scene.objects.unlink(handle) + context.scene.collection.objects.unlink(handle) bpy.data.objects.remove(handle, do_unlink=True) - context.scene.objects.unlink(child) + context.scene.collection.objects.unlink(child) bpy.data.objects.remove(child, do_unlink=True) - context.scene.objects.unlink(o) + context.scene.collection.objects.unlink(o) bpy.data.objects.remove(o, do_unlink=True) def update(self, context): @@ -1593,8 +1593,8 @@ class ARCHIPACK_OT_door(ArchipackCreateTool, Operator): if linked != o: archipack_door.datablock(linked).update(context) bpy.ops.object.select_all(action="DESELECT") - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o def unique(self, context): act = context.active_object @@ -1602,12 +1602,12 @@ class ARCHIPACK_OT_door(ArchipackCreateTool, Operator): bpy.ops.object.select_all(action="DESELECT") for o in sel: if archipack_door.filter(o): - o.select = True + o.select_set(state=True) for child in o.children: if 'archipack_hole' in child or (child.data is not None and 'archipack_door_panel' in child.data): child.hide_select = False - child.select = True + child.select_set(state=True) if len(context.selected_objects) > 0: bpy.ops.object.make_single_user(type='SELECTED_OBJECTS', object=True, obdata=True, material=False, texture=False, animation=False) @@ -1615,9 +1615,9 @@ class ARCHIPACK_OT_door(ArchipackCreateTool, Operator): if 'archipack_hole' in child: child.hide_select = True bpy.ops.object.select_all(action="DESELECT") - context.scene.objects.active = act + context.view_layer.objects.active = act for o in sel: - o.select = True + o.select_set(state=True) def execute(self, context): if context.mode == "OBJECT": @@ -1625,8 +1625,8 @@ class ARCHIPACK_OT_door(ArchipackCreateTool, Operator): bpy.ops.object.select_all(action="DESELECT") o = self.create(context) o.location = bpy.context.scene.cursor_location - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o self.manipulate() elif self.mode == 'DELETE': self.delete(context) @@ -1640,14 +1640,14 @@ class ARCHIPACK_OT_door(ArchipackCreateTool, Operator): return {'CANCELLED'} -class ARCHIPACK_OT_door_draw(ArchpackDrawTool, Operator): +class ARCHIPACK_OT_door_draw(ArchipackDrawTool, Operator): bl_idname = "archipack.door_draw" bl_label = "Draw Doors" bl_description = "Draw Doors over walls" bl_category = 'Archipack' bl_options = {'REGISTER', 'UNDO'} - filepath = StringProperty(default="") + filepath : StringProperty(default="") feedback = None stack = [] object_name = "" @@ -1659,7 +1659,7 @@ class ARCHIPACK_OT_door_draw(ArchpackDrawTool, Operator): def draw(self, context): layout = self.layout row = layout.row() - row.label("Use Properties panel (N) to define parms", icon='INFO') + row.label(text="Use Properties panel (N) to define parms", icon='INFO') def draw_callback(self, _self, context): self.feedback.draw(context) @@ -1670,32 +1670,32 @@ class ARCHIPACK_OT_door_draw(ArchpackDrawTool, Operator): if archipack_door.filter(o): - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o if event.shift: bpy.ops.archipack.door(mode="UNIQUE") new_w = o.copy() new_w.data = o.data - context.scene.objects.link(new_w) + context.scene.collection.objects.link(new_w) # instance subs for child in o.children: if "archipack_hole" not in child: new_c = child.copy() new_c.data = child.data new_c.parent = new_w - context.scene.objects.link(new_c) + context.scene.collection.objects.link(new_c) # dup handle if any for c in child.children: new_h = c.copy() new_h.data = c.data new_h.parent = new_c - context.scene.objects.link(new_h) + context.scene.collection.objects.link(new_h) o = new_w - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o else: bpy.ops.archipack.door(auto_manipulate=False, filepath=self.filepath) @@ -1704,8 +1704,8 @@ class ARCHIPACK_OT_door_draw(ArchpackDrawTool, Operator): self.object_name = o.name bpy.ops.archipack.generate_hole('INVOKE_DEFAULT') - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o def modal(self, context, event): @@ -1722,14 +1722,14 @@ class ARCHIPACK_OT_door_draw(ArchpackDrawTool, Operator): # hide hole from raycast if hole is not None: - o.hide = True - hole.hide = True + o.hide_viewport = True + hole.hide_viewport = True - res, tM, wall, y = self.mouse_hover_wall(context, event) + res, tM, wall, width, y, z_offset = self.mouse_hover_wall(context, event) if hole is not None: - o.hide = False - hole.hide = False + o.hide_viewport = False + hole.hide_viewport = False if res and d is not None: o.matrix_world = tM @@ -1749,14 +1749,14 @@ class ARCHIPACK_OT_door_draw(ArchpackDrawTool, Operator): if event.type in {'LEFTMOUSE', 'RET', 'NUMPAD_ENTER', 'SPACE'}: if wall is not None: - context.scene.objects.active = wall - wall.select = True + context.view_layer.objects.active = wall + wall.select_set(state=True) if bpy.ops.archipack.single_boolean.poll(): bpy.ops.archipack.single_boolean() - wall.select = False + wall.select_set(state=False) # o must be a door here if d is not None: - context.scene.objects.active = o + context.view_layer.objects.active = o self.stack.append(o) self.add_object(context, event) context.active_object.matrix_world = tM @@ -1771,9 +1771,9 @@ class ARCHIPACK_OT_door_draw(ArchpackDrawTool, Operator): ): if len(self.stack) > 0: last = self.stack.pop() - context.scene.objects.active = last + context.view_layer.objects.active = last bpy.ops.archipack.door(mode="DELETE") - context.scene.objects.active = o + context.view_layer.objects.active = o return {'RUNNING_MODAL'} if event.value == 'RELEASE': @@ -1797,11 +1797,11 @@ class ARCHIPACK_OT_door_draw(ArchpackDrawTool, Operator): # invoke with alt pressed will use current object as basis for linked copy if self.filepath == '' and archipack_door.filter(context.active_object): o = context.active_object - context.scene.objects.active = None + context.view_layer.objects.active = None bpy.ops.object.select_all(action="DESELECT") if o is not None: - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o self.add_object(context, event) self.feedback = FeedbackPanel() self.feedback.instructions(context, "Draw a door", "Click & Drag over a wall", [ diff --git a/archipack/archipack_fence.py b/archipack/archipack_fence.py index a94023fd..0196aac8 100644 --- a/archipack/archipack_fence.py +++ b/archipack/archipack_fence.py @@ -268,7 +268,7 @@ class FenceGenerator(): co.z *= self.user_defined_post_scale.z if 'Slope' in g: co.z += co.y * slope - verts.append(tM * co) + verts.append(tM @ co) matids += self.user_defined_mat faces += [tuple([i + f for i in p.vertices]) for p in m.polygons] uvs += self.user_defined_uvs @@ -341,7 +341,7 @@ class FenceGenerator(): if s < n_sections: v1 = subs[s + 1][0].v.normalized() dir = (v0 + v1).normalized() - scale = 1 / cos(0.5 * acos(min(1, max(-1, v0 * v1)))) + scale = 1 / cos(0.5 * acos(min(1, max(-1, v0.dot(v1))))) for p in profile: x, y = n.p + scale * p.x * dir z = zl + p.y + altitude @@ -556,7 +556,7 @@ class FenceGenerator(): if s < n_sections: v1 = sections[s + 1][0].v.normalized() dir = (v0 + v1).normalized() - scale = min(10, 1 / cos(0.5 * acos(min(1, max(-1, v0 * v1))))) + scale = min(10, 1 / cos(0.5 * acos(min(1, max(-1, v0.dot(v1) ))))) for p in profile: # x, y = n.p + scale * (x_offset + p.x) * dir x, y = n.p + scale * p.x * dir @@ -673,7 +673,7 @@ materials_enum = ( class archipack_fence_material(PropertyGroup): - index = EnumProperty( + index : EnumProperty( items=materials_enum, default='0', update=update @@ -684,7 +684,7 @@ class archipack_fence_material(PropertyGroup): find witch selected object this instance belongs to provide support for "copy to selected" """ - selected = [o for o in context.selected_objects] + selected = context.selected_objects[:] for o in selected: props = archipack_fence.datablock(o) if props: @@ -700,7 +700,7 @@ class archipack_fence_material(PropertyGroup): class archipack_fence_part(PropertyGroup): - type = EnumProperty( + type : EnumProperty( items=( ('S_FENCE', 'Straight fence', '', 0), ('C_FENCE', 'Curved fence', '', 1), @@ -708,21 +708,21 @@ class archipack_fence_part(PropertyGroup): default='S_FENCE', update=update_type ) - length = FloatProperty( + length : FloatProperty( name="Length", min=0.01, default=2.0, unit='LENGTH', subtype='DISTANCE', update=update ) - radius = FloatProperty( + radius : FloatProperty( name="Radius", min=0.01, default=0.7, unit='LENGTH', subtype='DISTANCE', update=update ) - da = FloatProperty( + da : FloatProperty( name="Angle", min=-pi, max=pi, @@ -730,7 +730,7 @@ class archipack_fence_part(PropertyGroup): subtype='ANGLE', unit='ROTATION', update=update ) - a0 = FloatProperty( + a0 : FloatProperty( name="Start angle", min=-2 * pi, max=2 * pi, @@ -738,13 +738,13 @@ class archipack_fence_part(PropertyGroup): subtype='ANGLE', unit='ROTATION', update=update ) - dz = FloatProperty( + dz : FloatProperty( name="delta z", default=0, unit='LENGTH', subtype='DISTANCE' ) - manipulators = CollectionProperty(type=archipack_manipulator) + manipulators : CollectionProperty(type=archipack_manipulator) def find_datablock_in_selection(self, context): """ @@ -783,43 +783,43 @@ class archipack_fence_part(PropertyGroup): class archipack_fence(ArchipackObject, Manipulable, PropertyGroup): - parts = CollectionProperty(type=archipack_fence_part) - user_defined_path = StringProperty( + parts : CollectionProperty(type=archipack_fence_part) + user_defined_path : StringProperty( name="User defined", update=update_path ) - user_defined_spline = IntProperty( + user_defined_spline : IntProperty( name="Spline index", min=0, default=0, update=update_path ) - user_defined_resolution = IntProperty( + user_defined_resolution : IntProperty( name="Resolution", min=1, max=128, default=12, update=update_path ) - n_parts = IntProperty( + n_parts : IntProperty( name="Parts", min=1, default=1, update=update_manipulators ) - x_offset = FloatProperty( + x_offset : FloatProperty( name="Offset", default=0.0, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - radius = FloatProperty( + radius : FloatProperty( name="Radius", min=0.01, default=0.7, unit='LENGTH', subtype='DISTANCE', update=update ) - da = FloatProperty( + da : FloatProperty( name="Angle", min=-pi, max=pi, @@ -827,7 +827,7 @@ class archipack_fence(ArchipackObject, Manipulable, PropertyGroup): subtype='ANGLE', unit='ROTATION', update=update ) - angle_limit = FloatProperty( + angle_limit : FloatProperty( name="Angle", min=0, max=2 * pi, @@ -835,7 +835,7 @@ class archipack_fence(ArchipackObject, Manipulable, PropertyGroup): subtype='ANGLE', unit='ROTATION', update=update_manipulators ) - shape = EnumProperty( + shape : EnumProperty( items=( ('RECTANGLE', 'Straight', '', 0), ('CIRCLE', 'Curved ', '', 1) @@ -843,106 +843,106 @@ class archipack_fence(ArchipackObject, Manipulable, PropertyGroup): default='RECTANGLE', update=update ) - post = BoolProperty( + post : BoolProperty( name='Enable', default=True, update=update ) - post_spacing = FloatProperty( + post_spacing : FloatProperty( name="Spacing", min=0.1, default=1.0, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - post_x = FloatProperty( + post_x : FloatProperty( name="Width", min=0.001, default=0.04, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - post_y = FloatProperty( + post_y : FloatProperty( name="Length", min=0.001, max=1000, default=0.04, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - post_z = FloatProperty( + post_z : FloatProperty( name="Height", min=0.001, default=1, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - post_alt = FloatProperty( + post_alt : FloatProperty( name="Altitude", default=0, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - user_defined_post_enable = BoolProperty( + user_defined_post_enable : BoolProperty( name="User", update=update, default=True ) - user_defined_post = StringProperty( + user_defined_post : StringProperty( name="User defined", update=update ) - idmat_post = EnumProperty( + idmat_post : EnumProperty( name="Post", items=materials_enum, default='1', update=update ) - subs = BoolProperty( + subs : BoolProperty( name='Enable', default=False, update=update ) - subs_spacing = FloatProperty( + subs_spacing : FloatProperty( name="Spacing", min=0.05, default=0.10, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - subs_x = FloatProperty( + subs_x : FloatProperty( name="Width", min=0.001, default=0.02, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - subs_y = FloatProperty( + subs_y : FloatProperty( name="Length", min=0.001, default=0.02, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - subs_z = FloatProperty( + subs_z : FloatProperty( name="Height", min=0.001, default=1, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - subs_alt = FloatProperty( + subs_alt : FloatProperty( name="Altitude", default=0, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - subs_offset_x = FloatProperty( + subs_offset_x : FloatProperty( name="Offset", default=0.0, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - subs_bottom = EnumProperty( + subs_bottom : EnumProperty( name="Bottom", items=( ('STEP', 'Follow step', '', 0), @@ -951,78 +951,78 @@ class archipack_fence(ArchipackObject, Manipulable, PropertyGroup): default='STEP', update=update ) - user_defined_subs_enable = BoolProperty( + user_defined_subs_enable : BoolProperty( name="User", update=update, default=True ) - user_defined_subs = StringProperty( + user_defined_subs : StringProperty( name="User defined", update=update ) - idmat_subs = EnumProperty( + idmat_subs : EnumProperty( name="Subs", items=materials_enum, default='1', update=update ) - panel = BoolProperty( + panel : BoolProperty( name='Enable', default=True, update=update ) - panel_alt = FloatProperty( + panel_alt : FloatProperty( name="Altitude", default=0.25, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - panel_x = FloatProperty( + panel_x : FloatProperty( name="Width", min=0.001, default=0.01, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - panel_z = FloatProperty( + panel_z : FloatProperty( name="Height", min=0.001, default=0.6, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - panel_dist = FloatProperty( + panel_dist : FloatProperty( name="Spacing", min=0.001, default=0.05, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - panel_offset_x = FloatProperty( + panel_offset_x : FloatProperty( name="Offset", default=0.0, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - idmat_panel = EnumProperty( + idmat_panel : EnumProperty( name="Panels", items=materials_enum, default='2', update=update ) - rail = BoolProperty( + rail : BoolProperty( name="Enable", update=update, default=False ) - rail_n = IntProperty( + rail_n : IntProperty( name="#", default=1, min=0, max=31, update=update ) - rail_x = FloatVectorProperty( + rail_x : FloatVectorProperty( name="Width", default=[ 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, @@ -1036,7 +1036,7 @@ class archipack_fence(ArchipackObject, Manipulable, PropertyGroup): unit='LENGTH', update=update ) - rail_z = FloatVectorProperty( + rail_z : FloatVectorProperty( name="Height", default=[ 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, @@ -1050,7 +1050,7 @@ class archipack_fence(ArchipackObject, Manipulable, PropertyGroup): unit='LENGTH', update=update ) - rail_offset = FloatVectorProperty( + rail_offset : FloatVectorProperty( name="Offset", default=[ 0, 0, 0, 0, 0, 0, 0, 0, @@ -1063,7 +1063,7 @@ class archipack_fence(ArchipackObject, Manipulable, PropertyGroup): unit='LENGTH', update=update ) - rail_alt = FloatVectorProperty( + rail_alt : FloatVectorProperty( name="Altitude", default=[ 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, @@ -1076,43 +1076,43 @@ class archipack_fence(ArchipackObject, Manipulable, PropertyGroup): unit='LENGTH', update=update ) - rail_mat = CollectionProperty(type=archipack_fence_material) + rail_mat : CollectionProperty(type=archipack_fence_material) - handrail = BoolProperty( + handrail : BoolProperty( name="Enable", update=update, default=True ) - handrail_offset = FloatProperty( + handrail_offset : FloatProperty( name="Offset", default=0.0, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - handrail_alt = FloatProperty( + handrail_alt : FloatProperty( name="Altitude", default=1.0, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - handrail_extend = FloatProperty( + handrail_extend : FloatProperty( name="Extend", min=0, default=0.1, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - handrail_slice = BoolProperty( + handrail_slice : BoolProperty( name='Slice', default=True, update=update ) - handrail_slice_right = BoolProperty( + handrail_slice_right : BoolProperty( name='Slice', default=True, update=update ) - handrail_profil = EnumProperty( + handrail_profil : EnumProperty( name="Profil", items=( ('SQUARE', 'Square', '', 0), @@ -1122,28 +1122,28 @@ class archipack_fence(ArchipackObject, Manipulable, PropertyGroup): default='SQUARE', update=update ) - handrail_x = FloatProperty( + handrail_x : FloatProperty( name="Width", min=0.001, default=0.04, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - handrail_y = FloatProperty( + handrail_y : FloatProperty( name="Height", min=0.001, default=0.04, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - handrail_radius = FloatProperty( + handrail_radius : FloatProperty( name="Radius", min=0.001, default=0.02, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - idmat_handrail = EnumProperty( + idmat_handrail : EnumProperty( name="Handrail", items=materials_enum, default='0', @@ -1151,25 +1151,25 @@ class archipack_fence(ArchipackObject, Manipulable, PropertyGroup): ) # UI layout related - parts_expand = BoolProperty( + parts_expand : BoolProperty( default=False ) - rail_expand = BoolProperty( + rail_expand : BoolProperty( default=False ) - idmats_expand = BoolProperty( + idmats_expand : BoolProperty( default=False ) - handrail_expand = BoolProperty( + handrail_expand : BoolProperty( default=False ) - post_expand = BoolProperty( + post_expand : BoolProperty( default=False ) - panel_expand = BoolProperty( + panel_expand : BoolProperty( default=False ) - subs_expand = BoolProperty( + subs_expand : BoolProperty( default=False ) @@ -1178,7 +1178,7 @@ class archipack_fence(ArchipackObject, Manipulable, PropertyGroup): # .auto_update = False # bulk changes # .auto_update = True - auto_update = BoolProperty( + auto_update : BoolProperty( options={'SKIP_SAVE'}, default=True, update=update_manipulators @@ -1226,26 +1226,27 @@ class archipack_fence(ArchipackObject, Manipulable, PropertyGroup): # add parts for i in range(len(self.parts), self.n_parts): self.parts.add() - + print("setup_manipulators") self.setup_manipulators() + print("update_parts.done") def interpolate_bezier(self, pts, wM, p0, p1, resolution): # straight segment, worth testing here # since this can lower points count by a resolution factor # use normalized to handle non linear t if resolution == 0: - pts.append(wM * p0.co.to_3d()) + pts.append(wM @ p0.co.to_3d()) else: v = (p1.co - p0.co).normalized() d1 = (p0.handle_right - p0.co).normalized() d2 = (p1.co - p1.handle_left).normalized() if d1 == v and d2 == v: - pts.append(wM * p0.co.to_3d()) + pts.append(wM @ p0.co.to_3d()) else: - seg = interpolate_bezier(wM * p0.co, - wM * p0.handle_right, - wM * p1.handle_left, - wM * p1.co, + seg = interpolate_bezier(wM @ p0.co, + wM @ p0.handle_right, + wM @ p1.handle_left, + wM @ p1.co, resolution + 1) for i in range(resolution): pts.append(seg[i].to_3d()) @@ -1264,7 +1265,7 @@ class archipack_fence(ArchipackObject, Manipulable, PropertyGroup): pts = [] if spline.type == 'POLY': pt = spline.points[0].co - pts = [wM * p.co.to_3d() for p in spline.points] + pts = [wM @ p.co.to_3d() for p in spline.points] if spline.use_cyclic_u: pts.append(pts[0]) elif spline.type == 'BEZIER': @@ -1280,7 +1281,7 @@ class archipack_fence(ArchipackObject, Manipulable, PropertyGroup): self.interpolate_bezier(pts, wM, p0, p1, resolution) pts.append(pts[0]) else: - pts.append(wM * points[-1].co) + pts.append(wM @ points[-1].co) auto_update = self.auto_update self.auto_update = False @@ -1305,12 +1306,7 @@ class archipack_fence(ArchipackObject, Manipulable, PropertyGroup): self.auto_update = auto_update - o.matrix_world = tM * Matrix([ - [1, 0, 0, pt.x], - [0, 1, 0, pt.y], - [0, 0, 1, pt.z], - [0, 0, 0, 1] - ]) + o.matrix_world = tM @ Matrix.Translation(pt) def update_path(self, context): path = context.scene.objects.get(self.user_defined_path) @@ -1335,7 +1331,7 @@ class archipack_fence(ArchipackObject, Manipulable, PropertyGroup): return g def update(self, context, manipulable_refresh=False): - + print("update") o = self.find_in_selection(context, self.auto_update) if o is None: @@ -1344,7 +1340,7 @@ class archipack_fence(ArchipackObject, Manipulable, PropertyGroup): # clean up manipulators before any data model change if manipulable_refresh: self.manipulable_disable(context) - + print("update_parts") self.update_parts() verts = [] @@ -1465,7 +1461,7 @@ class ARCHIPACK_PT_fence(Panel): bl_label = "Fence" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' - bl_category = 'ArchiPack' + bl_category = 'Archipack' @classmethod def poll(cls, context): @@ -1478,13 +1474,13 @@ class ARCHIPACK_PT_fence(Panel): scene = context.scene layout = self.layout row = layout.row(align=True) - row.operator('archipack.fence_manipulate', icon='HAND') + row.operator('archipack.fence_manipulate', icon='VIEW_PAN') box = layout.box() # box.label(text="Styles") row = box.row(align=True) row.operator("archipack.fence_preset_menu", text=bpy.types.ARCHIPACK_OT_fence_preset_menu.bl_label) - row.operator("archipack.fence_preset", text="", icon='ZOOMIN') - row.operator("archipack.fence_preset", text="", icon='ZOOMOUT').remove_active = True + row.operator("archipack.fence_preset", text="", icon='ADD') + row.operator("archipack.fence_preset", text="", icon='REMOVE').remove_active = True box = layout.box() row = box.row(align=True) row.operator("archipack.fence_curve_update", text="", icon='FILE_REFRESH') @@ -1619,25 +1615,35 @@ class ARCHIPACK_OT_fence(ArchipackCreateTool, Operator): bl_options = {'REGISTER', 'UNDO'} def create(self, context): + print("Create") m = bpy.data.meshes.new("Fence") o = bpy.data.objects.new("Fence", m) d = m.archipack_fence.add() # make manipulators selectable + print("manipulable_selectable") + d.manipulable_selectable = True - context.scene.objects.link(o) - o.select = True - context.scene.objects.active = o + context.scene.collection.objects.link(o) + o.select_set(state=True) + context.view_layer.objects.active = o + print("load_preset") self.load_preset(d) + print("add_material") + self.add_material(o) return o def execute(self, context): if context.mode == "OBJECT": + print("select_all") bpy.ops.object.select_all(action="DESELECT") o = self.create(context) - o.location = bpy.context.scene.cursor_location - o.select = True - context.scene.objects.active = o + print("select_all") + o.location = context.scene.cursor_location + o.select_set(state=True) + context.view_layer.objects.active = o + print("manipulate") + self.manipulate() return {'FINISHED'} else: @@ -1663,7 +1669,7 @@ class ARCHIPACK_OT_fence_curve_update(Operator): def draw(self, context): layout = self.layout row = layout.row() - row.label("Use Properties panel (N) to define parms", icon='INFO') + row.label(text="Use Properties panel (N) to define parms", icon='INFO') def execute(self, context): if context.mode == "OBJECT": @@ -1689,7 +1695,7 @@ class ARCHIPACK_OT_fence_from_curve(ArchipackCreateTool, Operator): def draw(self, context): layout = self.layout row = layout.row() - row.label("Use Properties panel (N) to define parms", icon='INFO') + row.label(text="Use Properties panel (N) to define parms", icon='INFO') def create(self, context): o = None @@ -1709,8 +1715,8 @@ class ARCHIPACK_OT_fence_from_curve(ArchipackCreateTool, Operator): bpy.ops.object.select_all(action="DESELECT") o = self.create(context) if o is not None: - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o # self.manipulate() return {'FINISHED'} else: diff --git a/archipack/archipack_floor.py b/archipack/archipack_floor.py index 25d4db2f..f53a78d7 100644 --- a/archipack/archipack_floor.py +++ b/archipack/archipack_floor.py @@ -225,7 +225,7 @@ class FloorGenerator(CutAblePolygon, CutAbleGenerator): # rotate seg seg.rotate(a) # rotate delta from rotation center to segment start - dp = rM * (seg.p0 - p0) + dp = rM @ (seg.p0 - p0) seg.translate(dp) def translate(self, idx_from, dp): @@ -305,7 +305,7 @@ class FloorGenerator(CutAblePolygon, CutAbleGenerator): use_dissolve_boundaries=False, verts=bm.verts, edges=bm.edges, - delimit=1) + delimit={'MATERIAL'}) bm.verts.ensure_lookup_table() @@ -333,11 +333,11 @@ class FloorGenerator(CutAblePolygon, CutAbleGenerator): bmesh.ops.bevel(bm, geom=geom, offset=d.bevel_amount, - offset_type=0, + offset_type='OFFSET', segments=1, # d.bevel_res profile=0.5, vertex_only=False, - clight_overlap=False, + clamp_overlap=False, material=-1) bm.to_mesh(o.data) @@ -366,7 +366,7 @@ class FloorGenerator(CutAblePolygon, CutAbleGenerator): use_dissolve_boundaries=False, verts=bm.verts, edges=bm.edges, - delimit=1) + delimit={'MATERIAL'}) bm.verts.ensure_lookup_table() @@ -925,7 +925,7 @@ class archipack_floor_part(PropertyGroup): A single manipulable polyline like segment polyline like segment line or arc based """ - type = EnumProperty( + type : EnumProperty( items=( ('S_SEG', 'Straight', '', 0), ('C_SEG', 'Curved', '', 1), @@ -933,19 +933,19 @@ class archipack_floor_part(PropertyGroup): default='S_SEG', update=update_type ) - length = FloatProperty( + length : FloatProperty( name="Length", min=0.01, default=2.0, update=update ) - radius = FloatProperty( + radius : FloatProperty( name="Radius", min=0.5, default=0.7, update=update ) - da = FloatProperty( + da : FloatProperty( name="Angle", min=-pi, max=pi, @@ -953,7 +953,7 @@ class archipack_floor_part(PropertyGroup): subtype='ANGLE', unit='ROTATION', update=update ) - a0 = FloatProperty( + a0 : FloatProperty( name="Start angle", min=-2 * pi, max=2 * pi, @@ -961,21 +961,21 @@ class archipack_floor_part(PropertyGroup): subtype='ANGLE', unit='ROTATION', update=update ) - offset = FloatProperty( + offset : FloatProperty( name="Offset", description="Side offset of segment", default=0, unit='LENGTH', subtype='DISTANCE', update=update ) - manipulators = CollectionProperty(type=archipack_manipulator) + manipulators : CollectionProperty(type=archipack_manipulator) def find_in_selection(self, context): """ find witch selected object this instance belongs to provide support for "copy to selected" """ - selected = [o for o in context.selected_objects] + selected = context.selected_objects[:] for o in selected: props = archipack_floor.datablock(o) if props: @@ -1002,35 +1002,35 @@ class archipack_floor_part(PropertyGroup): class archipack_floor(ArchipackObject, Manipulable, PropertyGroup): - n_parts = IntProperty( + n_parts : IntProperty( name="Parts", min=1, default=1, update=update_manipulators ) - parts = CollectionProperty(type=archipack_floor_part) - user_defined_path = StringProperty( + parts : CollectionProperty(type=archipack_floor_part) + user_defined_path : StringProperty( name="User defined", update=update_path ) - user_defined_resolution = IntProperty( + user_defined_resolution : IntProperty( name="Resolution", min=1, max=128, default=12, update=update_path ) - closed = BoolProperty( + closed : BoolProperty( default=True, name="Close", options={'SKIP_SAVE'}, update=update_manipulators ) # UI layout related - parts_expand = BoolProperty( + parts_expand : BoolProperty( options={'SKIP_SAVE'}, default=False ) - pattern = EnumProperty( + pattern : EnumProperty( name='Floor Pattern', items=(("boards", "Boards", ""), ("square_parquet", "Square Parquet", ""), @@ -1044,7 +1044,7 @@ class archipack_floor(ArchipackObject, Manipulable, PropertyGroup): default="boards", update=update ) - spacing = FloatProperty( + spacing : FloatProperty( name='Spacing', description='The amount of space between boards or tiles in both directions', unit='LENGTH', subtype='DISTANCE', @@ -1053,7 +1053,7 @@ class archipack_floor(ArchipackObject, Manipulable, PropertyGroup): precision=2, update=update ) - thickness = FloatProperty( + thickness : FloatProperty( name='Thickness', description='Thickness', unit='LENGTH', subtype='DISTANCE', @@ -1062,13 +1062,13 @@ class archipack_floor(ArchipackObject, Manipulable, PropertyGroup): precision=2, update=update ) - vary_thickness = BoolProperty( + vary_thickness : BoolProperty( name='Random Thickness', description='Vary thickness', default=False, update=update ) - thickness_variance = FloatProperty( + thickness_variance : FloatProperty( name='Variance', description='How much vary by', min=0, max=100, @@ -1078,7 +1078,7 @@ class archipack_floor(ArchipackObject, Manipulable, PropertyGroup): update=update ) - board_width = FloatProperty( + board_width : FloatProperty( name='Width', description='The width', unit='LENGTH', subtype='DISTANCE', @@ -1087,13 +1087,13 @@ class archipack_floor(ArchipackObject, Manipulable, PropertyGroup): precision=2, update=update ) - vary_width = BoolProperty( + vary_width : BoolProperty( name='Random Width', description='Vary width', default=False, update=update ) - width_variance = FloatProperty( + width_variance : FloatProperty( name='Variance', description='How much vary by', subtype='PERCENTAGE', @@ -1101,7 +1101,7 @@ class archipack_floor(ArchipackObject, Manipulable, PropertyGroup): precision=2, update=update ) - width_spacing = FloatProperty( + width_spacing : FloatProperty( name='Width Spacing', description='The amount of space between boards in the width direction', unit='LENGTH', subtype='DISTANCE', @@ -1111,7 +1111,7 @@ class archipack_floor(ArchipackObject, Manipulable, PropertyGroup): update=update ) - board_length = FloatProperty( + board_length : FloatProperty( name='Length', description='The length of the boards', unit='LENGTH', subtype='DISTANCE', @@ -1120,7 +1120,7 @@ class archipack_floor(ArchipackObject, Manipulable, PropertyGroup): default=2, update=update ) - short_board_length = FloatProperty( + short_board_length : FloatProperty( name='Length', description='The length of the boards', unit='LENGTH', subtype='DISTANCE', @@ -1129,27 +1129,27 @@ class archipack_floor(ArchipackObject, Manipulable, PropertyGroup): default=2, update=update ) - vary_length = BoolProperty( + vary_length : BoolProperty( name='Random Length', description='Vary board length', default=False, update=update ) - length_variance = FloatProperty( + length_variance : FloatProperty( name='Variance', description='How much board length can vary by', subtype='PERCENTAGE', min=1, max=100, default=50, precision=2, update=update ) - max_boards = IntProperty( + max_boards : IntProperty( name='Max Boards', description='Max number of boards in one row', min=1, default=20, update=update ) - length_spacing = FloatProperty( + length_spacing : FloatProperty( name='Length Spacing', description='The amount of space between boards in the length direction', unit='LENGTH', subtype='DISTANCE', @@ -1160,7 +1160,7 @@ class archipack_floor(ArchipackObject, Manipulable, PropertyGroup): ) # parquet specific - boards_in_group = IntProperty( + boards_in_group : IntProperty( name='Boards in Group', description='Number of boards in a group', min=1, default=4, @@ -1168,7 +1168,7 @@ class archipack_floor(ArchipackObject, Manipulable, PropertyGroup): ) # tile specific - tile_width = FloatProperty( + tile_width : FloatProperty( name='Width', description='Width of the tiles', unit='LENGTH', subtype='DISTANCE', @@ -1177,7 +1177,7 @@ class archipack_floor(ArchipackObject, Manipulable, PropertyGroup): precision=2, update=update ) - tile_length = FloatProperty( + tile_length : FloatProperty( name='Length', description='Length of the tiles', unit='LENGTH', subtype='DISTANCE', @@ -1188,13 +1188,13 @@ class archipack_floor(ArchipackObject, Manipulable, PropertyGroup): ) # grout - add_grout = BoolProperty( + add_grout : BoolProperty( name='Add Grout', description='Add grout', default=False, update=update ) - mortar_depth = FloatProperty( + mortar_depth : FloatProperty( name='Depth', description='The depth of the mortar from the surface of the tile', unit='LENGTH', subtype='DISTANCE', @@ -1206,19 +1206,19 @@ class archipack_floor(ArchipackObject, Manipulable, PropertyGroup): ) # regular tile - random_offset = BoolProperty( + random_offset : BoolProperty( name='Random Offset', description='Random amount of offset for each row of tiles', update=update, default=False ) - offset = FloatProperty( + offset : FloatProperty( name='Offset', description='How much to offset each row of tiles', min=0, max=100, default=0, precision=2, update=update ) - offset_variance = FloatProperty( + offset_variance : FloatProperty( name='Variance', description='How much to vary the offset each row of tiles', min=0.001, max=100, default=50, @@ -1227,13 +1227,13 @@ class archipack_floor(ArchipackObject, Manipulable, PropertyGroup): ) # bevel - bevel = BoolProperty( + bevel : BoolProperty( name='Bevel', update=update, default=False, description='Bevel upper faces' ) - bevel_amount = FloatProperty( + bevel_amount : FloatProperty( name='Bevel', description='Bevel amount', unit='LENGTH', subtype='DISTANCE', @@ -1241,29 +1241,29 @@ class archipack_floor(ArchipackObject, Manipulable, PropertyGroup): precision=2, step=0.05, update=update ) - solidify = BoolProperty( + solidify : BoolProperty( name="Solidify", default=True, update=update ) - vary_materials = BoolProperty( + vary_materials : BoolProperty( name="Random Material", default=True, description="Vary Material indexes", update=update) - matid = IntProperty( + matid : IntProperty( name="#variations", min=1, max=10, default=7, description="Material index maxi", update=update) - auto_update = BoolProperty( + auto_update : BoolProperty( options={'SKIP_SAVE'}, default=True, update=update_manipulators ) - z = FloatProperty( + z : FloatProperty( name="dumb z", description="Dumb z for manipulator placeholder", default=0.01, @@ -1324,18 +1324,18 @@ class archipack_floor(ArchipackObject, Manipulable, PropertyGroup): # since this can lower points count by a resolution factor # use normalized to handle non linear t if resolution == 0: - pts.append(wM * p0.co.to_3d()) + pts.append(wM @ p0.co.to_3d()) else: v = (p1.co - p0.co).normalized() d1 = (p0.handle_right - p0.co).normalized() d2 = (p1.co - p1.handle_left).normalized() if d1 == v and d2 == v: - pts.append(wM * p0.co.to_3d()) + pts.append(wM @ p0.co.to_3d()) else: - seg = interpolate_bezier(wM * p0.co, - wM * p0.handle_right, - wM * p1.handle_left, - wM * p1.co, + seg = interpolate_bezier(wM @ p0.co, + wM @ p0.handle_right, + wM @ p1.handle_left, + wM @ p1.co, resolution + 1) for i in range(resolution): pts.append(seg[i].to_3d()) @@ -1343,7 +1343,7 @@ class archipack_floor(ArchipackObject, Manipulable, PropertyGroup): def from_spline(self, context, wM, resolution, spline): pts = [] if spline.type == 'POLY': - pts = [wM * p.co.to_3d() for p in spline.points] + pts = [wM @ p.co.to_3d() for p in spline.points] if spline.use_cyclic_u: pts.append(pts[0]) elif spline.type == 'BEZIER': @@ -1358,18 +1358,13 @@ class archipack_floor(ArchipackObject, Manipulable, PropertyGroup): self.interpolate_bezier(pts, wM, p0, p1, resolution) pts.append(pts[0]) else: - pts.append(wM * points[-1].co) + pts.append(wM @ points[-1].co) - pt = wM.inverted() * pts[0] + pt = wM.inverted() @ pts[0] # pretranslate o = self.find_in_selection(context, self.auto_update) - o.matrix_world = wM * Matrix([ - [1, 0, 0, pt.x], - [0, 1, 0, pt.y], - [0, 0, 1, pt.z], - [0, 0, 0, 1] - ]) + o.matrix_world = wM @ Matrix.Translation(pt) self.from_points(pts) def from_points(self, pts): @@ -1565,8 +1560,8 @@ def update_operation(self, context): class archipack_floor_cutter_segment(ArchipackCutterPart, PropertyGroup): - manipulators = CollectionProperty(type=archipack_manipulator) - type = EnumProperty( + manipulators : CollectionProperty(type=archipack_manipulator) + type : EnumProperty( name="Type", items=( ('DEFAULT', 'Side', 'Side with rake', 0), @@ -1599,7 +1594,7 @@ class archipack_floor_cutter_segment(ArchipackCutterPart, PropertyGroup): class archipack_floor_cutter(ArchipackCutter, ArchipackObject, Manipulable, PropertyGroup): - parts = CollectionProperty(type=archipack_floor_cutter_segment) + parts : CollectionProperty(type=archipack_floor_cutter_segment) def update_points(self, context, o, pts, update_parent=False): """ @@ -1615,11 +1610,11 @@ class archipack_floor_cutter(ArchipackCutter, ArchipackObject, Manipulable, Prop d = archipack_floor.datablock(o.parent) if d is not None: - o.parent.select = True - context.scene.objects.active = o.parent + o.parent.select_set(state=True) + context.view_layer.objects.active = o.parent d.update(context) - o.parent.select = False - context.scene.objects.active = o + o.parent.select_set(state=False) + context.view_layer.objects.active = o # ------------------------------------------------------------------ @@ -1632,7 +1627,7 @@ class ARCHIPACK_PT_floor(Panel): bl_label = "Flooring" bl_space_type = "VIEW_3D" bl_region_type = "UI" - bl_category = "Archipack" + bl_category = 'Archipack' @classmethod def poll(cls, context): @@ -1648,7 +1643,7 @@ class ARCHIPACK_PT_floor(Panel): # retrieve datablock of your object props = archipack_floor.datablock(o) # manipulate - layout.operator("archipack.floor_manipulate", icon="HAND") + layout.operator("archipack.floor_manipulate", icon="VIEW_PAN") layout.separator() box = layout.box() row = box.row(align=True) @@ -1658,10 +1653,10 @@ class ARCHIPACK_PT_floor(Panel): text=bpy.types.ARCHIPACK_OT_floor_preset_menu.bl_label) row.operator("archipack.floor_preset", text="", - icon='ZOOMIN') + icon='ADD') row.operator("archipack.floor_preset", text="", - icon='ZOOMOUT').remove_active = True + icon='REMOVE').remove_active = True box = layout.box() box.operator('archipack.floor_cutter').parent = o.name @@ -1759,7 +1754,7 @@ class ARCHIPACK_PT_floor_cutter(Panel): bl_label = "Floor Cutter" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' - bl_category = 'ArchiPack' + bl_category = 'Archipack' @classmethod def poll(cls, context): @@ -1772,7 +1767,7 @@ class ARCHIPACK_PT_floor_cutter(Panel): layout = self.layout scene = context.scene box = layout.box() - box.operator('archipack.floor_cutter_manipulate', icon='HAND') + box.operator('archipack.floor_cutter_manipulate', icon='VIEW_PAN') box.prop(prop, 'operation', text="") box = layout.box() box.label(text="From curve") @@ -1824,9 +1819,9 @@ class ARCHIPACK_OT_floor(ArchipackCreateTool, Operator): p.a0 = angle_90 p.length = x d.n_parts = 4 - context.scene.objects.link(o) - o.select = True - context.scene.objects.active = o + context.scene.collection.objects.link(o) + o.select_set(state=True) + context.view_layer.objects.active = o self.load_preset(d) self.add_material(o) return o @@ -1837,8 +1832,8 @@ class ARCHIPACK_OT_floor(ArchipackCreateTool, Operator): o = self.create(context) o.location = context.scene.cursor_location # activate manipulators at creation time - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o self.manipulate() return {'FINISHED'} else: @@ -1864,7 +1859,7 @@ class ARCHIPACK_OT_floor_from_curve(ArchipackCreateTool, Operator): def draw(self, context): layout = self.layout row = layout.row() - row.label("Use Properties panel (N) to define parms", icon='INFO') + row.label(text="Use Properties panel (N) to define parms", icon='INFO') def create(self, context): curve = context.active_object @@ -1903,7 +1898,7 @@ class ARCHIPACK_OT_floor_from_wall(ArchipackCreateTool, Operator): wall = context.active_object wd = wall.data.archipack_wall2[0] bpy.ops.archipack.floor(auto_manipulate=False, filepath=self.filepath) - o = context.scene.objects.active + o = context.view_layer.objects.active d = archipack_floor.datablock(o) d.auto_update = False d.closed = True @@ -1931,8 +1926,8 @@ class ARCHIPACK_OT_floor_from_wall(ArchipackCreateTool, Operator): if context.mode == "OBJECT": bpy.ops.object.select_all(action="DESELECT") o = self.create(context) - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o if self.auto_manipulate: bpy.ops.archipack.floor_manipulate('INVOKE_DEFAULT') return {'FINISHED'} @@ -1948,7 +1943,7 @@ class ARCHIPACK_OT_floor_cutter(ArchipackCreateTool, Operator): bl_category = 'Archipack' bl_options = {'REGISTER', 'UNDO'} - parent = StringProperty("") + parent : StringProperty("") def create(self, context): m = bpy.data.meshes.new("Floor Cutter") @@ -1963,7 +1958,7 @@ class ARCHIPACK_OT_floor_cutter(ArchipackCreateTool, Operator): x1, y1, z = bbox[6] x = 0.2 * (x1 - x0) y = 0.2 * (y1 - y0) - o.matrix_world = parent.matrix_world * Matrix([ + o.matrix_world = parent.matrix_world @ Matrix([ [1, 0, 0, -3 * x], [0, 1, 0, 0], [0, 0, 1, 0], @@ -1986,9 +1981,9 @@ class ARCHIPACK_OT_floor_cutter(ArchipackCreateTool, Operator): o.location = context.scene.cursor_location # make manipulators selectable d.manipulable_selectable = True - context.scene.objects.link(o) - o.select = True - context.scene.objects.active = o + context.scene.collection.objects.link(o) + o.select_set(state=True) + context.view_layer.objects.active = o # self.add_material(o) self.load_preset(d) update_operation(d, context) @@ -2001,8 +1996,8 @@ class ARCHIPACK_OT_floor_cutter(ArchipackCreateTool, Operator): if context.mode == "OBJECT": bpy.ops.object.select_all(action="DESELECT") o = self.create(context) - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o self.manipulate() return {'FINISHED'} else: diff --git a/archipack/archipack_gl.py b/archipack/archipack_gl.py index 8c475617..578098f9 100644 --- a/archipack/archipack_gl.py +++ b/archipack/archipack_gl.py @@ -24,10 +24,12 @@ # Author: Stephen Leger (s-leger) # # ---------------------------------------------------------- - import bgl import blf +import gpu +from gpu_extras.batch import batch_for_shader import bpy +import numpy as np from math import sin, cos, atan2, pi from mathutils import Vector, Matrix from bpy_extras import view3d_utils, object_utils @@ -44,6 +46,7 @@ class DefaultColorScheme: default to this when not found in addon prefs Colors are FloatVectorProperty of size 4 and type COLOR_GAMMA """ + text_size = 14 feedback_size_main = 16 feedback_size_title = 14 feedback_size_shortcut = 11 @@ -52,6 +55,167 @@ class DefaultColorScheme: feedback_colour_shortcut = (0.51, 0.51, 0.51, 1.0) feedback_shortcut_area = (0, 0.4, 0.6, 0.2) feedback_title_area = (0, 0.4, 0.6, 0.5) + handle_colour_normal = (1.0, 1.0, 1.0, 1.0) + handle_colour_hover = (1.0, 1.0, 0.0, 1.0) + handle_colour_active = (1.0, 0.0, 0.0, 1.0) + handle_colour_selected = (0.0, 0.0, 0.7, 1.0) + handle_colour_inactive = (0.3, 0.3, 0.3, 1.0) + + +def get_prefs(context): + global __name__ + try: + addon_name = __name__.split('.')[0] + prefs = context.user_preferences.addons[addon_name].preferences + except: + prefs = DefaultColorScheme + pass + return prefs + + +g_poly = None +g_image = None +g_line = None + + +line_vertSrc = ''' +uniform mat4 ModelViewProjectionMatrix; + +in vec2 pos; + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); +} + +''' + +line_fragSrc = ''' +uniform vec4 color; + +out vec4 fragColor; + +void main() +{ + fragColor = color; +} +''' + +""" +# TESTS +_format = gpu.types.GPUVertFormat() +_pos_id = _format.attr_add( + id="pos", + comp_type="F32", + len=2, + fetch_mode="FLOAT") +coords = [(0,0), (200,100)] +vbo = gpu.types.GPUVertBuf(len=len(coords), format=_format) +""" + + +class GPU_Line: + def __init__(self): + # never call this in -b mode + if bpy.app.background: + return + self._format = gpu.types.GPUVertFormat() + self._pos_id = self._format.attr_add( + id="pos", + comp_type="F32", + len=2, + fetch_mode="FLOAT") + self.shader = gpu.types.GPUShader(line_vertSrc, line_fragSrc) + self.unif_color = self.shader.uniform_from_name("color") + self.color = np.array([0.0, 0.0, 0.0, 1.0], 'f') + + def batch_line_strip_create(self, coords): + vbo = gpu.types.GPUVertBuf(len=len(coords), format=self._format) + vbo.attr_fill(id=self._pos_id, data=coords) + batch_lines = gpu.types.GPUBatch(type="LINE_STRIP", buf=vbo) + batch_lines.program_set(self.shader) + return batch_lines + + def draw(self, color, list_verts_co): + if list_verts_co: + batch = self.batch_line_strip_create(list_verts_co) + self.color[0:4] = color[0:4] + self.shader.uniform_vector_float(self.unif_color, self.color, 4) + batch.draw() + del batch + + +class GPU_Poly: + + def __init__(self): + if bpy.app.background: + return + self._format = gpu.types.GPUVertFormat() + self._pos_id = self._format.attr_add( + id="pos", + comp_type="F32", + len=2, + fetch_mode="FLOAT") + self.shader = gpu.types.GPUShader(line_vertSrc, line_fragSrc) + self.unif_color = self.shader.uniform_from_name("color") + self.color = np.array([0.0, 0.0, 0.0, 0.5], 'f') + + def batch_create(self, coords): + vbo = gpu.types.GPUVertBuf(len=len(coords), format=self._format) + vbo.attr_fill(id=self._pos_id, data=coords) + batch = gpu.types.GPUBatch(type="TRI_FAN", buf=vbo) + # batch.program_set(self.shader) + # batch = batch_for_shader(self.shader, 'TRI_FAN', {"position": coords}) + return batch + + def draw(self, color, list_verts_co): + if list_verts_co: + self.shader.bind() + batch = self.batch_create(list_verts_co) + self.color[0:4] = color[0:4] + self.shader.uniform_vector_float(self.unif_color, self.color, 4) + batch.draw(self.shader) + + +class GPU_Image: + uvs = [(0, 0), (1, 0), (0, 1), (1, 1)] + indices = [(0, 1, 2), (2, 1, 3)] + + def __init__(self): + if bpy.app.background: + return + self._format = gpu.types.GPUVertFormat() + self._pos_id = self._format.attr_add( + id="pos", + comp_type="F32", + len=2, + fetch_mode="FLOAT") + self.shader = gpu.shader.from_builtin('2D_IMAGE') + + def batch_create(self, coords): + batch = batch_for_shader(self.shader, 'TRIS', + {"pos": coords, + "texCoord": self.uvs}, + indices=self.indices) + return batch + + def draw(self, texture_id, list_verts_co): + if list_verts_co: + batch = self.batch_create(list_verts_co) + + # in case someone disabled it before + bgl.glEnable(bgl.GL_TEXTURE_2D) + + # bind texture to image unit 0 + bgl.glActiveTexture(bgl.GL_TEXTURE0) + bgl.glBindTexture(bgl.GL_TEXTURE_2D, texture_id) + + self.shader.bind() + # tell shader to use the image that is bound to image unit 0 + self.shader.uniform_int("image", 0) + batch.draw(self.shader) + + bgl.glDisable(bgl.GL_TEXTURE_2D) class Gl(): @@ -61,9 +225,22 @@ class Gl(): 3 to convert pos from 3d 2 to keep pos as 2d absolute screen position """ + def __init__(self, - d=3, - colour=(0.0, 0.0, 0.0, 1.0)): + d=3, + colour=(0.0, 0.0, 0.0, 1.0)): + + global g_poly, g_image, g_line + + if g_poly is None: + g_poly = GPU_Poly() + + if g_image is None: + g_image = GPU_Image() + + if g_line is None: + g_line = GPU_Line() + # nth dimensions of input coords 3=word coords 2=pixel screen coords self.d = d self.pos_2d = Vector((0, 0)) @@ -77,13 +254,13 @@ class Gl(): """ coord given in local input coordsys """ if self.d == 2: - return coord + return Vector(coord) if render: return self.get_render_location(context, coord) region = context.region rv3d = context.region_data loc = view3d_utils.location_3d_to_region_2d(region, rv3d, coord, self.pos_2d) - return loc + return Vector(loc) def get_render_location(self, context, coord): scene = context.scene @@ -92,42 +269,32 @@ class Gl(): render_scale = scene.render.resolution_percentage / 100 render_size = (int(scene.render.resolution_x * render_scale), int(scene.render.resolution_y * render_scale)) - return [round(co_2d.x * render_size[0]), round(co_2d.y * render_size[1])] - - def _end(self): - - # print("_end") - bgl.glEnd() - bgl.glPopAttrib() - bgl.glLineWidth(1) - bgl.glDisable(bgl.GL_BLEND) - bgl.glColor4f(0.0, 0.0, 0.0, 1.0) - # print("_end %s" % (type(self).__name__)) + return Vector(round(co_2d.x * render_size[0]), round(co_2d.y * render_size[1])) class GlText(Gl): def __init__(self, - d=3, - label="", - value=None, - precision=2, - unit_mode='AUTO', - unit_type='SIZE', - dimension=1, - angle=0, - font_size=12, - colour=(1, 1, 1, 1), - z_axis=Vector((0, 0, 1))): + d=3, + label="", + value=None, + precision=4, + unit_mode='AUTO', + unit_type='SIZE', + dimension=1, + angle=0, + font_size=None, + colour=(1, 1, 1, 1), + z_axis=Vector((0, 0, 1))): """ d: [2|3] coords type: 2 for coords in screen pixels, 3 for 3d world location label : string label value : float value (will add unit according following settings) precision : integer rounding for values dimension : [1 - 3] nth dimension of unit (single, square, cubic) - unit_mode : ['AUTO','METER','CENTIMETER','MILIMETER','FEET','INCH','RADIANS','DEGREE'] + unit_mode : ['ADAPTIVE','METER','CENTIMETER','MILIMETER','FEET','INCH','RADIANS','DEGREE'] unit type to use to postfix values - auto use scene units setup + ADAPTIVE use scene units setup unit_type : ['SIZE','ANGLE'] unit type to add to value angle : angle to rotate text @@ -142,13 +309,17 @@ class GlText(Gl): self.dimension = dimension self.unit_type = unit_type self.unit_mode = unit_mode - - self.font_size = font_size + if font_size is None: + prefs = get_prefs(bpy.context) + self.font_size = prefs.text_size + else: + self.font_size = font_size self.angle = angle Gl.__init__(self, d) self.colour_inactive = colour # store text with units self._text = "" + self.cbuff = bgl.Buffer(bgl.GL_FLOAT, 4) def text_size(self, context): """ @@ -177,20 +348,25 @@ class GlText(Gl): def add_units(self, context): if self.value is None: return "" + system = context.scene.unit_settings.system if self.unit_type == 'ANGLE': scale = 1 + mode = 'ADAPTIVE' else: scale = context.scene.unit_settings.scale_length + mode = self.unit_mode + if mode == 'AUTO': + mode = context.scene.unit_settings.length_unit.upper() val = self.value * scale - mode = self.unit_mode - if mode == 'AUTO': + + if mode == 'ADAPTIVE': if self.unit_type == 'ANGLE': mode = context.scene.unit_settings.system_rotation else: - if context.scene.unit_settings.system == "IMPERIAL": + if system == "IMPERIAL": if round(val * (3.2808399 ** self.dimension), 2) >= 1.0: - mode = 'FEET' + mode = 'FOOT' else: mode = 'INCH' elif context.scene.unit_settings.system == "METRIC": @@ -201,7 +377,10 @@ class GlText(Gl): mode = 'CENTIMETER' else: mode = 'MILIMETER' + + # TODO: support for separate units (through 2.8 api) # convert values + unit = "" if mode == 'METER': unit = "m" elif mode == 'CENTIMETER': @@ -210,26 +389,38 @@ class GlText(Gl): elif mode == 'MILIMETER': val *= (1000 ** self.dimension) unit = 'mm' + elif mode in {'FOOT', 'FEET'}: + val *= (3.2808399 ** self.dimension) + unit = "ft" elif mode == 'INCH': val *= (39.3700787 ** self.dimension) unit = "in" - elif mode == 'FEET': - val *= (3.2808399 ** self.dimension) - unit = "ft" elif mode == 'RADIANS': unit = "" elif mode == 'DEGREES': val = self.value / pi * 180 unit = "°" - else: - unit = "" - if self.dimension == 2: - unit += "\u00b2" # Superscript two - elif self.dimension == 3: - unit += "\u00b3" # Superscript three - - fmt = "%1." + str(self.precision) + "f " + unit - return fmt % val + if system == 'IMPERIAL': + if self.dimension == 2: + unit = "sq " + unit + elif self.dimension == 3: + unit = "cu " + unit + elif system == 'METRIC': + if self.dimension == 2: + unit += "\u00b2" # Superscript two + elif self.dimension == 3: + unit += "\u00b3" # Superscript three + + fmt = "%1." + str(self.precision) + "f" + # remove trailing zeros + res = fmt % val + while res[-1] == '0': + res = res[:-1] + + if res[-1] == ".": + res = res + '0' + + return "{} {}".format(res, unit) def set_pos(self, context, value, pos_3d, direction, angle=0, normal=Vector((0, 0, 1))): self.up_axis = direction.normalized() @@ -243,66 +434,68 @@ class GlText(Gl): # print("draw_text %s %s" % (self.text, type(self).__name__)) self.render = render - x, y = self.position_2d_from_coord(context, self.pts[0], render) + p = self.position_2d_from_coord(context, self.pts[0], render) + # dirty fast assignment dpi, font_id = context.user_preferences.system.dpi, 0 - bgl.glColor4f(*self.colour) + + # self.cbuff[0:4] = self.colour + + # bgl.glEnableClientState(bgl.GL_COLOR_ARRAY) + # bgl.glColorPointer(4, bgl.GL_FLOAT, 0, self.cbuff) + blf.color(0, *self.colour) if self.angle != 0: blf.enable(font_id, blf.ROTATION) blf.rotation(font_id, self.angle) blf.size(font_id, self.font_size, dpi) - blf.position(font_id, x, y, 0) + blf.position(font_id, p.x, p.y, 0) blf.draw(font_id, self.text) if self.angle != 0: blf.disable(font_id, blf.ROTATION) + # bgl.glDisableClientState(bgl.GL_COLOR_ARRAY) + class GlBaseLine(Gl): def __init__(self, - d=3, - width=1, - style=bgl.GL_LINE, - closed=False): + d=3, + width=1, + style=bgl.GL_LINE, + closed=False, + n_pts=2): Gl.__init__(self, d) # default line width self.width = width # default line style self.style = style # allow closed lines - self.closed = False + self.closed = closed + + self.n_pts = n_pts def draw(self, context, render=False): """ render flag when rendering """ - - # print("draw_line %s" % (type(self).__name__)) - bgl.glPushAttrib(bgl.GL_ENABLE_BIT) - if self.style == bgl.GL_LINE_STIPPLE: - bgl.glLineStipple(1, 0x9999) - bgl.glEnable(self.style) + self.render = render bgl.glEnable(bgl.GL_BLEND) - if render: - # enable anti-alias on lines - bgl.glEnable(bgl.GL_LINE_SMOOTH) - bgl.glColor4f(*self.colour) bgl.glLineWidth(self.width) + list_verts_co = [ + tuple(self.position_2d_from_coord(context, pt, render)[0:2]) + for i, pt in enumerate(self.pts)] if self.closed: - bgl.glBegin(bgl.GL_LINE_LOOP) - else: - bgl.glBegin(bgl.GL_LINE_STRIP) - - for pt in self.pts: - x, y = self.position_2d_from_coord(context, pt, render) - bgl.glVertex2f(x, y) - self._end() + list_verts_co.append(list_verts_co[0]) + g_line.draw(self.colour, list_verts_co) + bgl.glLineWidth(1.0) + bgl.glDisable(bgl.GL_BLEND) class GlLine(GlBaseLine): """ 2d/3d Line """ + def __init__(self, d=3, p=None, v=None, p0=None, p1=None, z_axis=None): """ d=3 use 3d coords, d=2 use 2d pixels coords @@ -322,13 +515,13 @@ class GlLine(GlBaseLine): self.p = Vector(p0) self.v = Vector(p1) - self.p else: - self.p = Vector((0, 0, 0)) - self.v = Vector((0, 0, 0)) + self.p = Vector() + self.v = Vector() if z_axis is not None: self.z_axis = z_axis else: self.z_axis = Vector((0, 0, 1)) - GlBaseLine.__init__(self, d) + GlBaseLine.__init__(self, d, n_pts=2) @property def p0(self): @@ -391,7 +584,7 @@ class GlLine(GlBaseLine): def sized_normal(self, t, size): """ GlLine perpendicular on plane defined by z_axis and of given size - positioned at t in current line + positionned at t in current line lie on the right side p1 |--x @@ -425,7 +618,7 @@ class GlLine(GlBaseLine): v2d = self.v.to_2d() dl = v2d.length d = (self.v.x * dp.y - self.v.y * dp.x) / dl - t = (v2d * dp) / (dl * dl) + t = v2d.dot(dp) / (dl * dl) return t > 0 and t < 1, d, t @property @@ -436,10 +629,10 @@ class GlLine(GlBaseLine): class GlCircle(GlBaseLine): def __init__(self, - d=3, - radius=0, - center=Vector((0, 0, 0)), - z_axis=Vector((0, 0, 1))): + d=3, + radius=0, + center=Vector((0, 0, 0)), + z_axis=Vector((0, 0, 1))): self.r = radius self.c = center @@ -460,18 +653,19 @@ class GlCircle(GlBaseLine): self.z_axis = z self.a0 = 0 self.da = 2 * pi - GlBaseLine.__init__(self, d) + GlBaseLine.__init__(self, d, n_pts=60) def lerp(self, t): """ Linear interpolation """ a = self.a0 + t * self.da - return self.c + self.rM * Vector((self.r * cos(a), self.r * sin(a), 0)) + return self.c + self.rM @ Vector((self.r * cos(a), self.r * sin(a), 0)) @property def pts(self): n_pts = max(1, int(round(abs(self.da) / pi * 30, 0))) + self.n_pts = n_pts t_step = 1 / n_pts return [self.lerp(i * t_step) for i in range(n_pts + 1)] @@ -479,12 +673,12 @@ class GlCircle(GlBaseLine): class GlArc(GlCircle): def __init__(self, - d=3, - radius=0, - center=Vector((0, 0, 0)), - z_axis=Vector((0, 0, 1)), - a0=0, - da=0): + d=3, + radius=0, + center=Vector((0, 0, 0)), + z_axis=Vector((0, 0, 1)), + a0=0, + da=0): """ a0 and da arguments are in radians a0 = 0 on the x+ axis side @@ -526,8 +720,8 @@ class GlArc(GlCircle): ca = cos(a) sa = sin(a) n = GlLine(d=self.d, z_axis=self.z_axis) - n.p = self.c + self.rM * Vector((self.r * ca, self.r * sa, 0)) - n.v = self.rM * Vector((length * sa, -length * ca, 0)) + n.p = self.c + self.rM @ Vector((self.r * ca, self.r * sa, 0)) + n.v = self.rM @ Vector((length * sa, -length * ca, 0)) if self.da > 0: n.v = -n.v return n @@ -541,22 +735,23 @@ class GlArc(GlCircle): else: radius = self.r - offset return GlArc(d=self.d, - radius=radius, - center=self.c, - a0=self.a0, - da=self.da, - z_axis=self.z_axis) + radius=radius, + center=self.c, + a0=self.a0, + da=self.da, + z_axis=self.z_axis) class GlPolygon(Gl): def __init__(self, - colour=(0.0, 0.0, 0.0, 1.0), - d=3): - + colour=(0.3, 0.3, 0.3, 1.0), + d=3, n_pts=60): self.pts_3d = [] Gl.__init__(self, d, colour) + self.n_pts = min(n_pts, 60) + def set_pos(self, pts_3d): self.pts_3d = pts_3d @@ -568,52 +763,53 @@ class GlPolygon(Gl): """ render flag when rendering """ + # return - # print("draw_polygon") self.render = render - bgl.glPushAttrib(bgl.GL_ENABLE_BIT) - bgl.glEnable(bgl.GL_BLEND) - if render: - # enable anti-alias on polygons - bgl.glEnable(bgl.GL_POLYGON_SMOOTH) - bgl.glColor4f(*self.colour) - bgl.glBegin(bgl.GL_POLYGON) + if self.n_pts == 0: + return + + pts = self.pts - for pt in self.pts: - x, y = self.position_2d_from_coord(context, pt, render) - bgl.glVertex2f(x, y) - self._end() + g_vertices = [ + tuple(self.position_2d_from_coord(context, pt, render)[0:2]) + for i, pt in enumerate(pts)] + bgl.glEnable(bgl.GL_BLEND) + g_poly.draw(self.colour, g_vertices) + bgl.glDisable(bgl.GL_BLEND) class GlRect(GlPolygon): def __init__(self, - colour=(0.0, 0.0, 0.0, 1.0), - d=2): - GlPolygon.__init__(self, colour, d) + colour=(0.0, 0.0, 0.0, 1.0), + d=2): + GlPolygon.__init__(self, colour, d, n_pts=4) - def draw(self, context, render=False): + @property + def pts(self): + return self.pts_2d - self.render = render - bgl.glPushAttrib(bgl.GL_ENABLE_BIT) - bgl.glEnable(bgl.GL_BLEND) - if render: - # enable anti-alias on polygons - bgl.glEnable(bgl.GL_POLYGON_SMOOTH) - bgl.glColor4f(*self.colour) - p0 = self.pts[0] - p1 = self.pts[1] - bgl.glRectf(p0.x, p0.y, p1.x, p1.y) - self._end() + def draw(self, context, render=False): + pts = [ + self.position_2d_from_coord(context, pt, render) + for pt in self.pts_3d + ] + x0, y0 = pts[0] + x1, y1 = pts[1] + self.pts_2d = [Vector((x, y)) for x, y in [(x0, y0), (x0, y1), (x1, y1), (x1, y0)]] + GlPolygon.draw(self, context, render) class GlImage(Gl): def __init__(self, - d=2, - image=None): + d=2, + image=None): + # GImage bindcode[0] self.image = image self.colour_inactive = (1, 1, 1, 1) Gl.__init__(self, d) self.pts_2d = [Vector((0, 0)), Vector((10, 10))] + self.n_pts = 4 def set_pos(self, pts): self.pts_2d = pts @@ -625,38 +821,17 @@ class GlImage(Gl): def draw(self, context, render=False): if self.image is None: return - bgl.glPushAttrib(bgl.GL_ENABLE_BIT) + p0 = self.pts[0] p1 = self.pts[1] - bgl.glEnable(bgl.GL_BLEND) - bgl.glColor4f(*self.colour) - bgl.glRectf(p0.x, p0.y, p1.x, p1.y) - self.image.gl_load() - bgl.glEnable(bgl.GL_BLEND) - bgl.glBindTexture(bgl.GL_TEXTURE_2D, self.image.bindcode[0]) - bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MIN_FILTER, bgl.GL_NEAREST) - bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MAG_FILTER, bgl.GL_NEAREST) - bgl.glEnable(bgl.GL_TEXTURE_2D) - bgl.glBlendFunc(bgl.GL_SRC_ALPHA, bgl.GL_ONE_MINUS_SRC_ALPHA) - # bgl.glColor4f(1, 1, 1, 1) - bgl.glBegin(bgl.GL_QUADS) - bgl.glTexCoord2d(0, 0) - bgl.glVertex2d(p0.x, p0.y) - bgl.glTexCoord2d(0, 1) - bgl.glVertex2d(p0.x, p1.y) - bgl.glTexCoord2d(1, 1) - bgl.glVertex2d(p1.x, p1.y) - bgl.glTexCoord2d(1, 0) - bgl.glVertex2d(p1.x, p0.y) - bgl.glEnd() - self.image.gl_free() - bgl.glDisable(bgl.GL_TEXTURE_2D) + coords = [(p0.x, p0.y), (p1.x, p0.y), (p0.x, p1.y), (p1.x, p1.y)] + g_image.draw(self.image.bindcode, coords) class GlPolyline(GlBaseLine): - def __init__(self, colour, d=3): + def __init__(self, colour, d=3, n_pts=60): self.pts_3d = [] - GlBaseLine.__init__(self, d) + GlBaseLine.__init__(self, d, n_pts=n_pts) self.colour_inactive = colour def set_pos(self, pts_3d): @@ -670,17 +845,25 @@ class GlPolyline(GlBaseLine): class GlHandle(GlPolygon): - def __init__(self, sensor_size, size, draggable=False, selectable=False, d=3): + def __init__(self, sensor_size, size, draggable=False, selectable=False, d=3, n_pts=4): """ sensor_size : 2d size in pixels of sensor area size : 3d size of handle """ - GlPolygon.__init__(self, d=d) - self.colour_active = (1.0, 0.0, 0.0, 1.0) - self.colour_hover = (1.0, 1.0, 0.0, 1.0) - self.colour_normal = (1.0, 1.0, 1.0, 1.0) - self.colour_selected = (0.0, 0.0, 0.7, 1.0) + GlPolygon.__init__(self, d=d, n_pts=n_pts) + prefs = get_prefs(bpy.context) + self.colour_active = prefs.handle_colour_active + self.colour_hover = prefs.handle_colour_hover + self.colour_normal = prefs.handle_colour_normal + self.colour_selected = prefs.handle_colour_selected + self.colour_inactive = prefs.handle_colour_inactive + # variable symbol size in world coords self.size = size + # constant symbol size in pixels + self.symbol_size = sensor_size + # scale factor for constant symbol pixel size + self.scale = 1 + # sensor size in pixels self.sensor_width = sensor_size self.sensor_height = sensor_size self.pos_3d = Vector((0, 0, 0)) @@ -692,11 +875,38 @@ class GlHandle(GlPolygon): self.selectable = selectable self.selected = False + def scale_factor(self, context, pts): + """ + Compute screen scale factor for symbol + given 2 points in symbol direction (eg start and end of arrow) + """ + prefs = get_prefs(context) + if not prefs.constant_handle_size: + return 1 + + p2d = [] + for pt in pts: + p2d.append(self.position_2d_from_coord(context, pt)) + sx = [p.x for p in p2d] + sy = [p.y for p in p2d] + x = max(sx) - min(sx) + y = max(sy) - min(sy) + s = max(x, y) + if s > 0: + fac = self.symbol_size / s + else: + fac = 1 + return fac + def set_pos(self, context, pos_3d, direction, normal=Vector((0, 0, 1))): self.up_axis = direction.normalized() self.c_axis = self.up_axis.cross(normal) self.pos_3d = pos_3d self.pos_2d = self.position_2d_from_coord(context, self.sensor_center) + x = self.up_axis * 0.5 * self.size + y = self.c_axis * 0.5 * self.size + pts = [self.sensor_center + v for v in [-x, x, -y, y]] + self.scale = self.scale_factor(context, pts) def check_hover(self, pos_2d): if self.draggable: @@ -737,7 +947,7 @@ class GlHandle(GlPolygon): class SquareHandle(GlHandle): def __init__(self, sensor_size, size, draggable=False, selectable=False): - GlHandle.__init__(self, sensor_size, size, draggable, selectable) + GlHandle.__init__(self, sensor_size, size, draggable, selectable, n_pts=4) @property def pts(self): @@ -747,15 +957,15 @@ class SquareHandle(GlHandle): scale = 1 else: scale = 0.5 - x = n * self.size * scale - y = c * self.size * scale + x = n * self.scale * self.size * scale + y = c * self.scale * self.size * scale return [self.pos_3d - x - y, self.pos_3d + x - y, self.pos_3d + x + y, self.pos_3d - x + y] class TriHandle(GlHandle): def __init__(self, sensor_size, size, draggable=False, selectable=False): - GlHandle.__init__(self, sensor_size, size, draggable, selectable) + GlHandle.__init__(self, sensor_size, size, draggable, selectable, n_pts=3) @property def pts(self): @@ -767,11 +977,110 @@ class TriHandle(GlHandle): scale = 1 # else: # scale = 0.5 - x = n * self.size * 4 * scale - y = c * self.size * scale + x = n * self.scale * self.size * 4 * scale + y = c * self.scale * self.size * scale return [self.pos_3d - x + y, self.pos_3d - x - y, self.pos_3d] +class CruxHandle(GlHandle): + + def __init__(self, sensor_size, size, draggable=True, selectable=False): + GlHandle.__init__(self, sensor_size, size, draggable, selectable, n_pts=0) + self.branch_0 = GlPolygon((1, 1, 1, 1), d=3, n_pts=4) + self.branch_1 = GlPolygon((1, 1, 1, 1), d=3, n_pts=4) + + def set_pos(self, context, pos_3d, direction, normal=Vector((0, 0, 1))): + self.pos_3d = pos_3d + self.pos_2d = self.position_2d_from_coord(context, self.sensor_center) + o = self.pos_3d + d = 0.5 * self.size + x = direction.normalized() + y = x.cross(normal) + + sx = x * 0.5 * self.size + sy = y * 0.5 * self.size + pts = [o + v for v in [-sx, sx, -sy, sy]] + self.scale = self.scale_factor(context, pts) + + c = self.scale * d / 1.4242 + w = self.scale * self.size + s = w - c + + xs = x * s + xw = x * w + ys = y * s + yw = y * w + p0 = o + xs + yw + p1 = o + xw + ys + p2 = o - xs - yw + p3 = o - xw - ys + p4 = o - xs + yw + p5 = o + xw - ys + p6 = o + xs - yw + p7 = o - xw + ys + + self.branch_0.set_pos([p0, p1, p2, p3]) + self.branch_1.set_pos([p4, p5, p6, p7]) + + @property + def pts(self): + return [self.pos_3d] + + def draw(self, context, render=False): + self.render = render + self.branch_0.colour_inactive = self.colour + self.branch_1.colour_inactive = self.colour + self.branch_0.draw(context) + self.branch_1.draw(context) + + +class PlusHandle(GlHandle): + + def __init__(self, sensor_size, size, draggable=True, selectable=False): + GlHandle.__init__(self, sensor_size, size, draggable, selectable, n_pts=0) + self.branch_0 = GlPolygon((1, 1, 1, 1), d=3, n_pts=4) + self.branch_1 = GlPolygon((1, 1, 1, 1), d=3, n_pts=4) + + def set_pos(self, context, pos_3d, direction, normal=Vector((0, 0, 1))): + self.pos_3d = pos_3d + self.pos_2d = self.position_2d_from_coord(context, self.sensor_center) + o = self.pos_3d + x = direction.normalized() + y = x.cross(normal) + sx = x * 0.5 * self.size + sy = y * 0.5 * self.size + pts = [o + v for v in [-sx, sx, -sy, sy]] + self.scale = self.scale_factor(context, pts) + w = self.scale * self.size + s = self.scale * 0.25 * w + + xs = x * s + xw = x * w + ys = y * s + yw = y * w + p0 = o - xw + ys + p1 = o + xw + ys + p2 = o + xw - ys + p3 = o - xw - ys + p4 = o - xs + yw + p5 = o + xs + yw + p6 = o + xs - yw + p7 = o - xs - yw + self.branch_0.set_pos([p0, p1, p2, p3]) + self.branch_1.set_pos([p4, p5, p6, p7]) + + @property + def pts(self): + return [self.pos_3d] + + def draw(self, context, render=False): + self.render = render + self.branch_0.colour_inactive = self.colour + self.branch_1.colour_inactive = self.colour + self.branch_0.draw(context) + self.branch_1.draw(context) + + class EditableText(GlText, GlHandle): def __init__(self, sensor_size, size, draggable=False, selectable=False): GlHandle.__init__(self, sensor_size, size, draggable, selectable) @@ -783,10 +1092,10 @@ class EditableText(GlText, GlHandle): self.pos_3d = pos_3d self.value = value self._text = self.add_units(context) - x, y = self.text_size(context) + ts = self.text_size(context) self.pos_2d = self.position_2d_from_coord(context, pos_3d) - self.pos_2d.x += 0.5 * x - self.sensor_width, self.sensor_height = 0.5 * x, y + self.pos_2d.x += 0.5 * ts.x + self.sensor_width, self.sensor_height = 0.5 * ts.x, ts.y @property def sensor_center(self): @@ -796,10 +1105,10 @@ class EditableText(GlText, GlHandle): class ThumbHandle(GlHandle): def __init__(self, size_2d, label, image=None, draggable=False, selectable=False, d=2): - GlHandle.__init__(self, size_2d, size_2d, draggable, selectable, d) + GlHandle.__init__(self, size_2d, size_2d, draggable, selectable, d, n_pts=4) self.image = GlImage(image=image) self.label = GlText(d=2, label=label.replace("_", " ").capitalize()) - self.frame = GlPolyline((1, 1, 1, 1), d=2) + self.frame = GlPolyline((1, 1, 1, 1), d=2, n_pts=4) self.frame.closed = True self.size_2d = size_2d self.sensor_width = 0.5 * size_2d.x @@ -830,7 +1139,7 @@ class ThumbHandle(GlHandle): def draw(self, context, render=False): self.render = render self.image.colour_inactive = self.colour - GlHandle.draw(self, context, render=False) + # GlHandle.draw(self, context, render=False) self.image.draw(context, render=False) self.label.draw(context, render=False) self.frame.draw(context, render=False) @@ -850,8 +1159,8 @@ class Screen(): x_min = self.margin x_max = w - self.margin if system.use_region_overlap: + # system.window_draw_method in {'TRIPLE_BUFFER', 'ADAPTIVEMATIC'}): area = context.area - for r in area.regions: if r.type == 'TOOLS': x_min += r.width @@ -865,29 +1174,30 @@ class FeedbackPanel(): Feed-back panel inspired by np_station """ + def __init__(self, title='Archipack'): - prefs = self.get_prefs(bpy.context) + prefs = get_prefs(bpy.context) self.main_title = GlText(d=2, - label=title + " : ", - font_size=prefs.feedback_size_main, - colour=prefs.feedback_colour_main - ) + label=title + " : ", + font_size=prefs.feedback_size_main, + colour=prefs.feedback_colour_main + ) self.title = GlText(d=2, - font_size=prefs.feedback_size_title, - colour=prefs.feedback_colour_main - ) + font_size=prefs.feedback_size_title, + colour=prefs.feedback_colour_main + ) self.spacing = Vector(( 0.5 * prefs.feedback_size_shortcut, 0.5 * prefs.feedback_size_shortcut)) self.margin = 50 self.explanation = GlText(d=2, - font_size=prefs.feedback_size_shortcut, - colour=prefs.feedback_colour_main - ) - self.shortcut_area = GlPolygon(colour=prefs.feedback_shortcut_area, d=2) - self.title_area = GlPolygon(colour=prefs.feedback_title_area, d=2) + font_size=prefs.feedback_size_shortcut, + colour=prefs.feedback_colour_main + ) + self.shortcut_area = GlPolygon(colour=prefs.feedback_shortcut_area, d=2, n_pts=4) + self.title_area = GlPolygon(colour=prefs.feedback_title_area, d=2, n_pts=4) self.shortcuts = [] self.on = False self.show_title = True @@ -902,22 +1212,11 @@ class FeedbackPanel(): def enable(self): self.on = True - def get_prefs(self, context): - global __name__ - try: - # retrieve addon name from imports - addon_name = __name__.split('.')[0] - prefs = context.user_preferences.addons[addon_name].preferences - except: - prefs = DefaultColorScheme - pass - return prefs - def instructions(self, context, title, explanation, shortcuts): """ position from bottom to top """ - prefs = self.get_prefs(context) + prefs = get_prefs(context) self.explanation.label = explanation self.title.label = title @@ -926,16 +1225,17 @@ class FeedbackPanel(): for key, label in shortcuts: key = GlText(d=2, label=key, - font_size=prefs.feedback_size_shortcut, - colour=prefs.feedback_colour_key) + font_size=prefs.feedback_size_shortcut, + colour=prefs.feedback_colour_key) label = GlText(d=2, label=' : ' + label, - font_size=prefs.feedback_size_shortcut, - colour=prefs.feedback_colour_shortcut) + font_size=prefs.feedback_size_shortcut, + colour=prefs.feedback_colour_shortcut) ks = key.text_size(context) ls = label.text_size(context) self.shortcuts.append([key, ks, label, ls]) def draw(self, context, render=False): + if self.on: """ draw from bottom to top @@ -991,7 +1291,7 @@ class FeedbackPanel(): (x_max, self.margin), (x_max, pos.y), (x_min, pos.y) - ] + ] # small space between shortcut area and main title bar if n_shortcuts > 0: @@ -1002,7 +1302,7 @@ class FeedbackPanel(): (x_max, pos.y), (x_max, pos.y + main_title_size.y + 2 * self.spacing.y), (x_min, pos.y + main_title_size.y + 2 * self.spacing.y) - ] + ] pos.y += self.spacing.y title_size = self.title.text_size(context) @@ -1046,12 +1346,13 @@ class GlCursorFence(): """ Cursor crossing Fence """ - def __init__(self, width=1, colour=(1.0, 1.0, 1.0, 0.5), style=bgl.GL_LINE_STIPPLE): - self.line_x = GlLine(d=2) + + def __init__(self, width=1, colour=(1.0, 1.0, 1.0, 0.5), style=2852): + self.line_x = GlLine(d=2, n_pts=2) self.line_x.style = style self.line_x.width = width self.line_x.colour_inactive = colour - self.line_y = GlLine(d=2) + self.line_y = GlLine(d=2, n_pts=2) self.line_y.style = style self.line_y.width = width self.line_y.colour_inactive = colour @@ -1060,7 +1361,8 @@ class GlCursorFence(): def set_location(self, context, location): w = context.region.width h = context.region.height - x, y = location + p = Vector(location) + x, y = p.x, p.y self.line_x.p = Vector((0, y)) self.line_x.v = Vector((w, 0)) self.line_y.p = Vector((x, 0)) @@ -1080,27 +1382,29 @@ class GlCursorFence(): class GlCursorArea(): def __init__(self, - width=1, - bordercolour=(1.0, 1.0, 1.0, 0.5), - areacolour=(0.5, 0.5, 0.5, 0.08), - style=bgl.GL_LINE_STIPPLE): + width=1, + bordercolour=(1.0, 1.0, 1.0, 0.5), + areacolour=(0.5, 0.5, 0.5, 0.08), + style=2852): - self.border = GlPolyline(bordercolour, d=2) + self.border = GlPolyline(bordercolour, d=2, n_pts=4) self.border.style = style self.border.width = width self.border.closed = True - self.area = GlPolygon(areacolour, d=2) + self.area = GlPolygon(areacolour, d=2, n_pts=4) self.min = Vector((0, 0)) self.max = Vector((0, 0)) self.on = False def in_area(self, pt): return (self.min.x <= pt.x and self.max.x >= pt.x and - self.min.y <= pt.y and self.max.y >= pt.y) + self.min.y <= pt.y and self.max.y >= pt.y) def set_location(self, context, p0, p1): - x0, y0 = p0 - x1, y1 = p1 + p = Vector(p0) + x0, y0 = p.x, p.y + p = Vector(p1) + x1, y1 = p.x, p.y if x0 > x1: x1, x0 = x0, x1 if y0 > y1: diff --git a/archipack/archipack_handle.py b/archipack/archipack_handle.py index fcdb570e..d27603b0 100644 --- a/archipack/archipack_handle.py +++ b/archipack/archipack_handle.py @@ -32,17 +32,17 @@ def create_handle(context, parent, mesh): old = context.active_object handle = bpy.data.objects.new("Handle", mesh) handle['archipack_handle'] = True - context.scene.objects.link(handle) + context.scene.collection.objects.link(handle) modif = handle.modifiers.new('Subsurf', 'SUBSURF') modif.render_levels = 4 modif.levels = 1 handle.parent = parent handle.matrix_world = parent.matrix_world.copy() - context.scene.objects.active = handle + context.view_layer.objects.active = handle m = handle.archipack_material.add() m.category = 'handle' m.material = 'DEFAULT' - context.scene.objects.active = old + context.view_layer.objects.active = old return handle diff --git a/archipack/archipack_keymaps.py b/archipack/archipack_keymaps.py index c4c8176e..a30b31e9 100644 --- a/archipack/archipack_keymaps.py +++ b/archipack/archipack_keymaps.py @@ -24,6 +24,7 @@ # Author: Stephen Leger (s-leger) # # ---------------------------------------------------------- +import bpy class Keymaps: @@ -79,6 +80,10 @@ class Keymaps: event: simple event signature to compare like : if event == keymap.undo.event: """ + # Headless mode fails without this check + if bpy.app.background: + return {'type': None, 'event':(False, False, False, False, None, None)} + ev = context.window_manager.keyconfigs.user.keymaps[keyconfig].keymap_items[keymap_item] key = ev.type if ev.ctrl: @@ -89,6 +94,7 @@ class Keymaps: key += '+SHIFT' return {'type': key, 'name': ev.name, 'event': (ev.alt, ev.ctrl, ev.shift, ev.type, ev.value)} + def dump_keys(self, context, filename="c:\\tmp\\keymap.txt"): """ Utility for developers : diff --git a/archipack/archipack_manipulator.py b/archipack/archipack_manipulator.py index 5ed7312b..06efefff 100644 --- a/archipack/archipack_manipulator.py +++ b/archipack/archipack_manipulator.py @@ -30,7 +30,13 @@ from mathutils import Vector, Matrix from mathutils.geometry import intersect_line_plane, intersect_point_line, intersect_line_sphere from bpy_extras import view3d_utils from bpy.types import PropertyGroup, Operator -from bpy.props import FloatVectorProperty, StringProperty, CollectionProperty, BoolProperty +from bpy.props import ( + FloatVectorProperty, + StringProperty, + CollectionProperty, + BoolProperty +) + from bpy.app.handlers import persistent from .archipack_snap import snap_point from .archipack_keymaps import Keymaps @@ -67,14 +73,16 @@ from .archipack_gl import ( # (manips[key].manipulable.manip_stack) # Must investigate for a way to handle unselect after drag done. + +import logging +logger = logging.getLogger("archipack") + + """ - @TODO: - Last modal running wins. - Manipulateurs without snap and thus not running own modal, - may loose events events caught by select mode of last - manipulable enabled + Change object location when moving 1 point + When False, change data.origin instead """ - +USE_MOVE_OBJECT = True # Arrow sizes (world units) arrow_size = 0.05 # Handle area size (pixels) @@ -469,7 +477,7 @@ class Manipulator(): view_vector_mouse = view3d_utils.region_2d_to_vector_3d(region, rv3d, self.mouse_pos) ray_origin_mouse = view3d_utils.region_2d_to_origin_3d(region, rv3d, self.mouse_pos) pt = intersect_line_plane(ray_origin_mouse, ray_origin_mouse + view_vector_mouse, - self.origin, rM * self.manipulator.normal, False) + self.origin, rM @ self.manipulator.normal, False) # fix issue with parallel plane if pt is None: pt = intersect_line_plane(ray_origin_mouse, ray_origin_mouse + view_vector_mouse, @@ -495,18 +503,19 @@ class Manipulator(): """ try: if self.get_value(data, attr, index) != value: + o = self.o # switch context so unselected object may be manipulable too - old = context.active_object - state = self.o.select - self.o.select = True - context.scene.objects.active = self.o + old = context.object + state = o.select_get() + o.select_set(state=True) + context.view_layer.objects.active = o if index > -1: getattr(data, attr)[index] = value else: setattr(data, attr, value) - self.o.select = state - old.select = True - context.scene.objects.active = old + o.select_set(state=state) + old.select_set(state=True) + context.view_layer.objects.active = old except: pass @@ -516,11 +525,7 @@ class Manipulator(): tM Matrix source vec Vector translation """ - return tM * Matrix([ - [1, 0, 0, vec.x], - [0, 1, 0, vec.y], - [0, 0, 1, vec.z], - [0, 0, 0, 1]]) + return tM @ Matrix.Translation(vec) def _move(self, o, axis, value): if axis == 'x': @@ -538,15 +543,15 @@ class Manipulator(): """ old = context.active_object bpy.ops.object.select_all(action='DESELECT') - self.o.select = True - context.scene.objects.active = self.o + self.o.select_set(state=True) + context.view_layer.objects.active = self.o bpy.ops.object.select_linked(type='OBDATA') for o in context.selected_objects: if o != self.o: self._move(o, axis, value) bpy.ops.object.select_all(action='DESELECT') - old.select = True - context.scene.objects.active = old + old.select_set(state=True) + context.view_layer.objects.active = old def move(self, context, axis, value): """ @@ -555,68 +560,6 @@ class Manipulator(): self._move(self.o, axis, value) -# OUT OF ORDER -class SnapPointManipulator(Manipulator): - """ - np_station based snap manipulator - dosent update anything by itself. - NOTE : currently out of order - and disabled in __init__ - """ - def __init__(self, context, o, datablock, manipulator, handle_size, snap_callback=None): - - raise NotImplementedError - - self.handle = SquareHandle(handle_size, 1.2 * arrow_size, draggable=True) - Manipulator.__init__(self, context, o, datablock, manipulator, snap_callback) - - def check_hover(self): - self.handle.check_hover(self.mouse_pos) - - def mouse_press(self, context, event): - if self.handle.hover: - self.handle.hover = False - self.handle.active = True - self.o.select = True - # takeloc = self.o.matrix_world * self.manipulator.p0 - # print("Invoke sp_point_move %s" % (takeloc)) - # @TODO: - # implement and add draw and callbacks - # snap_point(takeloc, draw, callback) - return True - return False - - def mouse_release(self, context, event): - self.check_hover() - self.handle.active = False - # False to callback manipulable_release - return False - - def update(self, context, event): - # NOTE: - # dosent set anything internally - return - - def mouse_move(self, context, event): - """ - - """ - self.mouse_position(event) - if self.handle.active: - # self.handle.active = np_snap.is_running - # self.update(context) - # True here to callback manipulable_manipulate - return True - else: - self.check_hover() - return False - - def draw_callback(self, _self, context, render=False): - left, right, side, normal = self.manipulator.get_pts(self.o.matrix_world) - self.handle.set_pos(context, left, Vector((1, 0, 0)), normal=normal) - self.handle.draw(context, render) - - # Generic snap tool for line based archipack objects (fence, wall, maybe stair too) gl_pts3d = [] @@ -682,7 +625,7 @@ class WallSnapManipulator(Manipulator): ]) self.feedback.enable() self.handle.hover = False - self.o.select = True + self.o.select_set(state=True) takeloc, right, side, dz = self.manipulator.get_pts(self.o.matrix_world) dx = (right - takeloc).normalized() dy = dz.cross(dx) @@ -712,20 +655,20 @@ class WallSnapManipulator(Manipulator): np station callback on moving, place, or cancel """ global gl_pts3d + logger.debug("WallSnapManipulator.sp_callback") if state == 'SUCCESS': - - self.o.select = True + o = self.o + o.select_set(state=True) + context.view_layer.objects.active = o # apply changes to wall d = self.datablock - d.auto_update = False - g = d.get_generator() # rotation relative to object - rM = self.o.matrix_world.inverted().to_3x3() - delta = (rM * sp.delta).to_2d() - # x_axis = (rM * Vector((1, 0, 0))).to_2d() + rM = o.matrix_world.inverted().to_3x3() + delta =rM @ sp.delta + # x_axis = (rM @ Vector((1, 0, 0))).to_2d() # update generator idx = 0 @@ -734,7 +677,7 @@ class WallSnapManipulator(Manipulator): if selected: # new location in object space - pt = g.segs[idx].lerp(0) + delta + pt = g.segs[idx].lerp(0) + delta.to_2d() # move last point of segment before current if idx > 0: @@ -747,6 +690,7 @@ class WallSnapManipulator(Manipulator): # update properties from generator idx = 0 + for p0, p1, selected in gl_pts3d: if selected: @@ -759,7 +703,7 @@ class WallSnapManipulator(Manipulator): if idx > 1: part.a0 = w.delta_angle(g.segs[idx - 2]) else: - part.a0 = w.straight(1, 0).angle + part.a0 = w.a0 if "C_" in part.type: part.radius = w.r @@ -773,10 +717,14 @@ class WallSnapManipulator(Manipulator): if idx > 0: part.a0 = w.delta_angle(g.segs[idx - 1]) else: - part.a0 = w.straight(1, 0).angle + part.a0 = w.a0 # move object when point 0 - self.o.location += sp.delta - self.o.matrix_world.translation += sp.delta + if USE_MOVE_OBJECT: + d.move_object(o, o.matrix_world.translation + sp.delta) + # self.o.location += sp.delta + # self.o.matrix_world.translation += sp.delta + else: + d.origin += sp.delta if "C_" in part.type: part.radius = w.r @@ -790,15 +738,18 @@ class WallSnapManipulator(Manipulator): idx += 1 self.mouse_release(context, event) - d.auto_update = True + d.relocate_childs(context, o, g) + d.update(context) if state == 'CANCEL': self.mouse_release(context, event) + logger.debug("WallSnapManipulator.sp_callback done") return def sp_draw(self, sp, context): # draw wall placeholders + logger.debug("WallSnapManipulator.sp_draw") global gl_pts3d @@ -842,6 +793,7 @@ class WallSnapManipulator(Manipulator): self.label.set_pos(context, self.line.length, self.line.lerp(0.5), self.line.v, normal=Vector((0, 0, 1))) self.line.draw(context, render=False) self.label.draw(context, render=False) + logger.debug("WallSnapManipulator.sp_draw done") def mouse_move(self, context, event): self.mouse_position(event) @@ -1002,7 +954,6 @@ class SizeManipulator(Manipulator): ]) gl_pts3d = [left, right] snap_point(takemat=takemat, - draw=self.sp_draw, callback=self.sp_callback, constraint_axis=(True, False, False)) self.handle_right.active = True @@ -1085,32 +1036,31 @@ class SizeManipulator(Manipulator): self.label.draw(context, render) self.feedback.draw(context, render) - def sp_draw(self, sp, context): + def sp_callback(self, context, event, state, sp): + logger.debug("SizeManipulator.sp_callback") global gl_pts3d - if self.o is None: - return + p0 = gl_pts3d[0].copy() p1 = gl_pts3d[1].copy() - p1 += sp.delta - self.sp_update(context, p0, p1) - return - def sp_callback(self, context, event, state, sp): + if state != 'CANCEL': + p1 += sp.delta - if state == 'SUCCESS': - self.sp_draw(sp, context) - self.mouse_release(context, event) + length = (p0 - p1).length - if state == 'CANCEL': - p0 = gl_pts3d[0].copy() - p1 = gl_pts3d[1].copy() - self.sp_update(context, p0, p1) - self.mouse_release(context, event) + if state != 'CANCEL' and event.alt: + if event.shift: + length = round(length, 2) + else: + length = round(length, 1) - def sp_update(self, context, p0, p1): - length = (p0 - p1).length self.set_value(context, self.datablock, self.manipulator.prop1_name, length) + if state != 'RUNNING': + self.mouse_release(context, event) + + logger.debug("SizeManipulator.sp_callback done") + class SizeLocationManipulator(SizeManipulator): """ @@ -1190,7 +1140,7 @@ class SizeLocationManipulator(SizeManipulator): self.mouse_release(context, event) # must move back to original location itM = self.o.matrix_world.inverted() - dl = self.get_value(itM * self.original_location, self.manipulator.prop2_name) + dl = self.get_value(itM @ self.original_location, self.manipulator.prop2_name) self.move(context, self.manipulator.prop2_name, dl) self.set_value(context, self.datablock, self.manipulator.prop1_name, self.original_size) @@ -1263,7 +1213,6 @@ class SnapSizeLocationManipulator(SizeLocationManipulator): ]) gl_pts3d = [left, right] snap_point(takemat=takemat, - draw=self.sp_draw, callback=self.sp_callback, constraint_axis=(True, False, False)) @@ -1290,7 +1239,6 @@ class SnapSizeLocationManipulator(SizeLocationManipulator): ]) gl_pts3d = [left, right] snap_point(takemat=takemat, - draw=self.sp_draw, callback=self.sp_callback, constraint_axis=(True, False, False)) self.handle_left.active = True @@ -1305,50 +1253,50 @@ class SnapSizeLocationManipulator(SizeLocationManipulator): return False - def sp_draw(self, sp, context): + def sp_callback(self, context, event, state, sp): + logger.debug("SnapSizeLocationManipulator.sp_callback") global gl_pts3d - if self.o is None: - return p0 = gl_pts3d[0].copy() p1 = gl_pts3d[1].copy() - if self.handle_right.active: - p1 += sp.delta - else: - p0 += sp.delta - self.sp_update(context, p0, p1) - - # snapping child objects may require base object update - # eg manipulating windows requiring wall update - if self.snap_callback is not None: - snap_helper = context.active_object - self.snap_callback(context, o=self.o, manipulator=self) - context.scene.objects.active = snap_helper - - return - - def sp_callback(self, context, event, state, sp): - if state == 'SUCCESS': - self.sp_draw(sp, context) - self.mouse_release(context, event) - - if state == 'CANCEL': - p0 = gl_pts3d[0].copy() - p1 = gl_pts3d[1].copy() - self.sp_update(context, p0, p1) - self.mouse_release(context, event) + if state != 'CANCEL': + if self.handle_right.active: + p1 += sp.delta + else: + p0 += sp.delta - def sp_update(self, context, p0, p1): l0 = self.get_value(self.datablock, self.manipulator.prop1_name) length = (p0 - p1).length + + if state != 'CANCEL' and event.alt: + if event.shift: + length = round(length, 2) + else: + length = round(length, 1) + dp = length - l0 + if self.handle_left.active: dp = -dp dl = 0.5 * dp + + # snap_helper = context.object self.move(context, self.manipulator.prop2_name, dl) self.set_value(context, self.datablock, self.manipulator.prop1_name, length) self.move_linked(context, self.manipulator.prop2_name, dl) + # snapping child objects may require base object update + # eg manipulating windows requiring wall update + if self.snap_callback is not None: + snap_helper = context.active_object + self.snap_callback(context, o=self.o, manipulator=self) + snap_helper.select_set(state=True) + + if state != 'RUNNING': + self.mouse_release(context, event) + + logger.debug("SnapSizeLocationManipulator.sp_callback done") + class DeltaLocationManipulator(SizeManipulator): """ @@ -1388,7 +1336,6 @@ class DeltaLocationManipulator(SizeManipulator): ]) gl_pts3d = [p0] snap_point(takemat=takemat, - draw=self.sp_draw, callback=self.sp_callback, constraint_axis=( self.manipulator.prop1_name == 'x', @@ -1413,40 +1360,37 @@ class DeltaLocationManipulator(SizeManipulator): self.check_hover() return False - def sp_draw(self, sp, context): - global gl_pts3d - if self.o is None: - return - p0 = gl_pts3d[0].copy() - p1 = p0 + sp.delta - itM = self.o.matrix_world.inverted() - dl = self.get_value(itM * p1, self.manipulator.prop1_name) - self.move(context, self.manipulator.prop1_name, dl) - - # snapping child objects may require base object update - # eg manipulating windows requiring wall update - if self.snap_callback is not None: - snap_helper = context.active_object - self.snap_callback(context, o=self.o, manipulator=self) - context.scene.objects.active = snap_helper - - return - def sp_callback(self, context, event, state, sp): - - if state == 'SUCCESS': - self.sp_draw(sp, context) - self.mouse_release(context, event) + logger.debug("DeltaLocationManipulator.sp_callback") if state == 'CANCEL': self.cancel(context, event) + else: + global gl_pts3d + p0 = gl_pts3d[0].copy() + p1 = p0 + sp.delta + itM = self.o.matrix_world.inverted() + dl = self.get_value(itM @ p1, self.manipulator.prop1_name) + self.move(context, self.manipulator.prop1_name, dl) + + # snapping child objects may require base object update + # eg manipulating windows requiring wall update + if self.snap_callback is not None: + snap_helper = context.active_object + self.snap_callback(context, o=self.o, manipulator=self) + snap_helper.select_set(state=True) + + if state == 'SUCCESS': + self.mouse_release(context, event) + + logger.debug("DeltaLocationManipulator.sp_callback done") def cancel(self, context, event): if self.active: self.mouse_release(context, event) # must move back to original location itM = self.o.matrix_world.inverted() - dl = self.get_value(itM * self.original_location, self.manipulator.prop1_name) + dl = self.get_value(itM @ self.original_location, self.manipulator.prop1_name) self.move(context, self.manipulator.prop1_name, dl) def draw_callback(self, _self, context, render=False): @@ -1963,22 +1907,22 @@ class archipack_manipulator(PropertyGroup): p0, p1, p2 3d Vectors as base points to represent manipulators on screen normal Vector normal of plane on with draw manipulator """ - type_key = StringProperty(default='SIZE') + type_key : StringProperty(default='SIZE') # How 3d points are stored in manipulators ? # SIZE = 2 absolute positioned and a scaling vector # RADIUS = 1 absolute positioned (center) and 2 relatives (sides) # POLYGON = 2 absolute positioned and a relative vector (for rect polygons) - pts_mode = StringProperty(default='SIZE') - prop1_name = StringProperty() - prop2_name = StringProperty() - p0 = FloatVectorProperty(subtype='XYZ') - p1 = FloatVectorProperty(subtype='XYZ') - p2 = FloatVectorProperty(subtype='XYZ') + pts_mode : StringProperty(default='SIZE') + prop1_name : StringProperty() + prop2_name : StringProperty() + p0 : FloatVectorProperty(subtype='XYZ') + p1 : FloatVectorProperty(subtype='XYZ') + p2 : FloatVectorProperty(subtype='XYZ') # allow orientation of manipulators by default on xy plane, # but may be used to constrain heights on local object space - normal = FloatVectorProperty(subtype='XYZ', default=(0, 0, 1)) + normal : FloatVectorProperty(subtype='XYZ', default=(0, 0, 1)) def set_pts(self, pts, normal=None): """ @@ -1999,9 +1943,9 @@ class archipack_manipulator(PropertyGroup): """ rM = tM.to_3x3() if self.pts_mode in ['SIZE', 'POLYGON']: - return tM * self.p0, tM * self.p1, self.p2, rM * self.normal + return tM @ self.p0, tM @ self.p1, self.p2, rM @ self.normal else: - return tM * self.p0, rM * self.p1, rM * self.p2, rM * self.normal + return tM @ self.p0, rM @ self.p1, rM @ self.p2, rM @ self.normal def get_prefs(self, context): global __name__ @@ -2053,7 +1997,7 @@ class ARCHIPACK_OT_manipulate(Operator): bl_description = "Manipulate" bl_options = {'REGISTER', 'UNDO'} - object_name = StringProperty(default="") + object_name : StringProperty(default="") @classmethod def poll(self, context): @@ -2123,38 +2067,39 @@ class Manipulable(): Beware : prevent crash calling manipulable_disable() before changing manipulated data structure """ - manipulators = CollectionProperty( + manipulators : CollectionProperty( type=archipack_manipulator, # options={'SKIP_SAVE'}, # options={'HIDDEN'}, description="store 3d points to draw gl manipulators" ) - manipulable_refresh = BoolProperty( + + # TODO: make simple instance vars + manipulable_refresh : BoolProperty( default=False, options={'SKIP_SAVE'}, description="Flag enable to rebuild manipulators when data model change" ) - manipulate_mode = BoolProperty( + manipulate_mode : BoolProperty( default=False, options={'SKIP_SAVE'}, description="Flag manipulation state so we are able to toggle" ) - select_mode = BoolProperty( + select_mode : BoolProperty( default=False, options={'SKIP_SAVE'}, description="Flag select state so we are able to toggle" ) - manipulable_selectable = BoolProperty( + manipulable_selectable : BoolProperty( default=False, options={'SKIP_SAVE'}, description="Flag make manipulators selectable" ) - keymap = None - # selectable manipulators - manipulable_area = GlCursorArea() - manipulable_start_point = Vector((0, 0)) - manipulable_end_point = Vector((0, 0)) + keymap = None + manipulable_area = None + manipulable_start_point = None + manipulable_end_point = None manipulable_draw_handler = None def setup_manipulators(self): @@ -2171,6 +2116,13 @@ class Manipulable(): """ disable gl draw handlers """ + + if self.keymap is None: + self.keymap = Keymaps(context) + self.manipulable_area = GlCursorArea() + self.manipulable_start_point = Vector((0, 0)) + self.manipulable_end_point = Vector((0, 0)) + o = context.active_object if o is not None: self.manipulable_exit_selectmode(context) @@ -2259,6 +2211,7 @@ class Manipulable(): as it provide all needed functionality out of the box """ + # setup again when manipulators type change if self.manipulable_refresh: # print("manipulable_refresh") diff --git a/archipack/archipack_material.py b/archipack/archipack_material.py index ddb44009..2bcd3e40 100644 --- a/archipack/archipack_material.py +++ b/archipack/archipack_material.py @@ -181,7 +181,7 @@ class MatlibsManager(): def apply(self, context, slot_index, name, link=False): o = context.active_object - o.select = True + o.select_set(state=True) # material with same name exist in scene mat = self.from_data(name) @@ -367,12 +367,12 @@ def update(self, context): class archipack_material(PropertyGroup): - category = StringProperty( + category : StringProperty( name="Category", description="Archipack object name", default="" ) - material = EnumProperty( + material : EnumProperty( name="Material", description="Material Set name", items=material_enum, @@ -415,13 +415,13 @@ class archipack_material(PropertyGroup): return False for ob in sel: - context.scene.objects.active = ob + context.view_layer.objects.active = ob for slot_index, mat_name in enumerate(mats): if slot_index >= len(ob.material_slots): bpy.ops.object.material_slot_add() self.apply_material(context, slot_index, mat_name) - context.scene.objects.active = o + context.view_layer.objects.active = o return True @@ -431,7 +431,7 @@ class ARCHIPACK_PT_material(Panel): bl_label = "Archipack Material" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' - # bl_category = 'ArchiPack' + bl_category = 'Archipack' @classmethod def poll(cls, context): @@ -442,8 +442,8 @@ class ARCHIPACK_PT_material(Panel): props = context.active_object.archipack_material[0] row = layout.row(align=True) row.prop(props, 'material', text="") - row.operator('archipack.material_add', icon="ZOOMIN", text="") - row.operator('archipack.material_remove', icon="ZOOMOUT", text="") + row.operator('archipack.material_add', icon="ADD", text="") + row.operator('archipack.material_remove', icon="REMOVE", text="") class ARCHIPACK_OT_material(Operator): @@ -452,12 +452,12 @@ class ARCHIPACK_OT_material(Operator): bl_description = "Add archipack material" bl_options = {'REGISTER', 'UNDO'} - category = StringProperty( + category : StringProperty( name="Category", description="Archipack object name", default="" ) - material = StringProperty( + material : StringProperty( name="Material", description="Material Set name", default="" @@ -499,7 +499,7 @@ class ARCHIPACK_OT_material_add(Operator): bl_description = "Add a set of archipack material" bl_options = {'REGISTER', 'UNDO'} - material = StringProperty( + material : StringProperty( name="Material", description="Material Set name", default="" @@ -603,5 +603,5 @@ def unregister(): bpy.utils.unregister_class(ARCHIPACK_OT_material_add) bpy.utils.unregister_class(ARCHIPACK_OT_material_remove) bpy.utils.unregister_class(ARCHIPACK_OT_material_library) - bpy.utils.unregister_class(archipack_material) del Object.archipack_material + bpy.utils.unregister_class(archipack_material) diff --git a/archipack/archipack_object.py b/archipack/archipack_object.py index b479ea30..10da5be1 100644 --- a/archipack/archipack_object.py +++ b/archipack/archipack_object.py @@ -100,6 +100,7 @@ class ArchipackObject(): selected = context.selected_objects[:] for o in selected: + if self.__class__.datablock(o) == self: self.previously_selected = selected self.previously_active = active @@ -113,27 +114,41 @@ class ArchipackObject(): try: for o in self.previously_selected: - o.select = True + o.select_set(state=True) except: pass if self.previously_active is not None: - self.previously_active.select = True - context.scene.objects.active = self.previously_active + self.previously_active.select_set(state=True) + context.view_layer.objects.active = self.previously_active self.previously_selected = None self.previously_active = None + def move_object(self, o, p): + """ + When firstpoint is moving we must move object according + p is new x, y location in world coordsys + """ + p = Vector((p.x, p.y, o.matrix_world.translation.z)) + # p is in o coordsys + if o.parent: + o.location = p @ o.parent.matrix_world.inverted() + o.matrix_world.translation = p + else: + o.location = p + o.matrix_world.translation = p + class ArchipackCreateTool(): """ Shared property of archipack's create tool Operator """ - auto_manipulate = BoolProperty( + auto_manipulate : BoolProperty( name="Auto manipulate", description="Enable object's manipulators after create", options={'SKIP_SAVE'}, default=True ) - filepath = StringProperty( + filepath : StringProperty( options={'SKIP_SAVE'}, name="Preset", description="Full filename of python preset to load at create time", @@ -164,7 +179,10 @@ class ArchipackCreateTool(): if fallback: # fallback to load preset on background process try: - exec(compile(open(self.filepath).read(), self.filepath, 'exec')) + with open(self.filepath) as f: + lines = f.read() + cmp = compile(lines, self.filepath, 'exec') + exec(cmp) except: print("Archipack unable to load preset file : %s" % (self.filepath)) pass @@ -194,7 +212,7 @@ class ArchipackCreateTool(): pass -class ArchpackDrawTool(): +class ArchipackDrawTool(): """ Draw tools """ @@ -225,8 +243,9 @@ class ArchpackDrawTool(): view_vector_mouse = region_2d_to_vector_3d(region, rv3d, co2d) ray_origin_mouse = region_2d_to_origin_3d(region, rv3d, co2d) res, pos, normal, face_index, object, matrix_world = context.scene.ray_cast( - ray_origin_mouse, - view_vector_mouse) + view_layer=context.view_layer, + origin=ray_origin_mouse, + direction=view_vector_mouse) return res, pos, normal, face_index, object, matrix_world def mouse_hover_wall(self, context, event): @@ -245,5 +264,5 @@ class ArchpackDrawTool(): [x.y, y.y, z.y, pt.y], [x.z, y.z, z.z, o.matrix_world.translation.z], [0, 0, 0, 1] - ]), o, y - return False, Matrix(), None, Vector() + ]), o, d.width, y, 0 # d.z_offset + return False, Matrix(), None, 0, Vector(), 0 diff --git a/archipack/archipack_preset.py b/archipack/archipack_preset.py index dcaa7970..42668bb9 100644 --- a/archipack/archipack_preset.py +++ b/archipack/archipack_preset.py @@ -170,7 +170,9 @@ class PresetMenuItem(): def __init__(self, thumbsize, preset, image=None): name = bpy.path.display_name_from_filepath(preset) self.preset = preset - self.handle = ThumbHandle(thumbsize, name, image, draggable=True) + self.image = image + self.image.gl_load() + self.handle = ThumbHandle(thumbsize, name, self.image, draggable=True) self.enable = True def filter(self, keywords): @@ -179,6 +181,11 @@ class PresetMenuItem(): return False return True + def cleanup(self): + if self.image: + self.image.gl_free() + # bpy.data.images.remove(self.image) + def set_pos(self, context, pos): self.handle.set_pos(context, pos) @@ -268,12 +275,15 @@ class PresetMenu(): return file_list def clearImages(self): + for item in self.menuItems: + item.cleanup() for image in bpy.data.images: if image.filepath_raw in self.imageList: # image.user_clear() bpy.data.images.remove(image, do_unlink=True) self.imageList.clear() + def make_menuitem(self, filepath): """ @TODO: @@ -377,7 +387,7 @@ class PresetMenu(): class PresetMenuOperator(): - preset_operator = StringProperty( + preset_operator : StringProperty( options={'SKIP_SAVE'}, default="script.execute_preset" ) @@ -414,7 +424,11 @@ class PresetMenuOperator(): if self.preset_operator == 'script.execute_preset': # call from preset menu # ensure right active_object class - d = getattr(bpy.types, self.preset_subdir).datablock(context.active_object) + o = context.active_object + if o.data and self.preset_subdir in o.data: + d = getattr(o.data, self.preset_subdir)[0] + elif self.preset_subdir in o: + d = getattr(o, self.preset_subdir)[0] if d is not None: d.auto_update = False # print("Archipack execute_preset loading auto_update:%s" % d.auto_update) @@ -525,16 +539,22 @@ class ArchipackPreset(AddPresetBase): def background_render(self, context, cls, preset): generator = os.path.dirname(os.path.realpath(__file__)) + os.path.sep + "archipack_thumbs.py" + addon_name = __name__.split('.')[0] + matlib_path = context.user_preferences.addons[addon_name].preferences.matlib_path # Run external instance of blender like the original thumbnail generator. cmd = [ bpy.app.binary_path, "--background", + "--factory-startup", "-noaudio", + # "--addons", addon_name, "--python", generator, "--", + "addon:" + addon_name, + "matlib:" + matlib_path, "cls:" + cls, "preset:" + preset - ] + ] # print(repr(cmd)) subprocess.Popen(cmd) @@ -555,7 +575,7 @@ class ArchipackPreset(AddPresetBase): preset = os.path.join(target_path, filename) + ".py" cls = self.preset_subdir[10:] - print("post cb cls:%s preset:%s" % (cls, preset)) + # print("post cb cls:%s preset:%s" % (cls, preset)) self.background_render(context, cls, preset) return diff --git a/archipack/archipack_reference_point.py b/archipack/archipack_reference_point.py index 2f58c088..fe27b224 100644 --- a/archipack/archipack_reference_point.py +++ b/archipack/archipack_reference_point.py @@ -41,22 +41,22 @@ def update(self, context): class archipack_reference_point(PropertyGroup): - location_2d = FloatVectorProperty( + location_2d : FloatVectorProperty( subtype='XYZ', name="position 2d", default=Vector((0, 0, 0)) ) - location_3d = FloatVectorProperty( + location_3d : FloatVectorProperty( subtype='XYZ', name="position 3d", default=Vector((0, 0, 0)) ) - symbol_scale = FloatProperty( + symbol_scale : FloatProperty( name="Screen scale", default=1, min=0.01, update=update) - symbol_type = EnumProperty( + symbol_type : EnumProperty( name="Symbol type", default='WALL', items=( @@ -177,7 +177,7 @@ class ARCHIPACK_PT_reference_point(Panel): bl_label = "Reference point" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' - bl_category = 'ArchiPack' + bl_category = 'Archipack' @classmethod def poll(cls, context): @@ -206,12 +206,12 @@ class ARCHIPACK_OT_reference_point(Operator): bl_description = "Add reference point" bl_category = 'Archipack' bl_options = {'REGISTER', 'UNDO'} - location_3d = FloatVectorProperty( + location_3d : FloatVectorProperty( subtype='XYZ', name="position 3d", default=Vector((0, 0, 0)) ) - symbol_type = EnumProperty( + symbol_type : EnumProperty( name="Symbol type", default='WALL', items=( @@ -226,7 +226,7 @@ class ARCHIPACK_OT_reference_point(Operator): def draw(self, context): layout = self.layout row = layout.row() - row.label("Use Properties panel (N) to define parms", icon='INFO') + row.label(text="Use Properties panel (N) to define parms", icon='INFO') def create(self, context): x, y, z = context.scene.cursor_location @@ -234,21 +234,21 @@ class ARCHIPACK_OT_reference_point(Operator): m = bpy.data.meshes.new(name="Reference") o = bpy.data.objects.new("Reference", m) o.location = Vector((x, y, 0)) - context.scene.objects.link(o) + context.scene.collection.objects.link(o) d = o.archipack_reference_point.add() d.location_2d = Vector((x, y, 0)) d.location_3d = self.location_3d d.symbol_type = self.symbol_type - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o d.update(context) return o def execute(self, context): if context.mode == "OBJECT": o = self.create(context) - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o return {'FINISHED'} else: self.report({'WARNING'}, "Archipack: Option only valid in Object mode") @@ -298,7 +298,7 @@ class ARCHIPACK_OT_apply_holes(Operator): ctx['modifier'] = mod try: bpy.ops.object.modifier_apply(ctx, apply_as='DATA', - modifier=ctx['modifier'].name) + modifier=mod.name) except: pass @@ -327,12 +327,12 @@ class ARCHIPACK_OT_apply_holes(Operator): bpy.ops.object.select_all(action="DESELECT") for r in to_remove: r.hide_select = False - r.select = True - context.scene.objects.active = r + r.select_set(state=True) + context.view_layer.objects.active = r bpy.ops.object.delete(use_global=False) - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o return {'FINISHED'} else: @@ -410,9 +410,9 @@ class ARCHIPACK_OT_move_2d_reference_to_cursor(Operator): bpy.ops.object.select_all(action="DESELECT") bpy.ops.archipack.reference_point(location_3d=props.location_3d) for child in o.children: - child.select = True + child.select_set(state=True) bpy.ops.archipack.parent_to_reference() - context.scene.objects.unlink(o) + context.scene.collection.objects.unlink(o) return {'FINISHED'} else: self.report({'WARNING'}, "Archipack: Option only valid in Object mode") @@ -441,7 +441,7 @@ class ARCHIPACK_OT_parent_to_reference(Operator): # print("parent_to_reference parenting:%s objects" % (len(sel))) for child in sel: rs = child.matrix_world.to_3x3().to_4x4() - loc = itM * child.matrix_world.translation + loc = itM @ child.matrix_world.translation child.parent = None child.matrix_parent_inverse.identity() child.location = Vector((0, 0, 0)) diff --git a/archipack/archipack_rendering.py b/archipack/archipack_rendering.py index 8ea06ef9..533afffc 100644 --- a/archipack/archipack_rendering.py +++ b/archipack/archipack_rendering.py @@ -31,15 +31,14 @@ import bpy # noinspection PyUnresolvedReferences import bgl from shutil import copyfile -from os import path, remove, listdir -from sys import exc_info +from os import path, listdir import subprocess # noinspection PyUnresolvedReferences import bpy_extras.image_utils as img_utils # noinspection PyUnresolvedReferences from math import ceil from bpy.types import Operator -from bl_ui import properties_render +# from bl_ui import properties_render class ARCHIPACK_OT_render_thumbs(Operator): @@ -51,8 +50,8 @@ class ARCHIPACK_OT_render_thumbs(Operator): @classmethod def poll(cls, context): # Ensure CYCLES engine is available - return context.scene.archipack_progress < 0 and \ - 'CYCLES' in properties_render.RENDER_PT_render.COMPAT_ENGINES + # hasattr(context.scene, 'cycles') + return context.scene def background_render(self, context, cls, preset): generator = path.dirname(path.realpath(__file__)) + path.sep + "archipack_thumbs.py" @@ -64,6 +63,7 @@ class ARCHIPACK_OT_render_thumbs(Operator): "--background", "--factory-startup", "-noaudio", + # "--addons", addon_name, "--python", generator, "--", "addon:" + addon_name, @@ -71,6 +71,9 @@ class ARCHIPACK_OT_render_thumbs(Operator): "cls:" + cls, "preset:" + preset ] + + # print(" ".join(cmd)) + popen = subprocess.Popen(cmd, stdout=subprocess.PIPE, universal_newlines=True) for stdout_line in iter(popen.stdout.readline, ""): yield stdout_line @@ -158,12 +161,16 @@ class ARCHIPACK_OT_render_thumbs(Operator): for i, preset in enumerate(file_list): dir, file = preset cls = dir[10:] - context.scene.archipack_progress = (100 * i / ttl) + # context.scene.archipack_progress = (100 * i / ttl) + log_all = False for l in self.background_render(context, cls, file + ".py"): if "[log]" in l: print(l[5:].strip()) - # elif not "Fra:1" in l: - # print(l.strip()) + elif "blender.crash" in l: + print("Unexpected error") + log_all = True + if log_all: + print(l.strip()) def invoke(self, context, event): addon_name = __name__.split('.')[0] @@ -174,504 +181,16 @@ class ARCHIPACK_OT_render_thumbs(Operator): return context.window_manager.invoke_confirm(self, event) def execute(self, context): - context.scene.archipack_progress_text = 'Generating thumbs' - context.scene.archipack_progress = 0 + # context.scene.archipack_progress_text = 'Generating thumbs' + # context.scene.archipack_progress = 0 self.rebuild_thumbs(context) - context.scene.archipack_progress = -1 + # context.scene.archipack_progress = -1 return {'FINISHED'} -# ------------------------------------------------------------- -# Defines button for render -# -# ------------------------------------------------------------- -class ARCHIPACK_OT_render(Operator): - bl_idname = "archipack.render" - bl_label = "Render" - bl_category = 'Archipack' - bl_description = "Create a render image with measures. Use UV/Image editor to view image generated" - bl_category = 'Archipack' - - # -------------------------------------------------------------------- - # Get the final render image and return as image object - # - # return None if no render available - # -------------------------------------------------------------------- - - def get_render_image(self, outpath): - saved = False - # noinspection PyBroadException - try: - # noinspection PyBroadException - try: - result = bpy.data.images['Render Result'] - if result.has_data is False: - # this save produce to fill data image - result.save_render(outpath) - saved = True - except: - print("No render image found") - return None - - # Save and reload - if saved is False: - result.save_render(outpath) - - img = img_utils.load_image(outpath) - - return img - except: - print("Unexpected render image error") - return None - - # ------------------------------------- - # Save image to file - # ------------------------------------- - - def save_image(self, filepath, myimage): - # noinspection PyBroadException - try: - - # Save old info - settings = bpy.context.scene.render.image_settings - myformat = settings.file_format - mode = settings.color_mode - depth = settings.color_depth - - # Apply new info and save - settings.file_format = 'PNG' - settings.color_mode = "RGBA" - settings.color_depth = '8' - myimage.save_render(filepath) - print("Archipack: Image " + filepath + " saved") - - # Restore old info - settings.file_format = myformat - settings.color_mode = mode - settings.color_depth = depth - except: - print("Unexpected error:" + str(exc_info())) - self.report({'ERROR'}, "Archipack: Unable to save render image") - return - - # ------------------------------------------------------------- - # Render image main entry point - # - # ------------------------------------------------------------- - - def render_main(self, context, objlist, animation=False): - # noinspection PyBroadException,PyBroadException - # Save old info - scene = context.scene - render = scene.render - settings = render.image_settings - depth = settings.color_depth - settings.color_depth = '8' - # noinspection PyBroadException - try: - - # Get visible layers - layers = [] - for x in range(0, 20): - if scene.layers[x] is True: - layers.extend([x]) - - # -------------------- - # Get resolution - # -------------------- - render_scale = render.resolution_percentage / 100 - - width = int(render.resolution_x * render_scale) - height = int(render.resolution_y * render_scale) - # --------------------------------------- - # Get output path - # --------------------------------------- - temp_path = path.realpath(bpy.app.tempdir) - if len(temp_path) > 0: - outpath = path.join(temp_path, "archipack_tmp_render.png") - else: - self.report({'ERROR'}, - "Archipack: Unable to save temporary render image. Define a valid temp path") - settings.color_depth = depth - return False - - # Get Render Image - img = self.get_render_image(outpath) - if img is None: - self.report({'ERROR'}, - "Archipack: Unable to save temporary render image. Define a valid temp path") - settings.color_depth = depth - return False - - # ----------------------------- - # Calculate rows and columns - # ----------------------------- - tile_x = 240 - tile_y = 216 - row_num = ceil(height / tile_y) - col_num = ceil(width / tile_x) - print("Archipack: Image divided in " + str(row_num) + "x" + str(col_num) + " tiles") - - # pixels out of visible area - cut4 = (col_num * tile_x * 4) - width * 4 # pixels aout of drawing area - totpixel4 = width * height * 4 # total pixels RGBA - - viewport_info = bgl.Buffer(bgl.GL_INT, 4) - bgl.glGetIntegerv(bgl.GL_VIEWPORT, viewport_info) - - # Load image on memory - img.gl_load(0, bgl.GL_NEAREST, bgl.GL_NEAREST) - - # 2.77 API change - if bpy.app.version >= (2, 77, 0): - tex = img.bindcode[0] - else: - tex = img.bindcode - - # -------------------------------------------- - # Create output image (to apply texture) - # -------------------------------------------- - if "archipack_output" in bpy.data.images: - out_img = bpy.data.images["archipack_output"] - if out_img is not None: - # out_img.user_clear() - bpy.data.images.remove(out_img, do_unlink=True) - - out = bpy.data.images.new("archipack_output", width, height) - tmp_pixels = [1] * totpixel4 - - # -------------------------------- - # Loop for all tiles - # -------------------------------- - for row in range(0, row_num): - for col in range(0, col_num): - buffer = bgl.Buffer(bgl.GL_FLOAT, width * height * 4) - bgl.glDisable(bgl.GL_SCISSOR_TEST) # if remove this line, get blender screenshot not image - bgl.glViewport(0, 0, tile_x, tile_y) - - bgl.glMatrixMode(bgl.GL_PROJECTION) - bgl.glLoadIdentity() - - # defines ortographic view for single tile - x1 = tile_x * col - y1 = tile_y * row - bgl.gluOrtho2D(x1, x1 + tile_x, y1, y1 + tile_y) - - # Clear - bgl.glClearColor(0.0, 0.0, 0.0, 0.0) - bgl.glClear(bgl.GL_COLOR_BUFFER_BIT | bgl.GL_DEPTH_BUFFER_BIT) - - bgl.glEnable(bgl.GL_TEXTURE_2D) - bgl.glBindTexture(bgl.GL_TEXTURE_2D, tex) - - # defines drawing area - bgl.glBegin(bgl.GL_QUADS) - - bgl.glColor3f(1.0, 1.0, 1.0) - bgl.glTexCoord2f(0.0, 0.0) - bgl.glVertex2f(0.0, 0.0) - - bgl.glTexCoord2f(1.0, 0.0) - bgl.glVertex2f(width, 0.0) - - bgl.glTexCoord2f(1.0, 1.0) - bgl.glVertex2f(width, height) - - bgl.glTexCoord2f(0.0, 1.0) - bgl.glVertex2f(0.0, height) - - bgl.glEnd() - - # ----------------------------- - # Loop to draw all lines - # ----------------------------- - for o, d in objlist: - if o.hide is False: - # verify visible layer - for x in range(0, 20): - if o.layers[x] is True: - if x in layers: - context.scene.objects.active = o - # print("%s: %s" % (o.name, d.manip_stack)) - manipulators = d.manip_stack - if manipulators is not None: - for m in manipulators: - if m is not None: - m.draw_callback(m, context, render=True) - break - - # ----------------------------- - # Loop to draw all debug - # ----------------------------- - """ - if scene.archipack_debug is True: - selobj = bpy.context.selected_objects - for myobj in selobj: - if scene.archipack_debug_vertices is True: - draw_vertices(context, myobj, None, None) - if scene.archipack_debug_faces is True or scene.archipack_debug_normals is True: - draw_faces(context, myobj, None, None) - """ - """ - if scene.archipack_rf is True: - bgl.glColor3f(1.0, 1.0, 1.0) - rfcolor = scene.archipack_rf_color - rfborder = scene.archipack_rf_border - rfline = scene.archipack_rf_line - - bgl.glLineWidth(rfline) - bgl.glColor4f(rfcolor[0], rfcolor[1], rfcolor[2], rfcolor[3]) - - x1 = rfborder - x2 = width - rfborder - y1 = int(ceil(rfborder / (width / height))) - y2 = height - y1 - draw_rectangle((x1, y1), (x2, y2)) - """ - # -------------------------------- - # copy pixels to temporary area - # -------------------------------- - bgl.glFinish() - bgl.glReadPixels(0, 0, width, height, bgl.GL_RGBA, bgl.GL_FLOAT, buffer) # read image data - for y in range(0, tile_y): - # final image pixels position - p1 = (y * width * 4) + (row * tile_y * width * 4) + (col * tile_x * 4) - p2 = p1 + (tile_x * 4) - # buffer pixels position - b1 = y * width * 4 - b2 = b1 + (tile_x * 4) - - if p1 < totpixel4: # avoid pixel row out of area - if col == col_num - 1: # avoid pixel columns out of area - p2 -= cut4 - b2 -= cut4 - - tmp_pixels[p1:p2] = buffer[b1:b2] - - # ----------------------- - # Copy temporary to final - # ----------------------- - out.pixels = tmp_pixels[:] # Assign image data - img.gl_free() # free opengl image memory - - # delete image - # img.user_clear() - bpy.data.images.remove(img, do_unlink=True) - # remove temp file - remove(outpath) - # reset - bgl.glEnable(bgl.GL_SCISSOR_TEST) - # ----------------------- - # restore opengl defaults - # ----------------------- - bgl.glLineWidth(1) - bgl.glDisable(bgl.GL_BLEND) - bgl.glColor4f(0.0, 0.0, 0.0, 1.0) - # Saves image - if out is not None: - # and (scene.archipack_render is True or animation is True): - ren_path = bpy.context.scene.render.filepath - filename = "ap_frame" - if len(ren_path) > 0: - if ren_path.endswith(path.sep): - initpath = path.realpath(ren_path) + path.sep - else: - (initpath, filename) = path.split(ren_path) - - ftxt = "%04d" % scene.frame_current - outpath = path.realpath(path.join(initpath, filename + ftxt + ".png")) - - self.save_image(outpath, out) - - settings.color_depth = depth - return True - - except: - settings.color_depth = depth - print("Unexpected error:" + str(exc_info())) - self.report( - {'ERROR'}, - "Archipack: Unable to create render image. Be sure the output render path is correct" - ) - return False - - def get_objlist(self, context): - """ - Get objects with gl manipulators - """ - objlist = [] - for o in context.scene.objects: - if o.data is not None: - d = None - if 'archipack_window' in o.data: - d = o.data.archipack_window[0] - elif 'archipack_door' in o.data: - d = o.data.archipack_door[0] - elif 'archipack_wall2' in o.data: - d = o.data.archipack_wall2[0] - elif 'archipack_stair' in o.data: - d = o.data.archipack_stair[0] - elif 'archipack_fence' in o.data: - d = o.data.archipack_fence[0] - elif 'archipack_floor' in o.data: - d = o.data.archipack_floor[0] - elif 'archipack_roof' in o.data: - d = o.data.archipack_roof[0] - if d is not None: - objlist.append((o, d)) - return objlist - - def draw_gl(self, context): - objlist = self.get_objlist(context) - for o, d in objlist: - context.scene.objects.active = o - d.manipulable_disable(context) - d.manipulable_invoke(context) - return objlist - - def hide_gl(self, context, objlist): - for o, d in objlist: - context.scene.objects.active = o - d.manipulable_disable(context) - - # ------------------------------ - # Execute button action - # ------------------------------ - # noinspection PyMethodMayBeStatic,PyUnusedLocal - def execute(self, context): - scene = context.scene - wm = context.window_manager - msg = "New image created with measures. Open it in UV/image editor" - camera_msg = "Unable to render. No camera found" - - # ----------------------------- - # Check camera - # ----------------------------- - if scene.camera is None: - self.report({'ERROR'}, camera_msg) - return {'FINISHED'} - - objlist = self.draw_gl(context) - - # ----------------------------- - # Use current rendered image - # ----------------------------- - if wm.archipack.render_type == "1": - # noinspection PyBroadException - try: - result = bpy.data.images['Render Result'] - if result.has_data is False: - bpy.ops.render.render() - except: - bpy.ops.render.render() - - print("Archipack: Using current render image on buffer") - if self.render_main(context, objlist) is True: - self.report({'INFO'}, msg) - - # ----------------------------- - # OpenGL image - # ----------------------------- - elif wm.archipack.render_type == "2": - self.set_camera_view() - self.set_only_render(True) - - print("Archipack: Rendering opengl image") - bpy.ops.render.opengl() - if self.render_main(context, objlist) is True: - self.report({'INFO'}, msg) - - self.set_only_render(False) - - # ----------------------------- - # OpenGL Animation - # ----------------------------- - elif wm.archipack.render_type == "3": - oldframe = scene.frame_current - self.set_camera_view() - self.set_only_render(True) - flag = False - # loop frames - for frm in range(scene.frame_start, scene.frame_end + 1): - scene.frame_set(frm) - print("Archipack: Rendering opengl frame %04d" % frm) - bpy.ops.render.opengl() - flag = self.render_main(context, objlist, True) - if flag is False: - break - - self.set_only_render(False) - scene.frame_current = oldframe - if flag is True: - self.report({'INFO'}, msg) - - # ----------------------------- - # Image - # ----------------------------- - elif wm.archipack.render_type == "4": - print("Archipack: Rendering image") - bpy.ops.render.render() - if self.render_main(context, objlist) is True: - self.report({'INFO'}, msg) - - # ----------------------------- - # Animation - # ----------------------------- - elif wm.archipack.render_type == "5": - oldframe = scene.frame_current - flag = False - # loop frames - for frm in range(scene.frame_start, scene.frame_end + 1): - scene.frame_set(frm) - print("Archipack: Rendering frame %04d" % frm) - bpy.ops.render.render() - flag = self.render_main(context, objlist, True) - if flag is False: - break - - scene.frame_current = oldframe - if flag is True: - self.report({'INFO'}, msg) - - self.hide_gl(context, objlist) - - return {'FINISHED'} - - # --------------------- - # Set cameraView - # --------------------- - # noinspection PyMethodMayBeStatic - def set_camera_view(self): - for area in bpy.context.screen.areas: - if area.type == 'VIEW_3D': - area.spaces[0].region_3d.view_perspective = 'CAMERA' - - # ------------------------------------- - # Set only render status - # ------------------------------------- - # noinspection PyMethodMayBeStatic - def set_only_render(self, status): - screen = bpy.context.screen - - v3d = False - s = None - # get spaceview_3d in current screen - for a in screen.areas: - if a.type == 'VIEW_3D': - for s in a.spaces: - if s.type == 'VIEW_3D': - v3d = s - break - - if v3d is not False: - s.show_only_render = status - - def register(): - bpy.utils.register_class(ARCHIPACK_OT_render) bpy.utils.register_class(ARCHIPACK_OT_render_thumbs) def unregister(): - bpy.utils.unregister_class(ARCHIPACK_OT_render) bpy.utils.unregister_class(ARCHIPACK_OT_render_thumbs) diff --git a/archipack/archipack_roof.py b/archipack/archipack_roof.py index 7d396d36..5ab21a38 100644 --- a/archipack/archipack_roof.py +++ b/archipack/archipack_roof.py @@ -1564,7 +1564,7 @@ class RoofGenerator(CutAbleGenerator): use_dissolve_boundaries=False, verts=bm.verts, edges=bm.edges, - delimit=1) + delimit={'MATERIAL'}) geom = bm.faces[:] verts = bm.verts[:] @@ -1595,7 +1595,7 @@ class RoofGenerator(CutAbleGenerator): BEVEL_AMT_PERCENT }; """ - offset_type = 3 + offset_type = 'PERCENT' if d.tile_offset > 0: offset = - d.tile_offset / 100 @@ -1694,8 +1694,8 @@ class RoofGenerator(CutAbleGenerator): step = 100 / ttl - if d.quick_edit: - context.scene.archipack_progress_text = "Build tiles:" + # if d.quick_edit: + # context.scene.archipack_progress_text = "Build tiles:" for i, pan in enumerate(self.pans): @@ -1742,8 +1742,8 @@ class RoofGenerator(CutAbleGenerator): progress = step * i + substep * k # print("progress %s" % (progress)) - if d.quick_edit: - context.scene.archipack_progress = progress + # if d.quick_edit: + # context.scene.archipack_progress = progress y = k * dy @@ -1759,7 +1759,7 @@ class RoofGenerator(CutAbleGenerator): for j in range(nx): x = x0 + j * dx - lM = tM * Matrix([ + lM = tM @ Matrix([ [sx, 0, 0, x], [0, sy, 0, -y], [0, 0, sz, 0], @@ -1768,7 +1768,7 @@ class RoofGenerator(CutAbleGenerator): v = len(verts) - verts.extend([lM * p for p in t_pts]) + verts.extend([lM @ p for p in t_pts]) faces.extend([tuple(i + v for i in f) for f in t_faces]) mid = randint(idmat, idmat + rand) t_mats = [mid for i in range(n_faces)] @@ -1847,7 +1847,7 @@ class RoofGenerator(CutAbleGenerator): segs[-1].p1 = p f_geom = [f for f in bm.faces if not pan.inside(f.calc_center_median().to_2d(), segs)] if len(f_geom) > 0: - bmesh.ops.delete(bm, geom=f_geom, context=5) + bmesh.ops.delete(bm, geom=f_geom, context="FACES") self.cut_holes(bm, pan) @@ -1856,7 +1856,7 @@ class RoofGenerator(CutAbleGenerator): use_dissolve_boundaries=False, verts=bm.verts[:], edges=bm.edges[:], - delimit=1) + delimit={'MATERIAL'}) if d.tile_bevel: geom = bm.verts[:] @@ -1868,7 +1868,7 @@ class RoofGenerator(CutAbleGenerator): segments=d.tile_bevel_segs, profile=0.5, vertex_only=False, - clight_overlap=True, + clamp_overlap=True, material=-1) if d.tile_solidify: @@ -1881,8 +1881,8 @@ class RoofGenerator(CutAbleGenerator): bmed.bmesh_join(context, o, [bm], normal_update=True) bpy.ops.object.mode_set(mode='OBJECT') - if d.quick_edit: - context.scene.archipack_progress = -1 + # if d.quick_edit: + # context.scene.archipack_progress = -1 def _bargeboard(self, s, i, boundary, pan, width, height, altitude, offset, idmat, @@ -2774,7 +2774,7 @@ class RoofGenerator(CutAbleGenerator): use_dissolve_boundaries=False, verts=bm.verts, edges=bm.edges, - delimit=1) + delimit={'MATERIAL'}) geom = bm.faces[:] verts = bm.verts[:] @@ -3040,7 +3040,7 @@ class RoofGenerator(CutAbleGenerator): t_verts[i].z += dz * t_verts[i].y for k in range(n_x): - lM = tM * Matrix([ + lM = tM @ Matrix([ [1, 0, 0, x0 + k * dx], [0, -1, 0, 0], [0, 0, 1, 0], @@ -3048,7 +3048,7 @@ class RoofGenerator(CutAbleGenerator): ]) f = len(verts) - verts.extend([lM * p for p in t_verts]) + verts.extend([lM @ p for p in t_verts]) faces.extend([tuple(i + f for i in p) for p in t_faces]) matids.extend(t_idmats) uvs.extend(t_uvs) @@ -3132,14 +3132,14 @@ class RoofGenerator(CutAbleGenerator): t_verts[i].z -= t_verts[i].y * (pan.slope - d.tile_size_z / d.tile_size_y) for k in range(n_obj): - lM = tM * Matrix([ + lM = tM @ Matrix([ [1, 0, 0, x0 + k * dx], [0, -1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1] ]) v = len(verts) - verts.extend([lM * p for p in t_verts]) + verts.extend([lM @ p for p in t_verts]) faces.extend([tuple(i + v for i in f) for f in t_faces]) matids.extend(t_idmats) uvs.extend(t_uvs) @@ -3243,19 +3243,19 @@ class RoofGenerator(CutAbleGenerator): pts = [p.to_3d() for p in pts] if hole_obj is None: - context.scene.objects.active = o.parent + context.view_layer.objects.active = o.parent bpy.ops.archipack.roof_cutter(parent=d.t_parent, auto_manipulate=False) hole_obj = context.active_object else: - context.scene.objects.active = hole_obj + context.view_layer.objects.active = hole_obj - hole_obj.select = True + hole_obj.select_set(state=True) if d.parts[0].a0 < 0: y = -d.t_dist_y else: y = d.t_dist_y - hole_obj.matrix_world = o.matrix_world * Matrix([ + hole_obj.matrix_world = o.matrix_world @ Matrix([ [1, 0, 0, 0], [0, 1, 0, y], [0, 0, 1, 0], @@ -3265,15 +3265,15 @@ class RoofGenerator(CutAbleGenerator): hd = archipack_roof_cutter.datablock(hole_obj) hd.boundary = o.name hd.update_points(context, hole_obj, pts, update_parent=update_parent) - hole_obj.select = False + hole_obj.select_set(state=False) - context.scene.objects.active = o + context.view_layer.objects.active = o def change_coordsys(self, fromTM, toTM): """ move shape fromTM into toTM coordsys """ - dp = (toTM.inverted() * fromTM.translation).to_2d() + dp = (toTM.inverted() @ fromTM.translation).to_2d() da = toTM.row[1].to_2d().angle_signed(fromTM.row[1].to_2d()) ca = cos(da) sa = sin(da) @@ -3282,7 +3282,7 @@ class RoofGenerator(CutAbleGenerator): [sa, ca] ]) for s in self.segs: - tp = (rM * s.p0) - s.p0 + dp + tp = (rM @ s.p0) - s.p0 + dp s.rotate(da) s.translate(tp) @@ -3357,9 +3357,9 @@ class RoofGenerator(CutAbleGenerator): wall_t[widx].append((0, z, 0)) old = context.active_object - old_sel = wall.select - wall.select = True - context.scene.objects.active = wall + old_sel = wall.select_get() + wall.select_set(state=True) + context.view_layer.objects.active = wall wd.auto_update = False # setup splits count and first split to 0 @@ -3412,8 +3412,8 @@ class RoofGenerator(CutAbleGenerator): for s in wg.segs: s.as_curve(context) """ - wall.select = old_sel - context.scene.objects.active = old + wall.select_set(state=old_sel) + context.view_layer.objects.active = old def boundary(self, context, o): """ @@ -3494,14 +3494,14 @@ def update_components(self, context): class ArchipackSegment(): - length = FloatProperty( + length : FloatProperty( name="Length", min=0.01, max=1000.0, default=4.0, update=update ) - a0 = FloatProperty( + a0 : FloatProperty( name="Angle", min=-2 * pi, max=2 * pi, @@ -3509,17 +3509,17 @@ class ArchipackSegment(): subtype='ANGLE', unit='ROTATION', update=update_cutter ) - manipulators = CollectionProperty(type=archipack_manipulator) + manipulators : CollectionProperty(type=archipack_manipulator) class ArchipackLines(): - n_parts = IntProperty( + n_parts : IntProperty( name="Parts", min=1, default=1, update=update_manipulators ) # UI layout related - parts_expand = BoolProperty( + parts_expand : BoolProperty( default=False ) @@ -3580,37 +3580,37 @@ class ArchipackLines(): class archipack_roof_segment(ArchipackSegment, PropertyGroup): - bound_idx = IntProperty( + bound_idx : IntProperty( name="Link to", default=0, min=0, update=update_manipulators ) - width_left = FloatProperty( + width_left : FloatProperty( name="L Width", min=0.01, default=3.0, update=update_cutter ) - width_right = FloatProperty( + width_right : FloatProperty( name="R Width", min=0.01, default=3.0, update=update_cutter ) - slope_left = FloatProperty( + slope_left : FloatProperty( name="L slope", min=0.0, default=0.3, update=update_cutter ) - slope_right = FloatProperty( + slope_right : FloatProperty( name="R slope", min=0.0, default=0.3, update=update_cutter ) - auto_left = EnumProperty( + auto_left : EnumProperty( description="Left mode", name="Left", items=( @@ -3622,7 +3622,7 @@ class archipack_roof_segment(ArchipackSegment, PropertyGroup): default="AUTO", update=update_manipulators ) - auto_right = EnumProperty( + auto_right : EnumProperty( description="Right mode", name="Right", items=( @@ -3634,19 +3634,19 @@ class archipack_roof_segment(ArchipackSegment, PropertyGroup): default="AUTO", update=update_manipulators ) - triangular_end = BoolProperty( + triangular_end : BoolProperty( name="Triangular end", default=False, update=update ) - take_precedence = BoolProperty( + take_precedence : BoolProperty( name="Take precedence", description="On T segment take width precedence", default=False, update=update ) - constraint_type = EnumProperty( + constraint_type : EnumProperty( items=( ('HORIZONTAL', 'Horizontal', '', 0), ('SLOPE', 'Slope', '', 1) @@ -3655,7 +3655,7 @@ class archipack_roof_segment(ArchipackSegment, PropertyGroup): update=update_manipulators ) - enforce_part = EnumProperty( + enforce_part : EnumProperty( name="Enforce part", items=( ('AUTO', 'Auto', '', 0), @@ -3687,7 +3687,7 @@ class archipack_roof_segment(ArchipackSegment, PropertyGroup): if self.constraint_type == 'SLOPE': box.prop(self, "enforce_part", text="") else: - box.label("Part 1:") + box.label(text="Part 1:") box.prop(self, "length") box.prop(self, "a0") @@ -3720,63 +3720,63 @@ class archipack_roof_segment(ArchipackSegment, PropertyGroup): class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup): - parts = CollectionProperty(type=archipack_roof_segment) - z = FloatProperty( + parts : CollectionProperty(type=archipack_roof_segment) + z : FloatProperty( name="Altitude", default=3, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update_childs ) - slope_left = FloatProperty( + slope_left : FloatProperty( name="L slope", default=0.5, precision=2, step=1, update=update_childs ) - slope_right = FloatProperty( + slope_right : FloatProperty( name="R slope", default=0.5, precision=2, step=1, update=update_childs ) - width_left = FloatProperty( + width_left : FloatProperty( name="L width", default=3, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update_cutter ) - width_right = FloatProperty( + width_right : FloatProperty( name="R width", default=3, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update_cutter ) - draft = BoolProperty( + draft : BoolProperty( options={'SKIP_SAVE'}, name="Draft mode", default=False, update=update_manipulators ) - auto_update = BoolProperty( + auto_update : BoolProperty( options={'SKIP_SAVE'}, default=True, update=update_manipulators ) - quick_edit = BoolProperty( + quick_edit : BoolProperty( options={'SKIP_SAVE'}, name="Quick Edit", - default=True + default=False ) - tile_enable = BoolProperty( + tile_enable : BoolProperty( name="Enable", default=True, update=update_components ) - tile_solidify = BoolProperty( + tile_solidify : BoolProperty( name="Solidify", default=True, update=update_components ) - tile_height = FloatProperty( + tile_height : FloatProperty( name="Height", description="Amount for solidify", min=0, @@ -3784,12 +3784,12 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup unit='LENGTH', subtype='DISTANCE', update=update_components ) - tile_bevel = BoolProperty( + tile_bevel : BoolProperty( name="Bevel", default=False, update=update_components ) - tile_bevel_amt = FloatProperty( + tile_bevel_amt : FloatProperty( name="Amount", description="Amount for bevel", min=0, @@ -3797,19 +3797,19 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup unit='LENGTH', subtype='DISTANCE', update=update_components ) - tile_bevel_segs = IntProperty( + tile_bevel_segs : IntProperty( name="Segs", description="Bevel Segs", min=1, default=2, update=update_components ) - tile_alternate = BoolProperty( + tile_alternate : BoolProperty( name="Alternate", default=False, update=update_components ) - tile_offset = FloatProperty( + tile_offset : FloatProperty( name="Offset", description="Offset from start", min=0, @@ -3817,14 +3817,14 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup subtype="PERCENTAGE", update=update_components ) - tile_altitude = FloatProperty( + tile_altitude : FloatProperty( name="Altitude", description="Altitude from roof", default=0.1, unit='LENGTH', subtype='DISTANCE', update=update_components ) - tile_size_x = FloatProperty( + tile_size_x : FloatProperty( name="Width", description="Size of tiles on x axis", min=0.01, @@ -3832,7 +3832,7 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup unit='LENGTH', subtype='DISTANCE', update=update_components ) - tile_size_y = FloatProperty( + tile_size_y : FloatProperty( name="Length", description="Size of tiles on y axis", min=0.01, @@ -3840,7 +3840,7 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup unit='LENGTH', subtype='DISTANCE', update=update_components ) - tile_size_z = FloatProperty( + tile_size_z : FloatProperty( name="Thickness", description="Size of tiles on z axis", min=0.0, @@ -3848,7 +3848,7 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup unit='LENGTH', subtype='DISTANCE', update=update_components ) - tile_space_x = FloatProperty( + tile_space_x : FloatProperty( name="Width", description="Space between tiles on x axis", min=0.01, @@ -3856,7 +3856,7 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup unit='LENGTH', subtype='DISTANCE', update=update_components ) - tile_space_y = FloatProperty( + tile_space_y : FloatProperty( name="Length", description="Space between tiles on y axis", min=0.01, @@ -3864,25 +3864,25 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup unit='LENGTH', subtype='DISTANCE', update=update_components ) - tile_fit_x = BoolProperty( + tile_fit_x : BoolProperty( name="Fit x", description="Fit roof on x axis", default=True, update=update_components ) - tile_fit_y = BoolProperty( + tile_fit_y : BoolProperty( name="Fit y", description="Fit roof on y axis", default=True, update=update_components ) - tile_expand = BoolProperty( + tile_expand : BoolProperty( options={'SKIP_SAVE'}, name="Tiles", description="Expand tiles panel", default=False ) - tile_model = EnumProperty( + tile_model : EnumProperty( name="Model", items=( ('BRAAS1', 'Braas 1', '', 0), @@ -3899,14 +3899,14 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup default="BRAAS2", update=update_components ) - tile_side = FloatProperty( + tile_side : FloatProperty( name="Side", description="Space on side", default=0, unit='LENGTH', subtype='DISTANCE', update=update_components ) - tile_couloir = FloatProperty( + tile_couloir : FloatProperty( name="Valley", description="Space between tiles on valley", min=0, @@ -3914,7 +3914,7 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup unit='LENGTH', subtype='DISTANCE', update=update_components ) - tile_border = FloatProperty( + tile_border : FloatProperty( name="Bottom", description="Tiles offset from bottom", default=0, @@ -3922,25 +3922,25 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup update=update_components ) - gutter_expand = BoolProperty( + gutter_expand : BoolProperty( options={'SKIP_SAVE'}, name="Gutter", description="Expand gutter panel", default=False ) - gutter_enable = BoolProperty( + gutter_enable : BoolProperty( name="Enable", default=True, update=update_components ) - gutter_alt = FloatProperty( + gutter_alt : FloatProperty( name="Altitude", description="altitude", default=0, unit='LENGTH', subtype='DISTANCE', update=update_components ) - gutter_width = FloatProperty( + gutter_width : FloatProperty( name="Width", description="Width", min=0.01, @@ -3948,7 +3948,7 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup unit='LENGTH', subtype='DISTANCE', update=update_components ) - gutter_dist = FloatProperty( + gutter_dist : FloatProperty( name="Spacing", description="Spacing", min=0, @@ -3956,7 +3956,7 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup unit='LENGTH', subtype='DISTANCE', update=update_components ) - gutter_boudin = FloatProperty( + gutter_boudin : FloatProperty( name="Small width", description="Small width", min=0, @@ -3964,25 +3964,25 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup unit='LENGTH', subtype='DISTANCE', update=update_components ) - gutter_segs = IntProperty( + gutter_segs : IntProperty( default=6, min=1, name="Segs", update=update_components ) - beam_expand = BoolProperty( + beam_expand : BoolProperty( options={'SKIP_SAVE'}, name="Beam", description="Expand beam panel", default=False ) - beam_enable = BoolProperty( + beam_enable : BoolProperty( name="Ridge pole", default=True, update=update_components ) - beam_width = FloatProperty( + beam_width : FloatProperty( name="Width", description="Width", min=0.01, @@ -3990,7 +3990,7 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup unit='LENGTH', subtype='DISTANCE', update=update_components ) - beam_height = FloatProperty( + beam_height : FloatProperty( name="Height", description="Height", min=0.01, @@ -3998,26 +3998,26 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup unit='LENGTH', subtype='DISTANCE', update=update_components ) - beam_offset = FloatProperty( + beam_offset : FloatProperty( name="Offset", description="Distance from roof border", default=0.02, unit='LENGTH', subtype='DISTANCE', update=update_components ) - beam_alt = FloatProperty( + beam_alt : FloatProperty( name="Altitude", description="Altitude from roof", default=-0.15, unit='LENGTH', subtype='DISTANCE', update=update_components ) - beam_sec_enable = BoolProperty( + beam_sec_enable : BoolProperty( name="Hip rafter", default=True, update=update_components ) - beam_sec_width = FloatProperty( + beam_sec_width : FloatProperty( name="Width", description="Width", min=0.01, @@ -4025,7 +4025,7 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup unit='LENGTH', subtype='DISTANCE', update=update_components ) - beam_sec_height = FloatProperty( + beam_sec_height : FloatProperty( name="Height", description="Height", min=0.01, @@ -4033,19 +4033,19 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup unit='LENGTH', subtype='DISTANCE', update=update_components ) - beam_sec_alt = FloatProperty( + beam_sec_alt : FloatProperty( name="Altitude", description="Distance from roof", default=-0.1, unit='LENGTH', subtype='DISTANCE', update=update_components ) - rafter_enable = BoolProperty( + rafter_enable : BoolProperty( name="Rafter", default=True, update=update_components ) - rafter_width = FloatProperty( + rafter_width : FloatProperty( name="Width", description="Width", min=0.01, @@ -4053,7 +4053,7 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup unit='LENGTH', subtype='DISTANCE', update=update_components ) - rafter_height = FloatProperty( + rafter_height : FloatProperty( name="Height", description="Height", min=0.01, @@ -4061,7 +4061,7 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup unit='LENGTH', subtype='DISTANCE', update=update_components ) - rafter_spacing = FloatProperty( + rafter_spacing : FloatProperty( name="Spacing", description="Spacing", min=0.1, @@ -4069,7 +4069,7 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup unit='LENGTH', subtype='DISTANCE', update=update_components ) - rafter_start = FloatProperty( + rafter_start : FloatProperty( name="Offset", description="Spacing from roof border", min=0, @@ -4077,7 +4077,7 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup unit='LENGTH', subtype='DISTANCE', update=update_components ) - rafter_alt = FloatProperty( + rafter_alt : FloatProperty( name="Altitude", description="Altitude from roof", max=-0.0001, @@ -4086,25 +4086,25 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup update=update_components ) - hip_enable = BoolProperty( + hip_enable : BoolProperty( name="Enable", default=True, update=update_components ) - hip_expand = BoolProperty( + hip_expand : BoolProperty( options={'SKIP_SAVE'}, name="Hips", description="Expand hips panel", default=False ) - hip_alt = FloatProperty( + hip_alt : FloatProperty( name="Altitude", description="Hip altitude from roof", default=0.1, unit='LENGTH', subtype='DISTANCE', update=update_components ) - hip_space_x = FloatProperty( + hip_space_x : FloatProperty( name="Spacing", description="Space between hips", min=0.01, @@ -4112,7 +4112,7 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup unit='LENGTH', subtype='DISTANCE', update=update_components ) - hip_size_x = FloatProperty( + hip_size_x : FloatProperty( name="Length", description="Length of hip", min=0.01, @@ -4120,7 +4120,7 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup unit='LENGTH', subtype='DISTANCE', update=update_components ) - hip_size_y = FloatProperty( + hip_size_y : FloatProperty( name="Width", description="Width of hip", min=0.01, @@ -4128,7 +4128,7 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup unit='LENGTH', subtype='DISTANCE', update=update_components ) - hip_size_z = FloatProperty( + hip_size_z : FloatProperty( name="Height", description="Height of hip", min=0.0, @@ -4136,7 +4136,7 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup unit='LENGTH', subtype='DISTANCE', update=update_components ) - hip_model = EnumProperty( + hip_model : EnumProperty( name="Model", items=( ('ROUND', 'Round', '', 0), @@ -4146,32 +4146,32 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup default="ROUND", update=update_components ) - valley_altitude = FloatProperty( + valley_altitude : FloatProperty( name="Altitude", description="Valley altitude from roof", default=0.1, unit='LENGTH', subtype='DISTANCE', update=update_components ) - valley_enable = BoolProperty( + valley_enable : BoolProperty( name="Valley", default=True, update=update_components ) - fascia_enable = BoolProperty( + fascia_enable : BoolProperty( name="Enable", description="Enable Fascia", default=True, update=update_components ) - fascia_expand = BoolProperty( + fascia_expand : BoolProperty( options={'SKIP_SAVE'}, name="Fascia", description="Expand fascia panel", default=False ) - fascia_height = FloatProperty( + fascia_height : FloatProperty( name="Height", description="Height", min=0.01, @@ -4179,7 +4179,7 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup unit='LENGTH', subtype='DISTANCE', update=update_components ) - fascia_width = FloatProperty( + fascia_width : FloatProperty( name="Width", description="Width", min=0.01, @@ -4187,14 +4187,14 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup unit='LENGTH', subtype='DISTANCE', update=update_components ) - fascia_offset = FloatProperty( + fascia_offset : FloatProperty( name="Offset", description="Offset from roof border", default=0, unit='LENGTH', subtype='DISTANCE', update=update_components ) - fascia_altitude = FloatProperty( + fascia_altitude : FloatProperty( name="Altitude", description="Fascia altitude from roof", default=0.1, @@ -4202,19 +4202,19 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup update=update_components ) - bargeboard_enable = BoolProperty( + bargeboard_enable : BoolProperty( name="Enable", description="Enable Bargeboard", default=True, update=update_components ) - bargeboard_expand = BoolProperty( + bargeboard_expand : BoolProperty( options={'SKIP_SAVE'}, name="Bargeboard", description="Expand Bargeboard panel", default=False ) - bargeboard_height = FloatProperty( + bargeboard_height : FloatProperty( name="Height", description="Height", min=0.01, @@ -4222,7 +4222,7 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup unit='LENGTH', subtype='DISTANCE', update=update_components ) - bargeboard_width = FloatProperty( + bargeboard_width : FloatProperty( name="Width", description="Width", min=0.01, @@ -4230,14 +4230,14 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup unit='LENGTH', subtype='DISTANCE', update=update_components ) - bargeboard_offset = FloatProperty( + bargeboard_offset : FloatProperty( name="Offset", description="Offset from roof border", default=0.001, unit='LENGTH', subtype='DISTANCE', update=update_components ) - bargeboard_altitude = FloatProperty( + bargeboard_altitude : FloatProperty( name="Altitude", description="Fascia altitude from roof", default=0.1, @@ -4245,25 +4245,25 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup update=update_components ) - t_parent = StringProperty( + t_parent : StringProperty( name="Parent", default="", update=update_parent ) - t_part = IntProperty( + t_part : IntProperty( name="Part", description="Parent part index", default=0, min=0, update=update_cutter ) - t_dist_x = FloatProperty( + t_dist_x : FloatProperty( name="Dist x", description="Location on axis ", default=0, update=update_cutter ) - t_dist_y = FloatProperty( + t_dist_y : FloatProperty( name="Dist y", description="Lateral distance from axis", min=0.0001, @@ -4271,21 +4271,21 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup update=update_cutter ) - hole_offset_left = FloatProperty( + hole_offset_left : FloatProperty( name="Left", description="Left distance from border", min=0, default=0, update=update_cutter ) - hole_offset_right = FloatProperty( + hole_offset_right : FloatProperty( name="Right", description="Right distance from border", min=0, default=0, update=update_cutter ) - hole_offset_front = FloatProperty( + hole_offset_front : FloatProperty( name="Front", description="Front distance from border", default=0, @@ -4420,7 +4420,7 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup t = (d.t_dist_x / seg.length) x, y, z = seg.lerp(t).to_3d() dy = -seg.v.normalized() - child.matrix_world = o.matrix_world * Matrix([ + child.matrix_world = o.matrix_world @ Matrix([ [dy.x, -dy.y, 0, x], [dy.y, dy.x, 0, y], [0, 0, 1, z], @@ -4438,13 +4438,13 @@ class archipack_roof(ArchipackLines, ArchipackObject, Manipulable, PropertyGroup d = archipack_roof.datablock(child) if d is not None and d.t_parent == o.name: # print("upate_childs(%s)" % (child.name)) - child.select = True - context.scene.objects.active = child + child.select_set(state=True) + context.view_layer.objects.active = child # regenerate hole d.update(context, update_hole=True, update_parent=False) - child.select = False - o.select = True - context.scene.objects.active = o + child.select_set(state=False) + o.select_set(state=True) + context.view_layer.objects.active = o def update(self, context, @@ -4726,8 +4726,8 @@ def update_operation(self, context): class archipack_roof_cutter_segment(ArchipackCutterPart, PropertyGroup): - manipulators = CollectionProperty(type=archipack_manipulator) - type = EnumProperty( + manipulators : CollectionProperty(type=archipack_manipulator) + type : EnumProperty( name="Type", items=( ('SIDE', 'Side', 'Side with bargeboard', 0), @@ -4754,8 +4754,8 @@ class archipack_roof_cutter_segment(ArchipackCutterPart, PropertyGroup): class archipack_roof_cutter(ArchipackCutter, ArchipackObject, Manipulable, PropertyGroup): # boundary - parts = CollectionProperty(type=archipack_roof_cutter_segment) - boundary = StringProperty( + parts : CollectionProperty(type=archipack_roof_cutter_segment) + boundary : StringProperty( default="", name="Boundary", description="Boundary of t child to cut parent" @@ -4778,11 +4778,11 @@ class archipack_roof_cutter(ArchipackCutter, ArchipackObject, Manipulable, Prope d = archipack_roof.datablock(o.parent) if d is not None: - o.parent.select = True - context.scene.objects.active = o.parent + o.parent.select_set(state=True) + context.view_layer.objects.active = o.parent d.update(context, update_childs=False, update_hole=False) - o.parent.select = False - context.scene.objects.active = o + o.parent.select_set(state=False) + context.view_layer.objects.active = o # print("update_parent") @@ -4791,7 +4791,7 @@ class ARCHIPACK_PT_roof_cutter(Panel): bl_label = "Roof Cutter" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' - bl_category = 'ArchiPack' + bl_category = 'Archipack' @classmethod def poll(cls, context): @@ -4808,7 +4808,7 @@ class ARCHIPACK_PT_roof_cutter(Panel): box.label(text="Auto Cutter:") box.label(text=prop.boundary) else: - box.operator('archipack.roof_cutter_manipulate', icon='HAND') + box.operator('archipack.roof_cutter_manipulate', icon='VIEW_PAN') box.prop(prop, 'operation', text="") box = layout.box() box.label(text="From curve") @@ -4828,7 +4828,7 @@ class ARCHIPACK_PT_roof(Panel): bl_label = "Roof" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' - bl_category = 'ArchiPack' + bl_category = 'Archipack' @classmethod def poll(cls, context): @@ -4842,13 +4842,13 @@ class ARCHIPACK_PT_roof(Panel): scene = context.scene layout = self.layout row = layout.row(align=True) - row.operator('archipack.roof_manipulate', icon='HAND') + row.operator('archipack.roof_manipulate', icon='VIEW_PAN') box = layout.box() row = box.row(align=True) row.operator("archipack.roof_preset_menu", text=bpy.types.ARCHIPACK_OT_roof_preset_menu.bl_label) - row.operator("archipack.roof_preset", text="", icon='ZOOMIN') - row.operator("archipack.roof_preset", text="", icon='ZOOMOUT').remove_active = True + row.operator("archipack.roof_preset", text="", icon='ADD') + row.operator("archipack.roof_preset", text="", icon='REMOVE').remove_active = True box = layout.box() box.prop_search(prop, "t_parent", scene, "objects", text="Parent", icon='OBJECT_DATA') layout.operator('archipack.roof_cutter').parent = o.name @@ -5029,9 +5029,9 @@ class ARCHIPACK_OT_roof(ArchipackCreateTool, Operator): d = m.archipack_roof.add() # make manipulators selectable d.manipulable_selectable = True - context.scene.objects.link(o) - o.select = True - context.scene.objects.active = o + context.scene.collection.objects.link(o) + o.select_set(state=True) + context.view_layer.objects.active = o self.add_material(o) # disable progress bar when @@ -5050,8 +5050,8 @@ class ARCHIPACK_OT_roof(ArchipackCreateTool, Operator): bpy.ops.object.select_all(action="DESELECT") o = self.create(context) o.location = context.scene.cursor_location - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o self.manipulate() return {'FINISHED'} else: @@ -5066,7 +5066,7 @@ class ARCHIPACK_OT_roof_cutter(ArchipackCreateTool, Operator): bl_category = 'Archipack' bl_options = {'REGISTER', 'UNDO'} - parent = StringProperty("") + parent : StringProperty("") def create(self, context): m = bpy.data.meshes.new("Roof Cutter") @@ -5081,7 +5081,7 @@ class ARCHIPACK_OT_roof_cutter(ArchipackCreateTool, Operator): x1, y1, z = bbox[6] x = 0.2 * (x1 - x0) y = 0.2 * (y1 - y0) - o.matrix_world = parent.matrix_world * Matrix([ + o.matrix_world = parent.matrix_world @ Matrix([ [1, 0, 0, -3 * x], [0, 1, 0, 0], [0, 0, 1, 0], @@ -5104,9 +5104,9 @@ class ARCHIPACK_OT_roof_cutter(ArchipackCreateTool, Operator): o.location = context.scene.cursor_location # make manipulators selectable d.manipulable_selectable = True - context.scene.objects.link(o) - o.select = True - context.scene.objects.active = o + context.scene.collection.objects.link(o) + o.select_set(state=True) + context.view_layer.objects.active = o self.add_material(o) self.load_preset(d) update_operation(d, context) @@ -5119,8 +5119,8 @@ class ARCHIPACK_OT_roof_cutter(ArchipackCreateTool, Operator): if context.mode == "OBJECT": bpy.ops.object.select_all(action="DESELECT") o = self.create(context) - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o self.manipulate() return {'FINISHED'} else: @@ -5140,7 +5140,7 @@ class ARCHIPACK_OT_roof_from_curve(Operator): bl_category = 'Archipack' bl_options = {'REGISTER', 'UNDO'} - auto_manipulate = BoolProperty(default=True) + auto_manipulate : BoolProperty(default=True) @classmethod def poll(self, context): @@ -5149,7 +5149,7 @@ class ARCHIPACK_OT_roof_from_curve(Operator): def draw(self, context): layout = self.layout row = layout.row() - row.label("Use Properties panel (N) to define parms", icon='INFO') + row.label(text="Use Properties panel (N) to define parms", icon='INFO') def create(self, context): curve = context.active_object @@ -5159,9 +5159,9 @@ class ARCHIPACK_OT_roof_from_curve(Operator): # make manipulators selectable d.manipulable_selectable = True d.user_defined_path = curve.name - context.scene.objects.link(o) - o.select = True - context.scene.objects.active = o + context.scene.collection.objects.link(o) + o.select_set(state=True) + context.view_layer.objects.active = o d.update_path(context) spline = curve.data.splines[0] @@ -5172,14 +5172,14 @@ class ARCHIPACK_OT_roof_from_curve(Operator): else: pt = Vector((0, 0, 0)) # pretranslate - o.matrix_world = curve.matrix_world * Matrix([ + o.matrix_world = curve.matrix_world @ Matrix([ [1, 0, 0, pt.x], [0, 1, 0, pt.y], [0, 0, 1, pt.z], [0, 0, 0, 1] ]) - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o return o # ----------------------------------------------------- @@ -5250,7 +5250,7 @@ class ArchipackThrottleHandler(): def start_timer(self, context): self.start = time.time() - self._timer = context.window_manager.event_timer_add(self.delay, context.window) + self._timer = context.window_manager.event_timer_add(self.delay, window=context.window) def stop_timer(self, context): if self._timer is not None: @@ -5300,7 +5300,7 @@ class ARCHIPACK_OT_roof_throttle_update(Operator): bl_idname = "archipack.roof_throttle_update" bl_label = "Update childs with a delay" - name = StringProperty() + name : StringProperty() def kill_handler(self, context, name): if name in throttle_handlers.keys(): @@ -5321,16 +5321,16 @@ class ARCHIPACK_OT_roof_throttle_update(Operator): o = context.scene.objects.get(self.name) # print("delay update of %s" % (self.name)) if o is not None: - selected = o.select - o.select = True - context.scene.objects.active = o + selected = o.select_get() + o.select_set(state=True) + context.view_layer.objects.active = o d = o.data.archipack_roof[0] d.update(context, force_update=True, update_parent=False) # skip_parent_update=self.skip_parent_update) - o.select = selected - context.scene.objects.active = act + o.select_set(state=selected) + context.view_layer.objects.active = act del throttle_handlers[self.name] return {'FINISHED'} else: diff --git a/archipack/archipack_slab.py b/archipack/archipack_slab.py index a6cc9bf6..f4112b08 100644 --- a/archipack/archipack_slab.py +++ b/archipack/archipack_slab.py @@ -220,7 +220,7 @@ class SlabGenerator(CutAblePolygon, CutAbleGenerator): # rotate seg seg.rotate(a) # rotate delta from rotation center to segment start - dp = rM * (seg.p0 - p0) + dp = rM @ (seg.p0 - p0) seg.translate(dp) def translate(self, idx_from, dp): @@ -319,7 +319,7 @@ materials_enum = ( class archipack_slab_material(PropertyGroup): - index = EnumProperty( + index : EnumProperty( items=materials_enum, default='4', update=update @@ -349,8 +349,8 @@ class archipack_slab_child(PropertyGroup): """ Store child fences to be able to sync """ - child_name = StringProperty() - idx = IntProperty() + child_name : StringProperty() + idx : IntProperty() def get_child(self, context): d = None @@ -439,7 +439,7 @@ class ArchipackSegment(): @TODO: share this base class with stair, wall, fence, slab """ - type = EnumProperty( + type : EnumProperty( items=( ('S_SEG', 'Straight', '', 0), ('C_SEG', 'Curved', '', 1), @@ -447,19 +447,19 @@ class ArchipackSegment(): default='S_SEG', update=update_type ) - length = FloatProperty( + length : FloatProperty( name="Length", min=0.01, default=2.0, update=update ) - radius = FloatProperty( + radius : FloatProperty( name="Radius", min=0.5, default=0.7, update=update ) - da = FloatProperty( + da : FloatProperty( name="Angle", min=-pi, max=pi, @@ -467,7 +467,7 @@ class ArchipackSegment(): subtype='ANGLE', unit='ROTATION', update=update ) - a0 = FloatProperty( + a0 : FloatProperty( name="Start angle", min=-2 * pi, max=2 * pi, @@ -475,21 +475,21 @@ class ArchipackSegment(): subtype='ANGLE', unit='ROTATION', update=update ) - offset = FloatProperty( + offset : FloatProperty( name="Offset", description="Add to current segment offset", default=0, unit='LENGTH', subtype='DISTANCE', update=update ) - linked_idx = IntProperty(default=-1) + linked_idx : IntProperty(default=-1) # @TODO: # flag to handle wall's x_offset # when set add wall offset value to segment offset # pay attention at allowing per wall segment offset - manipulators = CollectionProperty(type=archipack_manipulator) + manipulators : CollectionProperty(type=archipack_manipulator) def find_in_selection(self, context): raise NotImplementedError @@ -543,38 +543,38 @@ class archipack_slab_part(ArchipackSegment, PropertyGroup): class archipack_slab(ArchipackObject, Manipulable, PropertyGroup): # boundary - n_parts = IntProperty( + n_parts : IntProperty( name="Parts", min=1, default=1, update=update_manipulators ) - parts = CollectionProperty(type=archipack_slab_part) - closed = BoolProperty( + parts : CollectionProperty(type=archipack_slab_part) + closed : BoolProperty( default=True, name="Close", options={'SKIP_SAVE'}, update=update_manipulators ) # UI layout related - parts_expand = BoolProperty( + parts_expand : BoolProperty( options={'SKIP_SAVE'}, default=False ) - x_offset = FloatProperty( + x_offset : FloatProperty( name="Offset", min=-1000, max=1000, default=0.0, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - z = FloatProperty( + z : FloatProperty( name="Thickness", default=0.3, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - auto_synch = BoolProperty( + auto_synch : BoolProperty( name="Auto-Synch", description="Keep wall in synch when editing", default=True, @@ -590,7 +590,7 @@ class archipack_slab(ArchipackObject, Manipulable, PropertyGroup): # .auto_update = False # bulk changes # .auto_update = True - auto_update = BoolProperty( + auto_update : BoolProperty( options={'SKIP_SAVE'}, default=True, update=update_manipulators @@ -696,17 +696,17 @@ class archipack_slab(ArchipackObject, Manipulable, PropertyGroup): o = context.active_object bpy.ops.archipack.fence(auto_manipulate=False) c = context.active_object - c.select = True + c.select_set(state=True) c.data.archipack_fence[0].n_parts = 3 - c.select = False + c.select_set(state=False) # link to o c.location = Vector((0, 0, 0)) c.parent = o c.location = g.segs[where + 1].p0.to_3d() self.add_child(c.name, where + 1) # c.matrix_world.translation = g.segs[where].p1.to_3d() - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o self.relocate_childs(context, o, g) def add_part(self, context, length): @@ -736,7 +736,7 @@ class archipack_slab(ArchipackObject, Manipulable, PropertyGroup): dmax = 0.2 for c in o.children: if (c.data and 'archipack_fence' in c.data): - pt = (itM * c.matrix_world.translation).to_2d() + pt = (itM @ c.matrix_world.translation).to_2d() for idx, seg in enumerate(g.segs): # may be optimized with a bound check res, d, t = seg.point_sur_segment(pt) @@ -874,14 +874,14 @@ class archipack_slab(ArchipackObject, Manipulable, PropertyGroup): else: d.parts[i].length = max(0.01, seg.length) - wall.select = True - context.scene.objects.active = wall + wall.select_set(state=True) + context.view_layer.objects.active = wall d.auto_update = True - wall.select = False + wall.select_set(state=False) - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o wall.matrix_world = o.matrix_world.copy() @@ -897,11 +897,11 @@ class archipack_slab(ArchipackObject, Manipulable, PropertyGroup): ca = cos(a) if d is not None: - c.select = True + c.select_set(state=True) # auto_update need object to be active to # setup manipulators on the right object - context.scene.objects.active = c + context.view_layer.objects.active = c d.auto_update = False for i, part in enumerate(d.parts): @@ -915,11 +915,11 @@ class archipack_slab(ArchipackObject, Manipulable, PropertyGroup): part.radius = self.parts[i + child.idx].radius d.parts[0].a0 = pi / 2 d.auto_update = True - c.select = False + c.select_set(state=False) - context.scene.objects.active = o + context.view_layer.objects.active = o # preTranslate - c.matrix_world = tM * Matrix([ + c.matrix_world = tM @ Matrix([ [sa, ca, 0, x], [-ca, sa, 0, y], [0, 0, 1, 0], @@ -1034,18 +1034,18 @@ class archipack_slab(ArchipackObject, Manipulable, PropertyGroup): # since this can lower points count by a resolution factor # use normalized to handle non linear t if resolution == 0: - pts.append(wM * p0.co.to_3d()) + pts.append(wM @ p0.co.to_3d()) else: v = (p1.co - p0.co).normalized() d1 = (p0.handle_right - p0.co).normalized() d2 = (p1.co - p1.handle_left).normalized() if d1 == v and d2 == v: - pts.append(wM * p0.co.to_3d()) + pts.append(wM @ p0.co.to_3d()) else: - seg = interpolate_bezier(wM * p0.co, - wM * p0.handle_right, - wM * p1.handle_left, - wM * p1.co, + seg = interpolate_bezier(wM @ p0.co, + wM @ p0.handle_right, + wM @ p1.handle_left, + wM @ p1.co, resolution + 1) for i in range(resolution): pts.append(seg[i].to_3d()) @@ -1053,7 +1053,7 @@ class archipack_slab(ArchipackObject, Manipulable, PropertyGroup): def from_spline(self, wM, resolution, spline): pts = [] if spline.type == 'POLY': - pts = [wM * p.co.to_3d() for p in spline.points] + pts = [wM @ p.co.to_3d() for p in spline.points] if spline.use_cyclic_u: pts.append(pts[0]) elif spline.type == 'BEZIER': @@ -1068,7 +1068,7 @@ class archipack_slab(ArchipackObject, Manipulable, PropertyGroup): self.interpolate_bezier(pts, wM, p0, p1, resolution) pts.append(pts[0]) else: - pts.append(wM * points[-1].co) + pts.append(wM @ points[-1].co) self.from_points(pts, spline.use_cyclic_u) @@ -1147,8 +1147,8 @@ class archipack_slab(ArchipackObject, Manipulable, PropertyGroup): # relocate before cutting segs self.relocate_childs(context, o, g) - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o g.cut(context, o) @@ -1244,8 +1244,8 @@ def update_operation(self, context): class archipack_slab_cutter_segment(ArchipackCutterPart, PropertyGroup): - manipulators = CollectionProperty(type=archipack_manipulator) - type = EnumProperty( + manipulators : CollectionProperty(type=archipack_manipulator) + type : EnumProperty( name="Type", items=( ('DEFAULT', 'Side', 'Side with rake', 0), @@ -1278,7 +1278,7 @@ class archipack_slab_cutter_segment(ArchipackCutterPart, PropertyGroup): class archipack_slab_cutter(ArchipackCutter, ArchipackObject, Manipulable, PropertyGroup): - parts = CollectionProperty(type=archipack_slab_cutter_segment) + parts : CollectionProperty(type=archipack_slab_cutter_segment) def update_points(self, context, o, pts, update_parent=False): self.auto_update = False @@ -1291,11 +1291,11 @@ class archipack_slab_cutter(ArchipackCutter, ArchipackObject, Manipulable, Prope d = archipack_slab.datablock(o.parent) if d is not None: - o.parent.select = True - context.scene.objects.active = o.parent + o.parent.select_set(state=True) + context.view_layer.objects.active = o.parent d.update(context) - o.parent.select = False - context.scene.objects.active = o + o.parent.select_set(state=False) + context.view_layer.objects.active = o class ARCHIPACK_PT_slab(Panel): @@ -1305,7 +1305,7 @@ class ARCHIPACK_PT_slab(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'UI' # bl_context = 'object' - bl_category = 'ArchiPack' + bl_category = 'Archipack' @classmethod def poll(cls, context): @@ -1317,7 +1317,7 @@ class ARCHIPACK_PT_slab(Panel): if prop is None: return layout = self.layout - layout.operator('archipack.slab_manipulate', icon='HAND') + layout.operator('archipack.slab_manipulate', icon='VIEW_PAN') box = layout.box() box.operator('archipack.slab_cutter').parent = o.name box = layout.box() @@ -1341,7 +1341,7 @@ class ARCHIPACK_PT_slab_cutter(Panel): bl_label = "Slab Cutter" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' - bl_category = 'ArchiPack' + bl_category = 'Archipack' @classmethod def poll(cls, context): @@ -1354,7 +1354,7 @@ class ARCHIPACK_PT_slab_cutter(Panel): layout = self.layout scene = context.scene box = layout.box() - box.operator('archipack.slab_cutter_manipulate', icon='HAND') + box.operator('archipack.slab_cutter_manipulate', icon='VIEW_PAN') box.prop(prop, 'operation', text="") box = layout.box() box.label(text="From curve") @@ -1380,7 +1380,7 @@ class ARCHIPACK_OT_slab_insert(Operator): bl_description = "Insert part" bl_category = 'Archipack' bl_options = {'REGISTER', 'UNDO'} - index = IntProperty(default=0) + index : IntProperty(default=0) def execute(self, context): if context.mode == "OBJECT": @@ -1400,7 +1400,7 @@ class ARCHIPACK_OT_slab_balcony(Operator): bl_description = "Insert part" bl_category = 'Archipack' bl_options = {'REGISTER', 'UNDO'} - index = IntProperty(default=0) + index : IntProperty(default=0) def execute(self, context): if context.mode == "OBJECT": @@ -1420,7 +1420,7 @@ class ARCHIPACK_OT_slab_remove(Operator): bl_description = "Remove part" bl_category = 'Archipack' bl_options = {'REGISTER', 'UNDO'} - index = IntProperty(default=0) + index : IntProperty(default=0) def execute(self, context): if context.mode == "OBJECT": @@ -1452,9 +1452,9 @@ class ARCHIPACK_OT_slab(ArchipackCreateTool, Operator): d = m.archipack_slab.add() # make manipulators selectable d.manipulable_selectable = True - context.scene.objects.link(o) - o.select = True - context.scene.objects.active = o + context.scene.collection.objects.link(o) + o.select_set(state=True) + context.view_layer.objects.active = o self.load_preset(d) self.add_material(o) return o @@ -1467,8 +1467,8 @@ class ARCHIPACK_OT_slab(ArchipackCreateTool, Operator): bpy.ops.object.select_all(action="DESELECT") o = self.create(context) o.location = bpy.context.scene.cursor_location - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o self.manipulate() return {'FINISHED'} else: @@ -1483,7 +1483,7 @@ class ARCHIPACK_OT_slab_from_curve(Operator): bl_category = 'Archipack' bl_options = {'REGISTER', 'UNDO'} - auto_manipulate = BoolProperty(default=True) + auto_manipulate : BoolProperty(default=True) @classmethod def poll(self, context): @@ -1496,12 +1496,12 @@ class ARCHIPACK_OT_slab_from_curve(Operator): def draw(self, context): layout = self.layout row = layout.row() - row.label("Use Properties panel (N) to define parms", icon='INFO') + row.label(text="Use Properties panel (N) to define parms", icon='INFO') def create(self, context): curve = context.active_object bpy.ops.archipack.slab(auto_manipulate=self.auto_manipulate) - o = context.scene.objects.active + o = context.view_layer.objects.active d = archipack_slab.datablock(o) spline = curve.data.splines[0] d.from_spline(curve.matrix_world, 12, spline) @@ -1512,12 +1512,7 @@ class ARCHIPACK_OT_slab_from_curve(Operator): else: pt = Vector((0, 0, 0)) # pretranslate - o.matrix_world = curve.matrix_world * Matrix([ - [1, 0, 0, pt.x], - [0, 1, 0, pt.y], - [0, 0, 1, pt.z], - [0, 0, 0, 1] - ]) + o.matrix_world = curve.matrix_world @ Matrix.Translation(pt) return o # ----------------------------------------------------- @@ -1540,8 +1535,8 @@ class ARCHIPACK_OT_slab_from_wall(Operator): bl_category = 'Archipack' bl_options = {'REGISTER', 'UNDO'} - auto_manipulate = BoolProperty(default=True) - ceiling = BoolProperty(default=False) + auto_manipulate : BoolProperty(default=True) + ceiling : BoolProperty(default=False) @classmethod def poll(self, context): @@ -1552,7 +1547,7 @@ class ARCHIPACK_OT_slab_from_wall(Operator): wall = context.active_object wd = wall.data.archipack_wall2[0] bpy.ops.archipack.slab(auto_manipulate=False) - o = context.scene.objects.active + o = context.view_layer.objects.active d = archipack_slab.datablock(o) d.auto_update = False d.closed = True @@ -1576,24 +1571,24 @@ class ARCHIPACK_OT_slab_from_wall(Operator): [0, 1, 0, 0], [0, 0, 1, wd.z + d.z], [0, 0, 0, 1], - ]) * wall.matrix_world + ]) @ wall.matrix_world else: o.matrix_world = wall.matrix_world.copy() bpy.ops.object.select_all(action='DESELECT') # parenting childs to wall reference point if wall.parent is None: x, y, z = wall.bound_box[0] - context.scene.cursor_location = wall.matrix_world * Vector((x, y, z)) + context.scene.cursor_location = wall.matrix_world @ Vector((x, y, z)) # fix issue #9 - context.scene.objects.active = wall + context.view_layer.objects.active = wall bpy.ops.archipack.reference_point() else: - wall.parent.select = True - context.scene.objects.active = wall.parent - wall.select = True - o.select = True + wall.parent.select_set(state=True) + context.view_layer.objects.active = wall.parent + wall.select_set(state=True) + o.select_set(state=True) bpy.ops.archipack.parent_to_reference() - wall.parent.select = False + wall.parent.select_set(state=False) return o @@ -1604,8 +1599,8 @@ class ARCHIPACK_OT_slab_from_wall(Operator): if context.mode == "OBJECT": bpy.ops.object.select_all(action="DESELECT") o = self.create(context) - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o if self.auto_manipulate: bpy.ops.archipack.slab_manipulate('INVOKE_DEFAULT') return {'FINISHED'} @@ -1621,7 +1616,7 @@ class ARCHIPACK_OT_slab_cutter(ArchipackCreateTool, Operator): bl_category = 'Archipack' bl_options = {'REGISTER', 'UNDO'} - parent = StringProperty("") + parent : StringProperty("") def create(self, context): m = bpy.data.meshes.new("Slab Cutter") @@ -1636,7 +1631,7 @@ class ARCHIPACK_OT_slab_cutter(ArchipackCreateTool, Operator): x1, y1, z = bbox[6] x = 0.2 * (x1 - x0) y = 0.2 * (y1 - y0) - o.matrix_world = parent.matrix_world * Matrix([ + o.matrix_world = parent.matrix_world @ Matrix([ [1, 0, 0, -3 * x], [0, 1, 0, 0], [0, 0, 1, 0], @@ -1659,9 +1654,9 @@ class ARCHIPACK_OT_slab_cutter(ArchipackCreateTool, Operator): o.location = context.scene.cursor_location # make manipulators selectable d.manipulable_selectable = True - context.scene.objects.link(o) - o.select = True - context.scene.objects.active = o + context.scene.collection.objects.link(o) + o.select_set(state=True) + context.view_layer.objects.active = o # self.add_material(o) self.load_preset(d) update_operation(d, context) @@ -1674,8 +1669,8 @@ class ARCHIPACK_OT_slab_cutter(ArchipackCreateTool, Operator): if context.mode == "OBJECT": bpy.ops.object.select_all(action="DESELECT") o = self.create(context) - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o self.manipulate() return {'FINISHED'} else: diff --git a/archipack/archipack_snap.py b/archipack/archipack_snap.py index 92e09595..33a59041 100644 --- a/archipack/archipack_snap.py +++ b/archipack/archipack_snap.py @@ -43,7 +43,7 @@ sp.delta action_callback(context, event, state, sp) - state in {'SUCCESS', 'CANCEL'} + state in {'RUNNING', 'SUCCESS', 'CANCEL'} sp.takeloc sp.placeloc sp.delta @@ -64,6 +64,9 @@ import bpy from bpy.types import Operator from mathutils import Vector, Matrix +import logging + +logger = logging.getLogger("archipack") def dumb_callback(context, event, state, sp): @@ -81,8 +84,8 @@ class SnapStore: callback = None draw = None helper = None - takeloc = Vector((0, 0, 0)) - placeloc = Vector((0, 0, 0)) + takeloc = Vector() + placeloc = Vector() constraint_axis = (True, True, False) helper_matrix = Matrix() transform_orientation = 'GLOBAL' @@ -93,20 +96,20 @@ class SnapStore: act = None sel = [] use_snap = False - snap_element = None + snap_elements = None snap_target = None pivot_point = None trans_orientation = None def snap_point(takeloc=None, - draw=dumb_draw, - callback=dumb_callback, - takemat=None, - constraint_axis=(True, True, False), - transform_orientation='GLOBAL', - mode='OBJECT', - release_confirm=True): + draw=None, + callback=dumb_callback, + takemat=None, + constraint_axis=(True, True, False), + transform_orientation='GLOBAL', + mode='OBJECT', + release_confirm=True): """ Invoke op from outside world in a convenient importable function @@ -126,16 +129,19 @@ def snap_point(takeloc=None, SnapStore.callback = callback SnapStore.constraint_axis = constraint_axis SnapStore.release_confirm = release_confirm + if takemat is not None: SnapStore.helper_matrix = takemat - takeloc = takemat.translation + takeloc = takemat.translation.copy() transform_orientation = 'LOCAL' elif takeloc is not None: - SnapStore.helper_matrix = Matrix().Translation(takeloc) + SnapStore.helper_matrix = Matrix.Translation(takeloc) else: raise ValueError("ArchipackSnap: Either takeloc or takemat must be defined") + SnapStore.takeloc = takeloc - SnapStore.placeloc = takeloc + SnapStore.placeloc = takeloc.copy() + SnapStore.transform_orientation = transform_orientation # @NOTE: unused mode var to switch between OBJECT and EDIT mode @@ -160,53 +166,56 @@ class ArchipackSnapBase(): - takeloc - placeloc """ + def __init__(self): self._draw_handler = None def init(self, context, event): # Store context data - if SnapStore.instances_running < 1: - SnapStore.sel = [o for o in context.selected_objects] - SnapStore.act = context.active_object - bpy.ops.object.select_all(action="DESELECT") - SnapStore.use_snap = context.tool_settings.use_snap - SnapStore.snap_element = context.tool_settings.snap_element - SnapStore.snap_target = context.tool_settings.snap_target - SnapStore.pivot_point = context.space_data.pivot_point - SnapStore.trans_orientation = context.space_data.transform_orientation + # if SnapStore.instances_running < 1: + SnapStore.sel = context.selected_objects[:] + SnapStore.act = context.object + bpy.ops.object.select_all(action="DESELECT") + ts = context.tool_settings + SnapStore.use_snap = ts.use_snap + SnapStore.snap_elements = ts.snap_elements + SnapStore.snap_target = ts.snap_target + SnapStore.pivot_point = ts.transform_pivot_point + SnapStore.trans_orientation = context.scene.transform_orientation self.create_helper(context) - SnapStore.instances_running += 1 - # print("ArchipackSnapBase init: %s" % (SnapStore.instances_running)) - self.set_transform_orientation(context) - args = (self, context) - self._draw_handler = bpy.types.SpaceView3D.draw_handler_add(SnapStore.draw, args, 'WINDOW', 'POST_PIXEL') + # Use a timer to broadcast a TIMER event while transform.translate is running + self._timer = context.window_manager.event_timer_add(0.1, window=context.window) + + if SnapStore.draw is not None: + args = (self, context) + self._draw_handler = bpy.types.SpaceView3D.draw_handler_add(SnapStore.draw, args, 'WINDOW', 'POST_PIXEL') + + def remove_timer(self, context): + if self._timer is not None: + context.window_manager.event_timer_remove(self._timer) def exit(self, context): - bpy.types.SpaceView3D.draw_handler_remove(self._draw_handler, 'WINDOW') - # trick to allow launch 2nd instance - # via callback, preserve context as it - SnapStore.instances_running -= 1 - # print("ArchipackSnapBase exit: %s" % (SnapStore.instances_running)) - if SnapStore.instances_running > 0: - return - self.destroy_helper(context) + self.remove_timer(context) + + if self._draw_handler is not None: + bpy.types.SpaceView3D.draw_handler_remove(self._draw_handler, 'WINDOW') + # Restore original context - context.tool_settings.use_snap = SnapStore.use_snap - context.tool_settings.snap_element = SnapStore.snap_element - context.tool_settings.snap_target = SnapStore.snap_target - context.space_data.pivot_point = SnapStore.pivot_point - context.space_data.transform_orientation = SnapStore.trans_orientation + if hasattr(context, "tool_settings"): + ts = context.tool_settings + ts.use_snap = SnapStore.use_snap + ts.snap_elements = SnapStore.snap_elements + ts.snap_target = SnapStore.snap_target + ts.transform_pivot_point = SnapStore.pivot_point + context.scene.transform_orientation = SnapStore.trans_orientation for o in SnapStore.sel: - o.select = True + o.select_set(state=True) if SnapStore.act is not None: - context.scene.objects.active = SnapStore.act - - def set_transform_orientation(self, context): - """ - Allow local constraint orientation to be set - """ - context.space_data.transform_orientation = SnapStore.transform_orientation + SnapStore.act.select_set(state=True) + context.view_layer.objects.active = SnapStore.act + self.destroy_helper(context) + logger.debug("Snap.exit %s", context.object.name) def create_helper(self, context): """ @@ -217,23 +226,25 @@ class ArchipackSnapBase(): Do target helper be linked to scene in order to work ? """ - - helper_idx = bpy.data.objects.find('Archipack_snap_helper') - if helper_idx > -1: - helper = bpy.data.objects[helper_idx] - if context.scene.objects.find('Archipack_snap_helper') < 0: - context.scene.objects.link(helper) + helper = bpy.data.objects.get('Archipack_snap_helper') + if helper is not None: + print("helper found") + if context.scene.objects.get('Archipack_snap_helper') is None: + print("link helper") + # context.scene.collection.objects.link(helper) + context.scene.collection.objects.link(helper) else: - bpy.ops.object.add(type='MESH') - helper = context.active_object - helper.name = 'Archipack_snap_helper' + print("create helper") + m = bpy.data.meshes.new("Archipack_snap_helper") + m.vertices.add(count=1) + helper = bpy.data.objects.new("Archipack_snap_helper", m) + context.scene.collection.objects.link(helper) helper.use_fake_user = True helper.data.use_fake_user = True - # hide snap helper - # helper.hide = True + helper.matrix_world = SnapStore.helper_matrix - helper.select = True - context.scene.objects.active = helper + helper.select_set(state=True) + context.view_layer.objects.active = helper SnapStore.helper = helper def destroy_helper(self, context): @@ -242,7 +253,8 @@ class ArchipackSnapBase(): currently only support OBJECT mode """ if SnapStore.helper is not None: - context.scene.objects.unlink(SnapStore.helper) + # @TODO: Fix this + # self.unlink_object_from_scene(context, SnapStore.helper) SnapStore.helper = None @property @@ -266,35 +278,61 @@ class ArchipackSnapBase(): class ARCHIPACK_OT_snap(ArchipackSnapBase, Operator): bl_idname = 'archipack.snap' bl_label = 'Archipack snap' - bl_options = {'UNDO'} + bl_options = {'INTERNAL'} # , 'UNDO' def modal(self, context, event): - # print("Snap.modal event %s %s" % (event.type, event.value)) + + if SnapStore.helper is not None: + logger.debug("Snap.modal event %s %s location:%s", + event.type, + event.value, + SnapStore.helper.location) + context.area.tag_redraw() - # NOTE: this part only run after transform LEFTMOUSE RELEASE - # or with ESC and RIGHTMOUSE - if event.type not in {'ESC', 'RIGHTMOUSE', 'LEFTMOUSE', 'MOUSEMOVE'}: - # print("Snap.modal skip unknown event %s %s" % (event.type, event.value)) - # self.report({'WARNING'}, "ARCHIPACK_OT_snap unknown event") - return{'PASS_THROUGH'} + + if event.type in ('TIMER', 'NOTHING'): + SnapStore.callback(context, event, 'RUNNING', self) + return {'PASS_THROUGH'} + + if event.type not in ('ESC', 'RIGHTMOUSE', 'LEFTMOUSE', 'MOUSEMOVE', 'INBETWEEN_MOUSEMOVE'): + return {'PASS_THROUGH'} + if event.type in ('ESC', 'RIGHTMOUSE'): SnapStore.callback(context, event, 'CANCEL', self) else: SnapStore.placeloc = SnapStore.helper.location - SnapStore.callback(context, event, 'SUCCESS', self) + # on tt modal exit with right click, the delta is 0 so exit + if self.delta.length == 0: + SnapStore.callback(context, event, 'CANCEL', self) + else: + SnapStore.callback(context, event, 'SUCCESS', self) + self.exit(context) # self.report({'INFO'}, "ARCHIPACK_OT_snap exit") - return{'FINISHED'} + return {'FINISHED'} def invoke(self, context, event): if context.area.type == 'VIEW_3D': - # print("Snap.invoke event %s %s" % (event.type, event.value)) + + if event.type in ('ESC', 'RIGHTMOUSE'): + return {'FINISHED'} + self.init(context, event) + + logger.debug("Snap.invoke event %s %s location:%s act:%s", + event.type, + event.value, + SnapStore.helper.location, context.object.name) + context.window_manager.modal_handler_add(self) + bpy.ops.transform.translate('INVOKE_DEFAULT', - constraint_axis=SnapStore.constraint_axis, - constraint_orientation=SnapStore.transform_orientation, - release_confirm=SnapStore.release_confirm) + constraint_axis=SnapStore.constraint_axis, + constraint_orientation=SnapStore.transform_orientation, + release_confirm=SnapStore.release_confirm) + + logger.debug("Snap.invoke transform.translate done") + return {'RUNNING_MODAL'} else: self.report({'WARNING'}, "View3D not found, cannot run operator") diff --git a/archipack/archipack_stair.py b/archipack/archipack_stair.py index 94a8da7c..8d512a65 100644 --- a/archipack/archipack_stair.py +++ b/archipack/archipack_stair.py @@ -234,16 +234,16 @@ class Stair(): def project_uv(self, rM, uvs, verts, indexes, up_axis='Z'): if up_axis == 'Z': - uvs.append([(rM * Vector(verts[i])).to_2d() for i in indexes]) + uvs.append([(rM @ Vector(verts[i])).to_2d() for i in indexes]) elif up_axis == 'Y': - uvs.append([(x, z) for x, y, z in [(rM * Vector(verts[i])) for i in indexes]]) + uvs.append([(x, z) for x, y, z in [(rM @ Vector(verts[i])) for i in indexes]]) else: - uvs.append([(y, z) for x, y, z in [(rM * Vector(verts[i])) for i in indexes]]) + uvs.append([(y, z) for x, y, z in [(rM @ Vector(verts[i])) for i in indexes]]) def get_proj_matrix(self, part, t, nose_y): # a matrix to project verts # into uv space for horizontal parts of this step - # so uv = (rM * vertex).to_2d() + # so uv = (rM @ vertex).to_2d() tl = t - nose_y / self.get_length("LEFT") tr = t - nose_y / self.get_length("RIGHT") t2, part, dz, shape = self.get_part(tl, "LEFT") @@ -264,7 +264,7 @@ class Stair(): # a matrix to project verts # into uv space for horizontal parts of this step - # so uv = (rM * vertex).to_2d() + # so uv = (rM @ vertex).to_2d() rM = self.get_proj_matrix(self, t, nose_y) if self.z_mode == 'LINEAR': @@ -1024,7 +1024,7 @@ class StairGenerator(): co.z += z1 if 'Slope' in g: co.z += co.y * slope - verts.append(tM * co) + verts.append(tM @ co) matids += self.user_defined_mat faces += [tuple([i + f for i in p.vertices]) for p in m.polygons] uvs += self.user_defined_uvs @@ -1106,7 +1106,7 @@ class StairGenerator(): if s < n_sections: v1 = subs[s + 1][0].v.normalized() dir = (v0 + v1).normalized() - scale = 1 / cos(0.5 * acos(min(1, max(-1, v0 * v1)))) + scale = 1 / cos(0.5 * acos(min(1, max(-1, v0.dot(v1))))) for p in profile: x, y = n.p + scale * p.x * dir z = zl + p.y + altitude @@ -1463,7 +1463,7 @@ class StairGenerator(): if s < n_sections: v1 = cur_sect[s + 1][0].v.normalized() dir = (v0 + v1).normalized() - scale = 1 / cos(0.5 * acos(min(1, max(-1, v0 * v1)))) + scale = 1 / cos(0.5 * acos(min(1, max(-1, v0.dot(v1))))) for p in profile: x, y = n.p + scale * p.x * dir z = zl + p.y + z_offset @@ -1546,7 +1546,7 @@ materials_enum = ( class archipack_stair_material(PropertyGroup): - index = EnumProperty( + index : EnumProperty( items=materials_enum, default='4', update=update @@ -1573,7 +1573,7 @@ class archipack_stair_material(PropertyGroup): class archipack_stair_part(PropertyGroup): - type = EnumProperty( + type : EnumProperty( items=( ('S_STAIR', 'Straight stair', '', 0), ('C_STAIR', 'Curved stair', '', 1), @@ -1585,21 +1585,21 @@ class archipack_stair_part(PropertyGroup): default='S_STAIR', update=update_manipulators ) - length = FloatProperty( + length : FloatProperty( name="Length", min=0.01, default=2.0, unit='LENGTH', subtype='DISTANCE', update=update ) - radius = FloatProperty( + radius : FloatProperty( name="Radius", min=0.01, default=0.7, unit='LENGTH', subtype='DISTANCE', update=update ) - da = FloatProperty( + da : FloatProperty( name="Angle", min=-pi, max=pi, @@ -1607,7 +1607,7 @@ class archipack_stair_part(PropertyGroup): subtype='ANGLE', unit='ROTATION', update=update ) - left_shape = EnumProperty( + left_shape : EnumProperty( items=( ('RECTANGLE', 'Straight', '', 0), ('CIRCLE', 'Curved ', '', 1) @@ -1615,7 +1615,7 @@ class archipack_stair_part(PropertyGroup): default='RECTANGLE', update=update ) - right_shape = EnumProperty( + right_shape : EnumProperty( items=( ('RECTANGLE', 'Straight', '', 0), ('CIRCLE', 'Curved ', '', 1) @@ -1623,7 +1623,7 @@ class archipack_stair_part(PropertyGroup): default='RECTANGLE', update=update ) - manipulators = CollectionProperty(type=archipack_manipulator) + manipulators : CollectionProperty(type=archipack_manipulator) def find_datablock_in_selection(self, context): """ @@ -1670,69 +1670,69 @@ class archipack_stair_part(PropertyGroup): class archipack_stair(ArchipackObject, Manipulable, PropertyGroup): - parts = CollectionProperty(type=archipack_stair_part) - n_parts = IntProperty( + parts : CollectionProperty(type=archipack_stair_part) + n_parts : IntProperty( name="Parts", min=1, max=32, default=1, update=update_manipulators ) - step_depth = FloatProperty( + step_depth : FloatProperty( name="Going", min=0.2, default=0.25, unit='LENGTH', subtype='DISTANCE', update=update ) - width = FloatProperty( + width : FloatProperty( name="Width", min=0.01, default=1.2, unit='LENGTH', subtype='DISTANCE', update=update ) - height = FloatProperty( + height : FloatProperty( name="Height", min=0.1, default=2.4, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - nose_y = FloatProperty( + nose_y : FloatProperty( name="Depth", min=0.0, default=0.02, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - x_offset = FloatProperty( + x_offset : FloatProperty( name="Offset", default=0.0, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - nose_z = FloatProperty( + nose_z : FloatProperty( name="Height", min=0.001, default=0.03, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - bottom_z = FloatProperty( + bottom_z : FloatProperty( name="Thickness", min=0.001, default=0.03, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - radius = FloatProperty( + radius : FloatProperty( name="Radius", min=0.5, default=0.7, unit='LENGTH', subtype='DISTANCE', update=update ) - da = FloatProperty( + da : FloatProperty( name="Angle", min=-pi, max=pi, @@ -1740,7 +1740,7 @@ class archipack_stair(ArchipackObject, Manipulable, PropertyGroup): subtype='ANGLE', unit='ROTATION', update=update ) - total_angle = FloatProperty( + total_angle : FloatProperty( name="Angle", min=-50 * pi, max=50 * pi, @@ -1748,7 +1748,7 @@ class archipack_stair(ArchipackObject, Manipulable, PropertyGroup): subtype='ANGLE', unit='ROTATION', update=update ) - steps_type = EnumProperty( + steps_type : EnumProperty( name="Steps", items=( ('CLOSED', 'Closed', '', 0), @@ -1758,7 +1758,7 @@ class archipack_stair(ArchipackObject, Manipulable, PropertyGroup): default='CLOSED', update=update ) - nose_type = EnumProperty( + nose_type : EnumProperty( name="Nosing", items=( ('STRAIGHT', 'Straight', '', 0), @@ -1767,7 +1767,7 @@ class archipack_stair(ArchipackObject, Manipulable, PropertyGroup): default='STRAIGHT', update=update ) - left_shape = EnumProperty( + left_shape : EnumProperty( items=( ('RECTANGLE', 'Straight', '', 0), ('CIRCLE', 'Curved ', '', 1) @@ -1775,7 +1775,7 @@ class archipack_stair(ArchipackObject, Manipulable, PropertyGroup): default='RECTANGLE', update=update ) - right_shape = EnumProperty( + right_shape : EnumProperty( items=( ('RECTANGLE', 'Straight', '', 0), ('CIRCLE', 'Curved ', '', 1) @@ -1783,7 +1783,7 @@ class archipack_stair(ArchipackObject, Manipulable, PropertyGroup): default='RECTANGLE', update=update ) - z_mode = EnumProperty( + z_mode : EnumProperty( name="Interp z", items=( ('STANDARD', 'Standard', '', 0), @@ -1793,7 +1793,7 @@ class archipack_stair(ArchipackObject, Manipulable, PropertyGroup): default='STANDARD', update=update ) - presets = EnumProperty( + presets : EnumProperty( items=( ('STAIR_I', 'I stair', '', 0), ('STAIR_L', 'L stair', '', 1), @@ -1803,131 +1803,131 @@ class archipack_stair(ArchipackObject, Manipulable, PropertyGroup): ), default='STAIR_I', update=update_preset ) - left_post = BoolProperty( + left_post : BoolProperty( name='left', default=True, update=update ) - right_post = BoolProperty( + right_post : BoolProperty( name='right', default=True, update=update ) - post_spacing = FloatProperty( + post_spacing : FloatProperty( name="Spacing", min=0.1, default=1.0, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - post_x = FloatProperty( + post_x : FloatProperty( name="Width", min=0.001, default=0.04, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - post_y = FloatProperty( + post_y : FloatProperty( name="Length", min=0.001, default=0.04, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - post_z = FloatProperty( + post_z : FloatProperty( name="Height", min=0.001, default=1, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - post_alt = FloatProperty( + post_alt : FloatProperty( name="Altitude", min=-100, default=0, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - post_offset_x = FloatProperty( + post_offset_x : FloatProperty( name="Offset", min=-100.0, max=100, default=0.02, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - post_corners = BoolProperty( + post_corners : BoolProperty( name="Only on edges", update=update, default=False ) - user_defined_post_enable = BoolProperty( + user_defined_post_enable : BoolProperty( name="User", update=update, default=True ) - user_defined_post = StringProperty( + user_defined_post : StringProperty( name="User defined", update=update ) - idmat_post = EnumProperty( + idmat_post : EnumProperty( name="Post", items=materials_enum, default='4', update=update ) - left_subs = BoolProperty( + left_subs : BoolProperty( name='left', default=False, update=update ) - right_subs = BoolProperty( + right_subs : BoolProperty( name='right', default=False, update=update ) - subs_spacing = FloatProperty( + subs_spacing : FloatProperty( name="Spacing", min=0.05, default=0.10, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - subs_x = FloatProperty( + subs_x : FloatProperty( name="Width", min=0.001, default=0.02, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - subs_y = FloatProperty( + subs_y : FloatProperty( name="Length", min=0.001, default=0.02, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - subs_z = FloatProperty( + subs_z : FloatProperty( name="Height", min=0.001, default=1, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - subs_alt = FloatProperty( + subs_alt : FloatProperty( name="Altitude", min=-100, default=0, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - subs_offset_x = FloatProperty( + subs_offset_x : FloatProperty( name="Offset", min=-100.0, max=100, default=0.0, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - subs_bottom = EnumProperty( + subs_bottom : EnumProperty( name="Bottom", items=( ('STEP', 'Follow step', '', 0), @@ -1936,88 +1936,88 @@ class archipack_stair(ArchipackObject, Manipulable, PropertyGroup): default='STEP', update=update ) - user_defined_subs_enable = BoolProperty( + user_defined_subs_enable : BoolProperty( name="User", update=update, default=True ) - user_defined_subs = StringProperty( + user_defined_subs : StringProperty( name="User defined", update=update ) - idmat_subs = EnumProperty( + idmat_subs : EnumProperty( name="Subs", items=materials_enum, default='4', update=update ) - left_panel = BoolProperty( + left_panel : BoolProperty( name='left', default=True, update=update ) - right_panel = BoolProperty( + right_panel : BoolProperty( name='right', default=True, update=update ) - panel_alt = FloatProperty( + panel_alt : FloatProperty( name="Altitude", default=0.25, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - panel_x = FloatProperty( + panel_x : FloatProperty( name="Width", min=0.001, default=0.01, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - panel_z = FloatProperty( + panel_z : FloatProperty( name="Height", min=0.001, default=0.6, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - panel_dist = FloatProperty( + panel_dist : FloatProperty( name="Spacing", min=0.001, default=0.05, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - panel_offset_x = FloatProperty( + panel_offset_x : FloatProperty( name="Offset", default=0.0, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - idmat_panel = EnumProperty( + idmat_panel : EnumProperty( name="Panels", items=materials_enum, default='5', update=update ) - left_rail = BoolProperty( + left_rail : BoolProperty( name="left", update=update, default=False ) - right_rail = BoolProperty( + right_rail : BoolProperty( name="right", update=update, default=False ) - rail_n = IntProperty( + rail_n : IntProperty( name="#", default=1, min=0, max=31, update=update ) - rail_x = FloatVectorProperty( + rail_x : FloatVectorProperty( name="Width", default=[ 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, @@ -2031,7 +2031,7 @@ class archipack_stair(ArchipackObject, Manipulable, PropertyGroup): unit='LENGTH', update=update ) - rail_z = FloatVectorProperty( + rail_z : FloatVectorProperty( name="Height", default=[ 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, @@ -2045,7 +2045,7 @@ class archipack_stair(ArchipackObject, Manipulable, PropertyGroup): unit='LENGTH', update=update ) - rail_offset = FloatVectorProperty( + rail_offset : FloatVectorProperty( name="Offset", default=[ 0, 0, 0, 0, 0, 0, 0, 0, @@ -2058,7 +2058,7 @@ class archipack_stair(ArchipackObject, Manipulable, PropertyGroup): unit='LENGTH', update=update ) - rail_alt = FloatVectorProperty( + rail_alt : FloatVectorProperty( name="Altitude", default=[ 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, @@ -2071,47 +2071,47 @@ class archipack_stair(ArchipackObject, Manipulable, PropertyGroup): unit='LENGTH', update=update ) - rail_mat = CollectionProperty(type=archipack_stair_material) + rail_mat : CollectionProperty(type=archipack_stair_material) - left_handrail = BoolProperty( + left_handrail : BoolProperty( name="left", update=update, default=True ) - right_handrail = BoolProperty( + right_handrail : BoolProperty( name="right", update=update, default=True ) - handrail_offset = FloatProperty( + handrail_offset : FloatProperty( name="Offset", default=0.0, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - handrail_alt = FloatProperty( + handrail_alt : FloatProperty( name="Altitude", default=1.0, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - handrail_extend = FloatProperty( + handrail_extend : FloatProperty( name="Extend", default=0.1, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - handrail_slice_left = BoolProperty( + handrail_slice_left : BoolProperty( name='Slice', default=True, update=update ) - handrail_slice_right = BoolProperty( + handrail_slice_right : BoolProperty( name='Slice', default=True, update=update ) - handrail_profil = EnumProperty( + handrail_profil : EnumProperty( name="Profil", items=( ('SQUARE', 'Square', '', 0), @@ -2121,21 +2121,21 @@ class archipack_stair(ArchipackObject, Manipulable, PropertyGroup): default='SQUARE', update=update ) - handrail_x = FloatProperty( + handrail_x : FloatProperty( name="Width", min=0.001, default=0.04, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - handrail_y = FloatProperty( + handrail_y : FloatProperty( name="Height", min=0.001, default=0.04, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - handrail_radius = FloatProperty( + handrail_radius : FloatProperty( name="Radius", min=0.001, default=0.02, precision=2, step=1, @@ -2143,85 +2143,85 @@ class archipack_stair(ArchipackObject, Manipulable, PropertyGroup): update=update ) - left_string = BoolProperty( + left_string : BoolProperty( name="left", update=update, default=False ) - right_string = BoolProperty( + right_string : BoolProperty( name="right", update=update, default=False ) - string_x = FloatProperty( + string_x : FloatProperty( name="Width", min=-100.0, default=0.02, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - string_z = FloatProperty( + string_z : FloatProperty( name="Height", default=0.3, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - string_offset = FloatProperty( + string_offset : FloatProperty( name="Offset", default=0.0, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - string_alt = FloatProperty( + string_alt : FloatProperty( name="Altitude", default=-0.04, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - idmat_bottom = EnumProperty( + idmat_bottom : EnumProperty( name="Bottom", items=materials_enum, default='1', update=update ) - idmat_raise = EnumProperty( + idmat_raise : EnumProperty( name="Raise", items=materials_enum, default='1', update=update ) - idmat_step_front = EnumProperty( + idmat_step_front : EnumProperty( name="Step front", items=materials_enum, default='3', update=update ) - idmat_top = EnumProperty( + idmat_top : EnumProperty( name="Top", items=materials_enum, default='3', update=update ) - idmat_side = EnumProperty( + idmat_side : EnumProperty( name="Side", items=materials_enum, default='1', update=update ) - idmat_step_side = EnumProperty( + idmat_step_side : EnumProperty( name="Step Side", items=materials_enum, default='3', update=update ) - idmat_handrail = EnumProperty( + idmat_handrail : EnumProperty( name="Handrail", items=materials_enum, default='3', update=update ) - idmat_string = EnumProperty( + idmat_string : EnumProperty( name="String", items=materials_enum, default='3', @@ -2229,35 +2229,35 @@ class archipack_stair(ArchipackObject, Manipulable, PropertyGroup): ) # UI layout related - parts_expand = BoolProperty( + parts_expand : BoolProperty( default=False ) - steps_expand = BoolProperty( + steps_expand : BoolProperty( default=False ) - rail_expand = BoolProperty( + rail_expand : BoolProperty( default=False ) - idmats_expand = BoolProperty( + idmats_expand : BoolProperty( default=False ) - handrail_expand = BoolProperty( + handrail_expand : BoolProperty( default=False ) - string_expand = BoolProperty( + string_expand : BoolProperty( default=False ) - post_expand = BoolProperty( + post_expand : BoolProperty( default=False ) - panel_expand = BoolProperty( + panel_expand : BoolProperty( default=False ) - subs_expand = BoolProperty( + subs_expand : BoolProperty( default=False ) - auto_update = BoolProperty( + auto_update : BoolProperty( options={'SKIP_SAVE'}, default=True, update=update_manipulators @@ -2539,7 +2539,7 @@ class ARCHIPACK_PT_stair(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'UI' # bl_context = 'object' - bl_category = 'ArchiPack' + bl_category = 'Archipack' @classmethod def poll(cls, context): @@ -2552,7 +2552,7 @@ class ARCHIPACK_PT_stair(Panel): scene = context.scene layout = self.layout row = layout.row(align=True) - row.operator('archipack.stair_manipulate', icon='HAND') + row.operator('archipack.stair_manipulate', icon='VIEW_PAN') row = layout.row(align=True) row.prop(prop, 'presets', text="") box = layout.box() @@ -2560,8 +2560,8 @@ class ARCHIPACK_PT_stair(Panel): row = box.row(align=True) # row.menu("ARCHIPACK_MT_stair_preset", text=bpy.types.ARCHIPACK_MT_stair_preset.bl_label) row.operator("archipack.stair_preset_menu", text=bpy.types.ARCHIPACK_OT_stair_preset_menu.bl_label) - row.operator("archipack.stair_preset", text="", icon='ZOOMIN') - row.operator("archipack.stair_preset", text="", icon='ZOOMOUT').remove_active = True + row.operator("archipack.stair_preset", text="", icon='ADD') + row.operator("archipack.stair_preset", text="", icon='REMOVE').remove_active = True box = layout.box() box.prop(prop, 'width') box.prop(prop, 'height') @@ -2753,9 +2753,9 @@ class ARCHIPACK_OT_stair(ArchipackCreateTool, Operator): m = bpy.data.meshes.new("Stair") o = bpy.data.objects.new("Stair", m) d = m.archipack_stair.add() - context.scene.objects.link(o) - o.select = True - context.scene.objects.active = o + context.scene.collection.objects.link(o) + o.select_set(state=True) + context.view_layer.objects.active = o self.load_preset(d) self.add_material(o) m.auto_smooth_angle = 0.20944 @@ -2769,8 +2769,8 @@ class ARCHIPACK_OT_stair(ArchipackCreateTool, Operator): bpy.ops.object.select_all(action="DESELECT") o = self.create(context) o.location = context.scene.cursor_location - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o self.manipulate() return {'FINISHED'} else: diff --git a/archipack/archipack_thumbs.py b/archipack/archipack_thumbs.py index bfc9d55e..cd5ced6d 100644 --- a/archipack/archipack_thumbs.py +++ b/archipack/archipack_thumbs.py @@ -33,38 +33,30 @@ def log(s): print("[log]" + s) -def generateThumb(context, cls, preset): - log("### RENDER THUMB ############################") - log("Start generating: " + cls) +def create_lamp(context, loc): + bpy.ops.object.light_add( + type='POINT', + radius=1, + view_align=False, + location=loc) + lamp = context.active_object + lamp.data.use_nodes = True + tree = lamp.data.node_tree + return tree, tree.nodes - # engine settings - context.scene.render.engine = 'CYCLES' - render = context.scene.cycles - render.progressive = 'PATH' - render.samples = 24 - try: - render.use_square_samples = True - except: - pass - render.preview_samples = 24 - render.aa_samples = 24 - render.transparent_max_bounces = 8 - render.transparent_min_bounces = 8 - render.transmission_bounces = 8 - render.max_bounces = 8 - render.min_bounces = 6 - render.caustics_refractive = False - render.caustics_reflective = False - render.use_transparent_shadows = True - render.diffuse_bounces = 1 - render.glossy_bounces = 4 - bpy.ops.object.select_all(action="SELECT") - bpy.ops.object.delete() - # create object, loading preset - getattr(bpy.ops.archipack, cls)('INVOKE_DEFAULT', filepath=preset, auto_manipulate=False) - o = context.active_object - size = o.dimensions +def create_camera(context, loc, rot): + bpy.ops.object.camera_add( + view_align=True, + enter_editmode=False, + location=loc, + rotation=rot) + cam = context.active_object + context.scene.camera = cam + return cam + + +def get_center(o): x, y, z = o.bound_box[0] min_x = x min_y = y @@ -73,27 +65,90 @@ def generateThumb(context, cls, preset): max_x = x max_y = y max_z = z - center = Vector(( + return Vector(( min_x + 0.5 * (max_x - min_x), min_y + 0.5 * (max_y - min_y), min_z + 0.5 * (max_z - min_z))) - # oposite / tan (0.5 * fov) where fov is 49.134 deg + +def apply_simple_material(o, name, color): + m = bpy.data.materials.new(name) + m.use_nodes = True + m.node_tree.nodes[1].inputs[0].default_value = color + o.data.materials.append(m) + + +# /home/stephen/blender-28-git/build_linux_full/bin/blender --background --factory-startup -noaudio --python /home/stephen/blender-28-git/build_linux_full/bin/2.80/scripts/addons/archipack/archipack_thumbs.py -- addon:archipack matlib:/medias/stephen/DATA/lib/ cls:roof preset:/home/stephen/.config/blender/2.80/scripts/presets/archipack_roof/square.py + + +def generateThumb(context, cls, preset, engine): + log("### RENDER THUMB ############################") + + # Cleanup scene + for o in context.scene.objects: + o.select_set(state=True) + + bpy.ops.object.delete() + + log("Start generating: %s" % cls) + + # setup render + + context.scene.render.engine = engine + + if engine == 'CYCLES': + cycles = context.scene.cycles + cycles.progressive = 'PATH' + cycles.samples = 24 + try: + cycles.use_square_samples = True + except: + pass + cycles.preview_samples = 24 + cycles.aa_samples = 24 + cycles.transparent_max_bounces = 8 + cycles.transparent_min_bounces = 8 + cycles.transmission_bounces = 8 + cycles.max_bounces = 8 + cycles.min_bounces = 6 + cycles.caustics_refractive = False + cycles.caustics_reflective = False + cycles.use_transparent_shadows = True + cycles.diffuse_bounces = 1 + cycles.glossy_bounces = 4 + + elif engine == 'BLENDER_EEVEE': + eevee = context.scene.eevee + + else: + raise RuntimeError("Unsupported render engine %s" % engine) + + render = context.scene.render + + # engine settings + render.resolution_x = 150 + render.resolution_y = 100 + render.filepath = preset[:-3] + ".png" + + # create object, loading preset + getattr(bpy.ops.archipack, cls)('INVOKE_DEFAULT', filepath=preset, auto_manipulate=False) + o = context.active_object + size = o.dimensions + center = get_center(o) + + # opposite / tan (0.5 * fov) where fov is 49.134 deg dist = max(size) / 0.32 - loc = center + dist * Vector((0.5, -1, 0.5)).normalized() + loc = center + dist * Vector((-0.5, -1, 0.5)).normalized() log("Prepare camera") - bpy.ops.object.camera_add(view_align=True, - enter_editmode=False, - location=loc, - rotation=(1.150952, 0.0, 0.462509)) - cam = context.active_object + cam = create_camera(context, loc, (1.150952, 0.0, -0.462509)) cam.data.lens = 50 - cam.select = True - context.scene.camera = cam - bpy.ops.object.select_all(action="DESELECT") - o.select = True + for ob in context.scene.objects: + ob.select_set(state=False) + + o.select_set(state=True) + bpy.ops.view3d.camera_to_view_selected() log("Prepare scene") @@ -103,63 +158,33 @@ def generateThumb(context, cls, preset): view_align=False, enter_editmode=False, location=(0, 0, 0) - ) + ) + p = context.active_object - m = bpy.data.materials.new("Plane") - m.use_nodes = True - m.node_tree.nodes[1].inputs[0].default_value = (1, 1, 1, 1) - p.data.materials.append(m) + apply_simple_material(p, "Plane", (1, 1, 1, 1)) # add 3 lights - bpy.ops.object.light_add( - type='POINT', - radius=1, - view_align=False, - location=(3.69736, -7, 6.0)) - l = context.active_object - l.data.use_nodes = True - tree = l.data.node_tree - nodes = l.data.node_tree.nodes + tree, nodes = create_lamp(context, (3.69736, -7, 6.0)) emit = nodes["Emission"] emit.inputs[1].default_value = 2000.0 - bpy.ops.object.light_add( - type='POINT', - radius=1, - view_align=False, - location=(9.414563179016113, 5.446230888366699, 5.903861999511719)) - l = context.active_object - l.data.use_nodes = True - tree = l.data.node_tree - nodes = l.data.node_tree.nodes + tree, nodes = create_lamp(context, (9.414563179016113, 5.446230888366699, 5.903861999511719)) emit = nodes["Emission"] falloff = nodes.new(type="ShaderNodeLightFalloff") falloff.inputs[0].default_value = 5 tree.links.new(falloff.outputs[2], emit.inputs[1]) - bpy.ops.object.light_add( - type='POINT', - radius=1, - view_align=False, - location=(-7.847615718841553, 1.03135085105896, 5.903861999511719)) - l = context.active_object - l.data.use_nodes = True - tree = l.data.node_tree - nodes = l.data.node_tree.nodes + tree, nodes = create_lamp(context, (-7.847615718841553, 1.03135085105896, 5.903861999511719)) emit = nodes["Emission"] falloff = nodes.new(type="ShaderNodeLightFalloff") falloff.inputs[0].default_value = 5 tree.links.new(falloff.outputs[2], emit.inputs[1]) # Set output filename. - render = context.scene.render - render.filepath = preset[:-3] + ".png" render.use_file_extension = True render.use_overwrite = True render.use_compositing = False render.use_sequencer = False - render.resolution_x = 150 - render.resolution_y = 100 render.resolution_percentage = 100 # render.image_settings.file_format = 'PNG' # render.image_settings.color_mode = 'RGBA' @@ -175,8 +200,9 @@ def generateThumb(context, cls, preset): if __name__ == "__main__": - preset = "" + preset = "" + engine = 'BLENDER_EEVEE' #'CYCLES' for arg in sys.argv: if arg.startswith("cls:"): cls = arg[4:] @@ -186,9 +212,14 @@ if __name__ == "__main__": matlib = arg[7:] if arg.startswith("addon:"): module = arg[6:] + if arg.startswith("engine:"): + engine = arg[7:] try: + # log("### ENABLE %s ADDON ############################" % module) bpy.ops.wm.addon_enable(module=module) + # log("### MATLIB PATH ############################") bpy.context.user_preferences.addons[module].preferences.matlib_path = matlib except: raise RuntimeError("module name not found") - generateThumb(bpy.context, cls, preset) + # log("### GENERATE ############################") + generateThumb(bpy.context, cls, preset, engine) diff --git a/archipack/archipack_truss.py b/archipack/archipack_truss.py index b8056daa..c8fe8768 100644 --- a/archipack/archipack_truss.py +++ b/archipack/archipack_truss.py @@ -43,7 +43,7 @@ def update(self, context): class archipack_truss(ArchipackObject, Manipulable, PropertyGroup): - truss_type = EnumProperty( + truss_type : EnumProperty( name="Type", items=( ('1', 'Prolyte E20', 'Prolyte E20', 0), @@ -57,40 +57,40 @@ class archipack_truss(ArchipackObject, Manipulable, PropertyGroup): default='2', update=update ) - z = FloatProperty( + z : FloatProperty( name="Height", default=2.0, min=0.01, unit='LENGTH', subtype='DISTANCE', update=update ) - segs = IntProperty( + segs : IntProperty( name="Segs", default=6, min=3, update=update ) - master_segs = IntProperty( + master_segs : IntProperty( name="Master Segs", default=1, min=1, update=update ) - master_count = IntProperty( + master_count : IntProperty( name="Masters", default=3, min=2, update=update ) - entre_axe = FloatProperty( + entre_axe : FloatProperty( name="Distance", default=0.239, min=0.001, unit='LENGTH', subtype='DISTANCE', update=update ) - master_radius = FloatProperty( + master_radius : FloatProperty( name="Radius", default=0.02415, min=0.0001, unit='LENGTH', subtype='DISTANCE', update=update ) - slaves_radius = FloatProperty( + slaves_radius : FloatProperty( name="Subs radius", default=0.01, min=0.0001, unit='LENGTH', subtype='DISTANCE', @@ -101,7 +101,7 @@ class archipack_truss(ArchipackObject, Manipulable, PropertyGroup): # .auto_update = False # bulk changes # .auto_update = True - auto_update = BoolProperty( + auto_update : BoolProperty( options={'SKIP_SAVE'}, default=True, update=update @@ -127,10 +127,10 @@ class archipack_truss(ArchipackObject, Manipulable, PropertyGroup): if not add: for seg in range(segs): - verts.append(tM * tMb * tmpverts[seg]) + verts.append(tM @ tMb @ tmpverts[seg]) for seg in range(segs): - verts.append(tM * tMt * tmpverts[seg]) + verts.append(tM @ tMt @ tmpverts[seg]) for seg in range(segs - 1): f = cv + seg @@ -280,7 +280,7 @@ class ARCHIPACK_PT_truss(Panel): bl_label = "Truss" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' - bl_category = 'ArchiPack' + bl_category = 'Archipack' @classmethod def poll(cls, context): @@ -292,7 +292,7 @@ class ARCHIPACK_PT_truss(Panel): return layout = self.layout row = layout.row(align=True) - row.operator('archipack.truss_manipulate', icon='HAND') + row.operator('archipack.truss_manipulate', icon='VIEW_PAN') box = layout.box() box.prop(prop, 'truss_type') box.prop(prop, 'z') @@ -318,9 +318,9 @@ class ARCHIPACK_OT_truss(ArchipackCreateTool, Operator): d = m.archipack_truss.add() # make manipulators selectable # d.manipulable_selectable = True - context.scene.objects.link(o) - o.select = True - context.scene.objects.active = o + context.scene.collection.objects.link(o) + o.select_set(state=True) + context.view_layer.objects.active = o self.load_preset(d) self.add_material(o) m.auto_smooth_angle = 1.15 @@ -334,8 +334,8 @@ class ARCHIPACK_OT_truss(ArchipackCreateTool, Operator): bpy.ops.object.select_all(action="DESELECT") o = self.create(context) o.location = bpy.context.scene.cursor_location - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o self.manipulate() return {'FINISHED'} else: diff --git a/archipack/archipack_wall2.py b/archipack/archipack_wall2.py index 1506e171..09836780 100644 --- a/archipack/archipack_wall2.py +++ b/archipack/archipack_wall2.py @@ -45,11 +45,14 @@ from .archipack_manipulator import ( GlPolygon, GlPolyline, GlLine, GlText, FeedbackPanel ) -from .archipack_object import ArchipackObject, ArchipackCreateTool, ArchpackDrawTool +from .archipack_object import ArchipackObject, ArchipackCreateTool, ArchipackDrawTool from .archipack_2d import Line, Arc from .archipack_snap import snap_point from .archipack_keymaps import Keymaps +import logging +logger = logging.getLogger("archipack") + class Wall(): def __init__(self, wall_z, z, t, flip): @@ -323,7 +326,7 @@ class WallGenerator(): for i in range(idx_from + 1, len(self.segs)): seg = self.segs[i] seg.rotate(a) - dp = rM * (seg.p0 - p0) + dp = rM @ (seg.p0 - p0) seg.translate(dp) def translate(self, idx_from, dp): @@ -338,7 +341,7 @@ class WallGenerator(): """ move shape fromTM into toTM coordsys """ - dp = (toTM.inverted() * fromTM.translation).to_2d() + dp = (toTM.inverted() @ fromTM.translation).to_2d() da = toTM.row[1].to_2d().angle_signed(fromTM.row[1].to_2d()) ca = cos(da) sa = sin(da) @@ -347,7 +350,7 @@ class WallGenerator(): [sa, ca] ]) for s in self.segs: - tp = (rM * s.p0) - s.p0 + dp + tp = (rM @ s.p0) - s.p0 + dp s.rotate(da) s.translate(tp) @@ -446,27 +449,27 @@ def update_t_part(self, context): if o.parent is None: # create a reference point and make it active x, y, z = w.bound_box[0] - context.scene.cursor_location = w.matrix_world * Vector((x, y, z)) + context.scene.cursor_location = w.matrix_world @ Vector((x, y, z)) # fix issue #9 - context.scene.objects.active = o + context.view_layer.objects.active = o bpy.ops.archipack.reference_point() - o.select = True + o.select_set(state=True) else: - context.scene.objects.active = o.parent - w.select = True + context.view_layer.objects.active = o.parent + w.select_set(state=True) else: # w has parent if o.parent is not w.parent: link_to_parent = True - context.scene.objects.active = w.parent - o.select = True + context.view_layer.objects.active = w.parent + o.select_set(state=True) if o.parent is not None: # store o.parent to delete it to_delete = o.parent for c in o.parent.children: if c is not o: c.hide_select = False - c.select = True + c.select_set(state=True) parent = context.active_object @@ -487,11 +490,11 @@ def update_t_part(self, context): ]) # dir in absolute world coordsys - dir = orM * og.segs[0].straight(1, 0).v + dir = orM @ og.segs[0].straight(1, 0).v # pt in w coordsys pos = otM.translation - pt = (wtM.inverted() * pos).to_2d() + pt = (wtM.inverted() @ pos).to_2d() for wall_idx, wall in enumerate(wg.segs): res, dist, t = wall.point_sur_segment(pt) @@ -504,8 +507,8 @@ def update_t_part(self, context): # rotation here is wrong when w has not parent while o has parent if res and t > 0 and t < 1 and abs(dist) < dmax: - x = wrM * wall.straight(1, t).v - y = wrM * wall.normal(t).v.normalized() + x = wrM @ wall.straight(1, t).v + y = wrM @ wall.normal(t).v.normalized() self.parts[0].a0 = dir.angle_signed(x) o.matrix_world = Matrix([ [x.x, -y.x, 0, pos.x], @@ -531,8 +534,8 @@ def update_t_part(self, context): # delete unneeded reference point if to_delete is not None: bpy.ops.object.select_all(action="DESELECT") - to_delete.select = True - context.scene.objects.active = to_delete + to_delete.select_set(state=True) + context.view_layer.objects.active = to_delete if bpy.ops.object.delete.poll(): bpy.ops.object.delete(use_global=False) @@ -624,7 +627,7 @@ def update_type(self, context): class archipack_wall2_part(PropertyGroup): - type = EnumProperty( + type : EnumProperty( items=( ('S_WALL', 'Straight', '', 0), ('C_WALL', 'Curved', '', 1) @@ -632,21 +635,21 @@ class archipack_wall2_part(PropertyGroup): default='S_WALL', update=update_type ) - length = FloatProperty( + length : FloatProperty( name="Length", min=0.01, default=2.0, unit='LENGTH', subtype='DISTANCE', update=update ) - radius = FloatProperty( + radius : FloatProperty( name="Radius", min=0.5, default=0.7, unit='LENGTH', subtype='DISTANCE', update=update ) - a0 = FloatProperty( + a0 : FloatProperty( name="Start angle", min=-pi, max=pi, @@ -654,7 +657,7 @@ class archipack_wall2_part(PropertyGroup): subtype='ANGLE', unit='ROTATION', update=update ) - da = FloatProperty( + da : FloatProperty( name="Angle", min=-pi, max=pi, @@ -662,7 +665,7 @@ class archipack_wall2_part(PropertyGroup): subtype='ANGLE', unit='ROTATION', update=update ) - z = FloatVectorProperty( + z : FloatVectorProperty( name="Height", default=[ 0, 0, 0, 0, 0, 0, 0, 0, @@ -673,7 +676,7 @@ class archipack_wall2_part(PropertyGroup): size=31, update=update ) - t = FloatVectorProperty( + t : FloatVectorProperty( name="Position", min=0, max=1, @@ -686,24 +689,24 @@ class archipack_wall2_part(PropertyGroup): size=31, update=update ) - splits = IntProperty( + splits : IntProperty( name="Splits", default=1, min=1, max=31, get=get_splits, set=set_splits ) - n_splits = IntProperty( + n_splits : IntProperty( name="Splits", default=1, min=1, max=31, update=update ) - auto_update = BoolProperty(default=True) - manipulators = CollectionProperty(type=archipack_manipulator) + auto_update : BoolProperty(default=True) + manipulators : CollectionProperty(type=archipack_manipulator) # ui related - expand = BoolProperty(default=False) + expand : BoolProperty(default=False) def _set_t(self, splits): t = 1 / splits @@ -766,11 +769,11 @@ class archipack_wall2_part(PropertyGroup): class archipack_wall2_child(PropertyGroup): # Size Loc # Delta Loc - manipulators = CollectionProperty(type=archipack_manipulator) - child_name = StringProperty() - wall_idx = IntProperty() - pos = FloatVectorProperty(subtype='XYZ') - flip = BoolProperty(default=False) + manipulators : CollectionProperty(type=archipack_manipulator) + child_name : StringProperty() + wall_idx : IntProperty() + pos : FloatVectorProperty(subtype='XYZ') + flip : BoolProperty(default=False) def get_child(self, context): d = None @@ -785,14 +788,14 @@ class archipack_wall2_child(PropertyGroup): class archipack_wall2(ArchipackObject, Manipulable, PropertyGroup): - parts = CollectionProperty(type=archipack_wall2_part) - n_parts = IntProperty( + parts : CollectionProperty(type=archipack_wall2_part) + n_parts : IntProperty( name="Parts", min=1, max=1024, default=1, update=update_manipulators ) - step_angle = FloatProperty( + step_angle : FloatProperty( description="Curved parts segmentation", name="Step angle", min=1 / 180 * pi, @@ -801,34 +804,34 @@ class archipack_wall2(ArchipackObject, Manipulable, PropertyGroup): subtype='ANGLE', unit='ROTATION', update=update ) - width = FloatProperty( + width : FloatProperty( name="Width", min=0.01, default=0.2, unit='LENGTH', subtype='DISTANCE', update=update ) - z = FloatProperty( + z : FloatProperty( name='Height', min=0.1, default=2.7, precision=2, unit='LENGTH', subtype='DISTANCE', description='height', update=update, ) - x_offset = FloatProperty( + x_offset : FloatProperty( name="Offset", min=-1, max=1, default=-1, precision=2, step=1, update=update ) - radius = FloatProperty( + radius : FloatProperty( name="Radius", min=0.5, default=0.7, unit='LENGTH', subtype='DISTANCE', update=update ) - da = FloatProperty( + da : FloatProperty( name="Angle", min=-pi, max=pi, @@ -836,32 +839,32 @@ class archipack_wall2(ArchipackObject, Manipulable, PropertyGroup): subtype='ANGLE', unit='ROTATION', update=update ) - flip = BoolProperty( + flip : BoolProperty( name="Flip", default=False, update=update_childs ) - closed = BoolProperty( + closed : BoolProperty( default=False, name="Close", update=update_manipulators ) - auto_update = BoolProperty( + auto_update : BoolProperty( options={'SKIP_SAVE'}, default=True, update=update_manipulators ) - realtime = BoolProperty( + realtime : BoolProperty( options={'SKIP_SAVE'}, default=True, name="Real Time", description="Relocate childs in realtime" ) # dumb manipulators to show sizes between childs - childs_manipulators = CollectionProperty(type=archipack_manipulator) + childs_manipulators : CollectionProperty(type=archipack_manipulator) # store to manipulate windows and doors - childs = CollectionProperty(type=archipack_wall2_child) - t_part = StringProperty( + childs : CollectionProperty(type=archipack_wall2_child) + t_part : StringProperty( name="Parent wall", description="This part will follow parent when set", default="", @@ -1014,18 +1017,18 @@ class archipack_wall2(ArchipackObject, Manipulable, PropertyGroup): def interpolate_bezier(self, pts, wM, p0, p1, resolution): if resolution == 0: - pts.append(wM * p0.co.to_3d()) + pts.append(wM @ p0.co.to_3d()) else: v = (p1.co - p0.co).normalized() d1 = (p0.handle_right - p0.co).normalized() d2 = (p1.co - p1.handle_left).normalized() if d1 == v and d2 == v: - pts.append(wM * p0.co.to_3d()) + pts.append(wM @ p0.co.to_3d()) else: - seg = interpolate_bezier(wM * p0.co, - wM * p0.handle_right, - wM * p1.handle_left, - wM * p1.co, + seg = interpolate_bezier(wM @ p0.co, + wM @ p0.handle_right, + wM @ p1.handle_left, + wM @ p1.co, resolution + 1) for i in range(resolution): pts.append(seg[i].to_3d()) @@ -1041,7 +1044,7 @@ class archipack_wall2(ArchipackObject, Manipulable, PropertyGroup): def from_spline(self, wM, resolution, spline): pts = [] if spline.type == 'POLY': - pts = [wM * p.co.to_3d() for p in spline.points] + pts = [wM @ p.co.to_3d() for p in spline.points] if spline.use_cyclic_u: pts.append(pts[0]) elif spline.type == 'BEZIER': @@ -1056,7 +1059,7 @@ class archipack_wall2(ArchipackObject, Manipulable, PropertyGroup): self.interpolate_bezier(pts, wM, p0, p1, resolution) pts.append(pts[0]) else: - pts.append(wM * points[-1].co) + pts.append(wM @ points[-1].co) if self.is_cw(pts): pts = list(reversed(pts)) @@ -1134,7 +1137,7 @@ class archipack_wall2(ArchipackObject, Manipulable, PropertyGroup): if not self.closed: dp = pts[0] - pts[-1] # pre-translate as dp is in local coordsys - o.matrix_world = o.matrix_world * Matrix([ + o.matrix_world = o.matrix_world @ Matrix([ [1, 0, 0, dp.x], [0, 1, 0, dp.y], [0, 0, 1, 0], @@ -1326,7 +1329,7 @@ class archipack_wall2(ArchipackObject, Manipulable, PropertyGroup): # pt in w coordsys pos = ctM.translation - pt = (witM * pos).to_2d() + pt = (witM @ pos).to_2d() for wall_idx, wall in enumerate(g.segs): # may be optimized with a bound check @@ -1337,7 +1340,7 @@ class archipack_wall2(ArchipackObject, Manipulable, PropertyGroup): # p0 if res and t > 0 and t < 1 and abs(dist) < dmax: # dir in world coordsys - dir = wrM * wall.sized_normal(t, 1).v + dir = wrM @ wall.sized_normal(t, 1).v wall_with_childs[wall_idx] = 1 m = self.childs_manipulators.add() m.type_key = 'DUMB_SIZE' @@ -1345,14 +1348,14 @@ class archipack_wall2(ArchipackObject, Manipulable, PropertyGroup): if "archipack_window" in cd: flip = self.flip else: - dir_y = crM * Vector((0, -1)) + dir_y = crM @ Vector((0, -1)) # let door orient where user want flip = (dir_y - dir).length > 0.5 # store z in wall space relocate.append(( child.name, wall_idx, - (t * wall.length, dist, (witM * pos).z), + (t * wall.length, dist, (witM @ pos).z), flip, t)) break @@ -1392,19 +1395,19 @@ class archipack_wall2(ArchipackObject, Manipulable, PropertyGroup): if d is not None: # print("change flip:%s width:%s" % (d.flip != child.flip, d.y != self.width)) if d.y != self.width or d.flip != child.flip: - c.select = True + c.select_set(state=True) d.auto_update = False d.flip = child.flip d.y = self.width d.auto_update = True - c.select = False + c.select_set(state=False) x, y = n.p - (0.5 * w * n.v) else: x, y = n.p - (child.pos.y * n.v) - context.scene.objects.active = o + context.view_layer.objects.active = o # preTranslate - c.matrix_world = tM * Matrix([ + c.matrix_world = tM @ Matrix([ [rx, -ry, 0, x], [ry, rx, 0, y], [0, 0, 1, child.pos.z], @@ -1445,7 +1448,7 @@ class archipack_wall2(ArchipackObject, Manipulable, PropertyGroup): # child is either a window or a door wall_has_childs = True dt = 0.5 * d.x / wall.length - pt = (itM * c.matrix_world.translation).to_2d() + pt = (itM @ c.matrix_world.translation).to_2d() res, y, t = wall.point_sur_segment(pt) child.pos = (wall.length * t, y, child.pos.z) p1 = wall.lerp(t - dt) @@ -1503,7 +1506,7 @@ class archipack_wall2(ArchipackObject, Manipulable, PropertyGroup): if o.parent is not None: for c in o.parent.children: if (archipack_wall2.datablock(c) == self): - context.scene.objects.active = c + context.view_layer.objects.active = c found = True break if found: @@ -1522,12 +1525,12 @@ class archipack_wall2(ArchipackObject, Manipulable, PropertyGroup): if o.parent is None: return g = self.get_generator() - itM = o.matrix_world.inverted() * o.parent.matrix_world + itM = o.matrix_world.inverted() @ o.parent.matrix_world for child in self.childs: c, d = child.get_child(context) if d is not None: wall = g.segs[child.wall_idx] - pt = (itM * c.location).to_2d() + pt = (itM @ c.location).to_2d() res, d, t = wall.point_sur_segment(pt) child.pos = (t * wall.length, d, child.pos.z) # update childs manipulators @@ -1631,14 +1634,14 @@ class archipack_wall2(ArchipackObject, Manipulable, PropertyGroup): tM = o.matrix_world up = Vector((0, 0, 1)) for seg in g.segs: - p = tM * seg.p0.to_3d() + p = tM @ seg.p0.to_3d() p.z = 0.01 # prevent self intersect - o.hide = True + o.hide_viewport = True res, pos, normal, face_index, r, matrix_world = context.scene.ray_cast( p, up) - o.hide = False + o.hide_viewport = False # print("res:%s" % res) if res and r.data is not None and "archipack_roof" in r.data: return r, r.data.archipack_roof[0] @@ -1659,7 +1662,7 @@ class ARCHIPACK_OT_wall2_throttle_update(Operator): bl_idname = "archipack.wall2_throttle_update" bl_label = "Update childs with a delay" - name = StringProperty() + name : StringProperty() def modal(self, context, event): global update_timer_updating @@ -1671,7 +1674,7 @@ class ARCHIPACK_OT_wall2_throttle_update(Operator): if o is not None: m = o.modifiers.get("AutoBoolean") if m is not None: - o.hide = False + o.hide_viewport = False # o.display_type = 'TEXTURED' # m.show_viewport = True @@ -1709,7 +1712,7 @@ class ARCHIPACK_PT_wall2(Panel): bl_label = "Wall" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' - bl_category = 'ArchiPack' + bl_category = 'Archipack' def draw(self, context): prop = archipack_wall2.datablock(context.object) @@ -1717,7 +1720,7 @@ class ARCHIPACK_PT_wall2(Panel): return layout = self.layout row = layout.row(align=True) - row.operator("archipack.wall2_manipulate", icon='HAND') + row.operator("archipack.wall2_manipulate", icon='VIEW_PAN') # row = layout.row(align=True) # row.prop(prop, 'realtime') box = layout.box() @@ -1765,11 +1768,11 @@ class ARCHIPACK_OT_wall2(ArchipackCreateTool, Operator): o = bpy.data.objects.new("Wall", m) d = m.archipack_wall2.add() d.manipulable_selectable = True - context.scene.objects.link(o) - o.select = True + context.scene.collection.objects.link(o) + o.select_set(state=True) # around 12 degree m.auto_smooth_angle = 0.20944 - context.scene.objects.active = o + context.view_layer.objects.active = o self.load_preset(d) self.add_material(o) return o @@ -1779,8 +1782,8 @@ class ARCHIPACK_OT_wall2(ArchipackCreateTool, Operator): bpy.ops.object.select_all(action="DESELECT") o = self.create(context) o.location = bpy.context.scene.cursor_location - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o self.manipulate() return {'FINISHED'} else: @@ -1795,7 +1798,7 @@ class ARCHIPACK_OT_wall2_from_curve(Operator): bl_category = 'Archipack' bl_options = {'REGISTER', 'UNDO'} - auto_manipulate = BoolProperty(default=True) + auto_manipulate : BoolProperty(default=True) @classmethod def poll(self, context): @@ -1805,7 +1808,7 @@ class ARCHIPACK_OT_wall2_from_curve(Operator): curve = context.active_object for spline in curve.data.splines: bpy.ops.archipack.wall2(auto_manipulate=self.auto_manipulate) - o = context.scene.objects.active + o = context.view_layer.objects.active d = archipack_wall2.datablock(o) d.from_spline(curve.matrix_world, 12, spline) if spline.type == 'POLY': @@ -1815,7 +1818,7 @@ class ARCHIPACK_OT_wall2_from_curve(Operator): else: pt = Vector((0, 0, 0)) # pretranslate - o.matrix_world = curve.matrix_world * Matrix([ + o.matrix_world = curve.matrix_world @ Matrix([ [1, 0, 0, pt.x], [0, 1, 0, pt.y], [0, 0, 1, pt.z], @@ -1831,8 +1834,8 @@ class ARCHIPACK_OT_wall2_from_curve(Operator): bpy.ops.object.select_all(action="DESELECT") o = self.create(context) if o is not None: - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o return {'FINISHED'} else: self.report({'WARNING'}, "Archipack: Option only valid in Object mode") @@ -1846,7 +1849,7 @@ class ARCHIPACK_OT_wall2_from_slab(Operator): bl_category = 'Archipack' bl_options = {'REGISTER', 'UNDO'} - auto_manipulate = BoolProperty(default=True) + auto_manipulate : BoolProperty(default=True) @classmethod def poll(self, context): @@ -1857,7 +1860,7 @@ class ARCHIPACK_OT_wall2_from_slab(Operator): slab = context.active_object wd = slab.data.archipack_slab[0] bpy.ops.archipack.wall2(auto_manipulate=self.auto_manipulate) - o = context.scene.objects.active + o = context.view_layer.objects.active d = archipack_wall2.datablock(o) d.auto_update = False d.parts.clear() @@ -1873,8 +1876,8 @@ class ARCHIPACK_OT_wall2_from_slab(Operator): p.radius = part.radius p.da = part.da p.a0 = part.a0 - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o d.auto_update = True # pretranslate o.matrix_world = slab.matrix_world.copy() @@ -1883,17 +1886,17 @@ class ARCHIPACK_OT_wall2_from_slab(Operator): # parenting childs to wall reference point if o.parent is None: x, y, z = o.bound_box[0] - context.scene.cursor_location = o.matrix_world * Vector((x, y, z)) + context.scene.cursor_location = o.matrix_world @ Vector((x, y, z)) # fix issue #9 - context.scene.objects.active = o + context.view_layer.objects.active = o bpy.ops.archipack.reference_point() else: - o.parent.select = True - context.scene.objects.active = o.parent - o.select = True - slab.select = True + o.parent.select_set(state=True) + context.view_layer.objects.active = o.parent + o.select_set(state=True) + slab.select_set(state=True) bpy.ops.archipack.parent_to_reference() - o.parent.select = False + o.parent.select_set(state=False) return o # ----------------------------------------------------- @@ -1903,8 +1906,8 @@ class ARCHIPACK_OT_wall2_from_slab(Operator): if context.mode == "OBJECT": bpy.ops.object.select_all(action="DESELECT") o = self.create(context) - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o return {'FINISHED'} else: self.report({'WARNING'}, "Archipack: Option only valid in Object mode") @@ -1918,7 +1921,7 @@ class ARCHIPACK_OT_wall2_fit_roof(Operator): bl_category = 'Archipack' bl_options = {'REGISTER', 'UNDO'} - inside = BoolProperty(default=False) + inside : BoolProperty(default=False) @classmethod def poll(self, context): @@ -1939,12 +1942,11 @@ class ARCHIPACK_OT_wall2_fit_roof(Operator): # ------------------------------------------------------------------ -class ARCHIPACK_OT_wall2_draw(ArchpackDrawTool, Operator): +class ARCHIPACK_OT_wall2_draw(ArchipackDrawTool, Operator): bl_idname = "archipack.wall2_draw" bl_label = "Draw a Wall" - bl_description = "Draw a Wall" + bl_description = "Create a wall by drawing its baseline in 3D view" bl_category = 'Archipack' - bl_options = {'REGISTER', 'UNDO'} o = None state = 'RUNNING' @@ -1993,7 +1995,7 @@ class ARCHIPACK_OT_wall2_draw(ArchpackDrawTool, Operator): self.line.draw(context) def sp_callback(self, context, event, state, sp): - # print("sp_callback event %s %s state:%s" % (event.type, event.value, state)) + logger.debug("ARCHIPACK_OT_wall2_draw.sp_callback event %s %s state:%s", event.type, event.value, state) if state == 'SUCCESS': @@ -2004,19 +2006,21 @@ class ARCHIPACK_OT_wall2_draw(ArchpackDrawTool, Operator): takeloc = sp.takeloc delta = sp.delta - old = context.active_object + old = context.object if self.o is None: bpy.ops.archipack.wall2(auto_manipulate=False) - o = context.active_object + o = context.object o.location = takeloc self.o = o d = archipack_wall2.datablock(o) + part = d.parts[0] part.length = delta.length else: o = self.o - o.select = True - context.scene.objects.active = o + # select and make active + o.select_set(state=True) + context.view_layer.objects.active = o d = archipack_wall2.datablock(o) # Check for end close to start and close when applicable dp = sp.placeloc - o.location @@ -2031,7 +2035,7 @@ class ARCHIPACK_OT_wall2_draw(ArchpackDrawTool, Operator): rM = o.matrix_world.inverted().to_3x3() g = d.get_generator() w = g.segs[-2] - dp = rM * delta + dp = rM @ delta da = atan2(dp.y, dp.x) - w.straight(1).angle a0 = part.a0 + da if a0 > pi: @@ -2039,8 +2043,10 @@ class ARCHIPACK_OT_wall2_draw(ArchpackDrawTool, Operator): if a0 < -pi: a0 += 2 * pi part.a0 = a0 + d.update(context) - context.scene.objects.active = old + old.select_set(state=True) + context.view_layer.objects.active = old self.flag_next = True context.area.tag_redraw() # print("feedback.on:%s" % self.feedback.on) @@ -2051,7 +2057,7 @@ class ARCHIPACK_OT_wall2_draw(ArchpackDrawTool, Operator): # print("sp_init event %s %s %s" % (event.type, event.value, state)) if state == 'SUCCESS': # point placed, check if a wall was under mouse - res, tM, wall, y = self.mouse_hover_wall(context, event) + res, tM, wall, width, y, z_offset = self.mouse_hover_wall(context, event) if res: d = archipack_wall2.datablock(wall) if event.ctrl: @@ -2078,8 +2084,8 @@ class ARCHIPACK_OT_wall2_draw(ArchpackDrawTool, Operator): so reverse order here when needed """ d = archipack_wall2.datablock(self.o) - g = d.get_generator() - pts = [seg.p0.to_3d() for seg in g.segs] + g = d.get_generator(axis=False) + pts = [seg.p0 for seg in g.segs] if d.closed: pts.append(pts[0]) @@ -2094,46 +2100,70 @@ class ARCHIPACK_OT_wall2_draw(ArchpackDrawTool, Operator): def modal(self, context, event): context.area.tag_redraw() - # print("modal event %s %s" % (event.type, event.value)) - if event.type == 'NONE': + if event.type in {'NONE', 'TIMER', 'EVT_TWEAK_L', 'WINDOW_DEACTIVATE'}: return {'PASS_THROUGH'} - if self.state == 'STARTING': - takeloc = self.mouse_to_plane(context, event) - # wait for takeloc being visible when button is over horizon - rv3d = context.region_data - viewinv = rv3d.view_matrix.inverted() + if self.keymap.check(event, self.keymap.delete): + self.feedback.disable() + bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') + self.o = None + return {'FINISHED', 'PASS_THROUGH'} - if (takeloc * viewinv).z < 0 or not rv3d.is_perspective: - # print("STARTING") + if self.state == 'STARTING' and event.type not in {'ESC', 'RIGHTMOUSE'}: + # wait for takeloc being visible when button is over horizon + takeloc = self.mouse_to_plane(context, event) + if takeloc is not None: + logger.debug("ARCHIPACK_OT_wall2_draw.modal(STARTING) location:%s", takeloc) snap_point(takeloc=takeloc, - callback=self.sp_init, - constraint_axis=(True, True, False), - release_confirm=True) + callback=self.sp_init, + constraint_axis=(True, True, False), + release_confirm=True) return {'RUNNING_MODAL'} elif self.state == 'RUNNING': # print("RUNNING") + logger.debug("ARCHIPACK_OT_wall2_draw.modal(RUNNING) location:%s", self.takeloc) self.state = 'CREATE' snap_point(takeloc=self.takeloc, - draw=self.sp_draw, - takemat=self.takemat, - transform_orientation=context.space_data.transform_orientation, - callback=self.sp_callback, - constraint_axis=(True, True, False), - release_confirm=self.max_style_draw_tool) + draw=self.sp_draw, + takemat=self.takemat, + transform_orientation=context.scene.transform_orientation, + callback=self.sp_callback, + constraint_axis=(True, True, False), + release_confirm=self.max_style_draw_tool) return {'RUNNING_MODAL'} + elif self.state != 'CANCEL' and event.type in {'C', 'c'}: + + logger.debug("ARCHIPACK_OT_wall2_draw.modal(%s) C pressed", self.state) + self.feedback.disable() + bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') + + o = self.o + # select and make active + o.select_set(state=True) + context.view_layer.objects.active = o + + d = archipack_wall2.datablock(o) + d.closed = True + + if bpy.ops.archipack.manipulate.poll(): + bpy.ops.archipack.manipulate('INVOKE_DEFAULT') + + return {'FINISHED'} + elif self.state != 'CANCEL' and event.type in {'LEFTMOUSE', 'RET', 'NUMPAD_ENTER', 'SPACE'}: # print('LEFTMOUSE %s' % (event.value)) self.feedback.instructions(context, "Draw a wall", "Click & Drag to add a segment", [ + ('ENTER', 'Add part'), + ('BACK_SPACE', 'Remove part'), ('CTRL', 'Snap'), + ('C', 'Close wall and exit'), ('MMBTN', 'Constraint to axis'), ('X Y', 'Constraint to axis'), - ('BACK_SPACE', 'Remove part'), ('RIGHTCLICK or ESC', 'exit') - ]) + ]) # press with max mode release with blender mode if self.max_style_draw_tool: @@ -2146,74 +2176,85 @@ class ARCHIPACK_OT_wall2_draw(ArchpackDrawTool, Operator): if self.flag_next: self.flag_next = False o = self.o - o.select = True - context.scene.objects.active = o + + # select and make active + o.select_set(state=True) + context.view_layer.objects.active = o + d = archipack_wall2.datablock(o) g = d.get_generator() p0 = g.segs[-2].p0 p1 = g.segs[-2].p1 dp = p1 - p0 - takemat = o.matrix_world * Matrix([ + takemat = o.matrix_world @ Matrix([ [dp.x, dp.y, 0, p1.x], [dp.y, -dp.x, 0, p1.y], [0, 0, 1, 0], [0, 0, 0, 1] ]) - takeloc = o.matrix_world * p1.to_3d() - o.select = False + takeloc = o.matrix_world @ p1.to_3d() + o.select_set(state=False) else: - takeloc = self.mouse_to_plane(context, event) takemat = None + takeloc = self.mouse_to_plane(context, event) - snap_point(takeloc=takeloc, - takemat=takemat, - draw=self.sp_draw, - callback=self.sp_callback, - constraint_axis=(True, True, False), - release_confirm=self.max_style_draw_tool) + if takeloc is not None: + logger.debug("ARCHIPACK_OT_wall2_draw.modal(CREATE) location:%s", takeloc) + + snap_point(takeloc=takeloc, + takemat=takemat, + draw=self.sp_draw, + callback=self.sp_callback, + constraint_axis=(True, True, False), + release_confirm=self.max_style_draw_tool) return {'RUNNING_MODAL'} if self.keymap.check(event, self.keymap.undo) or ( event.type in {'BACK_SPACE'} and event.value == 'RELEASE' - ): + ): if self.o is not None: o = self.o - o.select = True - context.scene.objects.active = o + + # select and make active + o.select_set(state=True) + context.view_layer.objects.active = o d = archipack_wall2.datablock(o) if d.n_parts > 1: d.n_parts -= 1 return {'RUNNING_MODAL'} if self.state == 'CANCEL' or (event.type in {'ESC', 'RIGHTMOUSE'} and - event.value == 'RELEASE'): + event.value == 'RELEASE'): self.feedback.disable() bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') - + logger.debug("ARCHIPACK_OT_wall2_draw.modal(CANCEL) %s", event.type) if self.o is None: - context.scene.objects.active = self.act for o in self.sel: - o.select = True + o.select_set(state=True) + # select and make active + self.act.select_set(state=True) + context.view_layer.objects.active = self.act + else: - self.o.select = True - context.scene.objects.active = self.o + o = self.o + o.select_set(state=True) + context.view_layer.objects.active = o # remove last segment with blender mode - d = archipack_wall2.datablock(self.o) + d = archipack_wall2.datablock(o) if not self.max_style_draw_tool: if not d.closed and d.n_parts > 1: d.n_parts -= 1 - - self.o.select = True - context.scene.objects.active = self.o + o.select_set(state=True) + context.view_layer.objects.active = o # make T child if self.parent is not None: d.t_part = self.parent - if bpy.ops.archipack.wall2_manipulate.poll(): - bpy.ops.archipack.wall2_manipulate('INVOKE_DEFAULT') + if bpy.ops.archipack.manipulate.poll(): + bpy.ops.archipack.manipulate('INVOKE_DEFAULT') return {'FINISHED'} @@ -2236,11 +2277,11 @@ class ARCHIPACK_OT_wall2_draw(ArchpackDrawTool, Operator): ('X Y', 'Constraint to axis'), ('SHIFT+CTRL+TAB', 'Switch snap mode'), ('RIGHTCLICK or ESC', 'exit without change') - ]) + ]) self.feedback.enable() args = (self, context) - self.sel = [o for o in context.selected_objects] + self.sel = context.selected_objects[:] self.act = context.active_object bpy.ops.object.select_all(action="DESELECT") @@ -2265,7 +2306,7 @@ class ARCHIPACK_OT_wall2_insert(Operator): bl_description = "Insert part" bl_category = 'Archipack' bl_options = {'REGISTER', 'UNDO'} - index = IntProperty(default=0) + index : IntProperty(default=0) def execute(self, context): if context.mode == "OBJECT": @@ -2286,7 +2327,7 @@ class ARCHIPACK_OT_wall2_remove(Operator): bl_description = "Remove part" bl_category = 'Archipack' bl_options = {'REGISTER', 'UNDO'} - index = IntProperty(default=0) + index : IntProperty(default=0) def execute(self, context): if context.mode == "OBJECT": @@ -2352,8 +2393,8 @@ class ARCHIPACK_OT_wall2_manipulate(Operator): d.setup_childs(o, g) d.update_childs(context, o, g) d.update(context) - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o return {'FINISHED'} diff --git a/archipack/archipack_window.py b/archipack/archipack_window.py index 1bf349db..618344b4 100644 --- a/archipack/archipack_window.py +++ b/archipack/archipack_window.py @@ -41,7 +41,7 @@ from .archipack_handle import create_handle, window_handle_vertical_01, window_h from .archipack_manipulator import Manipulable from .archipack_preset import ArchipackPreset, PresetMenuOperator from .archipack_gl import FeedbackPanel -from .archipack_object import ArchipackObject, ArchipackCreateTool, ArchpackDrawTool +from .archipack_object import ArchipackObject, ArchipackCreateTool, ArchipackDrawTool from .archipack_keymaps import Keymaps @@ -71,7 +71,7 @@ def get_cols(self): class archipack_window_panelrow(PropertyGroup): - width = FloatVectorProperty( + width : FloatVectorProperty( name="Width", min=0.5, max=100.0, @@ -84,7 +84,7 @@ class archipack_window_panelrow(PropertyGroup): size=31, update=update ) - fixed = BoolVectorProperty( + fixed : BoolVectorProperty( name="Fixed", default=[ False, False, False, False, False, False, False, False, @@ -95,7 +95,7 @@ class archipack_window_panelrow(PropertyGroup): size=32, update=update ) - cols = IntProperty( + cols : IntProperty( name="Panels", description="number of panels getter and setter, to avoid infinite recursion", min=1, @@ -103,7 +103,7 @@ class archipack_window_panelrow(PropertyGroup): default=2, get=get_cols, set=set_cols ) - n_cols = IntProperty( + n_cols : IntProperty( name="Panels", description="store number of panels, internal use only to avoid infinite recursion", min=1, @@ -111,14 +111,14 @@ class archipack_window_panelrow(PropertyGroup): default=2, update=update ) - height = FloatProperty( + height : FloatProperty( name="Height", min=0.1, default=1.0, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', update=update ) - auto_update = BoolProperty( + auto_update : BoolProperty( options={'SKIP_SAVE'}, name="auto_update", description="disable auto update to avoid infinite recursion", @@ -188,19 +188,19 @@ class archipack_window_panelrow(PropertyGroup): class archipack_window_panel(ArchipackObject, PropertyGroup): - center = FloatVectorProperty( + center : FloatVectorProperty( subtype='XYZ' ) - origin = FloatVectorProperty( + origin : FloatVectorProperty( subtype='XYZ' ) - size = FloatVectorProperty( + size : FloatVectorProperty( subtype='XYZ' ) - radius = FloatVectorProperty( + radius : FloatVectorProperty( subtype='XYZ' ) - angle_y = FloatProperty( + angle_y : FloatProperty( name='angle', unit='ROTATION', subtype='ANGLE', @@ -208,27 +208,27 @@ class archipack_window_panel(ArchipackObject, PropertyGroup): default=0, precision=2, description='angle' ) - frame_y = FloatProperty( + frame_y : FloatProperty( name='Depth', min=0, default=0.06, precision=2, unit='LENGTH', subtype='DISTANCE', description='frame depth' ) - frame_x = FloatProperty( + frame_x : FloatProperty( name='Width', min=0, default=0.06, precision=2, unit='LENGTH', subtype='DISTANCE', description='frame width' ) - curve_steps = IntProperty( + curve_steps : IntProperty( name="curve steps", min=1, max=128, default=1 ) - shape = EnumProperty( + shape : EnumProperty( name='Shape', items=( ('RECTANGLE', 'Rectangle', '', 0), @@ -239,19 +239,19 @@ class archipack_window_panel(ArchipackObject, PropertyGroup): ), default='RECTANGLE' ) - pivot = FloatProperty( + pivot : FloatProperty( name='pivot', min=-1, max=1, default=-1, precision=2, description='pivot' ) - side_material = IntProperty( + side_material : IntProperty( name="side material", min=0, max=2, default=0 ) - handle = EnumProperty( + handle : EnumProperty( name='Shape', items=( ('NONE', 'No handle', '', 0), @@ -260,24 +260,24 @@ class archipack_window_panel(ArchipackObject, PropertyGroup): ), default='NONE' ) - handle_model = IntProperty( + handle_model : IntProperty( name="handle model", default=1, min=1, max=2 ) - handle_altitude = FloatProperty( + handle_altitude : FloatProperty( name='handle altitude', min=0, default=0.2, precision=2, unit='LENGTH', subtype='DISTANCE', description='handle altitude' ) - fixed = BoolProperty( + fixed : BoolProperty( name="Fixed", default=False ) - enable_glass = BoolProperty( + enable_glass : BoolProperty( name="Enable glass", default=True ) @@ -404,7 +404,7 @@ class archipack_window_panel(ArchipackObject, PropertyGroup): def remove_handle(self, context, o): handle = self.find_handle(o) if handle is not None: - context.scene.objects.unlink(handle) + context.scene.collection.objects.unlink(handle) bpy.data.objects.remove(handle, do_unlink=True) def update(self, context): @@ -425,28 +425,28 @@ class archipack_window_panel(ArchipackObject, PropertyGroup): class archipack_window(ArchipackObject, Manipulable, PropertyGroup): - x = FloatProperty( + x : FloatProperty( name='Width', min=0.25, default=100.0, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='Width', update=update ) - y = FloatProperty( + y : FloatProperty( name='Depth', min=0.1, default=0.20, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='Depth', update=update, ) - z = FloatProperty( + z : FloatProperty( name='Height', min=0.1, default=1.2, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='height', update=update, ) - angle_y = FloatProperty( + angle_y : FloatProperty( name='Angle', unit='ROTATION', subtype='ANGLE', @@ -454,179 +454,179 @@ class archipack_window(ArchipackObject, Manipulable, PropertyGroup): default=0, precision=2, description='angle', update=update, ) - radius = FloatProperty( + radius : FloatProperty( name='Radius', min=0.1, default=2.5, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='radius', update=update, ) - elipsis_b = FloatProperty( + elipsis_b : FloatProperty( name='Ellipsis', min=0.1, default=0.5, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='ellipsis vertical size', update=update, ) - altitude = FloatProperty( + altitude : FloatProperty( name='Altitude', default=1.0, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='altitude', update=update, ) - offset = FloatProperty( + offset : FloatProperty( name='Offset', default=0.1, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='offset', update=update, ) - frame_y = FloatProperty( + frame_y : FloatProperty( name='Depth', min=0, default=0.06, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='frame depth', update=update, ) - frame_x = FloatProperty( + frame_x : FloatProperty( name='Width', min=0, default=0.06, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='frame width', update=update, ) - out_frame = BoolProperty( + out_frame : BoolProperty( name="Out frame", default=False, update=update, ) - out_frame_y = FloatProperty( + out_frame_y : FloatProperty( name='Side depth', min=0.001, default=0.02, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='frame side depth', update=update, ) - out_frame_y2 = FloatProperty( + out_frame_y2 : FloatProperty( name='Front depth', min=0.001, default=0.02, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='frame front depth', update=update, ) - out_frame_x = FloatProperty( + out_frame_x : FloatProperty( name='Front Width', min=0.0, default=0.1, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='frame width set to 0 disable front frame', update=update, ) - out_frame_offset = FloatProperty( + out_frame_offset : FloatProperty( name='Offset', min=0.0, default=0.0, precision=3, step=0.1, unit='LENGTH', subtype='DISTANCE', description='frame offset', update=update, ) - out_tablet_enable = BoolProperty( + out_tablet_enable : BoolProperty( name="Out tablet", default=True, update=update, ) - out_tablet_x = FloatProperty( + out_tablet_x : FloatProperty( name='Width', min=0.0, default=0.04, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='tablet width', update=update, ) - out_tablet_y = FloatProperty( + out_tablet_y : FloatProperty( name='Depth', min=0.001, default=0.04, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='tablet depth', update=update, ) - out_tablet_z = FloatProperty( + out_tablet_z : FloatProperty( name='Height', min=0.001, default=0.03, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='tablet height', update=update, ) - in_tablet_enable = BoolProperty( + in_tablet_enable : BoolProperty( name="In tablet", default=True, update=update, ) - in_tablet_x = FloatProperty( + in_tablet_x : FloatProperty( name='Width', min=0.0, default=0.04, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='tablet width', update=update, ) - in_tablet_y = FloatProperty( + in_tablet_y : FloatProperty( name='Depth', min=0.001, default=0.04, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='tablet depth', update=update, ) - in_tablet_z = FloatProperty( + in_tablet_z : FloatProperty( name='Height', min=0.001, default=0.03, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='tablet height', update=update, ) - blind_enable = BoolProperty( + blind_enable : BoolProperty( name="Blind", default=False, update=update, ) - blind_y = FloatProperty( + blind_y : FloatProperty( name='Depth', min=0.001, default=0.002, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='Store depth', update=update, ) - blind_z = FloatProperty( + blind_z : FloatProperty( name='Height', min=0.001, default=0.03, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='Store height', update=update, ) - blind_open = FloatProperty( + blind_open : FloatProperty( name='Open', min=0.0, max=100, default=80, precision=1, subtype='PERCENTAGE', description='Store open', update=update, ) - rows = CollectionProperty(type=archipack_window_panelrow) - n_rows = IntProperty( + rows : CollectionProperty(type=archipack_window_panelrow) + n_rows : IntProperty( name="Number of rows", min=1, max=32, default=1, update=update, ) - curve_steps = IntProperty( + curve_steps : IntProperty( name="Steps", min=6, max=128, default=16, update=update, ) - hole_outside_mat = IntProperty( + hole_outside_mat : IntProperty( name="Outside", min=0, max=128, default=0, update=update, ) - hole_inside_mat = IntProperty( + hole_inside_mat : IntProperty( name="Inside", min=0, max=128, default=1, update=update, ) - window_shape = EnumProperty( + window_shape : EnumProperty( name='Shape', items=( ('RECTANGLE', 'Rectangle', '', 0), @@ -637,7 +637,7 @@ class archipack_window(ArchipackObject, Manipulable, PropertyGroup): ), default='RECTANGLE', update=update, ) - window_type = EnumProperty( + window_type : EnumProperty( name='Type', items=( ('FLAT', 'Flat window', '', 0), @@ -645,59 +645,59 @@ class archipack_window(ArchipackObject, Manipulable, PropertyGroup): ), default='FLAT', update=update, ) - enable_glass = BoolProperty( + enable_glass : BoolProperty( name="Enable glass", default=True, update=update ) - warning = BoolProperty( + warning : BoolProperty( options={'SKIP_SAVE'}, name="Warning", default=False ) - handle_enable = BoolProperty( + handle_enable : BoolProperty( name='Handle', default=True, update=update_childs, ) - handle_altitude = FloatProperty( + handle_altitude : FloatProperty( name="Altitude", min=0, default=1.4, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='handle altitude', update=update_childs, ) - hole_margin = FloatProperty( + hole_margin : FloatProperty( name='Hole margin', min=0.0, default=0.1, precision=2, step=1, unit='LENGTH', subtype='DISTANCE', description='how much hole surround wall' ) - flip = BoolProperty( + flip : BoolProperty( default=False, update=update, description='flip outside and outside material of hole' ) # layout related - display_detail = BoolProperty( + display_detail : BoolProperty( options={'SKIP_SAVE'}, default=False ) - display_panels = BoolProperty( + display_panels : BoolProperty( options={'SKIP_SAVE'}, default=True ) - display_materials = BoolProperty( + display_materials : BoolProperty( options={'SKIP_SAVE'}, default=True ) - auto_update = BoolProperty( + auto_update : BoolProperty( options={'SKIP_SAVE'}, default=True, update=update ) - portal = BoolProperty( + portal : BoolProperty( default=False, name="Portal", description="Generate a portal", @@ -1002,7 +1002,7 @@ class archipack_window(ArchipackObject, Manipulable, PropertyGroup): lamp = self.find_portal(o) if self.portal: if lamp is None: - bpy.ops.object.light_add(type='AREA') + bpy.ops.object.lamp_add(type='AREA') lamp = context.active_object lamp.name = "Portal" lamp.parent = o @@ -1019,15 +1019,15 @@ class archipack_window(ArchipackObject, Manipulable, PropertyGroup): [0, 1, 0, 0.5 * self.z + self.altitude], [0, 0, 0, 1] ]) - lamp.matrix_world = o.matrix_world * tM + lamp.matrix_world = o.matrix_world @ tM elif lamp is not None: d = lamp.data - context.scene.objects.unlink(lamp) + context.scene.collection.objects.unlink(lamp) bpy.data.objects.remove(lamp) bpy.data.lights.remove(d) - context.scene.objects.active = o + context.view_layer.objects.active = o def setup_manipulators(self): if len(self.manipulators) == 4: @@ -1054,13 +1054,13 @@ class archipack_window(ArchipackObject, Manipulable, PropertyGroup): if archipack_window_panel.filter(child): to_remove -= 1 self.remove_handle(context, child) - context.scene.objects.unlink(child) + context.scene.collection.objects.unlink(child) bpy.data.objects.remove(child, do_unlink=True) def remove_handle(self, context, o): handle = self.find_handle(o) if handle is not None: - context.scene.objects.unlink(handle) + context.scene.collection.objects.unlink(handle) bpy.data.objects.remove(handle, do_unlink=True) def update_rows(self, context, o): @@ -1127,7 +1127,7 @@ class archipack_window(ArchipackObject, Manipulable, PropertyGroup): id = c_names.index(c.data.name) except: self.remove_handle(context, c) - context.scene.objects.unlink(c) + context.scene.collection.objects.unlink(c) bpy.data.objects.remove(c, do_unlink=True) # children ordering may not be the same, so get the right l_childs order @@ -1145,7 +1145,7 @@ class archipack_window(ArchipackObject, Manipulable, PropertyGroup): for i, child in enumerate(childs): if order[i] < 0: p = bpy.data.objects.new("Panel", child.data) - context.scene.objects.link(p) + context.scene.collection.objects.link(p) p.lock_location[0] = True p.lock_location[1] = True p.lock_location[2] = True @@ -1169,20 +1169,20 @@ class archipack_window(ArchipackObject, Manipulable, PropertyGroup): h = create_handle(context, p, handle.data) h.location = handle.location.copy() elif h is not None: - context.scene.objects.unlink(h) + context.scene.collection.objects.unlink(h) bpy.data.objects.remove(h, do_unlink=True) p.location = child.location.copy() # restore context - context.scene.objects.active = o + context.view_layer.objects.active = o def _synch_hole(self, context, linked, hole): l_hole = self.find_hole(linked) if l_hole is None: l_hole = bpy.data.objects.new("hole", hole.data) l_hole['archipack_hole'] = True - context.scene.objects.link(l_hole) + context.scene.collection.objects.link(l_hole) for mat in hole.data.materials: l_hole.data.materials.append(mat) l_hole.parent = linked @@ -1196,8 +1196,8 @@ class archipack_window(ArchipackObject, Manipulable, PropertyGroup): synch childs nodes of linked objects """ bpy.ops.object.select_all(action='DESELECT') - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o childs = self.get_childs_panels(context, o) hole = self.find_hole(o) bpy.ops.object.select_linked(type='OBDATA') @@ -1296,8 +1296,8 @@ class archipack_window(ArchipackObject, Manipulable, PropertyGroup): else: child = childs[child_n - 1] - child.select = True - context.scene.objects.active = child + child.select_set(state=True) + context.view_layer.objects.active = child props = archipack_window_panel.datablock(child) if props is not None: props.origin = Vector((origin[panel].x, offset.y, 0)) @@ -1442,7 +1442,7 @@ class archipack_window(ArchipackObject, Manipulable, PropertyGroup): if hole_obj is None: m = bpy.data.meshes.new("hole") hole_obj = bpy.data.objects.new("hole", m) - context.scene.objects.link(hole_obj) + context.scene.collection.objects.link(hole_obj) hole_obj['archipack_hole'] = True hole_obj.parent = o hole_obj.matrix_world = o.matrix_world.copy() @@ -1496,11 +1496,11 @@ class archipack_window(ArchipackObject, Manipulable, PropertyGroup): m = bpy.data.meshes.new("hole") o = bpy.data.objects.new("hole", m) o['archipack_robusthole'] = True - context.scene.objects.link(o) + context.scene.collection.objects.link(o) verts = hole.vertices(self.curve_steps, Vector((0, self.altitude, 0)), center, origin, size, radius, self.angle_y, 0, shape_z=shape_z, path_type=self.shape) - verts = [tM * Vector(v) for v in verts] + verts = [tM @ Vector(v) for v in verts] faces = hole.faces(self.curve_steps, path_type=self.shape) @@ -1511,8 +1511,8 @@ class archipack_window(ArchipackObject, Manipulable, PropertyGroup): bmed.buildmesh(context, o, verts, faces, matids=matids, uvs=uvs) # MaterialUtils.add_wall2_materials(o) - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o return o @@ -1522,13 +1522,13 @@ class ARCHIPACK_PT_window(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'UI' # bl_context = 'object' - bl_category = 'ArchiPack' + bl_category = 'Archipack' # layout related - display_detail = BoolProperty( + display_detail : BoolProperty( default=False ) - display_panels = BoolProperty( + display_panels : BoolProperty( default=True ) @@ -1542,7 +1542,7 @@ class ARCHIPACK_PT_window(Panel): if prop is None: return layout = self.layout - layout.operator('archipack.window_manipulate', icon='HAND') + layout.operator('archipack.window_manipulate', icon='VIEW_PAN') row = layout.row(align=True) row.operator('archipack.window', text="Refresh", icon='FILE_REFRESH').mode = 'REFRESH' if o.data.users > 1: @@ -1552,8 +1552,8 @@ class ARCHIPACK_PT_window(Panel): # box.label(text="Styles") row = box.row(align=True) row.operator("archipack.window_preset_menu", text=bpy.types.ARCHIPACK_OT_window_preset_menu.bl_label) - row.operator("archipack.window_preset", text="", icon='ZOOMIN') - row.operator("archipack.window_preset", text="", icon='ZOOMOUT').remove_active = True + row.operator("archipack.window_preset", text="", icon='ADD') + row.operator("archipack.window_preset", text="", icon='REMOVE').remove_active = True box = layout.box() box.prop(prop, 'window_type') box.prop(prop, 'x') @@ -1587,7 +1587,7 @@ class ARCHIPACK_PT_window(Panel): box = layout.box() box.prop(prop, 'enable_glass') box = layout.box() - box.label("Frame") + box.label(text="Frame") box.prop(prop, 'frame_x') box.prop(prop, 'frame_y') if prop.window_shape != 'CIRCLE': @@ -1654,7 +1654,7 @@ class ARCHIPACK_PT_window(Panel): row.prop(prop, "display_materials", icon="TRIA_RIGHT", icon_only=True, text="Materials", emboss=False) if prop.display_materials: box = layout.box() - box.label("Hole") + box.label(text="Hole") box.prop(prop, 'hole_inside_mat') box.prop(prop, 'hole_outside_mat') @@ -1666,7 +1666,7 @@ class ARCHIPACK_PT_window_panel(Panel): bl_label = "Window panel" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' - bl_category = 'ArchiPack' + bl_category = 'Archipack' @classmethod def poll(cls, context): @@ -1688,31 +1688,31 @@ class ARCHIPACK_OT_window(ArchipackCreateTool, Operator): bl_description = "Window" bl_category = 'Archipack' bl_options = {'REGISTER', 'UNDO'} - x = FloatProperty( + x : FloatProperty( name='width', min=0.1, max=10000, default=2.0, precision=2, description='Width' ) - y = FloatProperty( + y : FloatProperty( name='depth', min=0.1, max=10000, default=0.20, precision=2, description='Depth' ) - z = FloatProperty( + z : FloatProperty( name='height', min=0.1, max=10000, default=1.2, precision=2, description='height' ) - altitude = FloatProperty( + altitude : FloatProperty( name='altitude', min=0.0, max=10000, default=1.0, precision=2, description='altitude' ) - mode = EnumProperty( + mode : EnumProperty( items=( ('CREATE', 'Create', '', 0), ('DELETE', 'Delete', '', 1), @@ -1721,12 +1721,12 @@ class ARCHIPACK_OT_window(ArchipackCreateTool, Operator): ), default='CREATE' ) - # auto_manipulate = BoolProperty(default=True) + # auto_manipulate : BoolProperty(default=True) def draw(self, context): layout = self.layout row = layout.row() - row.label("Use Properties panel (N) to define parms", icon='INFO') + row.label(text="Use Properties panel (N) to define parms", icon='INFO') def create(self, context): m = bpy.data.meshes.new("Window") @@ -1736,14 +1736,14 @@ class ARCHIPACK_OT_window(ArchipackCreateTool, Operator): d.y = self.y d.z = self.z d.altitude = self.altitude - context.scene.objects.link(o) - o.select = True - context.scene.objects.active = o + context.scene.collection.objects.link(o) + o.select_set(state=True) + context.view_layer.objects.active = o self.add_material(o) self.load_preset(d) # select frame - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o return o def delete(self, context): @@ -1753,20 +1753,20 @@ class ARCHIPACK_OT_window(ArchipackCreateTool, Operator): for child in o.children: if child.type == 'LIGHT': d = child.data - context.scene.objects.unlink(child) + context.scene.collection.objects.unlink(child) bpy.data.objects.remove(child) bpy.data.lights.remove(d) elif 'archipack_hole' in child: - context.scene.objects.unlink(child) + context.scene.collection.objects.unlink(child) bpy.data.objects.remove(child, do_unlink=True) elif child.data is not None and 'archipack_window_panel' in child.data: for handle in child.children: if 'archipack_handle' in handle: - context.scene.objects.unlink(handle) + context.scene.collection.objects.unlink(handle) bpy.data.objects.remove(handle, do_unlink=True) - context.scene.objects.unlink(child) + context.scene.collection.objects.unlink(child) bpy.data.objects.remove(child, do_unlink=True) - context.scene.objects.unlink(o) + context.scene.collection.objects.unlink(o) bpy.data.objects.remove(o, do_unlink=True) def update(self, context): @@ -1780,8 +1780,8 @@ class ARCHIPACK_OT_window(ArchipackCreateTool, Operator): archipack_window.datablock(linked).update(context) bpy.ops.object.select_all(action="DESELECT") - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o def unique(self, context): act = context.active_object @@ -1789,13 +1789,13 @@ class ARCHIPACK_OT_window(ArchipackCreateTool, Operator): bpy.ops.object.select_all(action="DESELECT") for o in sel: if archipack_window.filter(o): - o.select = True + o.select_set(state=True) for child in o.children: if 'archipack_hole' in child or ( child.data is not None and 'archipack_window_panel' in child.data): child.hide_select = False - child.select = True + child.select_set(state=True) if len(context.selected_objects) > 0: bpy.ops.object.make_single_user(type='SELECTED_OBJECTS', object=True, obdata=True, material=False, texture=False, animation=False) @@ -1803,9 +1803,9 @@ class ARCHIPACK_OT_window(ArchipackCreateTool, Operator): if 'archipack_hole' in child: child.hide_select = True bpy.ops.object.select_all(action="DESELECT") - context.scene.objects.active = act + context.view_layer.objects.active = act for o in sel: - o.select = True + o.select_set(state=True) # ----------------------------------------------------- # Execute @@ -1816,8 +1816,8 @@ class ARCHIPACK_OT_window(ArchipackCreateTool, Operator): bpy.ops.object.select_all(action="DESELECT") o = self.create(context) o.location = bpy.context.scene.cursor_location - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o self.manipulate() elif self.mode == 'DELETE': self.delete(context) @@ -1831,14 +1831,14 @@ class ARCHIPACK_OT_window(ArchipackCreateTool, Operator): return {'CANCELLED'} -class ARCHIPACK_OT_window_draw(ArchpackDrawTool, Operator): +class ARCHIPACK_OT_window_draw(ArchipackDrawTool, Operator): bl_idname = "archipack.window_draw" bl_label = "Draw Windows" bl_description = "Draw Windows over walls" bl_category = 'Archipack' bl_options = {'REGISTER', 'UNDO'} - filepath = StringProperty(default="") + filepath : StringProperty(default="") feedback = None stack = [] object_name = "" @@ -1850,7 +1850,7 @@ class ARCHIPACK_OT_window_draw(ArchpackDrawTool, Operator): def draw(self, context): layout = self.layout row = layout.row() - row.label("Use Properties panel (N) to define parms", icon='INFO') + row.label(text="Use Properties panel (N) to define parms", icon='INFO') def draw_callback(self, _self, context): self.feedback.draw(context) @@ -1862,8 +1862,8 @@ class ARCHIPACK_OT_window_draw(ArchpackDrawTool, Operator): if archipack_window.filter(o): - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o if event.shift: bpy.ops.archipack.window(mode="UNIQUE") @@ -1871,23 +1871,23 @@ class ARCHIPACK_OT_window_draw(ArchpackDrawTool, Operator): # instance subs new_w = o.copy() new_w.data = o.data - context.scene.objects.link(new_w) + context.scene.collection.objects.link(new_w) for child in o.children: if "archipack_hole" not in child: new_c = child.copy() new_c.data = child.data new_c.parent = new_w - context.scene.objects.link(new_c) + context.scene.collection.objects.link(new_c) # dup handle if any for c in child.children: new_h = c.copy() new_h.data = c.data new_h.parent = new_c - context.scene.objects.link(new_h) + context.scene.collection.objects.link(new_h) o = new_w - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o else: bpy.ops.archipack.window(auto_manipulate=False, filepath=self.filepath) @@ -1896,8 +1896,8 @@ class ARCHIPACK_OT_window_draw(ArchpackDrawTool, Operator): self.object_name = o.name bpy.ops.archipack.generate_hole('INVOKE_DEFAULT') - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o def modal(self, context, event): @@ -1914,14 +1914,14 @@ class ARCHIPACK_OT_window_draw(ArchpackDrawTool, Operator): # hide hole from raycast if hole is not None: - o.hide = True - hole.hide = True + o.hide_viewport = True + hole.hide_viewport = True - res, tM, wall, y = self.mouse_hover_wall(context, event) + res, tM, wall, width, y, z_offset = self.mouse_hover_wall(context, event) if hole is not None: - o.hide = False - hole.hide = False + o.hide_viewport = False + hole.hide_viewport = False if res and d is not None: o.matrix_world = tM @@ -1939,14 +1939,14 @@ class ARCHIPACK_OT_window_draw(ArchpackDrawTool, Operator): if event.type in {'LEFTMOUSE', 'RET', 'NUMPAD_ENTER', 'SPACE'}: if wall is not None: - context.scene.objects.active = wall - wall.select = True + context.view_layer.objects.active = wall + wall.select_set(state=True) if bpy.ops.archipack.single_boolean.poll(): bpy.ops.archipack.single_boolean() - wall.select = False + wall.select_set(state=False) # o must be a window here if d is not None: - context.scene.objects.active = o + context.view_layer.objects.active = o self.stack.append(o) self.add_object(context, event) context.active_object.matrix_world = tM @@ -1960,9 +1960,9 @@ class ARCHIPACK_OT_window_draw(ArchpackDrawTool, Operator): ): if len(self.stack) > 0: last = self.stack.pop() - context.scene.objects.active = last + context.view_layer.objects.active = last bpy.ops.archipack.window(mode="DELETE") - context.scene.objects.active = o + context.view_layer.objects.active = o return {'RUNNING_MODAL'} if event.value == 'RELEASE': @@ -1986,11 +1986,11 @@ class ARCHIPACK_OT_window_draw(ArchpackDrawTool, Operator): # invoke with shift pressed will use current object as basis for linked copy if self.filepath == '' and archipack_window.filter(context.active_object): o = context.active_object - context.scene.objects.active = None + context.view_layer.objects.active = None bpy.ops.object.select_all(action="DESELECT") if o is not None: - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o self.add_object(context, event) self.feedback = FeedbackPanel() self.feedback.instructions(context, "Draw a window", "Click & Drag over a wall", [ @@ -2041,19 +2041,19 @@ class ARCHIPACK_OT_window_panel(Operator): bl_description = "Window panel" bl_category = 'Archipack' bl_options = {'REGISTER', 'UNDO'} - center = FloatVectorProperty( + center : FloatVectorProperty( subtype='XYZ' ) - origin = FloatVectorProperty( + origin : FloatVectorProperty( subtype='XYZ' ) - size = FloatVectorProperty( + size : FloatVectorProperty( subtype='XYZ' ) - radius = FloatVectorProperty( + radius : FloatVectorProperty( subtype='XYZ' ) - angle_y = FloatProperty( + angle_y : FloatProperty( name='angle', unit='ROTATION', subtype='ANGLE', @@ -2061,25 +2061,25 @@ class ARCHIPACK_OT_window_panel(Operator): default=0, precision=2, description='angle' ) - frame_y = FloatProperty( + frame_y : FloatProperty( name='Depth', min=0, max=100, default=0.06, precision=2, description='frame depth' ) - frame_x = FloatProperty( + frame_x : FloatProperty( name='Width', min=0, max=100, default=0.06, precision=2, description='frame width' ) - curve_steps = IntProperty( + curve_steps : IntProperty( name="curve steps", min=1, max=128, default=16 ) - shape = EnumProperty( + shape : EnumProperty( name='Shape', items=( ('RECTANGLE', 'Rectangle', '', 0), @@ -2090,19 +2090,19 @@ class ARCHIPACK_OT_window_panel(Operator): ), default='RECTANGLE' ) - pivot = FloatProperty( + pivot : FloatProperty( name='pivot', min=-1, max=1, default=-1, precision=2, description='pivot' ) - side_material = IntProperty( + side_material : IntProperty( name="side material", min=0, max=2, default=0 ) - handle = EnumProperty( + handle : EnumProperty( name='Handle', items=( ('NONE', 'No handle', '', 0), @@ -2111,27 +2111,27 @@ class ARCHIPACK_OT_window_panel(Operator): ), default='NONE' ) - handle_model = IntProperty( + handle_model : IntProperty( name="handle model", default=1, min=1, max=2 ) - handle_altitude = FloatProperty( + handle_altitude : FloatProperty( name='handle altitude', min=0, max=1000, default=0.2, precision=2, description='handle altitude' ) - fixed = BoolProperty( + fixed : BoolProperty( name="Fixed", default=False ) - material = StringProperty( + material : StringProperty( name="material", default="" ) - enable_glass = BoolProperty( + enable_glass : BoolProperty( name="Enable glass", default=True ) @@ -2139,7 +2139,7 @@ class ARCHIPACK_OT_window_panel(Operator): def draw(self, context): layout = self.layout row = layout.row() - row.label("Use Properties panel (N) to define parms", icon='INFO') + row.label(text="Use Properties panel (N) to define parms", icon='INFO') def create(self, context): m = bpy.data.meshes.new("Window Panel") @@ -2161,9 +2161,9 @@ class ARCHIPACK_OT_window_panel(Operator): d.handle_model = self.handle_model d.handle_altitude = self.handle_altitude d.enable_glass = self.enable_glass - context.scene.objects.link(o) - o.select = True - context.scene.objects.active = o + context.scene.collection.objects.link(o) + o.select_set(state=True) + context.view_layer.objects.active = o m = o.archipack_material.add() m.category = "window" m.material = self.material @@ -2180,8 +2180,8 @@ class ARCHIPACK_OT_window_panel(Operator): def execute(self, context): if context.mode == "OBJECT": o = self.create(context) - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o return {'FINISHED'} else: self.report({'WARNING'}, "Archipack: Option only valid in Object mode") diff --git a/archipack/bmesh_utils.py b/archipack/bmesh_utils.py index 1157d9a3..54805f7b 100644 --- a/archipack/bmesh_utils.py +++ b/archipack/bmesh_utils.py @@ -34,8 +34,8 @@ class BmeshEdit(): """ private, start bmesh editing of active object """ - o.select = True - context.scene.objects.active = o + o.select_set(state=True) + context.view_layer.objects.active = o bpy.ops.object.mode_set(mode='EDIT') bm = bmesh.from_edit_mesh(o.data) bm.verts.ensure_lookup_table() @@ -212,11 +212,11 @@ class BmeshEdit(): @staticmethod def bevel(context, o, offset, - offset_type=0, + offset_type='OFFSET', segments=1, profile=0.5, vertex_only=False, - clight_overlap=True, + clamp_overlap=True, material=-1, use_selection=True): """ @@ -245,7 +245,7 @@ class BmeshEdit(): segments=segments, profile=profile, vertex_only=vertex_only, - clight_overlap=clight_overlap, + clamp_overlap=clamp_overlap, material=material) bm.to_mesh(o.data) |