[Bf-extensions-cvs] SVN commit: /data/svn/bf-extensions [2509] contrib/py/scripts/addons/ curve_to_uniform_mesh.py: -curve_to_uniform_mesh.py by Denis Declara

yousef harfoush bat3a at msn.com
Mon Oct 24 01:00:56 CEST 2011


Revision: 2509
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-extensions&revision=2509
Author:   bat3a
Date:     2011-10-23 23:00:55 +0000 (Sun, 23 Oct 2011)
Log Message:
-----------
-curve_to_uniform_mesh.py by Denis Declara

Added Paths:
-----------
    contrib/py/scripts/addons/curve_to_uniform_mesh.py

Added: contrib/py/scripts/addons/curve_to_uniform_mesh.py
===================================================================
--- contrib/py/scripts/addons/curve_to_uniform_mesh.py	                        (rev 0)
+++ contrib/py/scripts/addons/curve_to_uniform_mesh.py	2011-10-23 23:00:55 UTC (rev 2509)
@@ -0,0 +1,440 @@
+# ##### 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 #####
+
+bl_addon_info = {
+    "name": "Curve to Uniform Mesh",
+    "author": "Denis Declara",
+    "version": (0, 1),
+    "blender": (2, 5, 3),
+    "api": 32411,
+    "location": "Toolshelf > search > Curve to Uniform Mesh",
+    "description": "This script converts bezier curves or text objects to a mesh",
+    "warning": "Beta",
+    "wiki_url": "",
+    "tracker_url": "",
+    "category": "Add Curve"}
+
+"""
+This script converts curves and text objects to an even mesh.
+"""
+
+##############################
+import bpy
+from bpy.props import *
+import mathutils
+from mathutils import Vector
+
+#######################################
+### Beginn of custom bezier classes ###
+#######################################
+
+# Simple class which holds a straight bezier segment
+class LinearBezierSegment:
+    s = Vector((0,1,0))
+    e = Vector((0,0,0))
+    
+    def __init__ (self, start, end):
+        self.s = start
+        self.e = end
+    
+    # This method returns the length of the line segment
+    def calculateLength(self):
+        return (start - end).length()
+
+    # This method evaluates the bezier curve at a
+    # point t in [0, 1] 
+    def at(self, t):        
+        return self.s + (self.e - self.s) * t
+    
+# Simple class which stores one cubic bezier segment
+# That is a segmend with start and end point, plus
+# two control points
+class CubicBezierSegment:
+    s  = Vector(( -1,  0, 0)) # First  bezier point
+    n1 = Vector((-.5,-.5, 0)) # Right  handle of the first bezier point
+    n2 = Vector((  0,  0, 0)) # Left   handle of the second bezier point
+    e  = Vector((  1,  0, 0)) # Second bezier point
+    
+    def __init__ (self, start, ctrl1, ctrl2, end):
+        self.s  = start
+        self.n1 = ctrl1
+        self.n2 = ctrl2
+        self.e  = end
+    
+    # This method evaluates the bezier curve at a
+    # point t in [0, 1]
+    def at(self, t):
+        # This method uses the method illustrated in this animation
+        # http://en.wikipedia.org/wiki/File:Bezier_3_big.gif
+
+        # Create the first segments
+        a = LinearBezierSegment(self.s,  self.n1).at(t)
+        b = LinearBezierSegment(self.n1, self.n2).at(t)
+        c = LinearBezierSegment(self.n2, self.e ).at(t)
+        
+        # Interpolate those segments
+        d = LinearBezierSegment(a, b).at(t)
+        e = LinearBezierSegment(b, c).at(t)
+        
+        # And finally interpolate one last time and return
+        f = LinearBezierSegment(d, e).at(t)
+        return f
+    
+    # Calculates an approximatino of the length. By subdividing
+    # the curve in straight segments. The amount of segments
+    # is specified by the parameter segments 
+    # The bigger the value, the more precise the approximation
+    # will be
+    def calculateLength(self, segments):
+        length = 0.0
+        lastPoint = self.at(0.0)
+        for i in range(0, segments):
+            t = (i + 1) / segments
+            nextPoint = self.at(t)
+            length += (lastPoint - nextPoint).length
+            lastPoint = nextPoint
+        return length
+    
+    # This function returns a collection of Vectors, with
+    # as many intermediate points as defined by the parameter
+    # segments. Moreover it will not include the last point
+    # if the argument excludeLast is set to true
+    def getIntermediatePoints(self, segments, excludeLast):
+        if not excludeLast:
+            segments += 1
+        
+        points = []
+        for i in range(0, segments):
+            t1 = i / segments
+            points.append(self.at(t1))
+        return points
+
+# This class basically represents a collection of
+# cubic bezier segments, forming a closed curve
+class CubicBezier:
+    segments = [] # Collection of cubic bezier segments
+
+    # Adds a segment at the end of the curve
+    def addSegment(self, segment):
+        self.segments.append(segment)
+    
+    # This function calculates the amount of subdivisions for
+    # each individual bezier segment, so that the subdivision
+    # results homogeneous
+    # - FirstPassResolution determines the precision of the length
+    #   approximation and therefore of the subdivision
+    # - SegmentsPerUnit determines the density of the subdivision
+    def calculateAdaptiveSegments(self, firstPassResolution = 8, segmentsPerUnit = 8):
+        # If there are no segments in the curve return an empty array
+        if len(self.segments) == 0:
+            return []        
+
+        # Create an array with the length of the segments
+        lengths = [segment.calculateLength(firstPassResolution)
+                   for segment in self.segments]
+
+        length = 0.0
+        # Sum up the length of each segment 
+        for l in lengths:
+            length += l
+                        
+        # Calculate adaptive subdivisions of segments:
+        nSegments = [0] * len(self.segments)
+        # Determine the amount of subdivisions to perform by
+        # multiplying the density by the total length 
+        segmentsToAssign = int(round(segmentsPerUnit * length))
+        # Distribute those subdivisions to the individual bezier
+        # segments evenly, based upon their length
+        for s in range(0, len(self.segments)):
+            nSegments[s] = 1 + int(lengths[s] * segmentsPerUnit)
+            segmentsToAssign -= nSegments[s]
+
+        # If, due to rounding errors, some subdivisions haven't
+        # been assigned, assign those
+        while segmentsToAssign > 0:
+            maxDeltaIndex = 0
+            for s in range(0, len(self.segments)):
+                # Delta0 and Delta1 represent the length of each subdivided segment
+                delta0 = lengths[maxDeltaIndex] / nSegments[maxDeltaIndex]
+                delta1 = lengths[s] / nSegments[s]
+
+                if (delta0 < delta1):
+                    maxDeltaIndex = s
+            # Assign one subdivision to the segment which has the biggest
+            # subdivided segments.
+            nSegments[maxDeltaIndex] += 1
+            segmentsToAssign -= 1
+        
+        # Finally after long computation return the optimal subdivisions for each segment
+        return nSegments
+
+    # This function returns a collection of Vectors, with
+    # a density of points  as defined by the parameter
+    # segmentsPerUnit. Moreover the precision can is set by
+    # the parameter firstPassResolution
+    def getIntermediatePoints(self, firstPassResolution = 8, segmentsPerUnit = 8):
+        points = []
+            
+        # Return if there are no segments in the curve
+        if len(self.segments) == 0:
+            return points
+
+        # Calculate adaptive subdivision of segments:
+        nSegments = self.calculateAdaptiveSegments(firstPassResolution, segmentsPerUnit)
+
+        # Ask to each bezier segment to generate as many points as defined by nSegments[i]
+        # and append those to the array points
+        for s in range(0, len(self.segments)):
+            segm = self.segments[s]            
+            # Exclude the last point, so we do not get any duplication
+            # in closed curves
+            points.extend(segm.getIntermediatePoints(nSegments[s], True))
+            
+        return points
+
+    # Calculates an approximatino of the length. By subdividing
+    # the curve in straight segments. The density of segments
+    # is specified by the parameter segmentsPerUnit 
+    # The bigger the value of segmentsPerUnit and firstPassResolution
+    # the more precise the approximation will be
+    def calculateLength(self, firstPassResolution = 8, segmentsPerUnit = 8):
+        # If the curve has no segments the length is of course 0
+        if (len(self.segments) == 0):
+            return 0.0
+            
+        length = 0.0
+
+        # Calculate adaptive segments:
+        nSegments = calculateAdaptiveSegments(firstPassResolution, segmentsPerUnit)
+
+        # Calculate adaptive length:
+        length = 0
+        for s in range(0, len(self.segments)):
+            segment = self.segments[s]
+            length += segment.calculateLength(nSegments[s])
+            
+        return length
+
+######################################
+### -End of custom bezier classes- ###
+######################################
+
+def main(context, obj, options):
+    #print("\n_______START_______")
+    # main vars
+    fillMesh = options[0]
+    lengthApp = options[1]
+    density = options[2]
+    beautifyIters = options[3]
+    if(options[4] == False): # If the execute checkbox is not checked return 
+        return;
+
+    verts = []
+    faces = []
+    curVertex = 0;
+
+    originalName = obj.name
+    isFontObject = (obj.type == 'FONT')
+    if isFontObject:
+        # Convert font objects into curves
+        bpy.ops.object.select_all(action='DESELECT')
+        obj.select = True
+        context.scene.objects.active = obj
+        bpy.ops.object.convert(target='CURVE', keep_original=True)
+        obj = bpy.context.active_object 
+        
+    # Deselect all of the objects in the scene
+    bpy.ops.object.select_all(action='DESELECT')
+    scene = context.scene
+    splines = obj.data.splines.values()
+
+    # create a mesh datablock
+    mesh = bpy.data.meshes.new("uniform_"+originalName)
+
+    # go through splines
+    for spline in splines:

@@ Diff output truncated at 10240 characters. @@


More information about the Bf-extensions-cvs mailing list