mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-26 18:21:59 +00:00
New 2D CAD offset operator
This commit is contained in:
@@ -25,6 +25,7 @@ classes = (
|
|||||||
operator.CadArcFrom3Points,
|
operator.CadArcFrom3Points,
|
||||||
operator.CadFillet,
|
operator.CadFillet,
|
||||||
operator.CadMitre,
|
operator.CadMitre,
|
||||||
|
operator.CadOffset,
|
||||||
operator.CadTrimExtend,
|
operator.CadTrimExtend,
|
||||||
workspace.CadHotkey,
|
workspace.CadHotkey,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ import bmesh
|
|||||||
import mathutils
|
import mathutils
|
||||||
import bpy_extras
|
import bpy_extras
|
||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
|
from mathutils import Vector, Matrix
|
||||||
|
from math import pi, radians, sin, cos, sqrt
|
||||||
|
|
||||||
messages = {
|
messages = {
|
||||||
"SHARED_VERTEX": "Shared Vertex, no intersection possible",
|
"SHARED_VERTEX": "Shared Vertex, no intersection possible",
|
||||||
@@ -40,7 +42,6 @@ class CadTrimExtend(bpy.types.Operator):
|
|||||||
return bool(obj) and obj.type == "MESH"
|
return bool(obj) and obj.type == "MESH"
|
||||||
|
|
||||||
def cancel_message(self, msg):
|
def cancel_message(self, msg):
|
||||||
print(msg)
|
|
||||||
self.report({"WARNING"}, msg)
|
self.report({"WARNING"}, msg)
|
||||||
return {"CANCELLED"}
|
return {"CANCELLED"}
|
||||||
|
|
||||||
@@ -73,7 +74,6 @@ class CadTrimExtend(bpy.types.Operator):
|
|||||||
bm.verts.index_update()
|
bm.verts.index_update()
|
||||||
bm.edges.index_update()
|
bm.edges.index_update()
|
||||||
bmesh.update_edit_mesh(me, loop_triangles=True)
|
bmesh.update_edit_mesh(me, loop_triangles=True)
|
||||||
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -87,7 +87,6 @@ class CadMitre(bpy.types.Operator):
|
|||||||
return bool(obj) and obj.type == "MESH"
|
return bool(obj) and obj.type == "MESH"
|
||||||
|
|
||||||
def cancel_message(self, msg):
|
def cancel_message(self, msg):
|
||||||
print(msg)
|
|
||||||
self.report({"WARNING"}, msg)
|
self.report({"WARNING"}, msg)
|
||||||
return {"CANCELLED"}
|
return {"CANCELLED"}
|
||||||
|
|
||||||
@@ -120,7 +119,6 @@ class CadMitre(bpy.types.Operator):
|
|||||||
bm.verts.index_update()
|
bm.verts.index_update()
|
||||||
bm.edges.index_update()
|
bm.edges.index_update()
|
||||||
bmesh.update_edit_mesh(me, loop_triangles=True)
|
bmesh.update_edit_mesh(me, loop_triangles=True)
|
||||||
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -257,7 +255,7 @@ class CadArcFrom2Points(bpy.types.Operator):
|
|||||||
|
|
||||||
v = selected_verts[0]
|
v = selected_verts[0]
|
||||||
bm.verts.remove(selected_verts[1])
|
bm.verts.remove(selected_verts[1])
|
||||||
axis = region_3d.view_rotation @ mathutils.Vector((0, 0, 1))
|
axis = region_3d.view_rotation @ Vector((0, 0, 1))
|
||||||
bmesh.ops.spin(
|
bmesh.ops.spin(
|
||||||
bm,
|
bm,
|
||||||
geom=[v],
|
geom=[v],
|
||||||
@@ -334,6 +332,202 @@ class CadArcFrom3Points(bpy.types.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
class CadOffset(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.cad_offset"
|
||||||
|
bl_label = "CAD Offset"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
distance: bpy.props.FloatProperty(name="Distance", default=0.1)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(self, context):
|
||||||
|
return context.mode == 'EDIT_MESH'
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
for prop in self.__class__.__annotations__.keys():
|
||||||
|
layout.prop(self, prop)
|
||||||
|
|
||||||
|
def cancel_message(self, msg):
|
||||||
|
self.report({"WARNING"}, msg)
|
||||||
|
return {"CANCELLED"}
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
# This is not the same as Mesh Tools or Sverchok. Mesh Tools is based on
|
||||||
|
# a 3D "rail" which allows fancy 3D edge offsets, but will get different
|
||||||
|
# results to traditional CAD, which expects offsets to occur on a
|
||||||
|
# defined 2D workplane. This CAD offset does a pure 2D operation, so it
|
||||||
|
# always looks correct from the desired "2D workplane". This also
|
||||||
|
# reduces the settings down to one parameter instead of the huge config
|
||||||
|
# dialog that Mesh Tools has. Sverchok is 2D based, but has a weird side
|
||||||
|
# effect of converting an unclosed loop into a closed loop which is also
|
||||||
|
# not what users expect.
|
||||||
|
bpy.ops.object.mode_set(mode="OBJECT")
|
||||||
|
bpy.ops.object.mode_set(mode="EDIT")
|
||||||
|
|
||||||
|
obj = context.active_object
|
||||||
|
mw = obj.matrix_world
|
||||||
|
|
||||||
|
bm = bmesh.from_edit_mesh(obj.data)
|
||||||
|
bm.verts.ensure_lookup_table()
|
||||||
|
bm.edges.ensure_lookup_table()
|
||||||
|
|
||||||
|
edges = [e for e in bm.edges if e.select and not e.hide]
|
||||||
|
|
||||||
|
if len(edges) < 1:
|
||||||
|
return self.cancel_message("NO_EDGES")
|
||||||
|
|
||||||
|
verts = set()
|
||||||
|
[verts.update(e.verts) for e in edges]
|
||||||
|
|
||||||
|
# Use the viewport angle to determine the offset direction
|
||||||
|
for area in bpy.context.screen.areas:
|
||||||
|
if area.type == 'VIEW_3D':
|
||||||
|
# Don't ask me, I don't know.
|
||||||
|
# view_matrix = area.spaces.active.region_3d.view_matrix
|
||||||
|
x = area.spaces.active.region_3d.view_rotation @ Vector((1,0,0))
|
||||||
|
y = area.spaces.active.region_3d.view_rotation @ Vector((0,1,0))
|
||||||
|
z = area.spaces.active.region_3d.view_rotation @ Vector((0,0,1))
|
||||||
|
wp = Matrix([x,y,z,Vector((0,0,0))]).to_4x4().transposed()
|
||||||
|
break
|
||||||
|
|
||||||
|
rotation = Matrix.Rotation(pi / 2, 2, 'Z')
|
||||||
|
rotation_i = Matrix.Rotation(- pi / 2, 2, 'Z')
|
||||||
|
|
||||||
|
# Create loops from edges
|
||||||
|
loop_edges = set(edges)
|
||||||
|
loops = []
|
||||||
|
while loop_edges:
|
||||||
|
edge = loop_edges.pop()
|
||||||
|
loop = [edge]
|
||||||
|
has_found_connected_edge = True
|
||||||
|
while has_found_connected_edge:
|
||||||
|
has_found_connected_edge = False
|
||||||
|
for edge in loop_edges.copy():
|
||||||
|
edge_verts = set(edge.verts)
|
||||||
|
if edge_verts & set(loop[0].verts):
|
||||||
|
loop.insert(0, edge)
|
||||||
|
loop_edges.remove(edge)
|
||||||
|
has_found_connected_edge = True
|
||||||
|
elif edge_verts & set(loop[-1].verts):
|
||||||
|
loop.append(edge)
|
||||||
|
loop_edges.remove(edge)
|
||||||
|
has_found_connected_edge = True
|
||||||
|
loops.append(loop)
|
||||||
|
|
||||||
|
for loop in loops:
|
||||||
|
all_verts = {v.index for e in loop for v in e.verts}
|
||||||
|
possible_v1s = []
|
||||||
|
is_closed = True
|
||||||
|
for edge in loop:
|
||||||
|
# If we have an open loop, start at either end instead
|
||||||
|
v = edge.verts[0]
|
||||||
|
if len(v.link_edges) == 1:
|
||||||
|
possible_v1s.append(v)
|
||||||
|
is_closed = False
|
||||||
|
else:
|
||||||
|
for link_edge in v.link_edges:
|
||||||
|
if link_edge.other_vert(v).index not in all_verts:
|
||||||
|
possible_v1s.append(v)
|
||||||
|
is_closed = False
|
||||||
|
break
|
||||||
|
v = edge.verts[1]
|
||||||
|
if len(v.link_edges) == 1:
|
||||||
|
possible_v1s.append(v)
|
||||||
|
is_closed = False
|
||||||
|
else:
|
||||||
|
for link_edge in v.link_edges:
|
||||||
|
if link_edge.other_vert(v).index not in all_verts:
|
||||||
|
possible_v1s.append(v)
|
||||||
|
is_closed = False
|
||||||
|
break
|
||||||
|
|
||||||
|
# Always start at the same vertex, so that when the operator is
|
||||||
|
# refreshed with new parameters the axes don't randomly get flipped.
|
||||||
|
if is_closed:
|
||||||
|
bm.verts.ensure_lookup_table()
|
||||||
|
bm.edges.ensure_lookup_table()
|
||||||
|
start = bm.verts[min(all_verts)]
|
||||||
|
else:
|
||||||
|
start = possible_v1s[0] if possible_v1s[0].index < possible_v1s[1].index else possible_v1s[1]
|
||||||
|
|
||||||
|
v1 = start
|
||||||
|
|
||||||
|
new_verts = []
|
||||||
|
processed_verts = set()
|
||||||
|
# [v0] --> v1 --> v2
|
||||||
|
while v1:
|
||||||
|
if v1.index in processed_verts:
|
||||||
|
break
|
||||||
|
|
||||||
|
link_verts = []
|
||||||
|
if len(v1.link_edges) == 1:
|
||||||
|
v = v1.link_edges[0].other_vert(v1)
|
||||||
|
link_verts.append(v) if v.index in all_verts else None
|
||||||
|
else:
|
||||||
|
v = v1.link_edges[0].other_vert(v1)
|
||||||
|
link_verts.append(v) if v.index in all_verts else None
|
||||||
|
v = v1.link_edges[1].other_vert(v1)
|
||||||
|
link_verts.append(v) if v.index in all_verts else None
|
||||||
|
|
||||||
|
if len(link_verts) == 1:
|
||||||
|
v2 = link_verts[0]
|
||||||
|
v0 = None if v2.index not in processed_verts else v2
|
||||||
|
v2 = None if v2.index in processed_verts else v2
|
||||||
|
else:
|
||||||
|
v2 = link_verts[0]
|
||||||
|
v0 = link_verts[1]
|
||||||
|
if v2.index in processed_verts:
|
||||||
|
if is_closed and v0.index in processed_verts:
|
||||||
|
v3 = start
|
||||||
|
v0 = v0 if v2 == v3 else v2
|
||||||
|
v2 = v3
|
||||||
|
else:
|
||||||
|
v0, v2 = v2, v0
|
||||||
|
|
||||||
|
normals = []
|
||||||
|
v1co = (wp.inverted() @ mw @ v1.co).to_2d()
|
||||||
|
if v2:
|
||||||
|
v2co = (wp.inverted() @ mw @ v2.co).to_2d()
|
||||||
|
direction = (v2co - v1co).normalized()
|
||||||
|
local_direction = (rotation @ direction).normalized()
|
||||||
|
normals.append(local_direction)
|
||||||
|
|
||||||
|
if v0:
|
||||||
|
v0co = (wp.inverted() @ mw @ v0.co).to_2d()
|
||||||
|
direction = (v0co - v1co).normalized()
|
||||||
|
local_direction = (rotation_i @ direction).normalized()
|
||||||
|
normals.append(local_direction)
|
||||||
|
|
||||||
|
if len(normals) == 2:
|
||||||
|
# https://stackoverflow.com/a/54042831/9627415
|
||||||
|
new_normal = (normals[0].lerp(normals[1], 0.5)).normalized()
|
||||||
|
offset_length = self.distance / sqrt((1 + normals[0].dot(normals[1]))/2)
|
||||||
|
offset = mw.inverted().to_quaternion() @ (wp.to_quaternion() @ (new_normal * offset_length).to_3d())
|
||||||
|
new_vert = v1.co + offset
|
||||||
|
new_verts.append(bm.verts.new(new_vert))
|
||||||
|
else:
|
||||||
|
normal = (normals[0] * self.distance).to_3d()
|
||||||
|
offset = mw.inverted().to_quaternion() @ (wp.to_quaternion() @ normal)
|
||||||
|
new_vert = v1.co + offset
|
||||||
|
new_verts.append(bm.verts.new(new_vert))
|
||||||
|
|
||||||
|
processed_verts.add(v1.index)
|
||||||
|
|
||||||
|
if v2 in processed_verts:
|
||||||
|
break
|
||||||
|
|
||||||
|
v1 = v2
|
||||||
|
|
||||||
|
[bm.edges.new((new_verts[i], new_verts[i + 1])) for i in range(len(new_verts) - 1)]
|
||||||
|
if is_closed:
|
||||||
|
bm.edges.new((new_verts[len(new_verts) - 1], new_verts[0]))
|
||||||
|
|
||||||
|
bm.verts.index_update()
|
||||||
|
bm.edges.index_update()
|
||||||
|
bmesh.update_edit_mesh(obj.data)
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class AddIfcCircle(bpy.types.Operator):
|
class AddIfcCircle(bpy.types.Operator):
|
||||||
bl_idname = "bim.add_ifccircle"
|
bl_idname = "bim.add_ifccircle"
|
||||||
bl_label = "Add IfcCircle"
|
bl_label = "Add IfcCircle"
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import os
|
|||||||
import bpy
|
import bpy
|
||||||
import blenderbim.bim.module.type.prop as type_prop
|
import blenderbim.bim.module.type.prop as type_prop
|
||||||
from bpy.types import WorkSpaceTool
|
from bpy.types import WorkSpaceTool
|
||||||
from blenderbim.bim.ifc import IfcStore
|
|
||||||
from blenderbim.bim.module.model.data import AuthoringData
|
from blenderbim.bim.module.model.data import AuthoringData
|
||||||
|
|
||||||
|
|
||||||
@@ -35,13 +34,12 @@ class CadTool(WorkSpaceTool):
|
|||||||
bl_widget = None
|
bl_widget = None
|
||||||
# https://docs.blender.org/api/current/bpy.types.KeyMapItems.html
|
# https://docs.blender.org/api/current/bpy.types.KeyMapItems.html
|
||||||
bl_keymap = (
|
bl_keymap = (
|
||||||
("bim.cad_hotkey", {"type": "E", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_E")]}),
|
|
||||||
("bim.cad_hotkey", {"type": "T", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_T")]}),
|
|
||||||
("bim.cad_hotkey", {"type": "Q", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_Q")]}),
|
|
||||||
("bim.cad_fillet", {"type": "F", "value": "PRESS", "shift": True}, {"properties": []}),
|
|
||||||
# Enable Mesh Tools add-on to get this amazing tool
|
|
||||||
("mesh.offset_edges", {"type": "O", "value": "PRESS", "shift": True}, {"properties": []}),
|
|
||||||
("bim.cad_hotkey", {"type": "C", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_C")]}),
|
("bim.cad_hotkey", {"type": "C", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_C")]}),
|
||||||
|
("bim.cad_hotkey", {"type": "E", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_E")]}),
|
||||||
|
("bim.cad_hotkey", {"type": "F", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_F")]}),
|
||||||
|
("bim.cad_hotkey", {"type": "O", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_O")]}),
|
||||||
|
("bim.cad_hotkey", {"type": "Q", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_Q")]}),
|
||||||
|
("bim.cad_hotkey", {"type": "T", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_T")]}),
|
||||||
("bim.cad_hotkey", {"type": "V", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_V")]}),
|
("bim.cad_hotkey", {"type": "V", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_V")]}),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -57,12 +55,12 @@ class CadTool(WorkSpaceTool):
|
|||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.label(text="", icon="EVENT_SHIFT")
|
row.label(text="", icon="EVENT_SHIFT")
|
||||||
row.label(text="", icon="EVENT_E")
|
row.label(text="", icon="EVENT_E")
|
||||||
row.operator("bim.hotkey", text="Extend").hotkey = "S_E"
|
row.operator("bim.cad_hotkey", text="Extend").hotkey = "S_E"
|
||||||
|
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.label(text="", icon="EVENT_SHIFT")
|
row.label(text="", icon="EVENT_SHIFT")
|
||||||
row.label(text="", icon="EVENT_T")
|
row.label(text="", icon="EVENT_T")
|
||||||
row.operator("bim.hotkey", text="Mitre").hotkey = "S_T"
|
row.operator("bim.cad_hotkey", text="Mitre").hotkey = "S_T"
|
||||||
|
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.label(text="", icon="EVENT_SHIFT")
|
row.label(text="", icon="EVENT_SHIFT")
|
||||||
@@ -73,25 +71,31 @@ class CadTool(WorkSpaceTool):
|
|||||||
row.label(text="", icon="EVENT_SHIFT")
|
row.label(text="", icon="EVENT_SHIFT")
|
||||||
row.label(text="", icon="EVENT_V")
|
row.label(text="", icon="EVENT_V")
|
||||||
row.operator("bim.set_arc_index", text="3-Point Arc")
|
row.operator("bim.set_arc_index", text="3-Point Arc")
|
||||||
|
|
||||||
|
row = layout.row(align=True)
|
||||||
|
row.label(text="", icon="EVENT_SHIFT")
|
||||||
|
row.label(text="", icon="EVENT_O")
|
||||||
|
row.operator("bim.cad_hotkey", text="Offset").hotkey = "S_O"
|
||||||
else:
|
else:
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.label(text="", icon="EVENT_SHIFT")
|
row.label(text="", icon="EVENT_SHIFT")
|
||||||
row.label(text="", icon="EVENT_E")
|
row.label(text="", icon="EVENT_E")
|
||||||
row.operator("bim.hotkey", text="Extend").hotkey = "S_E"
|
row.operator("bim.cad_hotkey", text="Extend").hotkey = "S_E"
|
||||||
|
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.label(text="", icon="EVENT_SHIFT")
|
row.label(text="", icon="EVENT_SHIFT")
|
||||||
row.label(text="", icon="EVENT_T")
|
row.label(text="", icon="EVENT_T")
|
||||||
row.operator("bim.hotkey", text="Mitre").hotkey = "S_T"
|
row.operator("bim.cad_hotkey", text="Mitre").hotkey = "S_T"
|
||||||
|
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.label(text="", icon="EVENT_SHIFT")
|
row.label(text="", icon="EVENT_SHIFT")
|
||||||
row.label(text="", icon="EVENT_F")
|
row.label(text="", icon="EVENT_F")
|
||||||
row.operator("bim.hotkey", text="Fillet").hotkey = "S_F"
|
row.operator("bim.cad_hotkey", text="Fillet").hotkey = "S_F"
|
||||||
|
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.label(text="", icon="EVENT_SHIFT")
|
row.label(text="", icon="EVENT_SHIFT")
|
||||||
row.label(text="Offset", icon="EVENT_O")
|
row.label(text="", icon="EVENT_O")
|
||||||
|
row.operator("bim.cad_hotkey", text="Offset").hotkey = "S_O"
|
||||||
|
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.label(text="", icon="EVENT_SHIFT")
|
row.label(text="", icon="EVENT_SHIFT")
|
||||||
@@ -99,7 +103,8 @@ class CadTool(WorkSpaceTool):
|
|||||||
|
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.label(text="", icon="EVENT_SHIFT")
|
row.label(text="", icon="EVENT_SHIFT")
|
||||||
row.label(text="3-Point Arc", icon="EVENT_V")
|
row.label(text="", icon="EVENT_V")
|
||||||
|
row.operator("bim.cad_hotkey", text="3-Point Arc").hotkey = "S_V"
|
||||||
|
|
||||||
|
|
||||||
class CadHotkey(bpy.types.Operator):
|
class CadHotkey(bpy.types.Operator):
|
||||||
@@ -107,17 +112,28 @@ class CadHotkey(bpy.types.Operator):
|
|||||||
bl_label = "CAD Hotkey"
|
bl_label = "CAD Hotkey"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
hotkey: bpy.props.StringProperty()
|
hotkey: bpy.props.StringProperty()
|
||||||
|
resolution: bpy.props.IntProperty(name="Arc Resolution", min=1, default=1)
|
||||||
|
radius: bpy.props.FloatProperty(name="Radius", default=0.1)
|
||||||
|
distance: bpy.props.FloatProperty(name="Distance", default=0.1)
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
self.props = context.scene.BIMModelProperties
|
|
||||||
self.has_ifc_class = True
|
|
||||||
try:
|
|
||||||
self.has_ifc_class = bool(self.props.ifc_class)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
getattr(self, f"hotkey_{self.hotkey}")()
|
getattr(self, f"hotkey_{self.hotkey}")()
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
if self.hotkey == "S_V":
|
||||||
|
if not self.is_profile():
|
||||||
|
row = self.layout.row()
|
||||||
|
row.prop(self, "resolution")
|
||||||
|
elif self.hotkey == "S_F":
|
||||||
|
row = self.layout.row()
|
||||||
|
row.prop(self, "resolution")
|
||||||
|
row = self.layout.row()
|
||||||
|
row.prop(self, "radius")
|
||||||
|
elif self.hotkey == "S_O":
|
||||||
|
row = self.layout.row()
|
||||||
|
row.prop(self, "distance")
|
||||||
|
|
||||||
def hotkey_S_C(self):
|
def hotkey_S_C(self):
|
||||||
if self.is_profile():
|
if self.is_profile():
|
||||||
bpy.ops.bim.add_ifccircle()
|
bpy.ops.bim.add_ifccircle()
|
||||||
@@ -127,6 +143,12 @@ class CadHotkey(bpy.types.Operator):
|
|||||||
def hotkey_S_E(self):
|
def hotkey_S_E(self):
|
||||||
bpy.ops.bim.cad_trim_extend()
|
bpy.ops.bim.cad_trim_extend()
|
||||||
|
|
||||||
|
def hotkey_S_F(self):
|
||||||
|
bpy.ops.bim.cad_fillet(resolution=self.resolution, radius=self.radius)
|
||||||
|
|
||||||
|
def hotkey_S_O(self):
|
||||||
|
bpy.ops.bim.cad_offset(distance=self.distance)
|
||||||
|
|
||||||
def hotkey_S_Q(self):
|
def hotkey_S_Q(self):
|
||||||
bpy.ops.bim.edit_extrusion_profile()
|
bpy.ops.bim.edit_extrusion_profile()
|
||||||
|
|
||||||
@@ -137,7 +159,7 @@ class CadHotkey(bpy.types.Operator):
|
|||||||
if self.is_profile():
|
if self.is_profile():
|
||||||
bpy.ops.bim.set_arc_index()
|
bpy.ops.bim.set_arc_index()
|
||||||
else:
|
else:
|
||||||
bpy.ops.bim.cad_arc_from_3_points()
|
bpy.ops.bim.cad_arc_from_3_points(resolution=self.resolution)
|
||||||
|
|
||||||
def is_profile(self):
|
def is_profile(self):
|
||||||
obj = bpy.context.active_object
|
obj = bpy.context.active_object
|
||||||
|
|||||||
Reference in New Issue
Block a user