[Bf-extensions-cvs] SVN commit: /data/svn/bf-extensions [680] contrib/py/scripts/addons/ curve_simplify.py:
Florian Meyer
florianfelix at web.de
Sun May 23 09:27:15 CEST 2010
Revision: 680
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-extensions&revision=680
Author: testscreenings
Date: 2010-05-23 09:27:14 +0200 (Sun, 23 May 2010)
Log Message:
-----------
Added Paths:
-----------
contrib/py/scripts/addons/curve_simplify.py
Added: contrib/py/scripts/addons/curve_simplify.py
===================================================================
--- contrib/py/scripts/addons/curve_simplify.py (rev 0)
+++ contrib/py/scripts/addons/curve_simplify.py 2010-05-23 07:27:14 UTC (rev 680)
@@ -0,0 +1,398 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+'''
+This script simplifies Curves.
+'''
+bl_addon_info = {
+ 'name': 'Curve: simplify curves',
+ 'author': 'testscreenings',
+ 'version': '1',
+ 'blender': (2, 5, 2),
+ 'location': '3dviev > simplify curves',
+ 'url': '',
+ 'description': 'this script simplifies curves',
+ 'category': 'Object'}
+####################################################
+import bpy
+from bpy.props import *
+import mathutils
+import math
+
+##############################
+#### simplipoly algorithm ####
+##############################
+# get SplineVertIndicies to keep
+def simplypoly(splineVerts, options):
+ # main vars
+ newVerts = [] # list of vertindices to keep
+ points = splineVerts # list of 3dVectors
+ pointCurva = [] # table with curvatures
+ curvatures = [] # averaged curvatures per vert
+ for p in points:
+ pointCurva.append([])
+ order = options[3] # order of sliding beziercurves
+ k_thresh = options[2] # curvature threshold
+ dis_error = options[6] # additional distance error
+
+ # get curvatures per vert
+ for i, point in enumerate(points[:-(order-1)]):
+ BVerts = points[i:i+order]
+ for b, BVert in enumerate(BVerts[1:-1]):
+ deriv1 = getDerivative(BVerts, 1/(order-1), order-1)
+ deriv2 = getDerivative(BVerts, 1/(order-1), order-2)
+ curva = getCurvature(deriv1, deriv2)
+ pointCurva[i+b+1].append(curva)
+
+ # average the curvatures
+ for i in range(len(points)):
+ avgCurva = sum(pointCurva[i]) / (order-1)
+ curvatures.append(avgCurva)
+
+ # get distancevalues per vert - same as Ramer-Douglas-Peucker
+ # but for every vert
+ distances = [0.0] #first vert is always kept
+ for i, point in enumerate(points[1:-1]):
+ dist = altitude(points[i], points[i+2], points[i+1])
+ distances.append(dist)
+ distances.append(0.0) # last vert is always kept
+
+ # generate list of vertindicies to keep
+ # tested against averaged curvatures and distances of neighbour verts
+ newVerts.append(0) # first vert is always kept
+ for i, curv in enumerate(curvatures):
+ if (curv > k_thresh*0.1
+ or distances[i] > dis_error*0.1):
+ newVerts.append(i)
+ newVerts.append(len(curvatures)-1) # last vert is always kept
+
+ return newVerts
+
+# get binomial coefficient
+def binom(n, m):
+ b = [0] * (n+1)
+ b[0] = 1
+ for i in range(1, n+1):
+ b[i] = 1
+ j = i-1
+ while j > 0:
+ b[j] += b[j-1]
+ j-= 1
+ return b[m]
+
+# get nth derivative of order(len(verts)) bezier curve
+def getDerivative(verts, t, nth):
+ order = len(verts) - 1 - nth
+ QVerts = []
+ for i in range(nth):
+ if QVerts:
+ verts = QVerts
+ derivVerts = []
+ for i in range(len(verts)-1):
+ derivVerts.append(verts[i+1] - verts[i])
+ QVerts = derivVerts
+ point = mathutils.Vector((0, 0, 0))
+ for i, vert in enumerate(QVerts):
+ point += binom(order, i) * math.pow(t, i) * math.pow(1-t, order-i) * vert
+ deriv = point
+ return deriv
+
+# get curvature from first, second derivative
+def getCurvature(deriv1, deriv2):
+ if deriv1.length == 0: # in case of points in straight line
+ curvature = 0
+ return curvature
+ curvature = (deriv1.cross(deriv2)).length / math.pow(deriv1.length, 3)
+ return curvature
+
+#########################################
+#### Ramer-Douglas-Peucker algorithm ####
+#########################################
+# get altitude of vert
+def altitude(point1, point2, pointn):
+ edge1 = point2 - point1
+ edge2 = pointn - point1
+ alpha = edge1.angle(edge2)
+ altitude = math.sin(alpha) * edge2.length
+ return altitude
+
+# iterate through verts
+def iterate(points, newVerts, error):
+ new = []
+ for newIndex in range(len(newVerts)-1):
+ bigVert = 0
+ alti_store = 0
+ for i, point in enumerate(points[newVerts[newIndex]+1:newVerts[newIndex+1]]):
+ alti = altitude(points[newVerts[newIndex]], points[newVerts[newIndex+1]], point)
+ if alti > alti_store:
+ alti_store = alti
+ if alti_store > error:
+ bigVert = i+1+newVerts[newIndex]
+ if bigVert:
+ new.append(bigVert)
+ if new == []:
+ return False
+ return new
+
+#### get SplineVertIndicies to keep
+def simplify_RDP(splineVerts, options):
+ #main vars
+ error = options[4]
+
+ # set first and last vert
+ newVerts = [0, len(splineVerts)-1]
+
+ # iterate through the points
+ new = 1
+ while new != False:
+ new = iterate(splineVerts, newVerts, error)
+ if new:
+ newVerts += new
+ newVerts.sort()
+ return newVerts
+
+##########################
+#### CURVE GENERATION ####
+##########################
+# set bezierhandles to auto
+def setBezierHandles(newCurve):
+ scene = bpy.context.scene
+ bpy.ops.object.mode_set(mode='EDIT', toggle=True)
+ bpy.ops.curve.select_all(action='SELECT')
+ bpy.ops.curve.handle_type_set(type='AUTOMATIC')
+ bpy.ops.object.mode_set(mode='OBJECT', toggle=True)
+
+# get array of new coords for new spline from vertindices
+def vertsToPoints(newVerts, splineVerts, splineType):
+ # main vars
+ newPoints = []
+
+ # array for BEZIER spline output
+ if splineType == 'BEZIER':
+ for v in newVerts:
+ newPoints += splineVerts[v].to_tuple()
+
+ # array for nonBEZIER output
+ else:
+ for v in newVerts:
+ newPoints += (splineVerts[v].to_tuple())
+ if splineType == 'NURBS':
+ newPoints.append(1) #for nurbs w=1
+ else: #for poly w=0
+ newPoints.append(0)
+ return newPoints
+
+#########################
+#### MAIN OPERATIONS ####
+#########################
+
+def main(context, obj, options):
+ #print("\n_______START_______")
+ # main vars
+ mode = options[0]
+ output = options[1]
+ degreeOut = options[5]
+ keepShort = options[7]
+ bpy.ops.object.select_all(action='DESELECT')
+ scene = context.scene
+ splines = obj.data.splines.values()
+
+ # create curvedatablock
+ curve = bpy.data.curves.new("simple_"+obj.name, type = 'CURVE')
+
+ # go through splines
+ for spline_i, spline in enumerate(splines):
+ # test if spline is a long enough
+ if len(spline.points) >= 7 or keepShort:
+ #check what type of spline to create
+ if output == 'INPUT':
+ splineType = spline.type
+ else:
+ splineType = output
+
+ # get vec3 list to simplify
+ if spline.type == 'BEZIER': # get bezierverts
+ splineVerts = spline.bezier_points.values()
+ splineVerts = [splineVert.co.copy()
+ for splineVert in spline.bezier_points.values()]
+
+ else: # verts from all other types of curves
+ splineVerts = [splineVert.co.copy().resize3D()
+ for splineVert in spline.points.values()]
+
+ # simplify spline according to mode
+ if mode == 'distance':
+ newVerts = simplify_RDP(splineVerts, options)
+
+ if mode == 'curvature':
+ newVerts = simplypoly(splineVerts, options)
+
+ # convert indicies into vectors3D
+ newPoints = vertsToPoints(newVerts, splineVerts, splineType)
+
+ # create new spline
+ newSpline = curve.splines.new(type = splineType)
+
+ # put newPoints into spline according to type
+ if splineType == 'BEZIER':
+ newSpline.bezier_points.add(int(len(newPoints)*0.33))
+ newSpline.bezier_points.foreach_set('co', newPoints)
+ else:
+ newSpline.points.add(int(len(newPoints)*0.25 - 1))
+ newSpline.points.foreach_set('co', newPoints)
+
+ # set degree of outputNurbsCurve
+ if output == 'NURBS':
+ newSpline.order_u = degreeOut
+
+ # splineoptions
+ newSpline.endpoint_u = spline.endpoint_u
+
+ # create ne object and put into scene
+ newCurve = bpy.data.objects.new("simple_"+obj.name, curve)
+ scene.objects.link(newCurve)
+ newCurve.selected = True
+ scene.objects.active = newCurve
+ newCurve.matrix = obj.matrix
+
+ # set bezierhandles to auto
+ setBezierHandles(newCurve)
+
+ #print("________END________\n")
+ return
+
+####################
+##### OPERATOR #####
+####################
+class CURVE_OT_simplify(bpy.types.Operator):
+ ''''''
+ bl_idname = "curve.simplify"
+ bl_label = "simplifiy curves"
+ bl_description = "simplify curves"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ ## Properties
+ opModes = [
+ ('distance', 'distance', 'distance'),
+ ('curvature', 'curvature', 'curvature')]
+ mode = EnumProperty(name="Mode",
+ description="choose algorithm to use",
+ items=opModes)
+ SplineTypes = [
+ ('INPUT', 'Input', 'same type as input spline'),
+ ('NURBS', 'Nurbs', 'NURBS'),
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-extensions-cvs
mailing list