[Bf-extensions-cvs] SVN commit: /data/svn/bf-extensions [3390] contrib/py/scripts/addons/ mesh_edgetools.py: Further work with "Fillet", and some work with "Slice" based on feedback from Sebastian Nell (CoDEmanX): a bugfix to prevent a script crash on invalid selection (no face selected) , choice to completely split the edge into two completely separate edges instead of sharing a new vert the point of intersection , and a choice to make a "copy" of the intersection vertices that are not a part of any edge.
Paul Marshall
portsidepaul at hotmail.com
Wed May 23 22:52:55 CEST 2012
Revision: 3390
http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-extensions&revision=3390
Author: brikbot
Date: 2012-05-23 20:52:55 +0000 (Wed, 23 May 2012)
Log Message:
-----------
Further work with "Fillet", and some work with "Slice" based on feedback from Sebastian Nell (CoDEmanX): a bugfix to prevent a script crash on invalid selection (no face selected), choice to completely split the edge into two completely separate edges instead of sharing a new vert the point of intersection, and a choice to make a "copy" of the intersection vertices that are not a part of any edge.
Modified Paths:
--------------
contrib/py/scripts/addons/mesh_edgetools.py
Modified: contrib/py/scripts/addons/mesh_edgetools.py
===================================================================
--- contrib/py/scripts/addons/mesh_edgetools.py 2012-05-23 20:33:55 UTC (rev 3389)
+++ contrib/py/scripts/addons/mesh_edgetools.py 2012-05-23 20:52:55 UTC (rev 3390)
@@ -78,7 +78,7 @@
'category': 'Mesh'}
import bpy, bmesh, mathutils
-from math import pi, radians, sin, sqrt, tan
+from math import acos, pi, radians, sqrt, tan
from mathutils import Matrix, Vector
from mathutils.geometry import (distance_point_to_plane,
interpolate_bezier,
@@ -306,7 +306,13 @@
# Tri math and theory:
# A triangle must be planar (three points define a plane). Therefore we just
# have to make sure that the line intersects inside the triangle.
-def intersect_line_face(edge, face):
+#
+# If the point is within the triangle, then the angle between the lines that
+# connect the point to the each individual point of the triangle will be
+# equal to 2 * PI. Otherwise, if the point is outside the triangle, then the
+# sum of the angles will be less.
+def intersect_line_face(edge, face, is_infinite = False, error = 0.000002):
+ int_co = None
# If we are dealing with a quad:
if len(face.verts) == 4:
edgeA = face.edges[0]
@@ -327,6 +333,10 @@
flipB = True
break
+ # Check to see if the quad is planar. We can go faster if it is.
+ if planar_quad(face):
+ squat = None #Just to keep an indentation error from happeneing for the time being.
+
# Define calculation coefficient constants:
# "xx1" is the x coordinate, "xx2" is the y coordinate, and "xx3" is the z
# coordinate.
@@ -440,17 +450,32 @@
y = (1 - t3) * a32 + t3 * b32
z = (1 - t3) * a33 + t3 * b33
- int_co = [True, Vector((x, y, z))]
+ int_co = Vector((x, y, z))
# If the line does not intersect the quad, we return "None":
- if t < 0 or t > 1 or t12 < 0 or t12 > 1:
- int_co[0] = False
-
- return int_co
+ if (t < 0 or t > 1 or t12 < 0 or t12 > 1) and not is_infinite:
+ int_co = None
elif len(face.verts) == 3:
- return int_co
+ p1, p2, p3 = face.verts[0], face.verts[1], face.verts[2]
+ int_co = intersect_line_plane(edge.verts[0], edge.verts[1], p1, face.normal)
+ if int_co != None:
+ pA = p1 - int_co
+ pB = p2 - int_co
+ pC = p3 - int_co
+ aAB = acos(pA.dot(pB))
+ aBC = acos(pB.dot(pC))
+ aCA = acos(pC.dot(pA))
+
+ sumA = aAB + aBC + aCA
+
+ # If the point is outside the triangle:
+ if (sumA > (pi + error) and sumA < (pi - error)) and not is_infinite:
+ int_co = None
+ return int_co
+
+
# project_point_plane
#
# Projects a point onto a plane. Returns a tuple of the projection vector
@@ -459,6 +484,22 @@
proj_co = intersect_line_plane(pt, pt + plane_no, plane_co, plane_no)
proj_ve = proj_co - pt
return (proj_ve, proj_co)
+
+
+# Tests a quad to see if it is planar:
+def planar_quad(face):
+ # Using a Cayley–Menger determinant to determine planarity:
+ d01 = pow((face.verts[0] - face.verts[1]).length, 2)
+ d02 = pow((face.verts[0] - face.verts[2]).length, 2)
+ d03 = pow((face.verts[0] - face.verts[3]).length, 2)
+ d12 = pow((face.verts[1] - face.verts[2]).length, 2)
+ d13 = pow((face.verts[1] - face.verts[3]).length, 2)
+ d23 = pow((face.verts[2] - face.verts[3]).length, 2)
+
+ if (2 * (-d01 * d02 * d12 + d01 * d03 * d12 + d02 * d03 * d12 - (d03 ** 2) * d12 - d03 * (d12 ** 2) + d01 * d02 * d13 - (d02 ** 2) * d13 - d01 * d03 * d13 + d02 * d03 * d13 + d02 * d12 * d13 + d03 * d12 * d13 - d02 * (d13 ** 2) - (d01 ** 2) * d23 + d01 * d02 * d23 + d01 * d03 * d23 - d02 * d03 * d23 + d01 * d12 * d23 + d03 * d12 * d23 + d01 * d13 * d23 + d02 * d13 * d23 - d12 * d13 * d23 - d01 * (d23 ** 2))) == 0:
+ return True
+ else:
+ return False
# ------------ FILLET/CHAMPHER HELPER METHODS -------------
@@ -797,7 +838,7 @@
# --- TODO COMPLETED ON 2/9/2012 ---
class Ortho(bpy.types.Operator):
bl_idname = "mesh.edgetools_ortho"
- bl_label = "Angle off Edge"
+ bl_label = "Angle Off Edge"
bl_description = ""
bl_options = {'REGISTER', 'UNDO'}
@@ -930,7 +971,7 @@
# It looks like an extrusion will add the new vert to the end of the verts
# list and leave the rest in the same location.
# ----------- EDIT -----------
- # It looks like I might be able to do this with in "bpy.data" with the ".add"
+ # It looks like I might be able to do this within "bpy.data" with the ".add"
# function.
# ------- BMESH UPDATE -------
# BMesh uses ".new()"
@@ -1065,6 +1106,7 @@
if verts.count(e.verts[1]) == 0:
verts.append(e.verts[1])
else:
+ bpy.ops.object.editmode_toggle()
self.report({'ERROR_INVALID_INPUT'}, "Active geometry is not an edge.")
return {'CANCELLED'}
self.shaftType = 1
@@ -1197,6 +1239,12 @@
bl_description = "Cuts edges at the plane defined by a selected face."
bl_options = {'REGISTER', 'UNDO'}
+ make_copy = BoolProperty(name = "Make Copy",
+ description = "Make new vertices at intersection points instead of spliting the edge",
+ default = False)
+ rip = BoolProperty(name = "Rip",
+ description = "Split into two edges that DO NOT share an intersection vertice.",
+ default = False)
pos = BoolProperty(name = "Positive",
description = "Remove the portion on the side of the face normal",
default = False)
@@ -1207,9 +1255,12 @@
def draw(self, context):
layout = self.layout
- layout.label("Remove Side:")
- layout.prop(self, "pos")
- layout.prop(self, "neg")
+ layout.prop(self, "make_copy")
+ if not self.make_copy:
+ layout.prop(self, "rip")
+ layout.label("Remove Side:")
+ layout.prop(self, "pos")
+ layout.prop(self, "neg")
@classmethod
@@ -1233,42 +1284,59 @@
bEdges = bm.edges
bFaces = bm.faces
- fVerts = []
+ face = None
normal = None
# Find the selected face. This will provide the plane to project onto:
for f in bFaces:
if f.select:
- for v in f.verts:
- fVerts.append(v)
+ face = f
normal = f.normal
f.select = False
break
+ if face == None:
+ bpy.ops.object.editmode_toggle()
+ self.report({'ERROR_INVALID_INPUT'}, "You must select a face as the cutting plane.")
+ return {'CANCELLED'}
+
for e in bEdges:
- if e.select:
- v1 = e.verts[0]
- v2 = e.verts[1]
- if v1 in fVerts and v2 in fVerts:
- e.select = False
- continue
- intersection = intersect_line_plane(v1.co, v2.co, fVerts[0].co, normal)
+ v1 = e.verts[0]
+ v2 = e.verts[1]
+ if e.select and (v1 not in face.verts and v2 not in face.verts):
+## For future consideration once some of the "funkyness" has been worked out of "intersect_line_face:
+## if len(face.verts) == 4:
+## intersection = intersect_line_face(e, face, True)
+## else:
+ intersection = intersect_line_plane(v1.co, v2.co, face.verts[0].co, normal)
if intersection != None:
- d1 = distance_point_to_plane(v1.co, fVerts[0].co, normal)
- d2 = distance_point_to_plane(v2.co, fVerts[0].co, normal)
+ d1 = distance_point_to_plane(v1.co, face.verts[0].co, normal)
+ d2 = distance_point_to_plane(v2.co, face.verts[0].co, normal)
# If they have different signs, then the edge crosses the plane:
if abs(d1 + d2) < abs(d1 - d2):
# Make the first vertice the positive vertice:
if d1 < d2:
v2, v1 = v1, v2
- new = list(bmesh.utils.edge_split(e, v1, 0.5))
- new[1].co = intersection
- e.select = False
- new[0].select = False
- if self.pos:
- bEdges.remove(new[0])
- if self.neg:
+ if self.make_copy:
+ new = bVerts.new()
+ new.co = intersection
+ elif self.rip:
+ newV1 = bVerts.new()
+ newV1.co = intersection
+ newV2 = bVerts.new()
+ newV2.co = intersection
+ newE1 = bEdges.new((v1, newV1))
+ newE2 = bEdges.new((v2, newV2))
bEdges.remove(e)
+ else:
+ new = list(bmesh.utils.edge_split(e, v1, 0.5))
+ new[1].co = intersection
+ e.select = False
+ new[0].select = False
+ if self.pos:
+ bEdges.remove(new[0])
+ if self.neg:
+ bEdges.remove(e)
bm.to_mesh(context.active_object.data)
bpy.ops.object.editmode_toggle()
@@ -1494,7 +1562,7 @@
radius = FloatProperty(name = "Radius",
description = "Radius of the edge fillet",
- min = 0.00001, max = 1024.0, softmax = 2.0,
+ min = 0.00001, max = 1024.0,
default = 0.5)
prop = EnumProperty(name = "Propagation",
items = [("m", "Minimal", "Minimal edge propagation"),
@@ -1502,7 +1570,7 @@
default = "m")
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-extensions-cvs
mailing list