From b144e6a025f745b57fb15b311f6dd44a6dc62946 Mon Sep 17 00:00:00 2001 From: gandalf3 Date: Thu, 6 Jul 2017 00:00:43 -0700 Subject: [PATCH] Remove unneccesary bulk of code in addons used for testing --- .../test_helpers/addons/dir_addon/__init__.py | 267 ------- tests/test_helpers/addons/singlefile_addon.PY | 716 ------------------ tests/test_helpers/addons/singlefile_addon.py | 715 ----------------- 3 files changed, 1698 deletions(-) diff --git a/tests/test_helpers/addons/dir_addon/__init__.py b/tests/test_helpers/addons/dir_addon/__init__.py index ae8cdf8..059b75e 100644 --- a/tests/test_helpers/addons/dir_addon/__init__.py +++ b/tests/test_helpers/addons/dir_addon/__init__.py @@ -32,270 +32,3 @@ bl_info = { "Scripts/Curve/Curve_Objects", "category": "Add Curve" } - -if "bpy" in locals(): - import importlib - importlib.reload(add_curve_aceous_galore) - importlib.reload(add_curve_spirals) - importlib.reload(add_curve_torus_knots) - importlib.reload(add_surface_plane_cone) - importlib.reload(add_curve_curly) - importlib.reload(beveltaper_curve) - importlib.reload(add_curve_celtic_links) - importlib.reload(add_curve_braid) - importlib.reload(add_curve_simple) - importlib.reload(add_curve_spirofit_bouncespline) - -else: - from . import add_curve_aceous_galore - from . import add_curve_spirals - from . import add_curve_torus_knots - from . import add_surface_plane_cone - from . import add_curve_curly - from . import beveltaper_curve - from . import add_curve_celtic_links - from . import add_curve_braid - from . import add_curve_simple - from . import add_curve_spirofit_bouncespline - -import bpy -from bpy.types import ( - Menu, - AddonPreferences, - ) -from bpy.props import ( - StringProperty, - BoolProperty, - ) - - -def convert_old_presets(data_path, msg_data_path, old_preset_subdir, - new_preset_subdir, fixdic={}, ext=".py"): - """ - convert old presets - """ - - def convert_presets(self, context): - if not getattr(self, data_path, False): - return None - import os - - target_path = os.path.join("presets", old_preset_subdir) - target_path = bpy.utils.user_resource('SCRIPTS', - target_path) - - # created an anytype op to run against preset - op = type('', (), {})() - - files = [f for f in os.listdir(target_path) if f.endswith(ext)] - if not files: - print("No old presets in %s" % target_path) - setattr(self, msg_data_path, "No old presets") - return None - - new_target_path = os.path.join("presets", new_preset_subdir) - new_target_path = bpy.utils.user_resource('SCRIPTS', - new_target_path, - create=True) - for f in files: - file = open(os.path.join(target_path, f)) - for line in file: - if line.startswith("op."): - exec(line) - file.close() - for key, items in fixdic.items(): - if hasattr(op, key) and isinstance(getattr(op, key), int): - setattr(op, key, items[getattr(op, key)]) - # create a new one - new_file_path = os.path.join(new_target_path, f) - if os.path.isfile(new_file_path): - # do nothing - print("Preset %s already exists, passing..." % f) - continue - file_preset = open(new_file_path, 'w') - file_preset.write("import bpy\n") - file_preset.write("op = bpy.context.active_operator\n") - - for prop, value in vars(op).items(): - if isinstance(value, str): - file_preset.write("op.%s = '%s'\n" % (prop, str(value))) - else: - file_preset.write("op.%s = %s\n" % (prop, str(value))) - file_preset.close() - print("Writing new preset to %s" % new_file_path) - - setattr(self, msg_data_path, "Converted %d old presets" % len(files)) - return None - - return convert_presets - - -# Addons Preferences - -class CurveExtraObjectsAddonPreferences(AddonPreferences): - bl_idname = __name__ - - spiral_fixdic = { - "spiral_type": ['ARCH', 'ARCH', 'LOG', 'SPHERE', 'TORUS'], - "curve_type": ['POLY', 'NURBS'], - "spiral_direction": ['COUNTER_CLOCKWISE', 'CLOCKWISE'] - } - update_spiral_presets_msg = StringProperty( - default="Nothing to do" - ) - update_spiral_presets = BoolProperty( - name="Update Old Presets", - description="Update presets to reflect data changes", - default=False, - update=convert_old_presets( - "update_spiral_presets", # this props name - "update_spiral_presets_msg", # message prop - "operator/curve.spirals", - "curve_extras/curve.spirals", - fixdic=spiral_fixdic - ) - ) - show_menu_list = BoolProperty( - name="Menu List", - description="Show/Hide the Add Menu items", - default=False - ) - show_panel_list = BoolProperty( - name="Panels List", - description="Show/Hide the Panel items", - default=False - ) - - def draw(self, context): - layout = self.layout - box = layout.box() - box.label(text="Spirals:") - - if self.update_spiral_presets: - box.label(self.update_spiral_presets_msg, icon="FILE_TICK") - else: - box.prop(self, "update_spiral_presets") - - icon_1 = "TRIA_RIGHT" if not self.show_menu_list else "TRIA_DOWN" - box = layout.box() - box.prop(self, "show_menu_list", emboss=False, icon=icon_1) - - if self.show_menu_list: - box.label(text="Items located in the Add Menu > Curve (default shortcut Ctrl + A):", - icon="LAYER_USED") - box.label(text="2D Objects:", icon="LAYER_ACTIVE") - box.label(text="Angle, Arc, Circle, Distance, Ellipse, Line, Point, Polygon,", - icon="LAYER_USED") - box.label(text="Polygon ab, Rectangle, Rhomb, Sector, Segment, Trapezoid", - icon="LAYER_USED") - box.label(text="Curve Profiles:", icon="LAYER_ACTIVE") - box.label(text="Arc, Arrow, Cogwheel, Cycloid, Flower, Helix (3D),", - icon="LAYER_USED") - box.label(text="Noise (3D), Nsided, Profile, Rectangle, Splat, Star", - icon="LAYER_USED") - box.label(text="Curve Spirals:", icon="LAYER_ACTIVE") - box.label(text="Archemedian, Logarithmic, Spheric, Torus", - icon="LAYER_USED") - box.label(text="Knots:", icon="LAYER_ACTIVE") - box.label(text="Torus Knots Plus, Celtic Links, Braid Knot", - icon="LAYER_USED") - box.label(text="Curly Curve", icon="LAYER_ACTIVE") - box.label(text="Bevel/Taper:", icon="LAYER_ACTIVE") - box.label(text="Add Curve as Bevel, Add Curve as Taper", - icon="LAYER_USED") - - box.label(text="Items located in the Add Menu > Surface (default shortcut Ctrl + A):", - icon="LAYER_USED") - box.label(text="Wedge, Cone, Star, Plane", - icon="LAYER_ACTIVE") - - icon_2 = "TRIA_RIGHT" if not self.show_panel_list else "TRIA_DOWN" - box = layout.box() - box.prop(self, "show_panel_list", emboss=False, icon=icon_2) - - if self.show_panel_list: - box.label(text="Panel located in 3D View Tools Region > Create:", - icon="LAYER_ACTIVE") - box.label(text="Spline:", icon="LAYER_ACTIVE") - box.label(text="SpiroFit, Bounce Spline, Catenary", icon="LAYER_USED") - box.label(text="Panel located in 3D View Tools Region > Tools:", - icon="LAYER_ACTIVE") - box.label(text="Simple Curve:", icon="LAYER_ACTIVE") - box.label(text="Available if the Active Object is a Curve was created with 2D Objects", - icon="LAYER_USED") - - -class INFO_MT_curve_knots_add1(Menu): - # Define the "Extras" menu - bl_idname = "curve_knots_add" - bl_label = "Plants" - - def draw(self, context): - layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' - - layout.operator("curve.torus_knot_plus", text="Torus Knot Plus") - layout.operator("curve.celtic_links", text="Celtic Links") - layout.operator("mesh.add_braid", text="Braid Knot") - - -# Define "Extras" menus -def menu_func(self, context): - if context.mode != 'OBJECT': - # fix in D2142 will allow to work in EDIT_CURVE - return None - - layout = self.layout - - layout.operator_menu_enum("mesh.curveaceous_galore", "ProfileType", - icon='CURVE_DATA') - layout.operator_menu_enum("curve.spirals", "spiral_type", - icon='CURVE_DATA') - layout.separator() - - layout.menu("curve_knots_add", text="Knots", icon='CURVE_DATA') - layout.separator() - layout.operator("curve.curlycurve", text="Curly Curve", - icon='CURVE_DATA') - layout.menu("OBJECT_MT_bevel_taper_curve_menu", text="Bevel/Taper", - icon='CURVE_DATA') - - -def menu_surface(self, context): - self.layout.separator() - if context.mode == 'EDIT_SURFACE': - self.layout.operator("curve.smooth_x_times", - text="Special Smooth", icon="MOD_CURVE") - elif context.mode == 'OBJECT': - self.layout.operator("object.add_surface_wedge", text="Wedge", - icon="SURFACE_DATA") - self.layout.operator("object.add_surface_cone", text="Cone", - icon="SURFACE_DATA") - self.layout.operator("object.add_surface_star", text="Star", - icon="SURFACE_DATA") - self.layout.operator("object.add_surface_plane", text="Plane", - icon="SURFACE_DATA") - - -def register(): - add_curve_simple.register() - bpy.utils.register_module(__name__) - - # Add "Extras" menu to the "Add Curve" menu - bpy.types.INFO_MT_curve_add.append(menu_func) - # Add "Extras" menu to the "Add Surface" menu - bpy.types.INFO_MT_surface_add.append(menu_surface) - - -def unregister(): - add_curve_simple.unregister() - # Remove "Extras" menu from the "Add Curve" menu. - bpy.types.INFO_MT_curve_add.remove(menu_func) - # Remove "Extras" menu from the "Add Surface" menu. - bpy.types.INFO_MT_surface_add.remove(menu_surface) - - bpy.utils.unregister_module(__name__) - - -if __name__ == "__main__": - register() diff --git a/tests/test_helpers/addons/singlefile_addon.PY b/tests/test_helpers/addons/singlefile_addon.PY index 1bb6fde..4c02cd9 100644 --- a/tests/test_helpers/addons/singlefile_addon.PY +++ b/tests/test_helpers/addons/singlefile_addon.PY @@ -45,719 +45,3 @@ bl_info = { "Scripts/Curve/Curve_Objects", "category": "Add Curve" } - - - -import bpy -from bpy.props import ( - FloatProperty, - IntProperty, - BoolProperty, - ) -from mathutils import ( - Vector, - Matrix, - ) -from collections import deque -from math import ( - pow, cos, - pi, atan2, - ) -from random import ( - random as rand_val, - seed as rand_seed, - ) -import time - - -def createIvyGeometry(IVY, growLeaves): - """Create the curve geometry for IVY""" - # Compute the local size and the gauss weight filter - # local_ivyBranchSize = IVY.ivyBranchSize # * radius * IVY.ivySize - gaussWeight = (1.0, 2.0, 4.0, 7.0, 9.0, 10.0, 9.0, 7.0, 4.0, 2.0, 1.0) - - # Create a new curve and intialise it - curve = bpy.data.curves.new("IVY", type='CURVE') - curve.dimensions = '3D' - curve.bevel_depth = 1 - curve.fill_mode = 'FULL' - curve.resolution_u = 4 - - if growLeaves: - # Create the ivy leaves - # Order location of the vertices - signList = ((-1.0, +1.0), - (+1.0, +1.0), - (+1.0, -1.0), - (-1.0, -1.0), - ) - - # Get the local size - # local_ivyLeafSize = IVY.ivyLeafSize # * radius * IVY.ivySize - - # Initialise the vertex and face lists - vertList = deque() - - # Store the methods for faster calling - addV = vertList.extend - rotMat = Matrix.Rotation - - # Loop over all roots to generate its nodes - for root in IVY.ivyRoots: - # Only grow if more than one node - numNodes = len(root.ivyNodes) - if numNodes > 1: - # Calculate the local radius - local_ivyBranchRadius = 1.0 / (root.parents + 1) + 1.0 - prevIvyLength = 1.0 / root.ivyNodes[-1].length - splineVerts = [ax for n in root.ivyNodes for ax in n.pos.to_4d()] - - radiusConstant = local_ivyBranchRadius * IVY.ivyBranchSize - splineRadii = [radiusConstant * (1.3 - n.length * prevIvyLength) - for n in root.ivyNodes] - - # Add the poly curve and set coords and radii - newSpline = curve.splines.new(type='POLY') - newSpline.points.add(len(splineVerts) // 4 - 1) - newSpline.points.foreach_set('co', splineVerts) - newSpline.points.foreach_set('radius', splineRadii) - - # Loop over all nodes in the root - for i, n in enumerate(root.ivyNodes): - for k in range(len(gaussWeight)): - idx = max(0, min(i + k - 5, numNodes - 1)) - n.smoothAdhesionVector += (gaussWeight[k] * - root.ivyNodes[idx].adhesionVector) - n.smoothAdhesionVector /= 56.0 - n.adhesionLength = n.smoothAdhesionVector.length - n.smoothAdhesionVector.normalize() - - if growLeaves and (i < numNodes - 1): - node = root.ivyNodes[i] - nodeNext = root.ivyNodes[i + 1] - - # Find the weight and normalize the smooth adhesion vector - weight = pow(node.length * prevIvyLength, 0.7) - - # Calculate the ground ivy and the new weight - groundIvy = max(0.0, -node.smoothAdhesionVector.z) - weight += groundIvy * pow(1 - node.length * - prevIvyLength, 2) - - # Find the alignment weight - alignmentWeight = node.adhesionLength - - # Calculate the needed angles - phi = atan2(node.smoothAdhesionVector.y, - node.smoothAdhesionVector.x) - pi / 2.0 - - theta = (0.5 * - node.smoothAdhesionVector.angle(Vector((0, 0, -1)), 0)) - - # Find the size weight - sizeWeight = 1.5 - (cos(2 * pi * weight) * 0.5 + 0.5) - - # Randomise the angles - phi += (rand_val() - 0.5) * (1.3 - alignmentWeight) - theta += (rand_val() - 0.5) * (1.1 - alignmentWeight) - - # Calculate the leaf size an append the face to the list - leafSize = IVY.ivyLeafSize * sizeWeight - - for j in range(10): - # Generate the probability - probability = rand_val() - - # If we need to grow a leaf, do so - if (probability * weight) > IVY.leafProbability: - - # Generate the random vector - randomVector = Vector((rand_val() - 0.5, - rand_val() - 0.5, - rand_val() - 0.5, - )) - - # Find the leaf center - center = (node.pos.lerp(nodeNext.pos, j / 10.0) + - IVY.ivyLeafSize * randomVector) - - # For each of the verts, rotate/scale and append - basisVecX = Vector((1, 0, 0)) - basisVecY = Vector((0, 1, 0)) - - horiRot = rotMat(theta, 3, 'X') - vertRot = rotMat(phi, 3, 'Z') - - basisVecX.rotate(horiRot) - basisVecY.rotate(horiRot) - - basisVecX.rotate(vertRot) - basisVecY.rotate(vertRot) - - basisVecX *= leafSize - basisVecY *= leafSize - - addV([k1 * basisVecX + k2 * basisVecY + center for - k1, k2 in signList]) - - # Add the object and link to scene - newCurve = bpy.data.objects.new("IVY_Curve", curve) - bpy.context.scene.objects.link(newCurve) - - if growLeaves: - faceList = [[4 * i + l for l in range(4)] for i in - range(len(vertList) // 4)] - - # Generate the new leaf mesh and link - me = bpy.data.meshes.new('IvyLeaf') - me.from_pydata(vertList, [], faceList) - me.update(calc_edges=True) - ob = bpy.data.objects.new('IvyLeaf', me) - bpy.context.scene.objects.link(ob) - - me.uv_textures.new("Leaves") - - # Set the uv texture coords - # TODO, this is non-functional, default uvs are ok? - ''' - for d in tex.data: - uv1, uv2, uv3, uv4 = signList - ''' - - ob.parent = newCurve - - -''' -def computeBoundingSphere(ob): - # Get the mesh data - me = ob.data - # Intialise the center - center = Vector((0.0, 0.0, 0.0)) - # Add all vertex coords - for v in me.vertices: - center += v.co - # Average over all verts - center /= len(me.vertices) - # Create the iterator and find its max - length_iter = ((center - v.co).length for v in me.vertices) - radius = max(length_iter) - return radius -''' - - -class IvyNode: - """ The basic class used for each point on the ivy which is grown.""" - __slots__ = ('pos', 'primaryDir', 'adhesionVector', 'adhesionLength', - 'smoothAdhesionVector', 'length', 'floatingLength', 'climb') - - def __init__(self): - self.pos = Vector((0, 0, 0)) - self.primaryDir = Vector((0, 0, 1)) - self.adhesionVector = Vector((0, 0, 0)) - self.smoothAdhesionVector = Vector((0, 0, 0)) - self.length = 0.0001 - self.floatingLength = 0.0 - self.climb = True - - -class IvyRoot: - """ The class used to hold all ivy nodes growing from this root point.""" - __slots__ = ('ivyNodes', 'alive', 'parents') - - def __init__(self): - self.ivyNodes = deque() - self.alive = True - self.parents = 0 - - -class Ivy: - """ The class holding all parameters and ivy roots.""" - __slots__ = ('ivyRoots', 'primaryWeight', 'randomWeight', - 'gravityWeight', 'adhesionWeight', 'branchingProbability', - 'leafProbability', 'ivySize', 'ivyLeafSize', 'ivyBranchSize', - 'maxFloatLength', 'maxAdhesionDistance', 'maxLength') - - def __init__(self, - primaryWeight=0.5, - randomWeight=0.2, - gravityWeight=1.0, - adhesionWeight=0.1, - branchingProbability=0.05, - leafProbability=0.35, - ivySize=0.02, - ivyLeafSize=0.02, - ivyBranchSize=0.001, - maxFloatLength=0.5, - maxAdhesionDistance=1.0): - - self.ivyRoots = deque() - self.primaryWeight = primaryWeight - self.randomWeight = randomWeight - self.gravityWeight = gravityWeight - self.adhesionWeight = adhesionWeight - self.branchingProbability = 1 - branchingProbability - self.leafProbability = 1 - leafProbability - self.ivySize = ivySize - self.ivyLeafSize = ivyLeafSize - self.ivyBranchSize = ivyBranchSize - self.maxFloatLength = maxFloatLength - self.maxAdhesionDistance = maxAdhesionDistance - self.maxLength = 0.0 - - # Normalize all the weights only on intialisation - sums = self.primaryWeight + self.randomWeight + self.adhesionWeight - self.primaryWeight /= sums - self.randomWeight /= sums - self.adhesionWeight /= sums - - def seed(self, seedPos): - # Seed the Ivy by making a new root and first node - tmpRoot = IvyRoot() - tmpIvy = IvyNode() - tmpIvy.pos = seedPos - - tmpRoot.ivyNodes.append(tmpIvy) - self.ivyRoots.append(tmpRoot) - - def grow(self, ob): - # Determine the local sizes - # local_ivySize = self.ivySize # * radius - # local_maxFloatLength = self.maxFloatLength # * radius - # local_maxAdhesionDistance = self.maxAdhesionDistance # * radius - - for root in self.ivyRoots: - # Make sure the root is alive, if not, skip - if not root.alive: - continue - - # Get the last node in the current root - prevIvy = root.ivyNodes[-1] - - # If the node is floating for too long, kill the root - if prevIvy.floatingLength > self.maxFloatLength: - root.alive = False - - # Set the primary direction from the last node - primaryVector = prevIvy.primaryDir - - # Make the random vector and normalize - randomVector = Vector((rand_val() - 0.5, rand_val() - 0.5, - rand_val() - 0.5)) + Vector((0, 0, 0.2)) - randomVector.normalize() - - # Calculate the adhesion vector - adhesionVector = adhesion(prevIvy.pos, ob, - self.maxAdhesionDistance) - - # Calculate the growing vector - growVector = self.ivySize * (primaryVector * self.primaryWeight + - randomVector * self.randomWeight + - adhesionVector * self.adhesionWeight) - - # Find the gravity vector - gravityVector = (self.ivySize * self.gravityWeight * - Vector((0, 0, -1))) - gravityVector *= pow(prevIvy.floatingLength / self.maxFloatLength, - 0.7) - - # Determine the new position vector - newPos = prevIvy.pos + growVector + gravityVector - - # Check for collisions with the object - climbing = collision(ob, prevIvy.pos, newPos) - - # Update the growing vector for any collisions - growVector = newPos - prevIvy.pos - gravityVector - growVector.normalize() - - # Create a new IvyNode and set its properties - tmpNode = IvyNode() - tmpNode.climb = climbing - tmpNode.pos = newPos - tmpNode.primaryDir = prevIvy.primaryDir.lerp(growVector, 0.5) - tmpNode.primaryDir.normalize() - tmpNode.adhesionVector = adhesionVector - tmpNode.length = prevIvy.length + (newPos - prevIvy.pos).length - - if tmpNode.length > self.maxLength: - self.maxLength = tmpNode.length - - # If the node isn't climbing, update it's floating length - # Otherwise set it to 0 - if not climbing: - tmpNode.floatingLength = prevIvy.floatingLength + (newPos - - prevIvy.pos).length - else: - tmpNode.floatingLength = 0.0 - - root.ivyNodes.append(tmpNode) - - # Loop through all roots to check if a new root is generated - for root in self.ivyRoots: - # Check the root is alive and isn't at high level of recursion - if (root.parents > 3) or (not root.alive): - continue - - # Check to make sure there's more than 1 node - if len(root.ivyNodes) > 1: - # Loop through all nodes in root to check if new root is grown - for node in root.ivyNodes: - # Set the last node of the root and find the weighting - prevIvy = root.ivyNodes[-1] - weight = 1.0 - (cos(2.0 * pi * node.length / - prevIvy.length) * 0.5 + 0.5) - - probability = rand_val() - - # Check if a new root is grown and if so, set its values - if (probability * weight > self.branchingProbability): - tmpNode = IvyNode() - tmpNode.pos = node.pos - tmpNode.floatingLength = node.floatingLength - - tmpRoot = IvyRoot() - tmpRoot.parents = root.parents + 1 - - tmpRoot.ivyNodes.append(tmpNode) - self.ivyRoots.append(tmpRoot) - return - - -def adhesion(loc, ob, max_l): - # Get transfor vector and transformed loc - tran_mat = ob.matrix_world.inverted() - tran_loc = tran_mat * loc - - # Compute the adhesion vector by finding the nearest point - nearest_result = ob.closest_point_on_mesh(tran_loc, max_l) - adhesion_vector = Vector((0.0, 0.0, 0.0)) - if nearest_result[0]: - # Compute the distance to the nearest point - adhesion_vector = ob.matrix_world * nearest_result[1] - loc - distance = adhesion_vector.length - # If it's less than the maximum allowed and not 0, continue - if distance: - # Compute the direction vector between the closest point and loc - adhesion_vector.normalize() - adhesion_vector *= 1.0 - distance / max_l - # adhesion_vector *= getFaceWeight(ob.data, nearest_result[3]) - return adhesion_vector - - -def collision(ob, pos, new_pos): - # Check for collision with the object - climbing = False - - # Transform vecs - tran_mat = ob.matrix_world.inverted() - tran_pos = tran_mat * pos - tran_new_pos = tran_mat * new_pos - tran_dir = tran_new_pos - tran_pos - - ray_result = ob.ray_cast(tran_pos, tran_dir, tran_dir.length) - # If there's a collision we need to check it - if ray_result[0]: - # Check whether the collision is going into the object - if tran_dir.dot(ray_result[2]) < 0.0: - # Find projection of the piont onto the plane - p0 = tran_new_pos - (tran_new_pos - - ray_result[1]).project(ray_result[2]) - # Reflect in the plane - tran_new_pos += 2 * (p0 - tran_new_pos) - new_pos *= 0 - new_pos += ob.matrix_world * tran_new_pos - climbing = True - return climbing - - -def check_mesh_faces(ob): - me = ob.data - if len(me.polygons) > 0: - return True - - return False - - -class IvyGen(bpy.types.Operator): - bl_idname = "curve.ivy_gen" - bl_label = "IvyGen" - bl_description = "Generate Ivy on an Mesh Object" - bl_options = {'REGISTER', 'UNDO'} - - maxIvyLength = FloatProperty( - name="Max Ivy Length", - description="Maximum ivy length in Blender Units", - default=1.0, - min=0.0, - soft_max=3.0, - subtype='DISTANCE', - unit='LENGTH' - ) - primaryWeight = FloatProperty( - name="Primary Weight", - description="Weighting given to the current direction", - default=0.5, - min=0.0, - soft_max=1.0 - ) - randomWeight = FloatProperty( - name="Random Weight", - description="Weighting given to the random direction", - default=0.2, - min=0.0, - soft_max=1.0 - ) - gravityWeight = FloatProperty( - name="Gravity Weight", - description="Weighting given to the gravity direction", - default=1.0, - min=0.0, - soft_max=1.0 - ) - adhesionWeight = FloatProperty( - name="Adhesion Weight", - description="Weighting given to the adhesion direction", - default=0.1, - min=0.0, - soft_max=1.0 - ) - branchingProbability = FloatProperty( - name="Branching Probability", - description="Probability of a new branch forming", - default=0.05, - min=0.0, - soft_max=1.0 - ) - leafProbability = FloatProperty( - name="Leaf Probability", - description="Probability of a leaf forming", - default=0.35, - min=0.0, - soft_max=1.0 - ) - ivySize = FloatProperty( - name="Ivy Size", - description="The length of an ivy segment in Blender" - " Units", - default=0.02, - min=0.0, - soft_max=1.0, - precision=3 - ) - ivyLeafSize = FloatProperty( - name="Ivy Leaf Size", - description="The size of the ivy leaves", - default=0.02, - min=0.0, - soft_max=0.5, - precision=3 - ) - ivyBranchSize = FloatProperty( - name="Ivy Branch Size", - description="The size of the ivy branches", - default=0.001, - min=0.0, - soft_max=0.1, - precision=4 - ) - maxFloatLength = FloatProperty( - name="Max Float Length", - description="The maximum distance that a branch " - "can live while floating", - default=0.5, - min=0.0, - soft_max=1.0) - maxAdhesionDistance = FloatProperty( - name="Max Adhesion Length", - description="The maximum distance that a branch " - "will feel the effects of adhesion", - default=1.0, - min=0.0, - soft_max=2.0, - precision=2 - ) - randomSeed = IntProperty( - name="Random Seed", - description="The seed governing random generation", - default=0, - min=0 - ) - maxTime = FloatProperty( - name="Maximum Time", - description="The maximum time to run the generation for " - "in seconds generation (0.0 = Disabled)", - default=0.0, - min=0.0, - soft_max=10 - ) - growLeaves = BoolProperty( - name="Grow Leaves", - description="Grow leaves or not", - default=True - ) - updateIvy = BoolProperty( - name="Update Ivy", - default=False - ) - - @classmethod - def poll(self, context): - # Check if there's an object and whether it's a mesh - ob = context.active_object - return ((ob is not None) and - (ob.type == 'MESH') and - (context.mode == 'OBJECT')) - - def invoke(self, context, event): - self.updateIvy = True - return self.execute(context) - - def execute(self, context): - if not self.updateIvy: - return {'PASS_THROUGH'} - - bpy.ops.object.mode_set(mode='EDIT', toggle=False) - bpy.ops.object.mode_set(mode='OBJECT', toggle=False) - - # Get the selected object - ob = context.active_object - - # Check if the mesh has at least one polygon since some functions - # are expecting them in the object's data (see T51753) - check_face = check_mesh_faces(ob) - if check_face is False: - self.report({'WARNING'}, - "Mesh Object doesn't have at least one Face. " - "Operation Cancelled") - return {"CANCELLED"} - - # Compute bounding sphere radius - # radius = computeBoundingSphere(ob) # Not needed anymore - - # Get the seeding point - seedPoint = context.scene.cursor_location - - # Fix the random seed - rand_seed(self.randomSeed) - - # Make the new ivy - IVY = Ivy(**self.as_keywords(ignore=('randomSeed', 'growLeaves', - 'maxIvyLength', 'maxTime', 'updateIvy'))) - - # Generate first root and node - IVY.seed(seedPoint) - - checkTime = False - maxLength = self.maxIvyLength # * radius - - # If we need to check time set the flag - if self.maxTime != 0.0: - checkTime = True - - t = time.time() - startPercent = 0.0 - checkAliveIter = [True, ] - - # Grow until 200 roots is reached or backup counter exceeds limit - while (any(checkAliveIter) and - (IVY.maxLength < maxLength) and - (not checkTime or (time.time() - t < self.maxTime))): - # Grow the ivy for this iteration - IVY.grow(ob) - - # Print the proportion of ivy growth to console - if (IVY.maxLength / maxLength * 100) > 10 * startPercent // 10: - print('%0.2f%% of Ivy nodes have grown' % - (IVY.maxLength / maxLength * 100)) - startPercent += 10 - if IVY.maxLength / maxLength > 1: - print("Halting Growth") - - # Make an iterator to check if all are alive - checkAliveIter = (r.alive for r in IVY.ivyRoots) - - # Create the curve and leaf geometry - createIvyGeometry(IVY, self.growLeaves) - print("Geometry Generation Complete") - - print("Ivy generated in %0.2f s" % (time.time() - t)) - - self.updateIvy = False - - return {'FINISHED'} - - def draw(self, context): - layout = self.layout - - layout.prop(self, 'updateIvy', icon='CURVE_DATA') - - properties = layout.operator('curve.ivy_gen', text="Add New Ivy") - properties.randomSeed = self.randomSeed - properties.maxTime = self.maxTime - properties.maxIvyLength = self.maxIvyLength - properties.ivySize = self.ivySize - properties.maxFloatLength = self.maxFloatLength - properties.maxAdhesionDistance = self.maxAdhesionDistance - properties.primaryWeight = self.primaryWeight - properties.randomWeight = self.randomWeight - properties.gravityWeight = self.gravityWeight - properties.adhesionWeight = self.adhesionWeight - properties.branchingProbability = self.branchingProbability - properties.leafProbability = self.leafProbability - properties.ivyBranchSize = self.ivyBranchSize - properties.ivyLeafSize = self.ivyLeafSize - properties.updateIvy = True - - prop_def = layout.operator('curve.ivy_gen', text="Add New Default Ivy") - prop_def.updateIvy = True - - layout.prop(self, 'growLeaves') - - box = layout.box() - box.label("Generation Settings:") - box.prop(self, 'randomSeed') - box.prop(self, 'maxTime') - - box = layout.box() - box.label("Size Settings:") - box.prop(self, 'maxIvyLength') - box.prop(self, 'ivySize') - box.prop(self, 'maxFloatLength') - box.prop(self, 'maxAdhesionDistance') - - box = layout.box() - box.label("Weight Settings:") - box.prop(self, 'primaryWeight') - box.prop(self, 'randomWeight') - box.prop(self, 'gravityWeight') - box.prop(self, 'adhesionWeight') - - box = layout.box() - box.label("Branch Settings:") - box.prop(self, 'branchingProbability') - box.prop(self, 'ivyBranchSize') - - if self.growLeaves: - box = layout.box() - box.label("Leaf Settings:") - box.prop(self, 'ivyLeafSize') - box.prop(self, 'leafProbability') - - -def menu_func(self, context): - self.layout.operator(IvyGen.bl_idname, text="Add Ivy to Mesh", - icon='OUTLINER_DATA_CURVE').updateIvy = True - - -def register(): - bpy.utils.register_module(__name__) - bpy.types.INFO_MT_curve_add.append(menu_func) - - -def unregister(): - bpy.types.INFO_MT_curve_add.remove(menu_func) - bpy.utils.unregister_module(__name__) - - -if __name__ == "__main__": - register() diff --git a/tests/test_helpers/addons/singlefile_addon.py b/tests/test_helpers/addons/singlefile_addon.py index 1bb6fde..0ef76df 100644 --- a/tests/test_helpers/addons/singlefile_addon.py +++ b/tests/test_helpers/addons/singlefile_addon.py @@ -46,718 +46,3 @@ bl_info = { "category": "Add Curve" } - - -import bpy -from bpy.props import ( - FloatProperty, - IntProperty, - BoolProperty, - ) -from mathutils import ( - Vector, - Matrix, - ) -from collections import deque -from math import ( - pow, cos, - pi, atan2, - ) -from random import ( - random as rand_val, - seed as rand_seed, - ) -import time - - -def createIvyGeometry(IVY, growLeaves): - """Create the curve geometry for IVY""" - # Compute the local size and the gauss weight filter - # local_ivyBranchSize = IVY.ivyBranchSize # * radius * IVY.ivySize - gaussWeight = (1.0, 2.0, 4.0, 7.0, 9.0, 10.0, 9.0, 7.0, 4.0, 2.0, 1.0) - - # Create a new curve and intialise it - curve = bpy.data.curves.new("IVY", type='CURVE') - curve.dimensions = '3D' - curve.bevel_depth = 1 - curve.fill_mode = 'FULL' - curve.resolution_u = 4 - - if growLeaves: - # Create the ivy leaves - # Order location of the vertices - signList = ((-1.0, +1.0), - (+1.0, +1.0), - (+1.0, -1.0), - (-1.0, -1.0), - ) - - # Get the local size - # local_ivyLeafSize = IVY.ivyLeafSize # * radius * IVY.ivySize - - # Initialise the vertex and face lists - vertList = deque() - - # Store the methods for faster calling - addV = vertList.extend - rotMat = Matrix.Rotation - - # Loop over all roots to generate its nodes - for root in IVY.ivyRoots: - # Only grow if more than one node - numNodes = len(root.ivyNodes) - if numNodes > 1: - # Calculate the local radius - local_ivyBranchRadius = 1.0 / (root.parents + 1) + 1.0 - prevIvyLength = 1.0 / root.ivyNodes[-1].length - splineVerts = [ax for n in root.ivyNodes for ax in n.pos.to_4d()] - - radiusConstant = local_ivyBranchRadius * IVY.ivyBranchSize - splineRadii = [radiusConstant * (1.3 - n.length * prevIvyLength) - for n in root.ivyNodes] - - # Add the poly curve and set coords and radii - newSpline = curve.splines.new(type='POLY') - newSpline.points.add(len(splineVerts) // 4 - 1) - newSpline.points.foreach_set('co', splineVerts) - newSpline.points.foreach_set('radius', splineRadii) - - # Loop over all nodes in the root - for i, n in enumerate(root.ivyNodes): - for k in range(len(gaussWeight)): - idx = max(0, min(i + k - 5, numNodes - 1)) - n.smoothAdhesionVector += (gaussWeight[k] * - root.ivyNodes[idx].adhesionVector) - n.smoothAdhesionVector /= 56.0 - n.adhesionLength = n.smoothAdhesionVector.length - n.smoothAdhesionVector.normalize() - - if growLeaves and (i < numNodes - 1): - node = root.ivyNodes[i] - nodeNext = root.ivyNodes[i + 1] - - # Find the weight and normalize the smooth adhesion vector - weight = pow(node.length * prevIvyLength, 0.7) - - # Calculate the ground ivy and the new weight - groundIvy = max(0.0, -node.smoothAdhesionVector.z) - weight += groundIvy * pow(1 - node.length * - prevIvyLength, 2) - - # Find the alignment weight - alignmentWeight = node.adhesionLength - - # Calculate the needed angles - phi = atan2(node.smoothAdhesionVector.y, - node.smoothAdhesionVector.x) - pi / 2.0 - - theta = (0.5 * - node.smoothAdhesionVector.angle(Vector((0, 0, -1)), 0)) - - # Find the size weight - sizeWeight = 1.5 - (cos(2 * pi * weight) * 0.5 + 0.5) - - # Randomise the angles - phi += (rand_val() - 0.5) * (1.3 - alignmentWeight) - theta += (rand_val() - 0.5) * (1.1 - alignmentWeight) - - # Calculate the leaf size an append the face to the list - leafSize = IVY.ivyLeafSize * sizeWeight - - for j in range(10): - # Generate the probability - probability = rand_val() - - # If we need to grow a leaf, do so - if (probability * weight) > IVY.leafProbability: - - # Generate the random vector - randomVector = Vector((rand_val() - 0.5, - rand_val() - 0.5, - rand_val() - 0.5, - )) - - # Find the leaf center - center = (node.pos.lerp(nodeNext.pos, j / 10.0) + - IVY.ivyLeafSize * randomVector) - - # For each of the verts, rotate/scale and append - basisVecX = Vector((1, 0, 0)) - basisVecY = Vector((0, 1, 0)) - - horiRot = rotMat(theta, 3, 'X') - vertRot = rotMat(phi, 3, 'Z') - - basisVecX.rotate(horiRot) - basisVecY.rotate(horiRot) - - basisVecX.rotate(vertRot) - basisVecY.rotate(vertRot) - - basisVecX *= leafSize - basisVecY *= leafSize - - addV([k1 * basisVecX + k2 * basisVecY + center for - k1, k2 in signList]) - - # Add the object and link to scene - newCurve = bpy.data.objects.new("IVY_Curve", curve) - bpy.context.scene.objects.link(newCurve) - - if growLeaves: - faceList = [[4 * i + l for l in range(4)] for i in - range(len(vertList) // 4)] - - # Generate the new leaf mesh and link - me = bpy.data.meshes.new('IvyLeaf') - me.from_pydata(vertList, [], faceList) - me.update(calc_edges=True) - ob = bpy.data.objects.new('IvyLeaf', me) - bpy.context.scene.objects.link(ob) - - me.uv_textures.new("Leaves") - - # Set the uv texture coords - # TODO, this is non-functional, default uvs are ok? - ''' - for d in tex.data: - uv1, uv2, uv3, uv4 = signList - ''' - - ob.parent = newCurve - - -''' -def computeBoundingSphere(ob): - # Get the mesh data - me = ob.data - # Intialise the center - center = Vector((0.0, 0.0, 0.0)) - # Add all vertex coords - for v in me.vertices: - center += v.co - # Average over all verts - center /= len(me.vertices) - # Create the iterator and find its max - length_iter = ((center - v.co).length for v in me.vertices) - radius = max(length_iter) - return radius -''' - - -class IvyNode: - """ The basic class used for each point on the ivy which is grown.""" - __slots__ = ('pos', 'primaryDir', 'adhesionVector', 'adhesionLength', - 'smoothAdhesionVector', 'length', 'floatingLength', 'climb') - - def __init__(self): - self.pos = Vector((0, 0, 0)) - self.primaryDir = Vector((0, 0, 1)) - self.adhesionVector = Vector((0, 0, 0)) - self.smoothAdhesionVector = Vector((0, 0, 0)) - self.length = 0.0001 - self.floatingLength = 0.0 - self.climb = True - - -class IvyRoot: - """ The class used to hold all ivy nodes growing from this root point.""" - __slots__ = ('ivyNodes', 'alive', 'parents') - - def __init__(self): - self.ivyNodes = deque() - self.alive = True - self.parents = 0 - - -class Ivy: - """ The class holding all parameters and ivy roots.""" - __slots__ = ('ivyRoots', 'primaryWeight', 'randomWeight', - 'gravityWeight', 'adhesionWeight', 'branchingProbability', - 'leafProbability', 'ivySize', 'ivyLeafSize', 'ivyBranchSize', - 'maxFloatLength', 'maxAdhesionDistance', 'maxLength') - - def __init__(self, - primaryWeight=0.5, - randomWeight=0.2, - gravityWeight=1.0, - adhesionWeight=0.1, - branchingProbability=0.05, - leafProbability=0.35, - ivySize=0.02, - ivyLeafSize=0.02, - ivyBranchSize=0.001, - maxFloatLength=0.5, - maxAdhesionDistance=1.0): - - self.ivyRoots = deque() - self.primaryWeight = primaryWeight - self.randomWeight = randomWeight - self.gravityWeight = gravityWeight - self.adhesionWeight = adhesionWeight - self.branchingProbability = 1 - branchingProbability - self.leafProbability = 1 - leafProbability - self.ivySize = ivySize - self.ivyLeafSize = ivyLeafSize - self.ivyBranchSize = ivyBranchSize - self.maxFloatLength = maxFloatLength - self.maxAdhesionDistance = maxAdhesionDistance - self.maxLength = 0.0 - - # Normalize all the weights only on intialisation - sums = self.primaryWeight + self.randomWeight + self.adhesionWeight - self.primaryWeight /= sums - self.randomWeight /= sums - self.adhesionWeight /= sums - - def seed(self, seedPos): - # Seed the Ivy by making a new root and first node - tmpRoot = IvyRoot() - tmpIvy = IvyNode() - tmpIvy.pos = seedPos - - tmpRoot.ivyNodes.append(tmpIvy) - self.ivyRoots.append(tmpRoot) - - def grow(self, ob): - # Determine the local sizes - # local_ivySize = self.ivySize # * radius - # local_maxFloatLength = self.maxFloatLength # * radius - # local_maxAdhesionDistance = self.maxAdhesionDistance # * radius - - for root in self.ivyRoots: - # Make sure the root is alive, if not, skip - if not root.alive: - continue - - # Get the last node in the current root - prevIvy = root.ivyNodes[-1] - - # If the node is floating for too long, kill the root - if prevIvy.floatingLength > self.maxFloatLength: - root.alive = False - - # Set the primary direction from the last node - primaryVector = prevIvy.primaryDir - - # Make the random vector and normalize - randomVector = Vector((rand_val() - 0.5, rand_val() - 0.5, - rand_val() - 0.5)) + Vector((0, 0, 0.2)) - randomVector.normalize() - - # Calculate the adhesion vector - adhesionVector = adhesion(prevIvy.pos, ob, - self.maxAdhesionDistance) - - # Calculate the growing vector - growVector = self.ivySize * (primaryVector * self.primaryWeight + - randomVector * self.randomWeight + - adhesionVector * self.adhesionWeight) - - # Find the gravity vector - gravityVector = (self.ivySize * self.gravityWeight * - Vector((0, 0, -1))) - gravityVector *= pow(prevIvy.floatingLength / self.maxFloatLength, - 0.7) - - # Determine the new position vector - newPos = prevIvy.pos + growVector + gravityVector - - # Check for collisions with the object - climbing = collision(ob, prevIvy.pos, newPos) - - # Update the growing vector for any collisions - growVector = newPos - prevIvy.pos - gravityVector - growVector.normalize() - - # Create a new IvyNode and set its properties - tmpNode = IvyNode() - tmpNode.climb = climbing - tmpNode.pos = newPos - tmpNode.primaryDir = prevIvy.primaryDir.lerp(growVector, 0.5) - tmpNode.primaryDir.normalize() - tmpNode.adhesionVector = adhesionVector - tmpNode.length = prevIvy.length + (newPos - prevIvy.pos).length - - if tmpNode.length > self.maxLength: - self.maxLength = tmpNode.length - - # If the node isn't climbing, update it's floating length - # Otherwise set it to 0 - if not climbing: - tmpNode.floatingLength = prevIvy.floatingLength + (newPos - - prevIvy.pos).length - else: - tmpNode.floatingLength = 0.0 - - root.ivyNodes.append(tmpNode) - - # Loop through all roots to check if a new root is generated - for root in self.ivyRoots: - # Check the root is alive and isn't at high level of recursion - if (root.parents > 3) or (not root.alive): - continue - - # Check to make sure there's more than 1 node - if len(root.ivyNodes) > 1: - # Loop through all nodes in root to check if new root is grown - for node in root.ivyNodes: - # Set the last node of the root and find the weighting - prevIvy = root.ivyNodes[-1] - weight = 1.0 - (cos(2.0 * pi * node.length / - prevIvy.length) * 0.5 + 0.5) - - probability = rand_val() - - # Check if a new root is grown and if so, set its values - if (probability * weight > self.branchingProbability): - tmpNode = IvyNode() - tmpNode.pos = node.pos - tmpNode.floatingLength = node.floatingLength - - tmpRoot = IvyRoot() - tmpRoot.parents = root.parents + 1 - - tmpRoot.ivyNodes.append(tmpNode) - self.ivyRoots.append(tmpRoot) - return - - -def adhesion(loc, ob, max_l): - # Get transfor vector and transformed loc - tran_mat = ob.matrix_world.inverted() - tran_loc = tran_mat * loc - - # Compute the adhesion vector by finding the nearest point - nearest_result = ob.closest_point_on_mesh(tran_loc, max_l) - adhesion_vector = Vector((0.0, 0.0, 0.0)) - if nearest_result[0]: - # Compute the distance to the nearest point - adhesion_vector = ob.matrix_world * nearest_result[1] - loc - distance = adhesion_vector.length - # If it's less than the maximum allowed and not 0, continue - if distance: - # Compute the direction vector between the closest point and loc - adhesion_vector.normalize() - adhesion_vector *= 1.0 - distance / max_l - # adhesion_vector *= getFaceWeight(ob.data, nearest_result[3]) - return adhesion_vector - - -def collision(ob, pos, new_pos): - # Check for collision with the object - climbing = False - - # Transform vecs - tran_mat = ob.matrix_world.inverted() - tran_pos = tran_mat * pos - tran_new_pos = tran_mat * new_pos - tran_dir = tran_new_pos - tran_pos - - ray_result = ob.ray_cast(tran_pos, tran_dir, tran_dir.length) - # If there's a collision we need to check it - if ray_result[0]: - # Check whether the collision is going into the object - if tran_dir.dot(ray_result[2]) < 0.0: - # Find projection of the piont onto the plane - p0 = tran_new_pos - (tran_new_pos - - ray_result[1]).project(ray_result[2]) - # Reflect in the plane - tran_new_pos += 2 * (p0 - tran_new_pos) - new_pos *= 0 - new_pos += ob.matrix_world * tran_new_pos - climbing = True - return climbing - - -def check_mesh_faces(ob): - me = ob.data - if len(me.polygons) > 0: - return True - - return False - - -class IvyGen(bpy.types.Operator): - bl_idname = "curve.ivy_gen" - bl_label = "IvyGen" - bl_description = "Generate Ivy on an Mesh Object" - bl_options = {'REGISTER', 'UNDO'} - - maxIvyLength = FloatProperty( - name="Max Ivy Length", - description="Maximum ivy length in Blender Units", - default=1.0, - min=0.0, - soft_max=3.0, - subtype='DISTANCE', - unit='LENGTH' - ) - primaryWeight = FloatProperty( - name="Primary Weight", - description="Weighting given to the current direction", - default=0.5, - min=0.0, - soft_max=1.0 - ) - randomWeight = FloatProperty( - name="Random Weight", - description="Weighting given to the random direction", - default=0.2, - min=0.0, - soft_max=1.0 - ) - gravityWeight = FloatProperty( - name="Gravity Weight", - description="Weighting given to the gravity direction", - default=1.0, - min=0.0, - soft_max=1.0 - ) - adhesionWeight = FloatProperty( - name="Adhesion Weight", - description="Weighting given to the adhesion direction", - default=0.1, - min=0.0, - soft_max=1.0 - ) - branchingProbability = FloatProperty( - name="Branching Probability", - description="Probability of a new branch forming", - default=0.05, - min=0.0, - soft_max=1.0 - ) - leafProbability = FloatProperty( - name="Leaf Probability", - description="Probability of a leaf forming", - default=0.35, - min=0.0, - soft_max=1.0 - ) - ivySize = FloatProperty( - name="Ivy Size", - description="The length of an ivy segment in Blender" - " Units", - default=0.02, - min=0.0, - soft_max=1.0, - precision=3 - ) - ivyLeafSize = FloatProperty( - name="Ivy Leaf Size", - description="The size of the ivy leaves", - default=0.02, - min=0.0, - soft_max=0.5, - precision=3 - ) - ivyBranchSize = FloatProperty( - name="Ivy Branch Size", - description="The size of the ivy branches", - default=0.001, - min=0.0, - soft_max=0.1, - precision=4 - ) - maxFloatLength = FloatProperty( - name="Max Float Length", - description="The maximum distance that a branch " - "can live while floating", - default=0.5, - min=0.0, - soft_max=1.0) - maxAdhesionDistance = FloatProperty( - name="Max Adhesion Length", - description="The maximum distance that a branch " - "will feel the effects of adhesion", - default=1.0, - min=0.0, - soft_max=2.0, - precision=2 - ) - randomSeed = IntProperty( - name="Random Seed", - description="The seed governing random generation", - default=0, - min=0 - ) - maxTime = FloatProperty( - name="Maximum Time", - description="The maximum time to run the generation for " - "in seconds generation (0.0 = Disabled)", - default=0.0, - min=0.0, - soft_max=10 - ) - growLeaves = BoolProperty( - name="Grow Leaves", - description="Grow leaves or not", - default=True - ) - updateIvy = BoolProperty( - name="Update Ivy", - default=False - ) - - @classmethod - def poll(self, context): - # Check if there's an object and whether it's a mesh - ob = context.active_object - return ((ob is not None) and - (ob.type == 'MESH') and - (context.mode == 'OBJECT')) - - def invoke(self, context, event): - self.updateIvy = True - return self.execute(context) - - def execute(self, context): - if not self.updateIvy: - return {'PASS_THROUGH'} - - bpy.ops.object.mode_set(mode='EDIT', toggle=False) - bpy.ops.object.mode_set(mode='OBJECT', toggle=False) - - # Get the selected object - ob = context.active_object - - # Check if the mesh has at least one polygon since some functions - # are expecting them in the object's data (see T51753) - check_face = check_mesh_faces(ob) - if check_face is False: - self.report({'WARNING'}, - "Mesh Object doesn't have at least one Face. " - "Operation Cancelled") - return {"CANCELLED"} - - # Compute bounding sphere radius - # radius = computeBoundingSphere(ob) # Not needed anymore - - # Get the seeding point - seedPoint = context.scene.cursor_location - - # Fix the random seed - rand_seed(self.randomSeed) - - # Make the new ivy - IVY = Ivy(**self.as_keywords(ignore=('randomSeed', 'growLeaves', - 'maxIvyLength', 'maxTime', 'updateIvy'))) - - # Generate first root and node - IVY.seed(seedPoint) - - checkTime = False - maxLength = self.maxIvyLength # * radius - - # If we need to check time set the flag - if self.maxTime != 0.0: - checkTime = True - - t = time.time() - startPercent = 0.0 - checkAliveIter = [True, ] - - # Grow until 200 roots is reached or backup counter exceeds limit - while (any(checkAliveIter) and - (IVY.maxLength < maxLength) and - (not checkTime or (time.time() - t < self.maxTime))): - # Grow the ivy for this iteration - IVY.grow(ob) - - # Print the proportion of ivy growth to console - if (IVY.maxLength / maxLength * 100) > 10 * startPercent // 10: - print('%0.2f%% of Ivy nodes have grown' % - (IVY.maxLength / maxLength * 100)) - startPercent += 10 - if IVY.maxLength / maxLength > 1: - print("Halting Growth") - - # Make an iterator to check if all are alive - checkAliveIter = (r.alive for r in IVY.ivyRoots) - - # Create the curve and leaf geometry - createIvyGeometry(IVY, self.growLeaves) - print("Geometry Generation Complete") - - print("Ivy generated in %0.2f s" % (time.time() - t)) - - self.updateIvy = False - - return {'FINISHED'} - - def draw(self, context): - layout = self.layout - - layout.prop(self, 'updateIvy', icon='CURVE_DATA') - - properties = layout.operator('curve.ivy_gen', text="Add New Ivy") - properties.randomSeed = self.randomSeed - properties.maxTime = self.maxTime - properties.maxIvyLength = self.maxIvyLength - properties.ivySize = self.ivySize - properties.maxFloatLength = self.maxFloatLength - properties.maxAdhesionDistance = self.maxAdhesionDistance - properties.primaryWeight = self.primaryWeight - properties.randomWeight = self.randomWeight - properties.gravityWeight = self.gravityWeight - properties.adhesionWeight = self.adhesionWeight - properties.branchingProbability = self.branchingProbability - properties.leafProbability = self.leafProbability - properties.ivyBranchSize = self.ivyBranchSize - properties.ivyLeafSize = self.ivyLeafSize - properties.updateIvy = True - - prop_def = layout.operator('curve.ivy_gen', text="Add New Default Ivy") - prop_def.updateIvy = True - - layout.prop(self, 'growLeaves') - - box = layout.box() - box.label("Generation Settings:") - box.prop(self, 'randomSeed') - box.prop(self, 'maxTime') - - box = layout.box() - box.label("Size Settings:") - box.prop(self, 'maxIvyLength') - box.prop(self, 'ivySize') - box.prop(self, 'maxFloatLength') - box.prop(self, 'maxAdhesionDistance') - - box = layout.box() - box.label("Weight Settings:") - box.prop(self, 'primaryWeight') - box.prop(self, 'randomWeight') - box.prop(self, 'gravityWeight') - box.prop(self, 'adhesionWeight') - - box = layout.box() - box.label("Branch Settings:") - box.prop(self, 'branchingProbability') - box.prop(self, 'ivyBranchSize') - - if self.growLeaves: - box = layout.box() - box.label("Leaf Settings:") - box.prop(self, 'ivyLeafSize') - box.prop(self, 'leafProbability') - - -def menu_func(self, context): - self.layout.operator(IvyGen.bl_idname, text="Add Ivy to Mesh", - icon='OUTLINER_DATA_CURVE').updateIvy = True - - -def register(): - bpy.utils.register_module(__name__) - bpy.types.INFO_MT_curve_add.append(menu_func) - - -def unregister(): - bpy.types.INFO_MT_curve_add.remove(menu_func) - bpy.utils.unregister_module(__name__) - - -if __name__ == "__main__": - register()