PDT: Modify Fillet functionality

This enables two non-connected edges to be filleted. The Process starts with an
intersection of the two edges, then fillets the corner according to input values
in the UI. This option is selected by setting the Int/Fillet checkbox.

The command Line version now takes the `fi...` format to intersect first. e.g.

`fi1.1,6,0.05` performs an intersected fillet of 1.6 units radius, 6 segments,
concave profile.
This commit is contained in:
Alan Odom 2020-01-02 19:15:18 +00:00 committed by Rune Morling
parent 4795316548
commit 0d40bb678c
6 changed files with 100 additions and 25 deletions

View File

@ -83,6 +83,7 @@ from .pdt_msg_strings import (
PDT_DES_FILLETRAD,
PDT_DES_FILLETSEG,
PDT_DES_FILLETVERTS,
PDT_DES_FILLINT,
PDT_DES_FLIPANG,
PDT_DES_FLIPPER,
PDT_DES_LIBCOLS,
@ -419,6 +420,11 @@ class PDTSceneProperties(PropertyGroup):
default=True,
description=PDT_DES_FILLETVERTS,
)
fillet_int : BoolProperty(
name="Intersect",
default=False,
description=PDT_DES_FILLINT,
)
class PDTPreferences(AddonPreferences):

View File

@ -30,6 +30,7 @@ from .pdt_functions import (
debug,
disAng,
getPercent,
intersection,
objCheck,
oops,
updateSel,
@ -86,6 +87,7 @@ def pdt_help(self, context):
label(text="- Fillet Options:")
label(text="v: Fillet Vertices")
label(text="e: Fillet Edges")
label(text="i: Fillet & Intersect 2 Disconnected Edges")
label(text="- Math Options:")
label(text="x, y, z: Send result to X, Y and Z input fields in PDT Design")
label(text="d, a, p: Send result to Distance, Angle or Percent input field in PDT Design")
@ -226,9 +228,9 @@ def command_run(self, context):
elif mode == "o":
pg.mathsout = num
return
# "x"/"y"/"z" modes are only legal for Math Operation
# "o"/"x"/"y"/"z" modes are only legal for Math Operation
else:
if mode in {"x", "y", "z"}:
if mode in {"o", "x", "y", "z"}:
pg.error = PDT_ERR_BADCOORDL
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
return
@ -855,7 +857,7 @@ def command_run(self, context):
# ---------------
# Fillet Geometry
elif oper == "F":
if mode not in {"v", "e"}:
if mode not in {"v", "e", "i"}:
pg.error = f"'{mode}' {PDT_ERR_NON_VALID} '{oper}'"
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
return
@ -871,7 +873,7 @@ def command_run(self, context):
pg.error = PDT_ERR_BAD3VALS
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
return
if mode == "v":
if mode in {"i", "v"}:
vert_bool = True
elif mode == "e":
vert_bool = False
@ -889,6 +891,32 @@ def command_run(self, context):
_profile = float(vals[2])
if _profile < 0.0 or _profile > 1.0:
_profile = 0.5 # This is a circular profile
if mode == "i":
# Fillet & Intersect Two Edges
edges = [e for e in bm.edges if e.select]
if len(edges) == 2 and len(verts) == 4:
va = edges[0].verts[0]
vo = edges[0].verts[1]
vl = edges[1].verts[0]
vf = edges[1].verts[1]
vector_delta, done = intersection(va.co, vo.co, vl.co, vf.co, plane)
if not done:
errmsg = f"{PDT_ERR_INT_LINES} {plane} {PDT_LAB_PLANE}"
self.report({"ERROR"}, errmsg)
return {"FINISHED"}
if (va.co - vector_delta).length < (vo.co - vector_delta).length:
va.co = vector_delta
vo.select_set(False)
else:
vo.co = vector_delta
va.select_set(False)
if (vl.co - vector_delta).length < (vf.co - vector_delta).length:
vl.co = vector_delta
vf.select_set(False)
else:
vf.co = vector_delta
vl.select_set(False)
bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.0001)
bpy.ops.mesh.bevel(
offset_type="OFFSET",
offset=_offset,

View File

@ -56,6 +56,7 @@ from .pdt_msg_strings import (
PDT_ERR_SEL_2_OBJS,
PDT_ERR_SEL_2_VERTIO,
PDT_ERR_SEL_2_VERTS,
PDT_ERR_SEL_2_EDGES,
PDT_ERR_SEL_3_OBJS,
PDT_ERR_SEL_3_VERTIO,
PDT_ERR_SEL_3_VERTS,
@ -837,13 +838,9 @@ class PDT_OT_PlacementInt(Operator):
elif len(edges) == 2:
ext_a = pg.extend
va = edges[0].verts[0]
actV = va.co
vo = edges[0].verts[1]
othV = vo.co
vl = edges[1].verts[0]
lstV = vl.co
vf = edges[1].verts[1]
fstV = vf.co
else:
errmsg = (
PDT_ERR_SEL_4_VERTS
@ -854,7 +851,7 @@ class PDT_OT_PlacementInt(Operator):
)
self.report({"ERROR"}, errmsg)
return {"FINISHED"}
vector_delta, done = intersection(actV, othV, lstV, fstV, plane)
vector_delta, done = intersection(va.co, vo.co, vl.co, vf.co, plane)
if not done:
errmsg = f"{PDT_ERR_INT_LINES} {plane} {PDT_LAB_PLANE}"
self.report({"ERROR"}, errmsg)
@ -880,7 +877,7 @@ class PDT_OT_PlacementInt(Operator):
nVert = None
proc = False
if (actV - vector_delta).length < (othV - vector_delta).length:
if (va.co - vector_delta).length < (vo.co - vector_delta).length:
if oper == "MV":
va.co = vector_delta
proc = True
@ -895,7 +892,7 @@ class PDT_OT_PlacementInt(Operator):
nVert = bm.verts.new(vector_delta)
bm.edges.new([vo, nVert])
if (lstV - vector_delta).length < (fstV - vector_delta).length:
if (vl.co - vector_delta).length < (vf.co - vector_delta).length:
if oper == "MV" and ext_a:
vl.co = vector_delta
elif oper == "EV" and ext_a:
@ -1186,22 +1183,63 @@ class PDT_OT_Fillet(Operator):
scene = context.scene
pg = scene.pdt_pg
plane = pg.plane
obj = context.view_layer.objects.active
bm = bmesh.from_edit_mesh(obj.data)
verts = [v for v in bm.verts if v.select]
if len(verts) == 0:
errmsg = PDT_ERR_SEL_1_VERT
self.report({"ERROR"}, errmsg)
return {"FINISHED"}
if pg.fillet_int:
# Fillet & Intersect Two Edges
edges = [e for e in bm.edges if e.select]
if len(edges) == 2 and len(verts) == 4:
va = edges[0].verts[0]
vo = edges[0].verts[1]
vl = edges[1].verts[0]
vf = edges[1].verts[1]
vector_delta, done = intersection(va.co, vo.co, vl.co, vf.co, plane)
if not done:
errmsg = f"{PDT_ERR_INT_LINES} {plane} {PDT_LAB_PLANE}"
self.report({"ERROR"}, errmsg)
return {"FINISHED"}
if (va.co - vector_delta).length < (vo.co - vector_delta).length:
va.co = vector_delta
vo.select_set(False)
else:
vo.co = vector_delta
va.select_set(False)
if (vl.co - vector_delta).length < (vf.co - vector_delta).length:
vl.co = vector_delta
vf.select_set(False)
else:
vf.co = vector_delta
vl.select_set(False)
bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.0001)
bpy.ops.mesh.bevel(
offset_type="OFFSET",
offset=pg.fillet_radius,
segments=pg.fillet_segments,
profile=pg.fillet_profile,
vertex_only=True,
)
return {"FINISHED"}
else:
errmsg = f"{PDT_ERR_SEL_2_EDGES} {len(edges)})"
self.report({"ERROR"}, errmsg)
return {"FINISHED"}
else:
bpy.ops.mesh.bevel(
offset_type="OFFSET",
offset=pg.fillet_radius,
segments=pg.fillet_segments,
profile=pg.fillet_profile,
vertex_only=pg.fillet_vertices_only,
)
return {"FINISHED"}
if len(verts) == 0:
errmsg = PDT_ERR_SEL_1_VERT
self.report({"ERROR"}, errmsg)
return {"FINISHED"}
else:
# Intersct Edges
bpy.ops.mesh.bevel(
offset_type="OFFSET",
offset=pg.fillet_radius,
segments=pg.fillet_segments,
profile=pg.fillet_profile,
vertex_only=pg.fillet_vertices_only,
)
return {"FINISHED"}
class PDT_OT_Angle2(Operator):

View File

@ -500,7 +500,7 @@ def objCheck(obj, scene, oper):
else:
return bm, True
if len(bm.select_history) >= 1:
if _oper not in {"D", "E", "G", "N", "S"}:
if _oper not in {"D", "E", "F", "G", "N", "S"}:
actV = checkSelection(1, bm, obj)
else:
verts = [v for v in bm.verts if v.select]

View File

@ -188,6 +188,7 @@ class PDT_PT_PanelDesign(Panel):
row.prop(pdt_pg, "fillet_vertices_only", text=PDT_LAB_USEVERTS)
row = box.row()
row.operator("pdt.fillet", text=f"{PDT_LAB_FILLET}")
row.prop(pdt_pg, "fillet_int", text="Int/Fillet")
class PDT_PT_PanelPivotPoint(Panel):

View File

@ -84,6 +84,7 @@ PDT_ERR_SEL_1_VERT = "Select at least 1 Vertex (Currently selected:"
PDT_ERR_SEL_2_VERTI = "Select at least 2 Vertices Individually (Currently selected:"
PDT_ERR_SEL_2_VERTIO = "Select Exactly 2 Vertices Individually (Currently selected:"
PDT_ERR_SEL_2_VERTS = "Select Exactly 2 Vertices (Currently selected:"
PDT_ERR_SEL_2_EDGES = "Select Only 2 Non-Intersecting Edges (Currently selected:"
PDT_ERR_SEL_3_VERTS = "Select Exactly 3 Vertices (Currently selected:"
PDT_ERR_SEL_3_VERTIO = "Select Exactly 3 Vertices Individually (Currently selected:"
PDT_ERR_SEL_2_V_1_E = "Select 2 Vertices Individually, or 1 Edge (Currently selected:"
@ -113,7 +114,7 @@ PDT_ERR_SCALEZERO = "Scale Distance is 0"
PDT_ERR_CHARS_NUM = "Bad Command Format, not enough Characters"
PDT_ERR_BADFLETTER = "Bad Operator (1st Letter); C D E F G N M P S V or ? only"
PDT_ERR_BADSLETTER = "Bad Mode (2nd Letter); A D I or P only (+ X Y & Z for Maths) (+ V & G for Fillet)"
PDT_ERR_BADSLETTER = "Bad Mode (2nd Letter); A D I or P only (+ X Y & Z for Maths) (+ I V & G for Fillet)"
PDT_ERR_BADMATHS = "Not a Valid Mathematical Expression!"
PDT_ERR_BADCOORDL = "X Y & Z Not permitted in anything other than Maths Operations"
PDT_ERR_BAD1VALS = "Bad Command - 1 Value needed"
@ -170,3 +171,4 @@ PDT_DES_FILLETRAD = "Fillet Radius"
PDT_DES_FILLETSEG = "Number of Fillet Segments"
PDT_DES_FILLETPROF = "Fillet Profile"
PDT_DES_FILLETVERTS = "Use Vertices, or Edges, Set to False for Extruded Geometry"
PDT_DES_FILLINT = "Intersect & Fillet Two Selected Edges"