diff --git a/tests/test_blenderpack.py b/tests/test_blenderpack.py index fd11cac..0d3528f 100644 --- a/tests/test_blenderpack.py +++ b/tests/test_blenderpack.py @@ -7,38 +7,56 @@ import blenderpack class test_blenderpack_make_repo(unittest.TestCase): helper_path = os.path.join('tests', 'test_helpers') - - def test_extract_blinfo_from_file(self): - with open(os.path.join(self.helper_path, 'ivy_gen_blinfo.txt'), 'r') as f: - expectation = f.read() - - reality = str(blenderpack.extract_blinfo(os.path.join(self.helper_path, 'addons', 'add_curve_ivygen.py'))) - self.assertEqual(expectation, reality) - - def test_extract_blinfo_from_zip(self): - with open(os.path.join(self.helper_path, 'extra_objects_blinfo.txt'), 'r') as f: - expectation = f.read() - - reality = str(blenderpack.extract_blinfo(os.path.join(self.helper_path, 'addons', 'add_curve_extra_objects.zip'))) - self.assertEqual(expectation, reality) - - def test_extract_blinfo_from_dir(self): - with open(os.path.join(self.helper_path, 'extra_objects_blinfo.txt'), 'r') as f: - expectation = f.read() - - reality = str(blenderpack.extract_blinfo(os.path.join(self.helper_path, 'addons', 'add_curve_extra_objects/'))) - self.assertEqual(expectation, reality) + addon_path = os.path.join(helper_path, 'addons') def test_extract_blinfo_from_nonexistent(self): + test_file = 'file_that_doesnt_exist' self.assertRaises( FileNotFoundError, - lambda: blenderpack.extract_blinfo(os.path.join(self.helper_path, 'addons', 'notathing')) + blenderpack.extract_blinfo, + os.path.join(self.addon_path, test_file) ) + def test_extract_blinfo_from_nonaddon(self): + test_file = 'not_an_addon.py' + self.assertRaises( + blenderpack.BadAddon, + blenderpack.extract_blinfo, + os.path.join(self.addon_path, test_file) + ) def test_make_repo_valid(self): blenderpack.make_repo(os.path.join(self.helper_path, 'addons')) + repojson = os.path.join(self.helper_path, 'addons', 'repo.json') + self.assertTrue(os.path.exists(repojson)) + with open(repojson, 'r') as f: + json.loads(f.read()) + + os.remove(repojson) + self.fail('unfinished test') def test_make_repo_from_nonexistent(self): blenderpack.make_repo(os.path.join(self.helper_path, 'addons')) + self.fail('unfinished test') + + +# testname: filename +bl_info_tests = { + 'test_extract_blinfo_from_file': 'real_addon.py', + 'test_extract_blinfo_from_zip': 'zipped_addon.zip', + 'test_extract_blinfo_from_dir': 'dir_addon', +} + +def generate_test(test_file): + def test(self): + reality = str(blenderpack.extract_blinfo(os.path.join(self.addon_path, test_file))) + with open(os.path.join(self.helper_path, test_file + '_output'), 'r') as f: + expectation = f.read() + self.assertEqual(expectation, reality) + return test + +for name, param in bl_info_tests.items(): + test_func = generate_test(param) + setattr(test_blenderpack_make_repo, 'test_{}'.format(name), test_func) + diff --git a/tests/test_helpers/addons/add_curve_extra_objects.zip b/tests/test_helpers/addons/add_curve_extra_objects.zip deleted file mode 100644 index c08089b..0000000 Binary files a/tests/test_helpers/addons/add_curve_extra_objects.zip and /dev/null differ diff --git a/tests/test_helpers/addons/add_curve_extra_objects/add_curve_aceous_galore.py b/tests/test_helpers/addons/add_curve_extra_objects/add_curve_aceous_galore.py deleted file mode 100644 index 59e1cae..0000000 --- a/tests/test_helpers/addons/add_curve_extra_objects/add_curve_aceous_galore.py +++ /dev/null @@ -1,1462 +0,0 @@ -# ##### 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_info = { - "name": "Curveaceous Galore!", - "author": "Jimmy Hazevoet, testscreenings", - "version": (0, 2, 1), - "blender": (2, 59), - "location": "View3D > Add > Curve", - "description": "Adds many different types of Curves", - "warning": "", - "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/" - "Scripts/Curve/Curves_Galore", - "category": "Add Curve", -} -""" - -import bpy -from bpy.props import ( - BoolProperty, - EnumProperty, - FloatProperty, - IntProperty, - ) -from mathutils import Matrix -from bpy.types import Operator -from math import ( - sin, cos, pi - ) -import mathutils.noise as Noise - - -# ------------------------------------------------------------ -# Some functions to use with others: -# ------------------------------------------------------------ - -# ------------------------------------------------------------ -# Generate random number: -def randnum(low=0.0, high=1.0, seed=0): - """ - randnum( low=0.0, high=1.0, seed=0 ) - - Create random number - Parameters: - low - lower range - (type=float) - high - higher range - (type=float) - seed - the random seed number, if seed is 0, the current time will be used instead - (type=int) - Returns: - a random number - (type=float) - """ - - Noise.seed_set(seed) - rnum = Noise.random() - rnum = rnum * (high - low) - rnum = rnum + low - return rnum - - -# ------------------------------------------------------------ -# Make some noise: -def vTurbNoise(x, y, z, iScale=0.25, Size=1.0, Depth=6, Hard=0, Basis=0, Seed=0): - """ - vTurbNoise((x,y,z), iScale=0.25, Size=1.0, Depth=6, Hard=0, Basis=0, Seed=0 ) - - Create randomised vTurbulence noise - - Parameters: - xyz - (x,y,z) float values. - (type=3-float tuple) - iScale - noise intensity scale - (type=float) - Size - noise size - (type=float) - Depth - number of noise values added. - (type=int) - Hard - noise hardness: 0 - soft noise; 1 - hard noise - (type=int) - basis - type of noise used for turbulence - (type=int) - Seed - the random seed number, if seed is 0, the current time will be used instead - (type=int) - Returns: - the generated turbulence vector. - (type=3-float list) - """ - rand = randnum(-100, 100, Seed) - if Basis is 9: - Basis = 14 - vTurb = Noise.turbulence_vector((x / Size + rand, y / Size + rand, z / Size + rand), - Depth, Hard, Basis) - tx = vTurb[0] * iScale - ty = vTurb[1] * iScale - tz = vTurb[2] * iScale - return tx, ty, tz - - -# ------------------------------------------------------------------- -# 2D Curve shape functions: -# ------------------------------------------------------------------- - -# ------------------------------------------------------------ -# 2DCurve: Profile: L, H, T, U, Z -def ProfileCurve(type=0, a=0.25, b=0.25): - """ - ProfileCurve( type=0, a=0.25, b=0.25 ) - - Create profile curve - - Parameters: - type - select profile type, L, H, T, U, Z - (type=int) - a - a scaling parameter - (type=float) - b - b scaling parameter - (type=float) - Returns: - a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n] - (type=list) - """ - - newpoints = [] - if type is 1: - # H: - a *= 0.5 - b *= 0.5 - newpoints = [ - [-1.0, 1.0, 0.0], [-1.0 + a, 1.0, 0.0], - [-1.0 + a, b, 0.0], [1.0 - a, b, 0.0], [1.0 - a, 1.0, 0.0], - [1.0, 1.0, 0.0], [1.0, -1.0, 0.0], [1.0 - a, -1.0, 0.0], - [1.0 - a, -b, 0.0], [-1.0 + a, -b, 0.0], [-1.0 + a, -1.0, 0.0], - [-1.0, -1.0, 0.0] - ] - elif type is 2: - # T: - a *= 0.5 - newpoints = [ - [-1.0, 1.0, 0.0], [1.0, 1.0, 0.0], - [1.0, 1.0 - b, 0.0], [a, 1.0 - b, 0.0], [a, -1.0, 0.0], - [-a, -1.0, 0.0], [-a, 1.0 - b, 0.0], [-1.0, 1.0 - b, 0.0] - ] - elif type is 3: - # U: - a *= 0.5 - newpoints = [ - [-1.0, 1.0, 0.0], [-1.0 + a, 1.0, 0.0], - [-1.0 + a, -1.0 + b, 0.0], [1.0 - a, -1.0 + b, 0.0], [1.0 - a, 1.0, 0.0], - [1.0, 1.0, 0.0], [1.0, -1.0, 0.0], [-1.0, -1.0, 0.0] - ] - elif type is 4: - # Z: - a *= 0.5 - newpoints = [ - [-0.5, 1.0, 0.0], [a, 1.0, 0.0], - [a, -1.0 + b, 0.0], [1.0, -1.0 + b, 0.0], [1.0, -1.0, 0.0], - [-a, -1.0, 0.0], [-a, 1.0 - b, 0.0], [-1.0, 1.0 - b, 0.0], - [-1.0, 1.0, 0.0] - ] - else: - # L: - newpoints = [ - [-1.0, 1.0, 0.0], [-1.0 + a, 1.0, 0.0], - [-1.0 + a, -1.0 + b, 0.0], [1.0, -1.0 + b, 0.0], - [1.0, -1.0, 0.0], [-1.0, -1.0, 0.0] - ] - return newpoints - - -# ------------------------------------------------------------ -# 2DCurve: Arrow -def ArrowCurve(type=1, a=1.0, b=0.5): - """ - ArrowCurve( type=1, a=1.0, b=0.5, c=1.0 ) - - Create arrow curve - - Parameters: - type - select type, Arrow1, Arrow2 - (type=int) - a - a scaling parameter - (type=float) - b - b scaling parameter - (type=float) - Returns: - a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n] - (type=list) - """ - - newpoints = [] - if type is 0: - # Arrow1: - a *= 0.5 - b *= 0.5 - newpoints = [ - [-1.0, b, 0.0], [-1.0 + a, b, 0.0], - [-1.0 + a, 1.0, 0.0], [1.0, 0.0, 0.0], - [-1.0 + a, -1.0, 0.0], [-1.0 + a, -b, 0.0], - [-1.0, -b, 0.0] - ] - elif type is 1: - # Arrow2: - newpoints = [[-a, b, 0.0], [a, 0.0, 0.0], [-a, -b, 0.0], [0.0, 0.0, 0.0]] - else: - # diamond: - newpoints = [[0.0, b, 0.0], [a, 0.0, 0.0], [0.0, -b, 0.0], [-a, 0.0, 0.0]] - return newpoints - - -# ------------------------------------------------------------ -# 2DCurve: Square / Rectangle -def RectCurve(type=1, a=1.0, b=0.5, c=1.0): - """ - RectCurve( type=1, a=1.0, b=0.5, c=1.0 ) - - Create square / rectangle curve - - Parameters: - type - select type, Square, Rounded square 1, Rounded square 2 - (type=int) - a - a scaling parameter - (type=float) - b - b scaling parameter - (type=float) - c - c scaling parameter - (type=float) - Returns: - a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n] - (type=list) - """ - - newpoints = [] - if type is 1: - # Rounded Rectangle: - newpoints = [ - [-a, b - b * 0.2, 0.0], [-a + a * 0.05, b - b * 0.05, 0.0], [-a + a * 0.2, b, 0.0], - [a - a * 0.2, b, 0.0], [a - a * 0.05, b - b * 0.05, 0.0], [a, b - b * 0.2, 0.0], - [a, -b + b * 0.2, 0.0], [a - a * 0.05, -b + b * 0.05, 0.0], [a - a * 0.2, -b, 0.0], - [-a + a * 0.2, -b, 0.0], [-a + a * 0.05, -b + b * 0.05, 0.0], [-a, -b + b * 0.2, 0.0] - ] - elif type is 2: - # Rounded Rectangle II: - newpoints = [] - x = a - y = b - r = c - if r > x: - r = x - 0.0001 - if r > y: - r = y - 0.0001 - if r > 0: - newpoints.append([-x + r, y, 0]) - newpoints.append([x - r, y, 0]) - newpoints.append([x, y - r, 0]) - newpoints.append([x, -y + r, 0]) - newpoints.append([x - r, -y, 0]) - newpoints.append([-x + r, -y, 0]) - newpoints.append([-x, -y + r, 0]) - newpoints.append([-x, y - r, 0]) - else: - newpoints.append([-x, y, 0]) - newpoints.append([x, y, 0]) - newpoints.append([x, -y, 0]) - newpoints.append([-x, -y, 0]) - else: - # Rectangle: - newpoints = [[-a, b, 0.0], [a, b, 0.0], [a, -b, 0.0], [-a, -b, 0.0]] - return newpoints - - -# ------------------------------------------------------------ -# 2DCurve: Star: -def StarCurve(starpoints=8, innerradius=0.5, outerradius=1.0, twist=0.0): - """ - StarCurve( starpoints=8, innerradius=0.5, outerradius=1.0, twist=0.0 ) - - Create star shaped curve - - Parameters: - starpoints - the number of points - (type=int) - innerradius - innerradius - (type=float) - outerradius - outerradius - (type=float) - twist - twist amount - (type=float) - Returns: - a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n] - (type=list) - """ - - newpoints = [] - step = 2.0 / starpoints - i = 0 - while i < starpoints: - t = i * step - x1 = cos(t * pi) * outerradius - y1 = sin(t * pi) * outerradius - newpoints.append([x1, y1, 0]) - x2 = cos(t * pi + (pi / starpoints + twist)) * innerradius - y2 = sin(t * pi + (pi / starpoints + twist)) * innerradius - newpoints.append([x2, y2, 0]) - i += 1 - return newpoints - - -# ------------------------------------------------------------ -# 2DCurve: Flower: -def FlowerCurve(petals=8, innerradius=0.5, outerradius=1.0, petalwidth=2.0): - """ - FlowerCurve( petals=8, innerradius=0.5, outerradius=1.0, petalwidth=2.0 ) - - Create flower shaped curve - - Parameters: - petals - the number of petals - (type=int) - innerradius - innerradius - (type=float) - outerradius - outerradius - (type=float) - petalwidth - width of petals - (type=float) - Returns: - a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n] - (type=list) - """ - - newpoints = [] - step = 2.0 / petals - pet = (step / pi * 2) * petalwidth - i = 0 - while i < petals: - t = i * step - x1 = cos(t * pi - (pi / petals)) * innerradius - y1 = sin(t * pi - (pi / petals)) * innerradius - newpoints.append([x1, y1, 0]) - x2 = cos(t * pi - pet) * outerradius - y2 = sin(t * pi - pet) * outerradius - newpoints.append([x2, y2, 0]) - x3 = cos(t * pi + pet) * outerradius - y3 = sin(t * pi + pet) * outerradius - newpoints.append([x3, y3, 0]) - i += 1 - return newpoints - - -# ------------------------------------------------------------ -# 2DCurve: Arc,Sector,Segment,Ring: -def ArcCurve(sides=6, startangle=0.0, endangle=90.0, innerradius=0.5, outerradius=1.0, type=3): - """ - ArcCurve( sides=6, startangle=0.0, endangle=90.0, innerradius=0.5, outerradius=1.0, type=3 ) - - Create arc shaped curve - - Parameters: - sides - number of sides - (type=int) - startangle - startangle - (type=float) - endangle - endangle - (type=float) - innerradius - innerradius - (type=float) - outerradius - outerradius - (type=float) - type - select type Arc,Sector,Segment,Ring - (type=int) - Returns: - a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n] - (type=list) - """ - - newpoints = [] - sides += 1 - angle = 2.0 * (1.0 / 360.0) - endangle -= startangle - step = (angle * endangle) / (sides - 1) - i = 0 - while i < sides: - t = (i * step) + angle * startangle - x1 = sin(t * pi) * outerradius - y1 = cos(t * pi) * outerradius - newpoints.append([x1, y1, 0]) - i += 1 - - # if type == 1: - # Arc: turn cyclic curve flag off! - - # Segment: - if type is 2: - newpoints.append([0, 0, 0]) - # Ring: - elif type is 3: - j = sides - 1 - while j > -1: - t = (j * step) + angle * startangle - x2 = sin(t * pi) * innerradius - y2 = cos(t * pi) * innerradius - newpoints.append([x2, y2, 0]) - j -= 1 - return newpoints - - -# ------------------------------------------------------------ -# 2DCurve: Cog wheel: -def CogCurve(theeth=8, innerradius=0.8, middleradius=0.95, outerradius=1.0, bevel=0.5): - """ - CogCurve( theeth=8, innerradius=0.8, middleradius=0.95, outerradius=1.0, bevel=0.5 ) - - Create cog wheel shaped curve - - Parameters: - theeth - number of theeth - (type=int) - innerradius - innerradius - (type=float) - middleradius - middleradius - (type=float) - outerradius - outerradius - (type=float) - bevel - bevel amount - (type=float) - Returns: - a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n] - (type=list) - """ - - newpoints = [] - step = 2.0 / theeth - pet = step / pi * 2 - bevel = 1.0 - bevel - i = 0 - while i < theeth: - t = i * step - x1 = cos(t * pi - (pi / theeth) - pet) * innerradius - y1 = sin(t * pi - (pi / theeth) - pet) * innerradius - newpoints.append([x1, y1, 0]) - x2 = cos(t * pi - (pi / theeth) + pet) * innerradius - y2 = sin(t * pi - (pi / theeth) + pet) * innerradius - newpoints.append([x2, y2, 0]) - x3 = cos(t * pi - pet) * middleradius - y3 = sin(t * pi - pet) * middleradius - newpoints.append([x3, y3, 0]) - x4 = cos(t * pi - (pet * bevel)) * outerradius - y4 = sin(t * pi - (pet * bevel)) * outerradius - newpoints.append([x4, y4, 0]) - x5 = cos(t * pi + (pet * bevel)) * outerradius - y5 = sin(t * pi + (pet * bevel)) * outerradius - newpoints.append([x5, y5, 0]) - x6 = cos(t * pi + pet) * middleradius - y6 = sin(t * pi + pet) * middleradius - newpoints.append([x6, y6, 0]) - i += 1 - return newpoints - - -# ------------------------------------------------------------ -# 2DCurve: nSide: -def nSideCurve(sides=6, radius=1.0): - """ - nSideCurve( sides=6, radius=1.0 ) - - Create n-sided curve - - Parameters: - sides - number of sides - (type=int) - radius - radius - (type=float) - Returns: - a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n] - (type=list) - """ - - newpoints = [] - step = 2.0 / sides - i = 0 - while i < sides: - t = i * step - x = sin(t * pi) * radius - y = cos(t * pi) * radius - newpoints.append([x, y, 0]) - i += 1 - return newpoints - - -# ------------------------------------------------------------ -# 2DCurve: Splat: -def SplatCurve(sides=24, scale=1.0, seed=0, basis=0, radius=1.0): - """ - SplatCurve( sides=24, scale=1.0, seed=0, basis=0, radius=1.0 ) - - Create splat curve - - Parameters: - sides - number of sides - (type=int) - scale - noise size - (type=float) - seed - noise random seed - (type=int) - basis - noise basis - (type=int) - radius - radius - (type=float) - Returns: - a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n] - (type=list) - """ - - newpoints = [] - step = 2.0 / sides - i = 0 - while i < sides: - t = i * step - turb = vTurbNoise(t, t, t, 1.0, scale, 6, 0, basis, seed) - turb = turb[2] * 0.5 + 0.5 - x = sin(t * pi) * radius * turb - y = cos(t * pi) * radius * turb - newpoints.append([x, y, 0]) - i += 1 - return newpoints - - -# ----------------------------------------------------------- -# Cycloid curve -def CycloidCurve(number=100, type=0, R=4.0, r=1.0, d=1.0): - """ - CycloidCurve( number=100, type=0, a=4.0, b=1.0 ) - - Create a Cycloid, Hypotrochoid / Hypocycloid or Epitrochoid / Epycycloid type of curve - - Parameters: - number - the number of points - (type=int) - type - types: Cycloid, Hypocycloid, Epicycloid - (type=int) - R = Radius a scaling parameter - (type=float) - r = Radius b scaling parameter - (type=float) - d = Distance scaling parameter - (type=float) - Returns: - a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n] - (type=list) - """ - - a = R - b = r - newpoints = [] - step = 2.0 / (number - 1) - i = 0 - if type is 1: - # Hypotrochoid / Hypocycloid - while i < number: - t = i * step - x = ((a - b) * cos(t * pi)) + (d * cos(((a + b) / b) * t * pi)) - y = ((a - b) * sin(t * pi)) - (d * sin(((a + b) / b) * t * pi)) - z = 0 - newpoints.append([x, y, z]) - i += 1 - elif type is 2: - # Epitrochoid / Epycycloid - while i < number: - t = i * step - x = ((a + b) * cos(t * pi)) - (d * cos(((a + b) / b) * t * pi)) - y = ((a + b) * sin(t * pi)) - (d * sin(((a + b) / b) * t * pi)) - z = 0 - newpoints.append([x, y, z]) - i += 1 - else: - # Cycloid - while i < number: - t = (i * step * pi) - x = (t - sin(t) * b) * a / pi - y = (1 - cos(t) * b) * a / pi - z = 0 - newpoints.append([x, y, z]) - i += 1 - return newpoints - - -# ----------------------------------------------------------- -# 3D curve shape functions: -# ----------------------------------------------------------- - -# ------------------------------------------------------------ -# 3DCurve: Helix: -def HelixCurve(number=100, height=2.0, startangle=0.0, endangle=360.0, width=1.0, a=0.0, b=0.0): - """ - HelixCurve( number=100, height=2.0, startangle=0.0, endangle=360.0, width=1.0, a=0.0, b=0.0 ) - - Create helix curve - - Parameters: - number - the number of points - (type=int) - height - height - (type=float) - startangle - startangle - (type=float) - endangle - endangle - (type=float) - width - width - (type=float) - a - a - (type=float) - b - b - (type=float) - Returns: - a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n] - (type=list) - """ - - newpoints = [] - angle = (2.0 / 360.0) * (endangle - startangle) - step = angle / (number - 1) - h = height / angle - start = startangle * 2.0 / 360.0 - a /= angle - i = 0 - while i < number: - t = (i * step + start) - x = sin((t * pi)) * (1.0 + cos(t * pi * a - (b * pi))) * (0.25 * width) - y = cos((t * pi)) * (1.0 + cos(t * pi * a - (b * pi))) * (0.25 * width) - z = (t * h) - h * start - newpoints.append([x, y, z]) - i += 1 - return newpoints - - -# ----------------------------------------------------------- -# 3D Noise curve -def NoiseCurve(type=0, number=100, length=2.0, size=0.5, - scale=[0.5, 0.5, 0.5], octaves=2, basis=0, seed=0): - """ - Create noise curve - - Parameters: - number - number of points - (type=int) - length - curve length - (type=float) - size - noise size - (type=float) - scale - noise intensity scale x,y,z - (type=list) - basis - noise basis - (type=int) - seed - noise random seed - (type=int) - type - noise curve type - (type=int) - Returns: - a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n] - (type=list) - """ - - newpoints = [] - step = (length / number) - i = 0 - if type is 1: - # noise circle - while i < number: - t = i * step - v = vTurbNoise(t, t, t, 1.0, size, octaves, 0, basis, seed) - x = sin(t * pi) + (v[0] * scale[0]) - y = cos(t * pi) + (v[1] * scale[1]) - z = v[2] * scale[2] - newpoints.append([x, y, z]) - i += 1 - elif type is 2: - # noise knot / ball - while i < number: - t = i * step - v = vTurbNoise(t, t, t, 1.0, 1.0, octaves, 0, basis, seed) - x = v[0] * scale[0] * size - y = v[1] * scale[1] * size - z = v[2] * scale[2] * size - newpoints.append([x, y, z]) - i += 1 - else: - # noise linear - while i < number: - t = i * step - v = vTurbNoise(t, t, t, 1.0, size, octaves, 0, basis, seed) - x = t + v[0] * scale[0] - y = v[1] * scale[1] - z = v[2] * scale[2] - newpoints.append([x, y, z]) - i += 1 - return newpoints - - -# ------------------------------------------------------------ -# calculates the matrix for the new object -# depending on user pref -def align_matrix(context): - - loc = Matrix.Translation(context.scene.cursor_location) - obj_align = context.user_preferences.edit.object_align - - if (context.space_data.type == 'VIEW_3D' and - obj_align == 'VIEW'): - rot = context.space_data.region_3d.view_matrix.to_3x3().inverted().to_4x4() - else: - rot = Matrix() - - align_matrix = loc * rot - return align_matrix - - -# ------------------------------------------------------------ -# Curve creation functions, sets bezierhandles to auto -def setBezierHandles(obj, mode='AUTOMATIC'): - scene = bpy.context.scene - - if obj.type != 'CURVE': - return - - scene.objects.active = obj - bpy.ops.object.mode_set(mode='EDIT', toggle=True) - bpy.ops.curve.select_all(action='SELECT') - bpy.ops.curve.handle_type_set(type=mode) - bpy.ops.object.mode_set(mode='OBJECT', toggle=True) - - -# get array of vertcoordinates acording to splinetype -def vertsToPoints(Verts, splineType): - - # main vars - vertArray = [] - - # array for BEZIER spline output (V3) - if splineType == 'BEZIER': - for v in Verts: - vertArray += v - - # array for nonBEZIER output (V4) - else: - for v in Verts: - vertArray += v - if splineType == 'NURBS': - # for nurbs w=1 - vertArray.append(1) - else: - # for poly w=0 - vertArray.append(0) - return vertArray - - -# create new CurveObject from vertarray and splineType -def createCurve(context, vertArray, self, align_matrix): - scene = context.scene - - # output splineType 'POLY' 'NURBS' 'BEZIER' - splineType = self.outputType - - # GalloreType as name - name = self.ProfileType - - # create curve - newCurve = bpy.data.curves.new(name, type='CURVE') - newSpline = newCurve.splines.new(type=splineType) - - # create spline from vertarray - if splineType == 'BEZIER': - newSpline.bezier_points.add(int(len(vertArray) * 0.33)) - newSpline.bezier_points.foreach_set('co', vertArray) - else: - newSpline.points.add(int(len(vertArray) * 0.25 - 1)) - newSpline.points.foreach_set('co', vertArray) - newSpline.use_endpoint_u = True - - # set curveOptions - newCurve.dimensions = self.shape - newSpline.use_cyclic_u = self.use_cyclic_u - newSpline.use_endpoint_u = self.endp_u - newSpline.order_u = self.order_u - - # create object with newCurve - new_obj = bpy.data.objects.new(name, newCurve) - scene.objects.link(new_obj) - new_obj.select = True - scene.objects.active = new_obj - new_obj.matrix_world = align_matrix - - # set bezierhandles - if splineType == 'BEZIER': - setBezierHandles(new_obj, self.handleType) - - return - - -# ------------------------------------------------------------ -# Main Function -def main(context, self, align_matrix): - # deselect all objects - bpy.ops.object.select_all(action='DESELECT') - - # options - proType = self.ProfileType - splineType = self.outputType - innerRadius = self.innerRadius - middleRadius = self.middleRadius - outerRadius = self.outerRadius - - # get verts - if proType == 'Profile': - verts = ProfileCurve( - self.ProfileCurveType, - self.ProfileCurvevar1, - self.ProfileCurvevar2 - ) - if proType == 'Arrow': - verts = ArrowCurve( - self.MiscCurveType, - self.MiscCurvevar1, - self.MiscCurvevar2 - ) - if proType == 'Rectangle': - verts = RectCurve( - self.MiscCurveType, - self.MiscCurvevar1, - self.MiscCurvevar2, - self.MiscCurvevar3 - ) - if proType == 'Flower': - verts = FlowerCurve( - self.petals, - innerRadius, - outerRadius, - self.petalWidth - ) - if proType == 'Star': - verts = StarCurve( - self.starPoints, - innerRadius, - outerRadius, - self.starTwist - ) - if proType == 'Arc': - verts = ArcCurve( - self.arcSides, - self.startAngle, - self.endAngle, - innerRadius, - outerRadius, - self.arcType - ) - if proType == 'Cogwheel': - verts = CogCurve( - self.teeth, - innerRadius, - middleRadius, - outerRadius, - self.bevel - ) - if proType == 'Nsided': - verts = nSideCurve( - self.Nsides, - outerRadius - ) - if proType == 'Splat': - verts = SplatCurve( - self.splatSides, - self.splatScale, - self.seed, - self.basis, - outerRadius - ) - if proType == 'Cycloid': - verts = CycloidCurve( - self.cycloPoints, - self.cycloType, - self.cyclo_a, - self.cyclo_b, - self.cyclo_d - ) - if proType == 'Helix': - verts = HelixCurve( - self.helixPoints, - self.helixHeight, - self.helixStart, - self.helixEnd, - self.helixWidth, - self.helix_a, - self.helix_b - ) - if proType == 'Noise': - verts = NoiseCurve( - self.noiseType, - self.noisePoints, - self.noiseLength, - self.noiseSize, - [self.noiseScaleX, self.noiseScaleY, self.noiseScaleZ], - self.noiseOctaves, - self.noiseBasis, - self.noiseSeed - ) - - # turn verts into array - vertArray = vertsToPoints(verts, splineType) - - # create object - createCurve(context, vertArray, self, align_matrix) - - return - - -class Curveaceous_galore(Operator): - bl_idname = "mesh.curveaceous_galore" - bl_label = "Curve Profiles" - bl_description = "Construct many types of curves" - bl_options = {'REGISTER', 'UNDO', 'PRESET'} - - # align_matrix for the invoke - align_matrix = None - - # general properties - ProfileType = EnumProperty( - name="Type", - description="Form of Curve to create", - items=[ - ('Arc', "Arc", "Arc"), - ('Arrow', "Arrow", "Arrow"), - ('Cogwheel', "Cogwheel", "Cogwheel"), - ('Cycloid', "Cycloid", "Cycloid"), - ('Flower', "Flower", "Flower"), - ('Helix', "Helix (3D)", "Helix"), - ('Noise', "Noise (3D)", "Noise"), - ('Nsided', "Nsided", "Nsided"), - ('Profile', "Profile", "Profile"), - ('Rectangle', "Rectangle", "Rectangle"), - ('Splat', "Splat", "Splat"), - ('Star', "Star", "Star")] - ) - outputType = EnumProperty( - name="Output splines", - description="Type of splines to output", - items=[ - ('POLY', "Poly", "Poly Spline type"), - ('NURBS', "Nurbs", "Nurbs Spline type"), - ('BEZIER', "Bezier", "Bezier Spline type")] - ) - # Curve Options - shape = EnumProperty( - name="2D / 3D", - description="2D or 3D Curve", - items=[ - ('2D', "2D", "2D"), - ('3D', "3D", "3D") - ] - ) - use_cyclic_u = BoolProperty( - name="Cyclic", - default=True, - description="make curve closed" - ) - endp_u = BoolProperty( - name="Use endpoint u", - default=True, - description="stretch to endpoints" - ) - order_u = IntProperty( - name="Order u", - default=4, - min=2, soft_min=2, - max=6, soft_max=6, - description="Order of nurbs spline" - ) - handleType = EnumProperty( - name="Handle type", - default='AUTOMATIC', - description="Bezier handles type", - items=[ - ('VECTOR', "Vector", "Vector type Bezier handles"), - ('AUTOMATIC', "Auto", "Automatic type Bezier handles")] - ) - # ProfileCurve properties - ProfileCurveType = IntProperty( - name="Type", - min=1, - max=5, - default=1, - description="Type of Curve's Profile" - ) - ProfileCurvevar1 = FloatProperty( - name="Variable 1", - default=0.25, - description="Variable 1 of Curve's Profile" - ) - ProfileCurvevar2 = FloatProperty( - name="Variable 2", - default=0.25, - description="Variable 2 of Curve's Profile" - ) - # Arrow, Rectangle, MiscCurve properties - MiscCurveType = IntProperty( - name="Type", - min=0, - max=3, - default=0, - description="Type of Curve" - ) - MiscCurvevar1 = FloatProperty( - name="Variable 1", - default=1.0, - description="Variable 1 of Curve" - ) - MiscCurvevar2 = FloatProperty( - name="Variable 2", - default=0.5, - description="Variable 2 of Curve" - ) - MiscCurvevar3 = FloatProperty( - name="Variable 3", - default=0.1, - min=0, - description="Variable 3 of Curve" - ) - # Common properties - innerRadius = FloatProperty( - name="Inner radius", - default=0.5, - min=0, - description="Inner radius" - ) - middleRadius = FloatProperty( - name="Middle radius", - default=0.95, - min=0, - description="Middle radius" - ) - outerRadius = FloatProperty( - name="Outer radius", - default=1.0, - min=0, - description="Outer radius" - ) - # Flower properties - petals = IntProperty( - name="Petals", - default=8, - min=2, - description="Number of petals" - ) - petalWidth = FloatProperty( - name="Petal width", - default=2.0, - min=0.01, - description="Petal width" - ) - # Star properties - starPoints = IntProperty( - name="Star points", - default=8, - min=2, - description="Number of star points" - ) - starTwist = FloatProperty( - name="Twist", - default=0.0, - description="Twist" - ) - # Arc properties - arcSides = IntProperty( - name="Arc sides", - default=6, - min=1, - description="Sides of arc" - ) - startAngle = FloatProperty( - name="Start angle", - default=0.0, - description="Start angle" - ) - endAngle = FloatProperty( - name="End angle", - default=90.0, - description="End angle" - ) - arcType = IntProperty( - name="Arc type", - default=3, - min=1, - max=3, - description="Sides of arc" - ) - # Cogwheel properties - teeth = IntProperty( - name="Teeth", - default=8, - min=2, - description="number of teeth" - ) - bevel = FloatProperty( - name="Bevel", - default=0.5, - min=0, - max=1, - description="Bevel" - ) - # Nsided property - Nsides = IntProperty( - name="Sides", - default=8, - min=3, - description="Number of sides" - ) - # Splat properties - splatSides = IntProperty( - name="Splat sides", - default=24, - min=3, - description="Splat sides" - ) - splatScale = FloatProperty( - name="Splat scale", - default=1.0, - min=0.0001, - description="Splat scale" - ) - seed = IntProperty( - name="Seed", - default=0, - min=0, - description="Seed" - ) - basis = IntProperty( - name="Basis", - default=0, - min=0, - max=14, - description="Basis" - ) - # Helix properties - helixPoints = IntProperty( - name="Resolution", - default=100, - min=3, - description="Resolution" - ) - helixHeight = FloatProperty( - name="Height", - default=2.0, - min=0, - description="Helix height" - ) - helixStart = FloatProperty( - name="Start angle", - default=0.0, - description="Helix start angle" - ) - helixEnd = FloatProperty( - name="Endangle", - default=360.0, - description="Helix end angle" - ) - helixWidth = FloatProperty( - name="Width", - default=1.0, - description="Helix width" - ) - helix_a = FloatProperty( - name="Variable 1", - default=0.0, - description="Helix Variable 1" - ) - helix_b = FloatProperty( - name="Variable 2", - default=0.0, - description="Helix Variable 2" - ) - # Cycloid properties - cycloPoints = IntProperty( - name="Resolution", - default=100, - min=3, - soft_min=3, - description="Resolution" - ) - cycloType = IntProperty( - name="Type", - default=1, - min=0, - max=2, - description="Type: Cycloid , Hypocycloid / Hypotrochoid , Epicycloid / Epitrochoid" - ) - cyclo_a = FloatProperty( - name="R", - default=1.0, - min=0.01, - description="Cycloid: R radius a" - ) - cyclo_b = FloatProperty( - name="r", - default=0.25, - min=0.01, - description="Cycloid: r radius b" - ) - cyclo_d = FloatProperty( - name="d", - default=0.25, - description="Cycloid: d distance" - ) - # Noise properties - noiseType = IntProperty( - name="Type", - default=0, - min=0, - max=2, - description="Noise curve type: Linear, Circular or Knot" - ) - noisePoints = IntProperty( - name="Resolution", - default=100, - min=3, - description="Resolution" - ) - noiseLength = FloatProperty( - name="Length", - default=2.0, - min=0.01, - description="Curve Length" - ) - noiseSize = FloatProperty( - name="Noise size", - default=1.0, - min=0.0001, - description="Noise size" - ) - noiseScaleX = FloatProperty( - name="Noise x", - default=1.0, - min=0.0001, - description="Noise x" - ) - noiseScaleY = FloatProperty( - name="Noise y", - default=1.0, - min=0.0001, - description="Noise y" - ) - noiseScaleZ = FloatProperty( - name="Noise z", - default=1.0, - min=0.0001, - description="Noise z" - ) - noiseOctaves = IntProperty( - name="Octaves", - default=2, - min=1, - max=16, - description="Basis" - ) - noiseBasis = IntProperty( - name="Basis", - default=0, - min=0, - max=9, - description="Basis" - ) - noiseSeed = IntProperty( - name="Seed", - default=1, - min=0, - description="Random Seed" - ) - - def draw(self, context): - layout = self.layout - - # general options - col = layout.column() - col.prop(self, 'ProfileType') - col.label(text=self.ProfileType + " Options:") - - # options per ProfileType - box = layout.box() - col = box.column(align=True) - - if self.ProfileType == 'Profile': - col.prop(self, "ProfileCurveType") - col.prop(self, "ProfileCurvevar1") - col.prop(self, "ProfileCurvevar2") - - elif self.ProfileType == 'Arrow': - col.prop(self, "MiscCurveType") - col.prop(self, "MiscCurvevar1", text="Height") - col.prop(self, "MiscCurvevar2", text="Width") - - elif self.ProfileType == 'Rectangle': - col.prop(self, "MiscCurveType") - col.prop(self, "MiscCurvevar1", text="Width") - col.prop(self, "MiscCurvevar2", text="Height") - if self.MiscCurveType is 2: - col.prop(self, "MiscCurvevar3", text="Corners") - - elif self.ProfileType == 'Flower': - col.prop(self, "petals") - col.prop(self, "petalWidth") - - col = box.column(align=True) - col.prop(self, "innerRadius") - col.prop(self, "outerRadius") - - elif self.ProfileType == 'Star': - col.prop(self, "starPoints") - col.prop(self, "starTwist") - - col = box.column(align=True) - col.prop(self, "innerRadius") - col.prop(self, "outerRadius") - - elif self.ProfileType == 'Arc': - col.prop(self, "arcType") - col.prop(self, "arcSides") - - col = box.column(align=True) - col.prop(self, "startAngle") - col.prop(self, "endAngle") - - col = box.column(align=True) - col.prop(self, "innerRadius") - col.prop(self, "outerRadius") - - elif self.ProfileType == 'Cogwheel': - col.prop(self, "teeth") - col.prop(self, "bevel") - - col = box.column(align=True) - col.prop(self, "innerRadius") - col.prop(self, "middleRadius") - col.prop(self, "outerRadius") - - elif self.ProfileType == 'Nsided': - col.prop(self, "Nsides") - col.prop(self, "outerRadius") - - elif self.ProfileType == 'Splat': - col.prop(self, "splatSides") - col.prop(self, "outerRadius") - - col = box.column(align=True) - col.prop(self, "splatScale") - col.prop(self, "seed") - col.prop(self, "basis") - - elif self.ProfileType == 'Cycloid': - col.prop(self, "cycloType") - col.prop(self, "cycloPoints") - - col = box.column(align=True) - col.prop(self, "cyclo_a") - col.prop(self, "cyclo_b") - if self.cycloType is not 0: - col.prop(self, "cyclo_d") - - elif self.ProfileType == 'Helix': - col.prop(self, "helixPoints") - col.prop(self, "helixHeight") - col.prop(self, "helixWidth") - - col = box.column(align=True) - col.prop(self, "helixStart") - col.prop(self, "helixEnd") - - col = box.column(align=True) - col.prop(self, "helix_a") - col.prop(self, "helix_b") - - elif self.ProfileType == 'Noise': - col.prop(self, "noiseType") - col.prop(self, "noisePoints") - col.prop(self, "noiseLength") - - col = box.column(align=True) - col.prop(self, "noiseSize") - col.prop(self, "noiseScaleX") - col.prop(self, "noiseScaleY") - col.prop(self, "noiseScaleZ") - - col = box.column(align=True) - col.prop(self, "noiseOctaves") - col.prop(self, "noiseBasis") - col.prop(self, "noiseSeed") - - col = layout.column() - col.label(text="Output Curve Type:") - col.row().prop(self, "outputType", expand=True) - - # output options - if self.outputType == 'NURBS': - col.prop(self, 'order_u') - elif self.outputType == 'BEZIER': - col.row().prop(self, 'handleType', expand=True) - - @classmethod - def poll(cls, context): - return context.scene is not None - - def execute(self, context): - # turn off undo - undo = context.user_preferences.edit.use_global_undo - context.user_preferences.edit.use_global_undo = False - - # deal with 2D - 3D curve differences - if self.ProfileType in ['Helix', 'Cycloid', 'Noise']: - self.shape = '3D' - else: - self.shape = '2D' - - if self.ProfileType in ['Helix', 'Noise', 'Cycloid']: - self.use_cyclic_u = False - if self.ProfileType in ['Cycloid']: - if self.cycloType is 0: - self.use_cyclic_u = False - else: - self.use_cyclic_u = True - else: - if self.ProfileType == 'Arc' and self.arcType is 1: - self.use_cyclic_u = False - else: - self.use_cyclic_u = True - - # main function - main(context, self, self.align_matrix or Matrix()) - - # restore pre operator undo state - context.user_preferences.edit.use_global_undo = undo - - return {'FINISHED'} - - def invoke(self, context, event): - # store creation_matrix - self.align_matrix = align_matrix(context) - self.execute(context) - - return {'FINISHED'} diff --git a/tests/test_helpers/addons/add_curve_extra_objects/add_curve_braid.py b/tests/test_helpers/addons/add_curve_extra_objects/add_curve_braid.py deleted file mode 100644 index 90b41e5..0000000 --- a/tests/test_helpers/addons/add_curve_extra_objects/add_curve_braid.py +++ /dev/null @@ -1,261 +0,0 @@ -# gpl: author Jared Forsyth - -""" -bl_info = { - "name": "New Braid", - "author": "Jared Forsyth ", - "version": (1, 0, 2), - "blender": (2, 6, 0), - "location": "View3D > Add > Mesh > New Braid", - "description": "Adds a new Braid", - "warning": "", - "wiki_url": "", - "category": "Add Mesh"} -""" - -import bpy -from bpy.props import ( - FloatProperty, - IntProperty, - BoolProperty, - ) -from bpy.types import Operator -from math import ( - sin, cos, - pi, - ) - - -def angle_point(center, angle, distance): - cx, cy = center - x = cos(angle) * distance - y = sin(angle) * distance - return x + cx, y + cy - - -def flat_hump(strands, mx=1, my=1, mz=1, resolution=2): - num = 4 * resolution - dy = 2 * pi / num - dz = 2 * pi * (strands - 1) / num - for i in range(num): - x = i * mx - y = cos(i * dy) * my - z = sin(i * dz) * mz - - yield x, y, z - - -def circle_hump(pos, strands, humps, radius=1, mr=1, mz=.2, resolution=2): - num = 5 * resolution - dt = 2 * pi / humps * strands / num - dr = 2 * pi * (strands - 1) / num - dz = 2 * pi / num - t0 = 2 * pi / humps * pos - - for i in range(num): - x, y = angle_point((0, 0), i * dt + t0, radius + sin(i * dr) * mr) - z = cos(i * dz) * mz - - yield x, y, z - - -def make_strands(strands, humps, radius=1, mr=1, mz=.2, resolution=2): - positions = [0 for x in range(humps)] - last = None - lines = [] - at = 0 - - while 0 in positions: - if positions[at]: - at = positions.index(0) - last = None - hump = list(circle_hump(at, strands, humps, radius, mr, mz, resolution)) - if last is None: - last = hump - lines.append(last) - else: - last.extend(hump) - positions[at] = 1 - at += strands - at %= humps - - return lines - - -def poly_line(curve, points, join=True, type='NURBS'): - polyline = curve.splines.new(type) - polyline.points.add(len(points) - 1) - for num in range(len(points)): - polyline.points[num].co = (points[num]) + (1,) - - polyline.order_u = len(polyline.points) - 1 - if join: - polyline.use_cyclic_u = True - - -def poly_lines(objname, curvename, lines, bevel=None, joins=False, ctype='NURBS'): - curve = bpy.data.curves.new(name=curvename, type='CURVE') - curve.dimensions = '3D' - - obj = bpy.data.objects.new(objname, curve) - obj.location = (0, 0, 0) # object origin - - for i, line in enumerate(lines): - poly_line(curve, line, joins if type(joins) == bool else joins[i], type=ctype) - - if bevel: - curve.bevel_object = bpy.data.objects[bevel] - return obj - - -def nurbs_circle(name, w, h): - pts = [(-w / 2, 0, 0), (0, -h / 2, 0), (w / 2, 0, 0), (0, h / 2, 0)] - return poly_lines(name, name + '_curve', [pts], joins=True) - - -def star_pts(r=1, ir=None, points=5, center=(0, 0)): - """ - Create points for a star. They are 2d - z is always zero - - r: the outer radius - ir: the inner radius - """ - if not ir: - ir = r / 5 - pts = [] - dt = pi * 2 / points - for i in range(points): - t = i * dt - ti = (i + .5) * dt - pts.append(angle_point(center, t, r) + (0,)) - pts.append(angle_point(center, ti, ir) + (0,)) - return pts - - -def defaultCircle(w=.6): - circle = nurbs_circle('braid_circle', w, w) - circle.hide = True - return circle - - -def defaultStar(): - star = poly_lines('star', 'staz', [tuple(star_pts(points=5, r=.5, ir=.05))], type='NURBS') - star.hide = True - return star - - -def awesome_braid(strands=3, sides=5, bevel='braid_circle', pointy=False, **kwds): - lines = make_strands(strands, sides, **kwds) - types = {True: 'POLY', False: 'NURBS'}[pointy] - return poly_lines('Braid', 'Braid_c', lines, bevel=bevel, joins=True, ctype=types) - - -class Braid(Operator): - bl_idname = "mesh.add_braid" - bl_label = "New Braid" - bl_description = ("Construct a new Braid\n" - "Creates two objects - the hidden one is used as the Bevel control") - bl_options = {'REGISTER', 'UNDO', 'PRESET'} - - strands = IntProperty( - name="Strands", - description="Number of Strands", - min=2, max=100, - default=3 - ) - sides = IntProperty( - name="Sides", - description="Number of Knot sides", - min=2, max=100, - default=5 - ) - radius = FloatProperty( - name="Radius", - description="Increase / decrease the diameter in X,Y axis", - default=1 - ) - thickness = FloatProperty( - name="Thickness", - description="The ratio between inner and outside diameters", - default=.3 - ) - strandsize = FloatProperty( - name="Bevel Depth", - description="Individual strand diameter (similar to Curve's Bevel depth)", - default=.3, - min=.01, max=10 - ) - width = FloatProperty( - name="Width", - description="Stretch the Braids along the Z axis", - default=.2 - ) - resolution = IntProperty( - name="Bevel Resolution", - description="Resolution of the Created curve\n" - "Increasing this value, will produce heavy geometry", - min=1, - max=100, soft_max=24, - default=2 - ) - pointy = BoolProperty( - name="Pointy", - description="Switch between round and sharp corners", - default=False - ) - - def draw(self, context): - layout = self.layout - - box = layout.box() - col = box.column(align=True) - col.label("Settings:") - col.prop(self, "strands") - col.prop(self, "sides") - - col = box.column(align=True) - col.prop(self, "radius") - col.prop(self, "thickness") - col.prop(self, "width") - - col = box.column() - col.prop(self, "pointy") - - box = layout.box() - col = box.column(align=True) - col.label("Geometry Options:") - col.prop(self, "strandsize") - col.prop(self, "resolution") - - def execute(self, context): - circle = defaultCircle(self.strandsize) - context.scene.objects.link(circle) - braid = awesome_braid( - self.strands, self.sides, - bevel=circle.name, - pointy=self.pointy, - radius=self.radius, - mr=self.thickness, - mz=self.width, - resolution=self.resolution - ) - base = context.scene.objects.link(braid) - - for ob in context.scene.objects: - ob.select = False - base.select = True - context.scene.objects.active = braid - - return {'FINISHED'} - - -def register(): - bpy.utils.register_class(Braid) - - -def unregister(): - bpy.utils.unregister_class(Braid) - - -if __name__ == "__main__": - register() diff --git a/tests/test_helpers/addons/add_curve_extra_objects/add_curve_celtic_links.py b/tests/test_helpers/addons/add_curve_extra_objects/add_curve_celtic_links.py deleted file mode 100644 index 66b800b..0000000 --- a/tests/test_helpers/addons/add_curve_extra_objects/add_curve_celtic_links.py +++ /dev/null @@ -1,284 +0,0 @@ -# Blender plugin for generating celtic knot curves from 3d meshes -# -# The MIT License (MIT) -# -# Copyright (c) 2013 Adam Newgas -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -bl_info = { - "name": "Celtic Knot", - "description": "", - "author": "Adam Newgas", - "version": (0, 1, 2), - "blender": (2, 74, 0), - "location": "View3D > Add > Curve", - "warning": "", - "wiki_url": "https://github.com/BorisTheBrave/celtic-knot/wiki", - "category": "Add Curve"} - -import bpy -import bmesh -from bpy.types import Operator -from bpy.props import ( - EnumProperty, - FloatProperty, - ) -from collections import defaultdict -from math import ( - pi, sin, - cos, - ) - - -class CelticKnotOperator(Operator): - bl_idname = "curve.celtic_links" - bl_label = "Celtic Links" - bl_description = "Select a low poly Mesh Object to cover with Knitted Links" - bl_options = {'REGISTER', 'UNDO', 'PRESET'} - - weave_up = FloatProperty( - name="Weave Up", - description="Distance to shift curve upwards over knots", - subtype="DISTANCE", - unit="LENGTH" - ) - weave_down = FloatProperty( - name="Weave Down", - description="Distance to shift curve downward under knots", - subtype="DISTANCE", - unit="LENGTH" - ) - handle_types = [ - ('ALIGNED', "Aligned", "Points at a fixed crossing angle"), - ('AUTO', "Auto", "Automatic control points") - ] - handle_type = EnumProperty( - items=handle_types, - name="Handle Type", - description="Controls what type the bezier control points use", - default='AUTO' - ) - - handle_type_map = {"AUTO": "AUTOMATIC", "ALIGNED": "ALIGNED"} - - crossing_angle = FloatProperty( - name="Crossing Angle", - description="Aligned only: the angle between curves in a knot", - default=pi / 4, - min=0, max=pi / 2, - subtype="ANGLE", - unit="ROTATION" - ) - crossing_strength = FloatProperty( - name="Crossing Strength", - description="Aligned only: strenth of bezier control points", - soft_min=0, - subtype="DISTANCE", - unit="LENGTH" - ) - geo_bDepth = FloatProperty( - name="Bevel Depth", - default=0.04, - min=0, soft_min=0, - description="Bevel Depth", - ) - - @classmethod - def poll(cls, context): - ob = context.active_object - return ((ob is not None) and (ob.mode == "OBJECT") and - (ob.type == "MESH") and (context.mode == "OBJECT")) - - def draw(self, context): - layout = self.layout - layout.prop(self, "handle_type") - - col = layout.column(align=True) - col.prop(self, "weave_up") - col.prop(self, "weave_down") - - col = layout.column(align=True) - col.active = False if self.handle_type == 'AUTO' else True - col.prop(self, "crossing_angle") - col.prop(self, "crossing_strength") - - layout.prop(self, "geo_bDepth") - - def execute(self, context): - # Cache some values - s = sin(self.crossing_angle) * self.crossing_strength - c = cos(self.crossing_angle) * self.crossing_strength - handle_type = self.handle_type - weave_up = self.weave_up - weave_down = self.weave_down - - # Create the new object - orig_obj = obj = context.active_object - curve = bpy.data.curves.new("Celtic", "CURVE") - curve.dimensions = "3D" - curve.twist_mode = "MINIMUM" - curve.fill_mode = "FULL" - curve.bevel_depth = 0.015 - curve.extrude = 0.003 - curve.bevel_resolution = 4 - obj = obj.data - midpoints = [] - - # Compute all the midpoints of each edge - for e in obj.edges.values(): - v1 = obj.vertices[e.vertices[0]] - v2 = obj.vertices[e.vertices[1]] - m = (v1.co + v2.co) / 2.0 - midpoints.append(m) - - bm = bmesh.new() - bm.from_mesh(obj) - # Stores which loops the curve has already passed through - loops_entered = defaultdict(lambda: False) - loops_exited = defaultdict(lambda: False) - # Loops on the boundary of a surface - - def ignorable_loop(loop): - return len(loop.link_loops) == 0 - - # Starting at loop, build a curve one vertex at a time - # until we start where we came from - # Forward means that for any two edges the loop crosses - # sharing a face, it is passing through in clockwise order - # else anticlockwise - - def make_loop(loop, forward): - current_spline = curve.splines.new("BEZIER") - current_spline.use_cyclic_u = True - first = True - # Data for the spline - # It's faster to store in an array and load into blender - # at once - cos = [] - handle_lefts = [] - handle_rights = [] - while True: - if forward: - if loops_exited[loop]: - break - loops_exited[loop] = True - # Follow the face around, ignoring boundary edges - while True: - loop = loop.link_loop_next - if not ignorable_loop(loop): - break - assert loops_entered[loop] is False - loops_entered[loop] = True - v = loop.vert.index - prev_loop = loop - # Find next radial loop - assert loop.link_loops[0] != loop - loop = loop.link_loops[0] - forward = loop.vert.index == v - else: - if loops_entered[loop]: - break - loops_entered[loop] = True - # Follow the face around, ignoring boundary edges - while True: - v = loop.vert.index - loop = loop.link_loop_prev - if not ignorable_loop(loop): - break - assert loops_exited[loop] is False - loops_exited[loop] = True - prev_loop = loop - # Find next radial loop - assert loop.link_loops[-1] != loop - loop = loop.link_loops[-1] - forward = loop.vert.index == v - - if not first: - current_spline.bezier_points.add() - first = False - midpoint = midpoints[loop.edge.index] - normal = loop.calc_normal() + prev_loop.calc_normal() - normal.normalize() - offset = weave_up if forward else weave_down - midpoint = midpoint + offset * normal - cos.extend(midpoint) - - if handle_type != "AUTO": - tangent = loop.link_loop_next.vert.co - loop.vert.co - tangent.normalize() - binormal = normal.cross(tangent).normalized() - if not forward: - tangent *= -1 - s_binormal = s * binormal - c_tangent = c * tangent - handle_left = midpoint - s_binormal - c_tangent - handle_right = midpoint + s_binormal + c_tangent - handle_lefts.extend(handle_left) - handle_rights.extend(handle_right) - - points = current_spline.bezier_points - points.foreach_set("co", cos) - if handle_type != "AUTO": - points.foreach_set("handle_left", handle_lefts) - points.foreach_set("handle_right", handle_rights) - - # Attempt to start a loop at each untouched loop in the entire mesh - for face in bm.faces: - for loop in face.loops: - if ignorable_loop(loop): - continue - if not loops_exited[loop]: - make_loop(loop, True) - if not loops_entered[loop]: - make_loop(loop, False) - - # Create an object from the curve - from bpy_extras import object_utils - object_utils.object_data_add(context, curve, operator=None) - # Set the handle type (this is faster than setting it pointwise) - bpy.ops.object.editmode_toggle() - bpy.ops.curve.select_all(action="SELECT") - bpy.ops.curve.handle_type_set(type=self.handle_type_map[handle_type]) - # Some blender versions lack the default - bpy.ops.curve.radius_set(radius=1.0) - bpy.ops.object.editmode_toggle() - # Restore active selection - curve_obj = context.active_object - - # apply the bevel setting since it was unused - try: - curve_obj.data.bevel_depth = self.geo_bDepth - except: - pass - context.scene.objects.active = orig_obj - - return {'FINISHED'} - - -def register(): - bpy.utils.register_class(CelticKnotOperator) - - -def unregister(): - bpy.utils.unregister_class(CelticKnotOperator) - - -if __name__ == "__main__": - register() diff --git a/tests/test_helpers/addons/add_curve_extra_objects/add_curve_curly.py b/tests/test_helpers/addons/add_curve_extra_objects/add_curve_curly.py deleted file mode 100644 index 779689a..0000000 --- a/tests/test_helpers/addons/add_curve_extra_objects/add_curve_curly.py +++ /dev/null @@ -1,491 +0,0 @@ -# gpl: author Cmomoney - -# DevBo Task https://developer.blender.org/T37299 - -bl_info = { - "name": "Curly Curves", - "author": "Cmomoney", - "version": (1, 1, 8), - "blender": (2, 69, 0), - "location": "View3D > Add > Curve > Curly Curve", - "description": "Adds a new Curly Curve", - "warning": "", - "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/" - "Py/Scripts/Curve/Curly_Curves", - "category": "Add Curve"} - -import bpy -from bpy.types import Operator -from bpy.props import ( - FloatProperty, - IntProperty, - ) -from bpy_extras.object_utils import ( - AddObjectHelper, - object_data_add, - ) - - -def add_type6(self, context): - - scale_x = self.scale_x - scale_y = self.scale_y - verts = [ - [0.047131 * scale_x, 0.065832 * scale_y, - 0.0, 0.010396 * scale_x, -0.186771 * scale_y, - 0.0, 0.076107 * scale_x, 0.19414 * scale_y, - 0.0, 0.0 * scale_x, -1.0 * scale_y, 0.0], - [0.451396 * scale_x, -0.48376 * scale_y, - 0.0, 0.433623 * scale_x, -0.587557 * scale_y, - 0.0, 0.525837 * scale_x, -0.423363 * scale_y, - 0.0, 0.15115 * scale_x, -0.704345 * scale_y, 0.0] - ] - lhandles = [ - [(-0.067558 * scale_x, 0.078418 * scale_y, 0.0), - (0.168759 * scale_x, -0.154334 * scale_y, 0.0), - (-0.236823 * scale_x, 0.262436 * scale_y, 0.0), - (0.233116 * scale_x, -0.596115 * scale_y, 0.0)], - [(0.498001 * scale_x, -0.493434 * scale_y, 0.0), - (0.375618 * scale_x, -0.55465 * scale_y, 0.0), - (0.634373 * scale_x, -0.49873 * scale_y, 0.0), - (0.225277 * scale_x, -0.526814 * scale_y, 0.0)] - ] - rhandles = [ - [(0.161825 * scale_x, 0.053245 * scale_y, 0.0), - (-0.262003 * scale_x, -0.242566 * scale_y, 0.0), - (0.519691 * scale_x, 0.097329 * scale_y, 0.0), - (-0.233116 * scale_x, -1.403885 * scale_y, 0.0)], - [(0.404788 * scale_x, -0.474085 * scale_y, 0.0), - (0.533397 * scale_x, -0.644158 * scale_y, 0.0), - (0.371983 * scale_x, -0.316529 * scale_y, 0.0), - (0.077022 * scale_x, -0.881876 * scale_y, 0.0)] - ] - make_curve(self, context, verts, lhandles, rhandles) - - -def add_type5(self, context): - - scale_x = self.scale_x - scale_y = self.scale_y - verts = [ - [0.047131 * scale_x, 0.065832 * scale_y, 0.0, - 0.010396 * scale_x, -0.186771 * scale_y, 0.0, - 0.076107 * scale_x, 0.19414 * scale_y, 0.0, - 0.0 * scale_x, -1.0 * scale_y, 0.0], - [0.086336 * scale_x, -0.377611 * scale_y, 0.0, - 0.022417 * scale_x, -0.461301 * scale_y, 0.0, - 0.079885 * scale_x, -0.281968 * scale_y, 0.0, - 0.129212 * scale_x, -0.747702 * scale_y, 0.0] - ] - lhandles = [ - [(-0.067558 * scale_x, 0.078419 * scale_y, 0.0), - (0.168759 * scale_x, -0.154335 * scale_y, 0.0), - (-0.236823 * scale_x, 0.262436 * scale_y, 0.0), - (0.233116 * scale_x, -0.596115 * scale_y, 0.0)], - [(0.047518 * scale_x, -0.350065 * scale_y, 0.0), - (0.086012 * scale_x, -0.481379 * scale_y, 0.0), - (-0.049213 * scale_x, -0.253793 * scale_y, 0.0), - (0.208763 * scale_x, -0.572534 * scale_y, 0.0)] - ] - rhandles = [ - [(0.161825 * scale_x, 0.053245 * scale_y, 0.0), - (-0.262003 * scale_x, -0.242566 * scale_y, 0.0), - (0.519691 * scale_x, 0.097329 * scale_y, 0.0), - (-0.233116 * scale_x, -1.403885 * scale_y, 0.0)], - [(0.125156 * scale_x, -0.405159 * scale_y, 0.0), - (-0.086972 * scale_x, -0.426766 * scale_y, 0.0), - (0.262886 * scale_x, -0.321908 * scale_y, 0.0), - (0.049661 * scale_x, -0.92287 * scale_y, 0.0)] - ] - make_curve(self, context, verts, lhandles, rhandles) - - -def add_type8(self, context): - - scale_x = self.scale_x - scale_y = self.scale_y - verts = [ - [-0.850431 * scale_x, -0.009091 * scale_y, - 0.0, -0.818807 * scale_x, -0.130518 * scale_y, - 0.0, -0.944931 * scale_x, 0.055065 * scale_y, - 0.0, -0.393355 * scale_x, -0.035521 * scale_y, - 0.0, 0.0 * scale_x, 0.348298 * scale_y, - 0.0, 0.393355 * scale_x, -0.035521 * scale_y, - 0.0, 0.978373 * scale_x, 0.185638 * scale_y, - 0.0, 0.771617 * scale_x, 0.272819 * scale_y, - 0.0, 0.864179 * scale_x, 0.188103 * scale_y, 0.0] - ] - lhandles = [ - [(-0.90478 * scale_x, -0.025302 * scale_y, 0.0), - (-0.753279 * scale_x, -0.085571 * scale_y, 0.0), - (-1.06406 * scale_x, -0.047879 * scale_y, 0.0), - (-0.622217 * scale_x, -0.022501 * scale_y, 0.0), - (0.181 * scale_x, 0.34879 * scale_y, 0.0), - (-0.101464 * scale_x, -0.063669 * scale_y, 0.0), - (0.933064 * scale_x, 0.03001 * scale_y, 0.0), - (0.82418 * scale_x, 0.39899 * scale_y, 0.0), - (0.827377 * scale_x, 0.144945 * scale_y, 0.0)] - ] - rhandles = [ - [(-0.796079 * scale_x, 0.007121 * scale_y, 0.0), - (-0.931521 * scale_x, -0.207832 * scale_y, 0.0), - (-0.822288 * scale_x, 0.161045 * scale_y, 0.0), - (0.101464 * scale_x, -0.063671 * scale_y, 0.0), - (-0.181193 * scale_x, 0.347805 * scale_y, 0.0), - (0.622217 * scale_x, -0.022502 * scale_y, 0.0), - (1.022383 * scale_x, 0.336808 * scale_y, 0.0), - (0.741059 * scale_x, 0.199468 * scale_y, 0.0), - (0.900979 * scale_x, 0.231258 * scale_y, 0.0)] - ] - make_curve(self, context, verts, lhandles, rhandles) - - -def add_type3(self, context): - - scale_x = self.scale_x - scale_y = self.scale_y - verts = [ - [-0.78652 * scale_x, -0.070157 * scale_y, - 0.0, -0.697972 * scale_x, -0.247246 * scale_y, - 0.0, -0.953385 * scale_x, -0.002048 * scale_y, - 0.0, 0.0 * scale_x, 0.0 * scale_y, - 0.0, 0.917448 * scale_x, 0.065788 * scale_y, - 0.0, 0.448535 * scale_x, 0.515947 * scale_y, - 0.0, 0.6111 * scale_x, 0.190831 * scale_y, 0.0] - ] - lhandles = [ - [(-0.86511 * scale_x, -0.112965 * scale_y, 0.0), - (-0.61153 * scale_x, -0.156423 * scale_y, 0.0), - (-1.103589 * scale_x, -0.199934 * scale_y, 0.0), - (-0.446315 * scale_x, 0.135163 * scale_y, 0.0), - (0.669383 * scale_x, -0.254463 * scale_y, 0.0), - (0.721512 * scale_x, 0.802759 * scale_y, 0.0), - (0.466815 * scale_x, 0.112232 * scale_y, 0.0)] - ] - rhandles = [ - [(-0.707927 * scale_x, -0.027348 * scale_y, 0.0), - (-0.846662 * scale_x, -0.40347 * scale_y, 0.0), - (-0.79875 * scale_x, 0.201677 * scale_y, 0.0), - (0.446315 * scale_x, -0.135163 * scale_y, 0.0), - (1.196752 * scale_x, 0.42637 * scale_y, 0.0), - (0.289834 * scale_x, 0.349204 * scale_y, 0.0), - (0.755381 * scale_x, 0.269428 * scale_y, 0.0)] - ] - make_curve(self, context, verts, lhandles, rhandles) - - -def add_type2(self, context): - - scale_x = self.scale_x - scale_y = self.scale_y - verts = [ - [-0.719632 * scale_x, -0.08781 * scale_y, - 0.0, -0.605138 * scale_x, -0.31612 * scale_y, - 0.0, -0.935392 * scale_x, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.935392 * scale_x, 0.0, 0.0, 0.605138 * scale_x, - -0.316119 * scale_y, 0.0, 0.719632 * scale_x, -0.08781 * scale_y, 0.0] - ] - lhandles = [ - [(-0.82125 * scale_x, -0.142999 * scale_y, 0.0), - (-0.493366 * scale_x, -0.199027 * scale_y, 0.0), - (-1.129601 * scale_x, -0.25513 * scale_y, 0.0), - (-0.467584 * scale_x, 0.00044 * scale_y, 0.0), - (0.735439 * scale_x, 0.262646 * scale_y, 0.0), - (0.797395 * scale_x, -0.517531 * scale_y, 0.0), - (0.618012 * scale_x, -0.032614 * scale_y, 0.0)] - ] - rhandles = [ - [(-0.618009 * scale_x, -0.032618 * scale_y, 0.0), - (-0.797396 * scale_x, -0.517532 * scale_y, 0.0), - (-0.735445 * scale_x, 0.262669 * scale_y, 0.0), - (0.468041 * scale_x, -0.00044 * scale_y, 0.0), - (1.129616 * scale_x, -0.255119 * scale_y, 0.0), - (0.493365 * scale_x, -0.199025 * scale_y, 0.0), - (0.821249 * scale_x, -0.143004 * scale_y, 0.0)] - ] - make_curve(self, context, verts, lhandles, rhandles) - - -def add_type10(self, context): - - scale_x = self.scale_x - scale_y = self.scale_y - verts = [ - [-0.999637 * scale_x, 0.000348 * scale_y, - 0.0, 0.259532 * scale_x, -0.017841 * scale_y, - 0.0, 0.482303 * scale_x, 0.780429 * scale_y, - 0.0, 0.573183 * scale_x, 0.506898 * scale_y, 0.0], - [0.259532 * scale_x, -0.017841 * scale_y, - 0.0, 0.554919 * scale_x, -0.140918 * scale_y, - 0.0, 0.752264 * scale_x, -0.819275 * scale_y, - 0.0, 0.824152 * scale_x, -0.514881 * scale_y, 0.0] - ] - lhandles = [ - [(-1.258333 * scale_x, -0.258348 * scale_y, 0.0), - (-0.240006 * scale_x, -0.15259 * scale_y, 0.0), - (0.79037 * scale_x, 0.857575 * scale_y, 0.0), - (0.376782 * scale_x, 0.430157 * scale_y, 0.0)], - [(0.224917 * scale_x, -0.010936 * scale_y, 0.0), - (0.514858 * scale_x, -0.122809 * scale_y, 0.0), - (1.057957 * scale_x, -0.886925 * scale_y, 0.0), - (0.61945 * scale_x, -0.464285 * scale_y, 0.0)] - ] - rhandles = [ - [(-0.74094 * scale_x, 0.259045 * scale_y, 0.0), - (0.768844 * scale_x, 0.119545 * scale_y, 0.0), - (0.279083 * scale_x, 0.729538 * scale_y, 0.0), - (0.643716 * scale_x, 0.534458 * scale_y, 0.0)], - [(0.294147 * scale_x, -0.024746 * scale_y, 0.0), - (1.03646 * scale_x, -0.358598 * scale_y, 0.0), - (0.547718 * scale_x, -0.774008 * scale_y, 0.0), - (0.897665 * scale_x, -0.533051 * scale_y, 0.0)] - ] - make_curve(self, context, verts, lhandles, rhandles) - - -def add_type9(self, context): - - scale_x = self.scale_x - scale_y = self.scale_y - verts = [ - [0.260968 * scale_x, -0.668118 * scale_y, - 0.0, 0.108848 * scale_x, -0.381587 * scale_y, - 0.0, 0.537002 * scale_x, -0.77303 * scale_y, - 0.0, -0.600421 * scale_x, -0.583106 * scale_y, - 0.0, -0.600412 * scale_x, 0.583103 * scale_y, - 0.0, 0.537002 * scale_x, 0.773025 * scale_y, - 0.0, 0.108854 * scale_x, 0.381603 * scale_y, - 0.0, 0.260966 * scale_x, 0.668129 * scale_y, 0.0] - ] - lhandles = [ - [(0.387973 * scale_x, -0.594856 * scale_y, 0.0), - (-0.027835 * scale_x, -0.532386 * scale_y, 0.0), - (0.775133 * scale_x, -0.442883 * scale_y, 0.0), - (-0.291333 * scale_x, -1.064385 * scale_y, 0.0), - (-0.833382 * scale_x, 0.220321 * scale_y, 0.0), - (0.291856 * scale_x, 1.112891 * scale_y, 0.0), - (0.346161 * scale_x, 0.119777 * scale_y, 0.0), - (0.133943 * scale_x, 0.741389 * scale_y, 0.0)] - ] - rhandles = [ - [(0.133951 * scale_x, -0.741386 * scale_y, 0.0), - (0.346154 * scale_x, -0.119772 * scale_y, 0.0), - (0.291863 * scale_x, -1.112896 * scale_y, 0.0), - (-0.833407 * scale_x, -0.220324 * scale_y, 0.0), - (-0.29134 * scale_x, 1.064389 * scale_y, 0.0), - (0.775125 * scale_x, 0.442895 * scale_y, 0.0), - (-0.029107 * scale_x, 0.533819 * scale_y, 0.0), - (0.387981 * scale_x, 0.594873 * scale_y, 0.0)] - ] - make_curve(self, context, verts, lhandles, rhandles) - - -def add_type7(self, context): - - scale_x = self.scale_x - scale_y = self.scale_y - verts = [ - [-0.850431 * scale_x, -0.009091 * scale_y, - 0.0, -0.818807 * scale_x, -0.130518 * scale_y, - 0.0, -0.944931 * scale_x, 0.055065 * scale_y, 0.0, - -0.393355 * scale_x, -0.035521 * scale_y, - 0.0, 0.0 * scale_x, 0.348298 * scale_y, - 0.0, 0.393355 * scale_x, -0.035521 * scale_y, - 0.0, 0.944931 * scale_x, 0.055065 * scale_y, - 0.0, 0.818807 * scale_x, -0.130518 * scale_y, - 0.0, 0.850431 * scale_x, -0.009091 * scale_y, 0.0] - ] - lhandles = [ - [(-0.90478 * scale_x, -0.025302 * scale_y, 0.0), - (-0.753279 * scale_x, -0.085571 * scale_y, 0.0), - (-1.06406 * scale_x, -0.047879 * scale_y, 0.0), - (-0.622217 * scale_x, -0.022502 * scale_y, 0.0), - (0.181 * scale_x, 0.348791 * scale_y, 0.0), - (-0.101464 * scale_x, -0.063671 * scale_y, 0.0), - (0.822288 * scale_x, 0.161045 * scale_y, 0.0), - (0.931521 * scale_x, -0.207832 * scale_y, 0.0), - (0.796079 * scale_x, 0.007121 * scale_y, 0.0)] - ] - rhandles = [ - [(-0.796079 * scale_x, 0.007121 * scale_y, 0.0), - (-0.931521 * scale_x, -0.207832 * scale_y, 0.0), - (-0.822288 * scale_x, 0.161045 * scale_y, 0.0), - (0.101464 * scale_x, -0.063671 * scale_y, 0.0), - (-0.181193 * scale_x, 0.347805 * scale_y, 0.0), - (0.622217 * scale_x, -0.022502 * scale_y, 0.0), - (1.06406 * scale_x, -0.047879 * scale_y, 0.0), - (0.753279 * scale_x, -0.085571 * scale_y, 0.0), - (0.90478 * scale_x, -0.025302 * scale_y, 0.0)] - ] - make_curve(self, context, verts, lhandles, rhandles) - - -def add_type4(self, context): - - scale_x = self.scale_x - scale_y = self.scale_y - verts = [ - [0.072838 * scale_x, -0.071461 * scale_y, - 0.0, -0.175451 * scale_x, -0.130711 * scale_y, - 0.0, 0.207269 * scale_x, 0.118064 * scale_y, - 0.0, 0 * scale_x, -1.0 * scale_y, 0.0] - ] - lhandles = [ - [(0.042135 * scale_x, 0.039756 * scale_y, 0), - (-0.086769 * scale_x, -0.265864 * scale_y, 0), - (0.002865 * scale_x, 0.364657 * scale_y, 0), - (0.233116 * scale_x, -0.596115 * scale_y, 0)] - ] - rhandles = [ - [(0.103542 * scale_x, -0.182683 * scale_y, 0), - (-0.327993 * scale_x, 0.101765 * scale_y, 0), - (0.417702 * scale_x, -0.135803 * scale_y, 0), - (-0.233116 * scale_x, -1.403885 * scale_y, 0)] - ] - make_curve(self, context, verts, lhandles, rhandles) - - -def add_type1(self, context): - - scale_x = self.scale_x - scale_y = self.scale_y - verts = [ - [-0.71753 * scale_x, -0.08781 * scale_y, - 0, -0.60337 * scale_x, -0.31612 * scale_y, 0, - -0.93266 * scale_x, 0, 0, 0, 0, 0, 0.93266 * scale_x, - 0, 0, 0.60337 * scale_x, 0.31612 * scale_y, - 0, 0.71753 * scale_x, 0.08781 * scale_y, 0] - ] - lhandles = [ - [(-0.81885 * scale_x, -0.143002 * scale_y, 0), - (-0.491926 * scale_x, -0.199026 * scale_y, 0), - (-1.126316 * scale_x, -0.255119 * scale_y, 0), - (-0.446315 * scale_x, 0.135164 * scale_y, 0), - (0.733297 * scale_x, -0.26265 * scale_y, 0), - (0.795065 * scale_x, 0.517532 * scale_y, 0), - (0.616204 * scale_x, 0.03262 * scale_y, 0)] - ] - rhandles = [ - [(-0.616204 * scale_x, -0.032618 * scale_y, 0), - (-0.795067 * scale_x, -0.517532 * scale_y, 0), - (-0.733297 * scale_x, 0.262651 * scale_y, 0), - (0.446315 * scale_x, -0.135163 * scale_y, 0), - (1.126316 * scale_x, 0.255119 * scale_y, 0), - (0.491924 * scale_x, 0.199026 * scale_y, 0), - (0.81885 * scale_x, 0.143004 * scale_y, 0)] - ] - make_curve(self, context, verts, lhandles, rhandles) - - -def make_curve(self, context, verts, lh, rh): - - types = self.types - curve_data = bpy.data.curves.new(name='CurlyCurve', type='CURVE') - curve_data.dimensions = '3D' - - for p in range(len(verts)): - c = 0 - spline = curve_data.splines.new(type='BEZIER') - spline.bezier_points.add(len(verts[p]) / 3 - 1) - spline.bezier_points.foreach_set('co', verts[p]) - - for bp in spline.bezier_points: - bp.handle_left_type = 'ALIGNED' - bp.handle_right_type = 'ALIGNED' - bp.handle_left.xyz = lh[p][c] - bp.handle_right.xyz = rh[p][c] - c += 1 - # something weird with this one - if types == 1 or types == 2 or types == 3: - spline.bezier_points[3].handle_left.xyz = lh[p][3] - object_data_add(context, curve_data, operator=self) - - -class add_curlycurve(Operator, AddObjectHelper): - bl_idname = "curve.curlycurve" - bl_label = "Add Curly Curve" - bl_description = "Create a Curly Curve" - bl_options = {'REGISTER', 'UNDO'} - - types = IntProperty( - name="Type", - description="Type of curly curve", - default=1, - min=1, max=10 - ) - scale_x = FloatProperty( - name="Scale X", - description="Scale on X axis", - default=1.0 - ) - scale_y = FloatProperty( - name="Scale Y", - description="Scale on Y axis", - default=1.0 - ) - - def draw(self, context): - layout = self.layout - - col = layout.column(align=True) - # AddObjectHelper props - col.prop(self, "view_align") - col.prop(self, "location") - col.prop(self, "rotation") - - col = layout.column() - col.label("Curve:") - col.prop(self, "types") - - col = layout.column(align=True) - col.label("Resize:") - col.prop(self, "scale_x") - col.prop(self, "scale_y") - - def execute(self, context): - if self.types == 1: - add_type1(self, context) - if self.types == 2: - add_type2(self, context) - if self.types == 3: - add_type3(self, context) - if self.types == 4: - add_type4(self, context) - if self.types == 5: - add_type5(self, context) - if self.types == 6: - add_type6(self, context) - if self.types == 7: - add_type7(self, context) - if self.types == 8: - add_type8(self, context) - if self.types == 9: - add_type9(self, context) - if self.types == 10: - add_type10(self, context) - - return {'FINISHED'} - - -# Registration - -def add_curlycurve_button(self, context): - self.layout.operator( - add_curlycurve.bl_idname, - text="Add Curly Curve", - icon='PLUGIN' - ) - - -def register(): - bpy.utils.register_class(add_curlycurve) - bpy.types.INFO_MT_curve_add.append(add_curlycurve_button) - - -def unregister(): - bpy.utils.unregister_class(add_curlycurve) - bpy.types.INFO_MT_curve_add.remove(add_curlycurve_button) - - -if __name__ == "__main__": - register() diff --git a/tests/test_helpers/addons/add_curve_extra_objects/add_curve_simple.py b/tests/test_helpers/addons/add_curve_extra_objects/add_curve_simple.py deleted file mode 100644 index 3e85fa1..0000000 --- a/tests/test_helpers/addons/add_curve_extra_objects/add_curve_simple.py +++ /dev/null @@ -1,1747 +0,0 @@ -# ##### 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_info = { - "name": "Simple Curve", - "author": "Spivak Vladimir (http://cwolf3d.korostyshev.net)", - "version": (1, 5, 3), - "blender": (2, 6, 9), - "location": "View3D > Add > Curve", - "description": "Adds Simple Curve", - "warning": "", - "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/" - "Py/Scripts/Curve/Simple_curves", - "category": "Add Curve"} - - -# ------------------------------------------------------------ - -import bpy -from bpy.types import ( - Operator, - Menu, - Panel, - PropertyGroup, - ) -from bpy.props import ( - BoolProperty, - EnumProperty, - FloatProperty, - FloatVectorProperty, - IntProperty, - StringProperty, - PointerProperty, - ) -from mathutils import ( - Vector, - Matrix, - ) -from math import ( - sin, asin, sqrt, - acos, cos, pi, - radians, tan, - hypot, - ) -# from bpy_extras.object_utils import * - - -# ------------------------------------------------------------ -# Point: - -def SimplePoint(): - newpoints = [] - - newpoints.append([0.0, 0.0, 0.0]) - - return newpoints - - -# ------------------------------------------------------------ -# Line: - -def SimpleLine(c1=[0.0, 0.0, 0.0], c2=[2.0, 2.0, 2.0]): - newpoints = [] - - c3 = Vector(c2) - Vector(c1) - newpoints.append([0.0, 0.0, 0.0]) - newpoints.append([c3[0], c3[1], c3[2]]) - - return newpoints - - -# ------------------------------------------------------------ -# Angle: - -def SimpleAngle(length=1.0, angle=45.0): - newpoints = [] - - angle = radians(angle) - newpoints.append([length, 0.0, 0.0]) - newpoints.append([0.0, 0.0, 0.0]) - newpoints.append([length * cos(angle), length * sin(angle), 0.0]) - - return newpoints - - -# ------------------------------------------------------------ -# Distance: - -def SimpleDistance(length=1.0, center=True): - newpoints = [] - - if center: - newpoints.append([-length / 2, 0.0, 0.0]) - newpoints.append([length / 2, 0.0, 0.0]) - else: - newpoints.append([0.0, 0.0, 0.0]) - newpoints.append([length, 0.0, 0.0]) - - return newpoints - - -# ------------------------------------------------------------ -# Circle: - -def SimpleCircle(sides=4, radius=1.0): - newpoints = [] - - angle = radians(360) / sides - newpoints.append([radius, 0, 0]) - j = 1 - while j < sides: - t = angle * j - x = cos(t) * radius - y = sin(t) * radius - newpoints.append([x, y, 0]) - j += 1 - - return newpoints - - -# ------------------------------------------------------------ -# Ellipse: - -def SimpleEllipse(a=2.0, b=1.0): - newpoints = [] - - newpoints.append([a, 0.0, 0.0]) - newpoints.append([0.0, b, 0.0]) - newpoints.append([-a, 0.0, 0.0]) - newpoints.append([0.0, -b, 0.0]) - - return newpoints - - -# ------------------------------------------------------------ -# Arc: - -def SimpleArc(sides=0, radius=1.0, startangle=0.0, endangle=45.0): - newpoints = [] - - startangle = radians(startangle) - endangle = radians(endangle) - sides += 1 - - angle = (endangle - startangle) / sides - x = cos(startangle) * radius - y = sin(startangle) * radius - newpoints.append([x, y, 0]) - j = 1 - while j < sides: - t = angle * j - x = cos(t + startangle) * radius - y = sin(t + startangle) * radius - newpoints.append([x, y, 0]) - j += 1 - x = cos(endangle) * radius - y = sin(endangle) * radius - newpoints.append([x, y, 0]) - - return newpoints - - -# ------------------------------------------------------------ -# Sector: - -def SimpleSector(sides=0, radius=1.0, startangle=0.0, endangle=45.0): - newpoints = [] - - startangle = radians(startangle) - endangle = radians(endangle) - sides += 1 - - newpoints.append([0, 0, 0]) - angle = (endangle - startangle) / sides - x = cos(startangle) * radius - y = sin(startangle) * radius - newpoints.append([x, y, 0]) - j = 1 - while j < sides: - t = angle * j - x = cos(t + startangle) * radius - y = sin(t + startangle) * radius - newpoints.append([x, y, 0]) - j += 1 - x = cos(endangle) * radius - y = sin(endangle) * radius - newpoints.append([x, y, 0]) - - return newpoints - - -# ------------------------------------------------------------ -# Segment: - -def SimpleSegment(sides=0, a=2.0, b=1.0, startangle=0.0, endangle=45.0): - newpoints = [] - - startangle = radians(startangle) - endangle = radians(endangle) - sides += 1 - - angle = (endangle - startangle) / sides - x = cos(startangle) * a - y = sin(startangle) * a - newpoints.append([x, y, 0]) - j = 1 - while j < sides: - t = angle * j - x = cos(t + startangle) * a - y = sin(t + startangle) * a - newpoints.append([x, y, 0]) - j += 1 - x = cos(endangle) * a - y = sin(endangle) * a - newpoints.append([x, y, 0]) - - x = cos(endangle) * b - y = sin(endangle) * b - newpoints.append([x, y, 0]) - j = sides - while j > 0: - t = angle * j - x = cos(t + startangle) * b - y = sin(t + startangle) * b - newpoints.append([x, y, 0]) - j -= 1 - x = cos(startangle) * b - y = sin(startangle) * b - newpoints.append([x, y, 0]) - - return newpoints - - -# ------------------------------------------------------------ -# Rectangle: - -def SimpleRectangle(width=2.0, length=2.0, rounded=0.0, center=True): - newpoints = [] - - r = rounded / 2 - - if center: - x = width / 2 - y = length / 2 - if rounded != 0.0: - newpoints.append([-x + r, y, 0.0]) - newpoints.append([x - r, y, 0.0]) - newpoints.append([x, y - r, 0.0]) - newpoints.append([x, -y + r, 0.0]) - newpoints.append([x - r, -y, 0.0]) - newpoints.append([-x + r, -y, 0.0]) - newpoints.append([-x, -y + r, 0.0]) - newpoints.append([-x, y - r, 0.0]) - else: - newpoints.append([-x, y, 0.0]) - newpoints.append([x, y, 0.0]) - newpoints.append([x, -y, 0.0]) - newpoints.append([-x, -y, 0.0]) - - else: - x = width - y = length - if rounded != 0.0: - newpoints.append([r, y, 0.0]) - newpoints.append([x - r, y, 0.0]) - newpoints.append([x, y - r, 0.0]) - newpoints.append([x, r, 0.0]) - newpoints.append([x - r, 0.0, 0.0]) - newpoints.append([r, 0.0, 0.0]) - newpoints.append([0.0, r, 0.0]) - newpoints.append([0.0, y - r, 0.0]) - else: - newpoints.append([0.0, 0.0, 0.0]) - newpoints.append([0.0, y, 0.0]) - newpoints.append([x, y, 0.0]) - newpoints.append([x, 0.0, 0.0]) - - return newpoints - - -# ------------------------------------------------------------ -# Rhomb: - -def SimpleRhomb(width=2.0, length=2.0, center=True): - newpoints = [] - x = width / 2 - y = length / 2 - - if center: - newpoints.append([-x, 0.0, 0.0]) - newpoints.append([0.0, y, 0.0]) - newpoints.append([x, 0.0, 0.0]) - newpoints.append([0.0, -y, 0.0]) - else: - newpoints.append([x, 0.0, 0.0]) - newpoints.append([0.0, y, 0.0]) - newpoints.append([x, length, 0.0]) - newpoints.append([width, y, 0.0]) - - return newpoints - - -# ------------------------------------------------------------ -# Polygon: - -def SimplePolygon(sides=3, radius=1.0): - newpoints = [] - angle = radians(360.0) / sides - j = 0 - - while j < sides: - t = angle * j - x = sin(t) * radius - y = cos(t) * radius - newpoints.append([x, y, 0.0]) - j += 1 - - return newpoints - - -# ------------------------------------------------------------ -# Polygon_ab: - -def SimplePolygon_ab(sides=3, a=2.0, b=1.0): - newpoints = [] - angle = radians(360.0) / sides - j = 0 - - while j < sides: - t = angle * j - x = sin(t) * a - y = cos(t) * b - newpoints.append([x, y, 0.0]) - j += 1 - - return newpoints - - -# ------------------------------------------------------------ -# Trapezoid: - -def SimpleTrapezoid(a=2.0, b=1.0, h=1.0, center=True): - newpoints = [] - x = a / 2 - y = b / 2 - r = h / 2 - - if center: - newpoints.append([-x, -r, 0.0]) - newpoints.append([-y, r, 0.0]) - newpoints.append([y, r, 0.0]) - newpoints.append([x, -r, 0.0]) - - else: - newpoints.append([0.0, 0.0, 0.0]) - newpoints.append([x - y, h, 0.0]) - newpoints.append([x + y, h, 0.0]) - newpoints.append([a, 0.0, 0.0]) - - return newpoints - - -# ------------------------------------------------------------ -# calculates the matrix for the new object -# depending on user pref - -def align_matrix(context, location): - loc = Matrix.Translation(location) - obj_align = context.user_preferences.edit.object_align - if (context.space_data.type == 'VIEW_3D' and - obj_align == 'VIEW'): - rot = context.space_data.region_3d.view_matrix.to_3x3().inverted().to_4x4() - else: - rot = Matrix() - align_matrix = loc * rot - - return align_matrix - - -# ------------------------------------------------------------ -# Main Function - -def main(context, self, align_matrix): - # deselect all objects - bpy.ops.object.select_all(action='DESELECT') - - # create object - name = self.Simple_Type # Type as name - - # create curve - scene = bpy.context.scene - newCurve = bpy.data.curves.new(name, type='CURVE') # curvedatablock - newSpline = newCurve.splines.new('BEZIER') # spline - - # set curveOptions - newCurve.dimensions = self.shape - newSpline.use_endpoint_u = True - - sides = abs(int((self.Simple_endangle - self.Simple_startangle) / 90)) - - # get verts - if self.Simple_Type == 'Point': - verts = SimplePoint() - newSpline.use_cyclic_u = False - - if self.Simple_Type == 'Line': - verts = SimpleLine(self.Simple_startlocation, self.Simple_endlocation) - newSpline.use_cyclic_u = False - newCurve.dimensions = '3D' - - if self.Simple_Type == 'Distance': - verts = SimpleDistance(self.Simple_length, self.Simple_center) - newSpline.use_cyclic_u = False - - if self.Simple_Type == 'Angle': - verts = SimpleAngle(self.Simple_length, self.Simple_angle) - newSpline.use_cyclic_u = False - - if self.Simple_Type == 'Circle': - if self.Simple_sides < 4: - self.Simple_sides = 4 - verts = SimpleCircle(self.Simple_sides, self.Simple_radius) - newSpline.use_cyclic_u = True - - if self.Simple_Type == 'Ellipse': - verts = SimpleEllipse(self.Simple_a, self.Simple_b) - newSpline.use_cyclic_u = True - - if self.Simple_Type == 'Arc': - if self.Simple_sides < sides: - self.Simple_sides = sides - if self.Simple_radius == 0: - return {'FINISHED'} - verts = SimpleArc( - self.Simple_sides, self.Simple_radius, - self.Simple_startangle, self.Simple_endangle - ) - newSpline.use_cyclic_u = False - - if self.Simple_Type == 'Sector': - if self.Simple_sides < sides: - self.Simple_sides = sides - - if self.Simple_radius == 0: - return {'FINISHED'} - - verts = SimpleSector( - self.Simple_sides, self.Simple_radius, - self.Simple_startangle, self.Simple_endangle - ) - newSpline.use_cyclic_u = True - - if self.Simple_Type == 'Segment': - if self.Simple_sides < sides: - self.Simple_sides = sides - if self.Simple_a == 0 or self.Simple_b == 0: - return {'FINISHED'} - verts = SimpleSegment( - self.Simple_sides, self.Simple_a, self.Simple_b, - self.Simple_startangle, self.Simple_endangle - ) - newSpline.use_cyclic_u = True - - if self.Simple_Type == 'Rectangle': - verts = SimpleRectangle( - self.Simple_width, self.Simple_length, - self.Simple_rounded, self.Simple_center - ) - newSpline.use_cyclic_u = True - - if self.Simple_Type == 'Rhomb': - verts = SimpleRhomb( - self.Simple_width, self.Simple_length, self.Simple_center - ) - newSpline.use_cyclic_u = True - - if self.Simple_Type == 'Polygon': - if self.Simple_sides < 3: - self.Simple_sides = 3 - verts = SimplePolygon( - self.Simple_sides, self.Simple_radius - ) - newSpline.use_cyclic_u = True - - if self.Simple_Type == 'Polygon_ab': - if self.Simple_sides < 3: - self.Simple_sides = 3 - verts = SimplePolygon_ab( - self.Simple_sides, self.Simple_a, self.Simple_b - ) - newSpline.use_cyclic_u = True - - if self.Simple_Type == 'Trapezoid': - verts = SimpleTrapezoid( - self.Simple_a, self.Simple_b, self.Simple_h, self.Simple_center - ) - newSpline.use_cyclic_u = True - - vertArray = [] - for v in verts: - vertArray += v - - newSpline.bezier_points.add(int(len(vertArray) * 0.333333333)) - newSpline.bezier_points.foreach_set('co', vertArray) - - # create object with newCurve - SimpleCurve = bpy.data.objects.new(name, newCurve) # object - scene.objects.link(SimpleCurve) # place in active scene - SimpleCurve.select = True # set as selected - scene.objects.active = SimpleCurve # set as active - SimpleCurve.matrix_world = align_matrix # apply matrix - SimpleCurve.rotation_euler = self.Simple_rotation_euler - - all_points = [p for p in newSpline.bezier_points] - d = 2 * 0.27606262 - n = 0 - for p in all_points: - p.handle_right_type = 'VECTOR' - p.handle_left_type = 'VECTOR' - n += 1 - - if self.Simple_Type == 'Circle' or self.Simple_Type == 'Arc' or \ - self.Simple_Type == 'Sector' or self.Simple_Type == 'Segment' or \ - self.Simple_Type == 'Ellipse': - - for p in all_points: - p.handle_right_type = 'FREE' - p.handle_left_type = 'FREE' - - if self.Simple_Type == 'Circle': - i = 0 - for p1 in all_points: - if i != n - 1: - p2 = all_points[i + 1] - u1 = asin(p1.co.y / self.Simple_radius) - u2 = asin(p2.co.y / self.Simple_radius) - if p1.co.x > 0 and p2.co.x < 0: - u1 = acos(p1.co.x / self.Simple_radius) - u2 = acos(p2.co.x / self.Simple_radius) - elif p1.co.x < 0 and p2.co.x > 0: - u1 = acos(p1.co.x / self.Simple_radius) - u2 = acos(p2.co.x / self.Simple_radius) - u = u2 - u1 - if u < 0: - u = -u - l = 4 / 3 * tan(1 / 4 * u) * self.Simple_radius - v1 = Vector((-p1.co.y, p1.co.x, 0)) - v1.normalize() - v2 = Vector((-p2.co.y, p2.co.x, 0)) - v2.normalize() - vh1 = v1 * l - vh2 = v2 * l - v1 = Vector((p1.co.x, p1.co.y, 0)) + vh1 - v2 = Vector((p2.co.x, p2.co.y, 0)) - vh2 - p1.handle_right = v1 - p2.handle_left = v2 - if i == n - 1: - p2 = all_points[0] - u1 = asin(p1.co.y / self.Simple_radius) - u2 = asin(p2.co.y / self.Simple_radius) - if p1.co.x > 0 and p2.co.x < 0: - u1 = acos(p1.co.x / self.Simple_radius) - u2 = acos(p2.co.x / self.Simple_radius) - elif p1.co.x < 0 and p2.co.x > 0: - u1 = acos(p1.co.x / self.Simple_radius) - u2 = acos(p2.co.x / self.Simple_radius) - u = u2 - u1 - if u < 0: - u = -u - l = 4 / 3 * tan(1 / 4 * u) * self.Simple_radius - v1 = Vector((-p1.co.y, p1.co.x, 0)) - v1.normalize() - v2 = Vector((-p2.co.y, p2.co.x, 0)) - v2.normalize() - vh1 = v1 * l - vh2 = v2 * l - v1 = Vector((p1.co.x, p1.co.y, 0)) + vh1 - v2 = Vector((p2.co.x, p2.co.y, 0)) - vh2 - p1.handle_right = v1 - p2.handle_left = v2 - i += 1 - - if self.Simple_Type == 'Ellipse': - all_points[0].handle_right = Vector((self.Simple_a, self.Simple_b * d, 0)) - all_points[0].handle_left = Vector((self.Simple_a, -self.Simple_b * d, 0)) - all_points[1].handle_right = Vector((-self.Simple_a * d, self.Simple_b, 0)) - all_points[1].handle_left = Vector((self.Simple_a * d, self.Simple_b, 0)) - all_points[2].handle_right = Vector((-self.Simple_a, -self.Simple_b * d, 0)) - all_points[2].handle_left = Vector((-self.Simple_a, self.Simple_b * d, 0)) - all_points[3].handle_right = Vector((self.Simple_a * d, -self.Simple_b, 0)) - all_points[3].handle_left = Vector((-self.Simple_a * d, -self.Simple_b, 0)) - - if self.Simple_Type == 'Arc': - i = 0 - for p1 in all_points: - if i != n - 1: - p2 = all_points[i + 1] - u1 = asin(p1.co.y / self.Simple_radius) - u2 = asin(p2.co.y / self.Simple_radius) - if p1.co.x > 0 and p2.co.x < 0: - u1 = acos(p1.co.x / self.Simple_radius) - u2 = acos(p2.co.x / self.Simple_radius) - elif p1.co.x < 0 and p2.co.x > 0: - u1 = acos(p1.co.x / self.Simple_radius) - u2 = acos(p2.co.x / self.Simple_radius) - u = u2 - u1 - if u < 0: - u = -u - l = 4 / 3 * tan(1 / 4 * u) * self.Simple_radius - v1 = Vector((-p1.co.y, p1.co.x, 0)) - v1.normalize() - v2 = Vector((-p2.co.y, p2.co.x, 0)) - v2.normalize() - vh1 = v1 * l - vh2 = v2 * l - if self.Simple_startangle < self.Simple_endangle: - v1 = Vector((p1.co.x, p1.co.y, 0)) + vh1 - v2 = Vector((p2.co.x, p2.co.y, 0)) - vh2 - p1.handle_right = v1 - p2.handle_left = v2 - else: - v1 = Vector((p1.co.x, p1.co.y, 0)) - vh1 - v2 = Vector((p2.co.x, p2.co.y, 0)) + vh2 - p1.handle_right = v1 - p2.handle_left = v2 - i += 1 - - if self.Simple_Type == 'Sector': - i = 0 - for p1 in all_points: - if i == 0: - p1.handle_right_type = 'VECTOR' - p1.handle_left_type = 'VECTOR' - elif i != n - 1: - p2 = all_points[i + 1] - u1 = asin(p1.co.y / self.Simple_radius) - u2 = asin(p2.co.y / self.Simple_radius) - if p1.co.x > 0 and p2.co.x < 0: - u1 = acos(p1.co.x / self.Simple_radius) - u2 = acos(p2.co.x / self.Simple_radius) - elif p1.co.x < 0 and p2.co.x > 0: - u1 = acos(p1.co.x / self.Simple_radius) - u2 = acos(p2.co.x / self.Simple_radius) - u = u2 - u1 - if u < 0: - u = -u - l = 4 / 3 * tan(1 / 4 * u) * self.Simple_radius - v1 = Vector((-p1.co.y, p1.co.x, 0)) - v1.normalize() - v2 = Vector((-p2.co.y, p2.co.x, 0)) - v2.normalize() - vh1 = v1 * l - vh2 = v2 * l - if self.Simple_startangle < self.Simple_endangle: - v1 = Vector((p1.co.x, p1.co.y, 0)) + vh1 - v2 = Vector((p2.co.x, p2.co.y, 0)) - vh2 - p1.handle_right = v1 - p2.handle_left = v2 - else: - v1 = Vector((p1.co.x, p1.co.y, 0)) - vh1 - v2 = Vector((p2.co.x, p2.co.y, 0)) + vh2 - p1.handle_right = v1 - p2.handle_left = v2 - i += 1 - - if self.Simple_Type == 'Segment': - i = 0 - for p1 in all_points: - if i < n / 2 - 1: - p2 = all_points[i + 1] - u1 = asin(p1.co.y / self.Simple_a) - u2 = asin(p2.co.y / self.Simple_a) - if p1.co.x > 0 and p2.co.x < 0: - u1 = acos(p1.co.x / self.Simple_a) - u2 = acos(p2.co.x / self.Simple_a) - elif p1.co.x < 0 and p2.co.x > 0: - u1 = acos(p1.co.x / self.Simple_a) - u2 = acos(p2.co.x / self.Simple_a) - u = u2 - u1 - if u < 0: - u = -u - l = 4 / 3 * tan(1 / 4 * u) * self.Simple_a - v1 = Vector((-p1.co.y, p1.co.x, 0)) - v1.normalize() - v2 = Vector((-p2.co.y, p2.co.x, 0)) - v2.normalize() - vh1 = v1 * l - vh2 = v2 * l - if self.Simple_startangle < self.Simple_endangle: - v1 = Vector((p1.co.x, p1.co.y, 0)) + vh1 - v2 = Vector((p2.co.x, p2.co.y, 0)) - vh2 - p1.handle_right = v1 - p2.handle_left = v2 - else: - v1 = Vector((p1.co.x, p1.co.y, 0)) - vh1 - v2 = Vector((p2.co.x, p2.co.y, 0)) + vh2 - p1.handle_right = v1 - p2.handle_left = v2 - elif i != n / 2 - 1 and i != n - 1: - p2 = all_points[i + 1] - u1 = asin(p1.co.y / self.Simple_b) - u2 = asin(p2.co.y / self.Simple_b) - if p1.co.x > 0 and p2.co.x < 0: - u1 = acos(p1.co.x / self.Simple_b) - u2 = acos(p2.co.x / self.Simple_b) - elif p1.co.x < 0 and p2.co.x > 0: - u1 = acos(p1.co.x / self.Simple_b) - u2 = acos(p2.co.x / self.Simple_b) - u = u2 - u1 - if u < 0: - u = -u - l = 4 / 3 * tan(1 / 4 * u) * self.Simple_b - v1 = Vector((-p1.co.y, p1.co.x, 0)) - v1.normalize() - v2 = Vector((-p2.co.y, p2.co.x, 0)) - v2.normalize() - vh1 = v1 * l - vh2 = v2 * l - if self.Simple_startangle < self.Simple_endangle: - v1 = Vector((p1.co.x, p1.co.y, 0)) - vh1 - v2 = Vector((p2.co.x, p2.co.y, 0)) + vh2 - p1.handle_right = v1 - p2.handle_left = v2 - else: - v1 = Vector((p1.co.x, p1.co.y, 0)) + vh1 - v2 = Vector((p2.co.x, p2.co.y, 0)) - vh2 - p1.handle_right = v1 - p2.handle_left = v2 - - i += 1 - all_points[0].handle_left_type = 'VECTOR' - all_points[n - 1].handle_right_type = 'VECTOR' - all_points[int(n / 2) - 1].handle_right_type = 'VECTOR' - all_points[int(n / 2)].handle_left_type = 'VECTOR' - - SimpleCurve.s_curve.Simple = True - SimpleCurve.s_curve.Simple_Change = False - SimpleCurve.s_curve.Simple_Type = self.Simple_Type - SimpleCurve.s_curve.Simple_startlocation = self.Simple_startlocation - SimpleCurve.s_curve.Simple_endlocation = self.Simple_endlocation - SimpleCurve.s_curve.Simple_a = self.Simple_a - SimpleCurve.s_curve.Simple_b = self.Simple_b - SimpleCurve.s_curve.Simple_h = self.Simple_h - SimpleCurve.s_curve.Simple_angle = self.Simple_angle - SimpleCurve.s_curve.Simple_startangle = self.Simple_startangle - SimpleCurve.s_curve.Simple_endangle = self.Simple_endangle - SimpleCurve.s_curve.Simple_rotation_euler = self.Simple_rotation_euler - SimpleCurve.s_curve.Simple_sides = self.Simple_sides - SimpleCurve.s_curve.Simple_radius = self.Simple_radius - SimpleCurve.s_curve.Simple_center = self.Simple_center - SimpleCurve.s_curve.Simple_width = self.Simple_width - SimpleCurve.s_curve.Simple_length = self.Simple_length - SimpleCurve.s_curve.Simple_rounded = self.Simple_rounded - - bpy.ops.object.mode_set(mode='EDIT', toggle=True) - bpy.ops.curve.select_all(action='SELECT') - bpy.ops.object.mode_set(mode='OBJECT', toggle=True) - - return - - -# ------------------------------------------------------------ -# Delete simple curve - -def SimpleDelete(name): - if bpy.ops.object.mode_set.poll(): - bpy.ops.object.mode_set(mode='OBJECT') - - bpy.context.scene.objects.active = bpy.data.objects[name] - bpy.ops.object.delete() - - return - - -# ------------------------------------------------------------ -# Simple operator - -class Simple(Operator): - bl_idname = "curve.simple" - bl_label = "Simple Curve" - bl_description = "Construct a Simple Curve" - bl_options = {'REGISTER', 'UNDO'} - - # align_matrix for the invoke - align_matrix = Matrix() - - # change properties - Simple = BoolProperty( - name="Simple", - default=True, - description="Simple Curve" - ) - Simple_Change = BoolProperty( - name="Change", - default=False, - description="Change Simple Curve" - ) - Simple_Delete = StringProperty( - name="Delete", - description="Delete Simple Curve" - ) - # general properties - Types = [('Point', "Point", "Construct a Point"), - ('Line', "Line", "Construct a Line"), - ('Distance', "Distance", "Contruct a two point Distance"), - ('Angle', "Angle", "Construct an Angle"), - ('Circle', "Circle", "Construct a Circle"), - ('Ellipse', "Ellipse", "Construct an Ellipse"), - ('Arc', "Arc", "Construct an Arc"), - ('Sector', "Sector", "Construct a Sector"), - ('Segment', "Segment", "Construct a Segment"), - ('Rectangle', "Rectangle", "Construct a Rectangle"), - ('Rhomb', "Rhomb", "Construct a Rhomb"), - ('Polygon', "Polygon", "Construct a Polygon"), - ('Polygon_ab', "Polygon ab", "Construct a Polygon ab"), - ('Trapezoid', "Trapezoid", "Construct a Trapezoid") - ] - Simple_Type = EnumProperty( - name="Type", - description="Form of Curve to create", - items=Types - ) - # Line properties - Simple_startlocation = FloatVectorProperty( - name="", - description="Start location", - default=(0.0, 0.0, 0.0), - subtype='TRANSLATION' - ) - Simple_endlocation = FloatVectorProperty( - name="", - description="End location", - default=(2.0, 2.0, 2.0), - subtype='TRANSLATION' - ) - Simple_rotation_euler = FloatVectorProperty( - name="", - description="Rotation", - default=(0.0, 0.0, 0.0), - subtype='EULER' - ) - # Trapezoid properties - Simple_a = FloatProperty( - name="Side a", - default=2.0, - min=0.0, soft_min=0.0, - unit='LENGTH', - description="a side Value" - ) - Simple_b = FloatProperty( - name="Side b", - default=1.0, - min=0.0, soft_min=0.0, - unit='LENGTH', - description="b side Value" - ) - Simple_h = FloatProperty( - name="Height", - default=1.0, - unit='LENGTH', - description="Height of the Trapezoid - distance between a and b" - ) - Simple_angle = FloatProperty( - name="Angle", - default=45.0, - description="Angle" - ) - Simple_startangle = FloatProperty( - name="Start angle", - default=0.0, - min=-360.0, soft_min=-360.0, - max=360.0, soft_max=360.0, - description="Start angle" - ) - Simple_endangle = FloatProperty( - name="End angle", - default=45.0, - min=-360.0, soft_min=-360.0, - max=360.0, soft_max=360.0, - description="End angle" - ) - Simple_sides = IntProperty( - name="Sides", - default=3, - min=0, soft_min=0, - description="Sides" - ) - Simple_radius = FloatProperty( - name="Radius", - default=1.0, - min=0.0, soft_min=0.0, - unit='LENGTH', - description="Radius" - ) - Simple_center = BoolProperty( - name="Length center", - default=True, - description="Length center" - ) - - Angle_types = [('Degrees', "Degrees", "Use Degrees"), - ('Radians', "Radians", "Use Radians")] - Simple_degrees_or_radians = EnumProperty( - name="Degrees or radians", - description="Degrees or radians", - items=Angle_types - ) - # Rectangle properties - Simple_width = FloatProperty( - name="Width", - default=2.0, - min=0.0, soft_min=0, - unit='LENGTH', - description="Width" - ) - Simple_length = FloatProperty( - name="Length", - default=2.0, - min=0.0, soft_min=0.0, - unit='LENGTH', - description="Length" - ) - Simple_rounded = FloatProperty( - name="Rounded", - default=0.0, - min=0.0, soft_min=0.0, - unit='LENGTH', - description="Rounded corners" - ) - # Curve Options - shapeItems = [ - ('2D', "2D", "2D shape Curve"), - ('3D', "3D", "3D shape Curve")] - shape = EnumProperty( - name="2D / 3D", - items=shapeItems, - description="2D or 3D Curve" - ) - - def draw(self, context): - layout = self.layout - - # general options - col = layout.column() - col.prop(self, "Simple_Type") - - l = 0 - s = 0 - - if self.Simple_Type == 'Line': - box = layout.box() - col = box.column(align=True) - col.label(text=self.Simple_Type + " Options:") - col.prop(self, "Simple_endlocation") - v = Vector(self.Simple_endlocation) - Vector(self.Simple_startlocation) - l = v.length - - if self.Simple_Type == 'Distance': - box = layout.box() - col = box.column(align=True) - col.label(text=self.Simple_Type + " Options:") - col.prop(self, "Simple_length") - col.prop(self, "Simple_center") - l = self.Simple_length - - if self.Simple_Type == 'Angle': - box = layout.box() - col = box.column(align=True) - col.label(text=self.Simple_Type + " Options:") - col.prop(self, "Simple_length") - col.prop(self, "Simple_angle") - - row = layout.row() - row.prop(self, "Simple_degrees_or_radians", expand=True) - - if self.Simple_Type == 'Circle': - box = layout.box() - col = box.column(align=True) - col.label(text=self.Simple_Type + " Options:") - col.prop(self, "Simple_sides") - col.prop(self, "Simple_radius") - - l = 2 * pi * abs(self.Simple_radius) - s = pi * self.Simple_radius * self.Simple_radius - - if self.Simple_Type == 'Ellipse': - box = layout.box() - col = box.column(align=True) - col.label(text=self.Simple_Type + " Options:") - col.prop(self, "Simple_a", text="Radius a") - col.prop(self, "Simple_b", text="Radius b") - - l = pi * (3 * (self.Simple_a + self.Simple_b) - - sqrt((3 * self.Simple_a + self.Simple_b) * - (self.Simple_a + 3 * self.Simple_b))) - - s = pi * abs(self.Simple_b) * abs(self.Simple_a) - - if self.Simple_Type == 'Arc': - box = layout.box() - col = box.column(align=True) - col.label(text=self.Simple_Type + " Options:") - col.prop(self, "Simple_sides") - col.prop(self, "Simple_radius") - - col = box.column(align=True) - col.prop(self, "Simple_startangle") - col.prop(self, "Simple_endangle") - row = layout.row() - row.prop(self, "Simple_degrees_or_radians", expand=True) - - l = abs(pi * self.Simple_radius * (self.Simple_endangle - self.Simple_startangle) / 180) - - if self.Simple_Type == 'Sector': - box = layout.box() - col = box.column(align=True) - col.label(text=self.Simple_Type + " Options:") - col.prop(self, "Simple_sides") - col.prop(self, "Simple_radius") - - col = box.column(align=True) - col.prop(self, "Simple_startangle") - col.prop(self, "Simple_endangle") - row = layout.row() - row.prop(self, "Simple_degrees_or_radians", expand=True) - - l = abs(pi * self.Simple_radius * - (self.Simple_endangle - self.Simple_startangle) / 180) + self.Simple_radius * 2 - - s = pi * self.Simple_radius * self.Simple_radius * \ - abs(self.Simple_endangle - self.Simple_startangle) / 360 - - if self.Simple_Type == 'Segment': - box = layout.box() - col = box.column(align=True) - col.label(text=self.Simple_Type + " Options:") - col.prop(self, "Simple_sides") - col.prop(self, "Simple_a", text="Radius a") - col.prop(self, "Simple_b", text="Radius b") - - col = box.column(align=True) - col.prop(self, "Simple_startangle") - col.prop(self, "Simple_endangle") - - row = layout.row() - row.prop(self, "Simple_degrees_or_radians", expand=True) - - la = abs(pi * self.Simple_a * (self.Simple_endangle - self.Simple_startangle) / 180) - lb = abs(pi * self.Simple_b * (self.Simple_endangle - self.Simple_startangle) / 180) - l = abs(self.Simple_a - self.Simple_b) * 2 + la + lb - - sa = pi * self.Simple_a * self.Simple_a * \ - abs(self.Simple_endangle - self.Simple_startangle) / 360 - - sb = pi * self.Simple_b * self.Simple_b * \ - abs(self.Simple_endangle - self.Simple_startangle) / 360 - - s = abs(sa - sb) - - if self.Simple_Type == 'Rectangle': - box = layout.box() - col = box.column(align=True) - col.label(text=self.Simple_Type + " Options:") - col.prop(self, "Simple_width") - col.prop(self, "Simple_length") - col.prop(self, "Simple_rounded") - - box.prop(self, "Simple_center") - l = 2 * abs(self.Simple_width) + 2 * abs(self.Simple_length) - s = abs(self.Simple_width) * abs(self.Simple_length) - - if self.Simple_Type == 'Rhomb': - box = layout.box() - col = box.column(align=True) - col.label(text=self.Simple_Type + " Options:") - col.prop(self, "Simple_width") - col.prop(self, "Simple_length") - col.prop(self, "Simple_center") - - g = hypot(self.Simple_width / 2, self.Simple_length / 2) - l = 4 * g - s = self.Simple_width * self.Simple_length / 2 - - if self.Simple_Type == 'Polygon': - box = layout.box() - col = box.column(align=True) - col.label(text=self.Simple_Type + " Options:") - col.prop(self, "Simple_sides") - col.prop(self, "Simple_radius") - - if self.Simple_Type == 'Polygon_ab': - box = layout.box() - col = box.column(align=True) - col.label(text="Polygon ab Options:") - col.prop(self, "Simple_sides") - col.prop(self, "Simple_a") - col.prop(self, "Simple_b") - - if self.Simple_Type == 'Trapezoid': - box = layout.box() - col = box.column(align=True) - col.label(text=self.Simple_Type + " Options:") - col.prop(self, "Simple_a") - col.prop(self, "Simple_b") - col.prop(self, "Simple_h") - - box.prop(self, "Simple_center") - g = hypot(self.Simple_h, (self.Simple_a - self.Simple_b) / 2) - l = self.Simple_a + self.Simple_b + g * 2 - s = (abs(self.Simple_a) + abs(self.Simple_b)) / 2 * self.Simple_h - - row = layout.row() - row.prop(self, "shape", expand=True) - box = layout.box() - box.label("Location:") - box.prop(self, "Simple_startlocation") - box = layout.box() - box.label("Rotation:") - box.prop(self, "Simple_rotation_euler") - - if l != 0 or s != 0: - box = layout.box() - box.label(text="Statistics:", icon="INFO") - if l != 0: - l_str = str(round(l, 4)) - box.label("Length: " + l_str) - if s != 0: - s_str = str(round(s, 4)) - box.label("Area: " + s_str) - - @classmethod - def poll(cls, context): - return context.scene is not None - - def execute(self, context): - if self.Simple_Change: - SimpleDelete(self.Simple_Delete) - - # go to object mode - if bpy.ops.object.mode_set.poll(): - bpy.ops.object.mode_set(mode='OBJECT') - - # turn off undo - undo = bpy.context.user_preferences.edit.use_global_undo - bpy.context.user_preferences.edit.use_global_undo = False - - # main function - self.align_matrix = align_matrix(context, self.Simple_startlocation) - main(context, self, self.align_matrix) - - # restore pre operator undo state - bpy.context.user_preferences.edit.use_global_undo = undo - - return {'FINISHED'} - - def invoke(self, context, event): - # store creation_matrix - if self.Simple_Change: - bpy.context.scene.cursor_location = self.Simple_startlocation - else: - self.Simple_startlocation = bpy.context.scene.cursor_location - - self.align_matrix = align_matrix(context, self.Simple_startlocation) - self.execute(context) - - return {'FINISHED'} - - -# ------------------------------------------------------------ -# Fillet - -class BezierPointsFillet(Operator): - bl_idname = "curve.bezier_points_fillet" - bl_label = "Bezier points Fillet" - bl_description = "Bezier points Fillet" - bl_options = {'REGISTER', 'UNDO'} - - Fillet_radius = FloatProperty( - name="Radius", - default=0.25, - unit='LENGTH', - description="Radius" - ) - Types = [('Round', "Round", "Round"), - ('Chamfer', "Chamfer", "Chamfer")] - Fillet_Type = EnumProperty( - name="Type", - description="Fillet type", - items=Types - ) - - def draw(self, context): - layout = self.layout - - # general options - col = layout.column() - col.prop(self, "Fillet_radius") - col.prop(self, "Fillet_Type", expand=True) - - @classmethod - def poll(cls, context): - return context.scene is not None - - def execute(self, context): - # go to object mode - if bpy.ops.object.mode_set.poll(): - bpy.ops.object.mode_set(mode='OBJECT') - bpy.ops.object.mode_set(mode='EDIT') - - # turn off undo - undo = bpy.context.user_preferences.edit.use_global_undo - bpy.context.user_preferences.edit.use_global_undo = False - - # main function - spline = bpy.context.object.data.splines.active - selected = [p for p in spline.bezier_points if p.select_control_point] - - bpy.ops.curve.handle_type_set(type='VECTOR') - n = 0 - ii = [] - for p in spline.bezier_points: - if p.select_control_point: - ii.append(n) - n += 1 - else: - n += 1 - - if n > 2: - jn = 0 - for j in ii: - - j += jn - - selected_all = [p for p in spline.bezier_points] - - bpy.ops.curve.select_all(action='DESELECT') - - if j != 0 and j != n - 1: - selected_all[j].select_control_point = True - selected_all[j + 1].select_control_point = True - bpy.ops.curve.subdivide() - selected_all = [p for p in spline.bezier_points] - selected4 = [selected_all[j - 1], selected_all[j], - selected_all[j + 1], selected_all[j + 2]] - jn += 1 - n += 1 - - elif j == 0: - selected_all[j].select_control_point = True - selected_all[j + 1].select_control_point = True - bpy.ops.curve.subdivide() - selected_all = [p for p in spline.bezier_points] - selected4 = [selected_all[n], selected_all[0], - selected_all[1], selected_all[2]] - jn += 1 - n += 1 - - elif j == n - 1: - selected_all[j].select_control_point = True - selected_all[j - 1].select_control_point = True - bpy.ops.curve.subdivide() - selected_all = [p for p in spline.bezier_points] - selected4 = [selected_all[0], selected_all[n], - selected_all[n - 1], selected_all[n - 2]] - - selected4[2].co = selected4[1].co - s1 = Vector(selected4[0].co) - Vector(selected4[1].co) - s2 = Vector(selected4[3].co) - Vector(selected4[2].co) - s1.normalize() - s11 = Vector(selected4[1].co) + s1 * self.Fillet_radius - selected4[1].co = s11 - s2.normalize() - s22 = Vector(selected4[2].co) + s2 * self.Fillet_radius - selected4[2].co = s22 - - if self.Fillet_Type == 'Round': - if j != n - 1: - selected4[2].handle_right_type = 'VECTOR' - selected4[1].handle_left_type = 'VECTOR' - selected4[1].handle_right_type = 'ALIGNED' - selected4[2].handle_left_type = 'ALIGNED' - else: - selected4[1].handle_right_type = 'VECTOR' - selected4[2].handle_left_type = 'VECTOR' - selected4[2].handle_right_type = 'ALIGNED' - selected4[1].handle_left_type = 'ALIGNED' - if self.Fillet_Type == 'Chamfer': - selected4[2].handle_right_type = 'VECTOR' - selected4[1].handle_left_type = 'VECTOR' - selected4[1].handle_right_type = 'VECTOR' - selected4[2].handle_left_type = 'VECTOR' - - bpy.ops.curve.select_all(action='SELECT') - bpy.ops.curve.spline_type_set(type='BEZIER') - - # restore pre operator undo state - bpy.context.user_preferences.edit.use_global_undo = undo - - return {'FINISHED'} - - def invoke(self, context, event): - self.execute(context) - - return {'FINISHED'} - - -def subdivide_cubic_bezier(p1, p2, p3, p4, t): - p12 = (p2 - p1) * t + p1 - p23 = (p3 - p2) * t + p2 - p34 = (p4 - p3) * t + p3 - p123 = (p23 - p12) * t + p12 - p234 = (p34 - p23) * t + p23 - p1234 = (p234 - p123) * t + p123 - return [p12, p123, p1234, p234, p34] - - -# ------------------------------------------------------------ -# BezierDivide Operator - -class BezierDivide(Operator): - bl_idname = "curve.bezier_spline_divide" - bl_label = "Bezier Spline Divide" - bl_description = "Bezier Divide (enters edit mode) for Fillet Curves" - bl_options = {'REGISTER', 'UNDO'} - - # align_matrix for the invoke - align_matrix = Matrix() - - Bezier_t = FloatProperty( - name="t (0% - 100%)", - default=50.0, - min=0.0, soft_min=0.0, - max=100.0, soft_max=100.0, - description="t (0% - 100%)" - ) - - @classmethod - def poll(cls, context): - return context.scene is not None - - def execute(self, context): - # go to object mode - if bpy.ops.object.mode_set.poll(): - bpy.ops.object.mode_set(mode='OBJECT') - bpy.ops.object.mode_set(mode='EDIT') - - # turn off undo - undo = bpy.context.user_preferences.edit.use_global_undo - bpy.context.user_preferences.edit.use_global_undo = False - - # main function - spline = bpy.context.object.data.splines.active - selected_all = [p for p in spline.bezier_points if p.select_control_point] - h = subdivide_cubic_bezier( - selected_all[0].co, selected_all[0].handle_right, - selected_all[1].handle_left, selected_all[1].co, self.Bezier_t / 100 - ) - - selected_all[0].handle_right_type = 'FREE' - selected_all[0].handle_left_type = 'FREE' - selected_all[1].handle_right_type = 'FREE' - selected_all[1].handle_left_type = 'FREE' - bpy.ops.curve.subdivide(1) - selected_all = [p for p in spline.bezier_points if p.select_control_point] - - selected_all[0].handle_right = h[0] - selected_all[1].co = h[2] - selected_all[1].handle_left = h[1] - selected_all[1].handle_right = h[3] - selected_all[2].handle_left = h[4] - - # restore pre operator undo state - bpy.context.user_preferences.edit.use_global_undo = undo - - return {'FINISHED'} - - def invoke(self, context, event): - self.execute(context) - - return {'FINISHED'} - - -# ------------------------------------------------------------ -# Simple change panel - -class SimplePanel(Panel): - bl_label = "Simple Curve" - bl_space_type = "VIEW_3D" - bl_region_type = "TOOLS" - bl_options = {'DEFAULT_CLOSED'} - bl_category = "Tools" - - @classmethod - def poll(cls, context): - if not context.active_object: - pass - elif context.object.s_curve.Simple is True: - return (context.object) - - def draw(self, context): - if context.object.s_curve.Simple is True: - layout = self.layout - obj = context.object - row = layout.row() - - simple_change = row.operator("curve.simple", text="Change", - icon="OUTLINER_DATA_CURVE") - simple_change.Simple_Change = True - simple_change.Simple_Delete = obj.name - simple_change.Simple_Type = obj.s_curve.Simple_Type - simple_change.Simple_startlocation = obj.location - simple_change.Simple_endlocation = obj.s_curve.Simple_endlocation - - simple_change.Simple_a = obj.s_curve.Simple_a - simple_change.Simple_b = obj.s_curve.Simple_b - simple_change.Simple_h = obj.s_curve.Simple_h - - simple_change.Simple_angle = obj.s_curve.Simple_angle - simple_change.Simple_startangle = obj.s_curve.Simple_startangle - simple_change.Simple_endangle = obj.s_curve.Simple_endangle - simple_change.Simple_rotation_euler = obj.rotation_euler - - simple_change.Simple_sides = obj.s_curve.Simple_sides - simple_change.Simple_radius = obj.s_curve.Simple_radius - simple_change.Simple_center = obj.s_curve.Simple_center - simple_change.Simple_width = obj.s_curve.Simple_width - simple_change.Simple_length = obj.s_curve.Simple_length - simple_change.Simple_rounded = obj.s_curve.Simple_rounded - - -# ------------------------------------------------------------ -# Fillet tools panel - -class SimpleEdit(Operator): - bl_idname = "object._simple_edit" - bl_label = "Create Curves" - bl_description = "Subdivide and Fillet Curves" - bl_options = {'REGISTER', 'UNDO'} - - @classmethod - def poll(cls, context): - vertex = [] - nselected = [] - n = 0 - obj = context.active_object - if obj is not None: - if obj.type == 'CURVE': - for i in obj.data.splines: - for j in i.bezier_points: - n += 1 - if j.select_control_point: - nselected.append(n) - vertex.append(obj.matrix_world * j.co) - - if len(vertex) > 0 and n > 2: - return (context.active_object) - if len(vertex) == 2 and abs(nselected[0] - nselected[1]) == 1: - return (context.active_object) - - selected = 0 - for obj in context.selected_objects: - if obj.type == 'CURVE': - selected += 1 - - if selected >= 2: - return (context.selected_objects) - - def draw(self, context): - vertex = [] - selected = [] - n = 0 - obj = context.active_object - if obj is not None: - if obj.type == 'CURVE': - for i in obj.data.splines: - for j in i.bezier_points: - n += 1 - if j.select_control_point: - selected.append(n) - vertex.append(obj.matrix_world * j.co) - - if len(vertex) > 0 and n > 2: - layout = self.layout - row = layout.row() - row.operator("curve.bezier_points_fillet", text="Fillet") - - if len(vertex) == 2 and abs(selected[0] - selected[1]) == 1: - layout = self.layout - row = layout.row() - row.operator("curve.bezier_spline_divide", text="Divide") - - -# ------------------------------------------------------------ -# location update - -def StartLocationUpdate(self, context): - - bpy.context.scene.cursor_location = self.Simple_startlocation - return - - -# ------------------------------------------------------------ -# Add properties to objects - -class SimpleVariables(PropertyGroup): - - Simple = BoolProperty() - Simple_Change = BoolProperty() - - # general properties - Types = [('Point', "Point", "Construct a Point"), - ('Line', "Line", "Construct a Line"), - ('Distance', "Distance", "Contruct a two point Distance"), - ('Angle', "Angle", "Construct an Angle"), - ('Circle', "Circle", "Construct a Circle"), - ('Ellipse', "Ellipse", "Construct an Ellipse"), - ('Arc', "Arc", "Construct an Arc"), - ('Sector', "Sector", "Construct a Sector"), - ('Segment', "Segment", "Construct a Segment"), - ('Rectangle', "Rectangle", "Construct a Rectangle"), - ('Rhomb', "Rhomb", "Construct a Rhomb"), - ('Polygon', "Polygon", "Construct a Polygon"), - ('Polygon_ab', "Polygon ab", "Construct a Polygon ab"), - ('Trapezoid', "Trapezoid", "Construct a Trapezoid") - ] - Simple_Type = EnumProperty( - name="Type", - description="Form of Curve to create", - items=Types - ) - # Line properties - Simple_startlocation = FloatVectorProperty( - name="Start location", - description="Start location", - default=(0.0, 0.0, 0.0), - subtype='TRANSLATION', - update=StartLocationUpdate - ) - Simple_endlocation = FloatVectorProperty( - name="End location", - description="End location", - default=(2.0, 2.0, 2.0), - subtype='TRANSLATION' - ) - Simple_rotation_euler = FloatVectorProperty( - name="Rotation", - description="Rotation", - default=(0.0, 0.0, 0.0), - subtype='EULER' - ) - # Trapezoid properties - Simple_a = FloatProperty( - name="Side a", - default=2.0, - min=0.0, soft_min=0.0, - unit='LENGTH', - description="a side Value" - ) - Simple_b = FloatProperty( - name="Side b", - default=1.0, - min=0.0, soft_min=0.0, - unit='LENGTH', - description="b side Value" - ) - Simple_h = FloatProperty( - name="Height", - default=1.0, - unit='LENGTH', - description="Height of the Trapezoid - distance between a and b" - ) - Simple_angle = FloatProperty( - name="Angle", - default=45.0, - description="Angle" - ) - Simple_startangle = FloatProperty( - name="Start angle", - default=0.0, - min=-360.0, soft_min=-360.0, - max=360.0, soft_max=360.0, - description="Start angle" - ) - Simple_endangle = FloatProperty( - name="End angle", - default=45.0, - min=-360.0, soft_min=-360.0, - max=360.0, soft_max=360.0, - description="End angle" - ) - Simple_sides = IntProperty( - name="Sides", - default=3, - min=3, soft_min=3, - description="Number of Sides" - ) - Simple_radius = FloatProperty( - name="Radius", - default=1.0, - min=0.0, soft_min=0.0, - unit='LENGTH', - description="Radius" - ) - Simple_center = BoolProperty( - name="Length center", - default=True, - description="Length center" - ) - # Rectangle properties - Simple_width = FloatProperty( - name="Width", - default=2.0, - min=0.0, soft_min=0.0, - unit='LENGTH', - description="Width" - ) - Simple_length = FloatProperty( - name="Length", - default=2.0, - min=0.0, soft_min=0.0, - unit='LENGTH', - description="Length" - ) - Simple_rounded = FloatProperty( - name="Rounded", - default=0.0, - unit='LENGTH', - description="Rounded corners" - ) - - -class INFO_MT_simple_menu(Menu): - bl_idname = "INFO_MT_simple_menu" - bl_label = "2D Objects" - - def draw(self, context): - self.layout.operator_context = 'INVOKE_REGION_WIN' - - oper1 = self.layout.operator(Simple.bl_idname, text="Angle", icon="MOD_CURVE") - oper1.Simple_Change = False - oper1.Simple_Type = "Angle" - - oper2 = self.layout.operator(Simple.bl_idname, text="Arc", icon="MOD_CURVE") - oper2.Simple_Change = False - oper2.Simple_Type = "Arc" - - oper3 = self.layout.operator(Simple.bl_idname, text="Circle", icon="MOD_CURVE") - oper3.Simple_Change = False - oper3.Simple_Type = "Circle" - - oper4 = self.layout.operator(Simple.bl_idname, text="Distance", icon="MOD_CURVE") - oper4.Simple_Change = False - oper4.Simple_Type = "Distance" - - oper5 = self.layout.operator(Simple.bl_idname, text="Ellipse", icon="MOD_CURVE") - oper5.Simple_Change = False - oper5.Simple_Type = "Ellipse" - - oper6 = self.layout.operator(Simple.bl_idname, text="Line", icon="MOD_CURVE") - oper6.Simple_Change = False - oper6.Simple_Type = "Line" - - oper7 = self.layout.operator(Simple.bl_idname, text="Point", icon="MOD_CURVE") - oper7.Simple_Change = False - oper7.Simple_Type = "Point" - - oper8 = self.layout.operator(Simple.bl_idname, text="Polygon", icon="MOD_CURVE") - oper8.Simple_Change = False - oper8.Simple_Type = "Polygon" - - oper9 = self.layout.operator(Simple.bl_idname, text="Polygon ab", icon="MOD_CURVE") - oper9.Simple_Change = False - oper9.Simple_Type = "Polygon_ab" - - oper10 = self.layout.operator(Simple.bl_idname, text="Rectangle", icon="MOD_CURVE") - oper10.Simple_Change = False - oper10.Simple_Type = "Rectangle" - - oper11 = self.layout.operator(Simple.bl_idname, text="Rhomb", icon="MOD_CURVE") - oper11.Simple_Change = False - oper11.Simple_Type = "Rhomb" - - oper12 = self.layout.operator(Simple.bl_idname, text="Sector", icon="MOD_CURVE") - oper12.Simple_Change = False - oper12.Simple_Type = "Sector" - - oper13 = self.layout.operator(Simple.bl_idname, text="Segment", icon="MOD_CURVE") - oper13.Simple_Change = False - oper13.Simple_Type = "Segment" - - oper14 = self.layout.operator(Simple.bl_idname, text="Trapezoid", icon="MOD_CURVE") - oper14.Simple_Change = False - oper14.Simple_Type = "Trapezoid" - - -# Register - -def Simple_button(self, context): - layout = self.layout - layout.separator() - self.layout.menu("INFO_MT_simple_menu", icon="MOD_CURVE") - - -def register(): - bpy.utils.register_class(Simple) - bpy.utils.register_class(BezierPointsFillet) - bpy.utils.register_class(BezierDivide) - bpy.utils.register_class(SimplePanel) - bpy.utils.register_class(SimpleEdit) - bpy.utils.register_class(INFO_MT_simple_menu) - bpy.utils.register_class(SimpleVariables) - - bpy.types.INFO_MT_curve_add.append(Simple_button) - - bpy.types.Object.s_curve = PointerProperty(type=SimpleVariables) - - -def unregister(): - bpy.utils.unregister_class(Simple) - bpy.utils.unregister_class(BezierPointsFillet) - bpy.utils.unregister_class(BezierDivide) - bpy.utils.unregister_class(SimplePanel) - bpy.utils.unregister_class(SimpleEdit) - bpy.utils.unregister_class(INFO_MT_simple_menu) - bpy.utils.unregister_class(SimpleVariables) - - bpy.types.INFO_MT_curve_add.remove(Simple_button) - del bpy.types.Object.s_curve - - -if __name__ == "__main__": - register() diff --git a/tests/test_helpers/addons/add_curve_extra_objects/add_curve_spirals.py b/tests/test_helpers/addons/add_curve_extra_objects/add_curve_spirals.py deleted file mode 100644 index 522f637..0000000 --- a/tests/test_helpers/addons/add_curve_extra_objects/add_curve_spirals.py +++ /dev/null @@ -1,424 +0,0 @@ -# gpl: author Alejandro Omar Chocano Vasquez - -""" -bl_info = { - "name": "Spirals", - "description": "Make spirals", - "author": "Alejandro Omar Chocano Vasquez", - "version": (1, 2, 1), - "blender": (2, 62, 0), - "location": "View3D > Add > Curve", - "warning": "", - "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.4/Py/" - "Scripts/Object/Spirals", - "tracker_url": "http://alexvaqp.googlepages.com?" - "func=detail&aid=", - "category": "Add Curve", -} -""" - -import bpy -import time -from bpy.props import ( - EnumProperty, - BoolProperty, - FloatProperty, - IntProperty, - ) -from math import ( - sin, cos, pi - ) -from bpy_extras.object_utils import object_data_add -from bpy.types import ( - Operator, - Menu, - ) -from bl_operators.presets import AddPresetBase - - -# make normal spiral -# ---------------------------------------------------------------------------- - -def make_spiral(props, context): - # archemedian and logarithmic can be plotted in cylindrical coordinates - - # INPUT: turns->degree->max_phi, steps, direction - # Initialise Polar Coordinate Enviroment - props.degree = 360 * props.turns # If you want to make the slider for degree - steps = props.steps * props.turns # props.steps[per turn] -> steps[for the whole spiral] - props.z_scale = props.dif_z * props.turns - - max_phi = pi * props.degree / 180 # max angle in radian - step_phi = max_phi / steps # angle in radians between two vertices - - if props.spiral_direction == 'CLOCKWISE': - step_phi *= -1 # flip direction - max_phi *= -1 - - step_z = props.z_scale / (steps - 1) # z increase in one step - - verts = [] - verts.extend([props.radius, 0, 0, 1]) - - cur_phi = 0 - cur_z = 0 - - # Archemedean: dif_radius, radius - cur_rad = props.radius - step_rad = props.dif_radius / (steps * 360 / props.degree) - # radius increase per angle for archemedean spiral| - # (steps * 360/props.degree)...Steps needed for 360 deg - # Logarithmic: radius, B_force, ang_div, dif_z - - while abs(cur_phi) <= abs(max_phi): - cur_phi += step_phi - cur_z += step_z - - if props.spiral_type == 'ARCH': - cur_rad += step_rad - if props.spiral_type == 'LOG': - # r = a*e^{|theta| * b} - cur_rad = props.radius * pow(props.B_force, abs(cur_phi)) - - px = cur_rad * cos(cur_phi) - py = cur_rad * sin(cur_phi) - verts.extend([px, py, cur_z, 1]) - - return verts - - -# make Spheric spiral -# ---------------------------------------------------------------------------- - -def make_spiral_spheric(props, context): - # INPUT: turns, steps[per turn], radius - # use spherical Coordinates - step_phi = (2 * pi) / props.steps # Step of angle in radians for one turn - steps = props.steps * props.turns # props.steps[per turn] -> steps[for the whole spiral] - - max_phi = 2 * pi * props.turns # max angle in radian - step_phi = max_phi / steps # angle in radians between two vertices - if props.spiral_direction == 'CLOCKWISE': # flip direction - step_phi *= -1 - max_phi *= -1 - step_theta = pi / (steps - 1) # theta increase in one step (pi == 180 deg) - - verts = [] - verts.extend([0, 0, -props.radius, 1]) # First vertex at south pole - - cur_phi = 0 - cur_theta = -pi / 2 # Beginning at south pole - - while abs(cur_phi) <= abs(max_phi): - # Coordinate Transformation sphere->rect - px = props.radius * cos(cur_theta) * cos(cur_phi) - py = props.radius * cos(cur_theta) * sin(cur_phi) - pz = props.radius * sin(cur_theta) - - verts.extend([px, py, pz, 1]) - cur_theta += step_theta - cur_phi += step_phi - - return verts - - -# make torus spiral -# ---------------------------------------------------------------------------- - -def make_spiral_torus(props, context): - # INPUT: turns, steps, inner_radius, curves_number, - # mul_height, dif_inner_radius, cycles - max_phi = 2 * pi * props.turns * props.cycles # max angle in radian - step_phi = 2 * pi / props.steps # Step of angle in radians between two vertices - - if props.spiral_direction == 'CLOCKWISE': # flip direction - step_phi *= -1 - max_phi *= -1 - - step_theta = (2 * pi / props.turns) / props.steps - step_rad = props.dif_radius / (props.steps * props.turns) - step_inner_rad = props.dif_inner_radius / props.steps - step_z = props.dif_z / (props.steps * props.turns) - - verts = [] - - cur_phi = 0 # Inner Ring Radius Angle - cur_theta = 0 # Ring Radius Angle - cur_rad = props.radius - cur_inner_rad = props.inner_radius - cur_z = 0 - n_cycle = 0 - - while abs(cur_phi) <= abs(max_phi): - # Torus Coordinates -> Rect - px = (cur_rad + cur_inner_rad * cos(cur_phi)) * \ - cos(props.curves_number * cur_theta) - py = (cur_rad + cur_inner_rad * cos(cur_phi)) * \ - sin(props.curves_number * cur_theta) - pz = cur_inner_rad * sin(cur_phi) + cur_z - - verts.extend([px, py, pz, 1]) - - if props.touch and cur_phi >= n_cycle * 2 * pi: - step_z = ((n_cycle + 1) * props.dif_inner_radius + - props.inner_radius) * 2 / (props.steps * props.turns) - n_cycle += 1 - - cur_theta += step_theta - cur_phi += step_phi - cur_rad += step_rad - cur_inner_rad += step_inner_rad - cur_z += step_z - - return verts - - -def draw_curve(props, context): - if props.spiral_type == 'ARCH': - verts = make_spiral(props, context) - if props.spiral_type == 'LOG': - verts = make_spiral(props, context) - if props.spiral_type == 'SPHERE': - verts = make_spiral_spheric(props, context) - if props.spiral_type == 'TORUS': - verts = make_spiral_torus(props, context) - - curve_data = bpy.data.curves.new(name='Spiral', type='CURVE') - curve_data.dimensions = '3D' - - spline = curve_data.splines.new(type=props.curve_type) - """ - if props.curve_type == 0: - spline = curve_data.splines.new(type='POLY') - elif props.curve_type == 1: - spline = curve_data.splines.new(type='NURBS') - """ - spline.points.add(len(verts) * 0.25 - 1) - # Add only one quarter of points as elements in verts, - # because verts looks like: "x,y,z,?,x,y,z,?,x,..." - spline.points.foreach_set('co', verts) - new_obj = object_data_add(context, curve_data) - - -class CURVE_OT_spirals(Operator): - bl_idname = "curve.spirals" - bl_label = "Curve Spirals" - bl_description = "Create different types of spirals" - bl_options = {'REGISTER', 'UNDO'} - - spiral_type = EnumProperty( - items=[('ARCH', "Archemedian", "Archemedian"), - ("LOG", "Logarithmic", "Logarithmic"), - ("SPHERE", "Spheric", "Spheric"), - ("TORUS", "Torus", "Torus")], - default='ARCH', - name="Spiral Type", - description="Type of spiral to add" - ) - curve_type = EnumProperty( - items=[('POLY', "Poly", "PolyLine"), - ("NURBS", "NURBS", "NURBS")], - default='POLY', - name="Curve Type", - description="Type of spline to use" - ) - spiral_direction = EnumProperty( - items=[('COUNTER_CLOCKWISE', "Counter Clockwise", - "Wind in a counter clockwise direction"), - ("CLOCKWISE", "Clockwise", - "Wind in a clockwise direction")], - default='COUNTER_CLOCKWISE', - name="Spiral Direction", - description="Direction of winding" - ) - turns = IntProperty( - default=1, - min=1, max=1000, - description="Length of Spiral in 360 deg" - ) - steps = IntProperty( - default=24, - min=2, max=1000, - description="Number of Vertices per turn" - ) - radius = FloatProperty( - default=1.00, - min=0.00, max=100.00, - description="Radius for first turn" - ) - dif_z = FloatProperty( - default=0, - min=-10.00, max=100.00, - description="Increase in Z axis per turn" - ) - # needed for 1 and 2 spiral_type - # Archemedian variables - dif_radius = FloatProperty( - default=0.00, - min=-50.00, max=50.00, - description="Radius increment in each turn" - ) - # step between turns(one turn equals 360 deg) - # Log variables - B_force = FloatProperty( - default=1.00, - min=0.00, max=30.00, - description="Factor of exponent" - ) - # Torus variables - inner_radius = FloatProperty( - default=0.20, - min=0.00, max=100, - description="Inner Radius of Torus" - ) - dif_inner_radius = FloatProperty( - default=0, - min=-10, max=100, - description="Increase of inner Radius per Cycle" - ) - dif_radius = FloatProperty( - default=0, - min=-10, max=100, - description="Increase of Torus Radius per Cycle" - ) - cycles = FloatProperty( - default=1, - min=0.00, max=1000, - description="Number of Cycles" - ) - curves_number = IntProperty( - default=1, - min=1, max=400, - description="Number of curves of spiral" - ) - touch = BoolProperty( - default=False, - description="No empty spaces between cycles" - ) - - def draw(self, context): - layout = self.layout - col = layout.column_flow(align=True) - - col.label("Presets:") - - row = col.row(align=True) - row.menu("OBJECT_MT_spiral_curve_presets", - text=bpy.types.OBJECT_MT_spiral_curve_presets.bl_label) - row.operator("curve_extras.spiral_presets", text="", icon='ZOOMIN') - op = row.operator("curve_extras.spiral_presets", text="", icon='ZOOMOUT') - op.remove_active = True - - layout.prop(self, "spiral_type") - layout.prop(self, "curve_type") - layout.prop(self, "spiral_direction") - - col = layout.column(align=True) - col.label(text="Spiral Parameters:") - col.prop(self, "turns", text="Turns") - col.prop(self, "steps", text="Steps") - - box = layout.box() - if self.spiral_type == 'ARCH': - box.label("Archemedian Settings:") - col = box.column(align=True) - col.prop(self, "dif_radius", text="Radius Growth") - col.prop(self, "radius", text="Radius") - col.prop(self, "dif_z", text="Height") - - if self.spiral_type == 'LOG': - box.label("Logarithmic Settings:") - col = box.column(align=True) - col.prop(self, "radius", text="Radius") - col.prop(self, "B_force", text="Expansion Force") - col.prop(self, "dif_z", text="Height") - - if self.spiral_type == 'SPHERE': - box.label("Spheric Settings:") - box.prop(self, "radius", text="Radius") - - if self.spiral_type == 'TORUS': - box.label("Torus Settings:") - col = box.column(align=True) - col.prop(self, "cycles", text="Number of Cycles") - - if self.dif_inner_radius == 0 and self.dif_z == 0: - self.cycles = 1 - col.prop(self, "radius", text="Radius") - - if self.dif_z == 0: - col.prop(self, "dif_z", text="Height per Cycle") - else: - box2 = box.box() - col2 = box2.column(align=True) - col2.prop(self, "dif_z", text="Height per Cycle") - col2.prop(self, "touch", text="Make Snail") - - col = box.column(align=True) - col.prop(self, "curves_number", text="Curves Number") - col.prop(self, "inner_radius", text="Inner Radius") - col.prop(self, "dif_radius", text="Increase of Torus Radius") - col.prop(self, "dif_inner_radius", text="Increase of Inner Radius") - - @classmethod - def poll(cls, context): - return context.scene is not None - - def execute(self, context): - time_start = time.time() - draw_curve(self, context) - - self.report({'INFO'}, - "Drawing Spiral Finished: %.4f sec" % (time.time() - time_start)) - - return {'FINISHED'} - - -class CURVE_EXTRAS_OT_spirals_presets(AddPresetBase, Operator): - bl_idname = "curve_extras.spiral_presets" - bl_label = "Spirals" - bl_description = "Spirals Presets" - preset_menu = "OBJECT_MT_spiral_curve_presets" - preset_subdir = "curve_extras/curve.spirals" - - preset_defines = [ - "op = bpy.context.active_operator", - ] - preset_values = [ - "op.spiral_type", - "op.curve_type", - "op.spiral_direction", - "op.turns", - "op.steps", - "op.radius", - "op.dif_z", - "op.dif_radius", - "op.B_force", - "op.inner_radius", - "op.dif_inner_radius", - "op.cycles", - "op.curves_number", - "op.touch", - ] - - -class OBJECT_MT_spiral_curve_presets(Menu): - '''Presets for curve.spiral''' - bl_label = "Spiral Curve Presets" - bl_idname = "OBJECT_MT_spiral_curve_presets" - preset_subdir = "curve_extras/curve.spirals" - preset_operator = "script.execute_preset" - - draw = bpy.types.Menu.draw_preset - - -def register(): - bpy.utils.register_module(__name__) - - -def unregister(): - bpy.utils.unregister_module(__name__) - - -if __name__ == "__main__": - register() diff --git a/tests/test_helpers/addons/add_curve_extra_objects/add_curve_spirofit_bouncespline.py b/tests/test_helpers/addons/add_curve_extra_objects/add_curve_spirofit_bouncespline.py deleted file mode 100644 index 33caf12..0000000 --- a/tests/test_helpers/addons/add_curve_extra_objects/add_curve_spirofit_bouncespline.py +++ /dev/null @@ -1,1014 +0,0 @@ -# ##### 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_info = { - "name": "SpiroFit, BounceSpline and Catenary", - "author": "Antonio Osprite, Liero, Atom, Jimmy Hazevoet", - "version": (0, 2, 1), - "blender": (2, 78, 0), - "location": "Toolshelf > Create Tab", - "description": "SpiroFit, BounceSpline and Catenary adds " - "splines to selected mesh or objects", - "warning": "", - "wiki_url": "", - "category": "Object", - } - -import bpy -from bpy.types import ( - Operator, - Panel, - ) -from bpy.props import ( - BoolProperty, - EnumProperty, - FloatProperty, - IntProperty, - StringProperty, - ) -from mathutils import ( - Matrix, - Vector, - ) -from math import ( - sin, cos, - pi, sqrt, - pow, radians - ) -import random as r - - -# ------------------------------------------------------------ -# "Build a spiral that fit the active object" -# Spirofit, original blender 2.45 script by: Antonio Osprite -# http://www.kino3d.com/forum/viewtopic.php?t=5374 -# ------------------------------------------------------------ -def distance(v1, v2): - d = (Vector(v1) - Vector(v2)).length - return d - - -def spiral_point(step, radius, z_coord, spires, waves, wave_iscale, rndm): - x = radius * cos(spires * step) + (r.random() - 0.5) * rndm - y = radius * sin(spires * step) + (r.random() - 0.5) * rndm - z = z_coord + (cos(waves * step * pi) * wave_iscale) + (r.random() - 0.5) * rndm - return [x, y, z] - - -def spirofit_spline(obj, - spire_resolution=4, - spires=4, - offset=0.0, - waves=0, - wave_iscale=0.0, - rndm_spire=0.0, - direction=False, - map_method='RAYCAST' - ): - - points = [] - bb = obj.bound_box - bb_xmin = min([v[0] for v in bb]) - bb_ymin = min([v[1] for v in bb]) - bb_zmin = min([v[2] for v in bb]) - bb_xmax = max([v[0] for v in bb]) - bb_ymax = max([v[1] for v in bb]) - bb_zmax = max([v[2] for v in bb]) - - radius = distance([bb_xmax, bb_ymax, bb_zmin], [bb_xmin, bb_ymin, bb_zmin]) / 2.0 - height = bb_zmax - bb_zmin - cx = (bb_xmax + bb_xmin) / 2.0 - cy = (bb_ymax + bb_ymin) / 2.0 - steps = spires * spire_resolution - - for i in range(steps + 1): - t = bb_zmin + (2 * pi / steps) * i - z = bb_zmin + (float(height) / steps) * i - if direction: - t = -t - cp = spiral_point(t, radius, z, spires, waves, wave_iscale, rndm_spire) - - if map_method == 'RAYCAST': - success, hit, nor, index = obj.ray_cast(Vector(cp), (Vector([cx, cy, z]) - Vector(cp))) - if success: - points.append((hit + offset * nor)) - - elif map_method == 'CLOSESTPOINT': - success, hit, nor, index = obj.closest_point_on_mesh(cp) - if success: - points.append((hit + offset * nor)) - - return points - - -class SpiroFitSpline(Operator): - bl_idname = "object.add_spirofit_spline" - bl_label = "SpiroFit" - bl_description = "Wrap selected mesh in a spiral" - bl_options = {'REGISTER', 'UNDO', 'PRESET'} - - map_method = EnumProperty( - name="Mapping", - default='RAYCAST', - description="Mapping method", - items=[('RAYCAST', 'Ray cast', 'Ray casting'), - ('CLOSESTPOINT', 'Closest point', 'Closest point on mesh')] - ) - direction = BoolProperty( - name="Direction", - description="Spire direction", - default=False - ) - spire_resolution = IntProperty( - name="Spire Resolution", - default=8, - min=3, - max=1024, - soft_max=128, - description="Number of steps for one turn" - ) - spires = IntProperty( - name="Spires", - default=4, - min=1, - max=1024, - soft_max=128, - description="Number of turns" - ) - offset = FloatProperty( - name="Offset", - default=0.0, - precision=3, - description="Use normal direction to offset spline" - ) - waves = IntProperty( - name="Wave", - default=0, - min=0, - description="Wave amount" - ) - wave_iscale = FloatProperty( - name="Wave Intensity", - default=0.0, - min=0.0, - precision=3, - description="Wave intensity scale" - ) - rndm_spire = FloatProperty( - name="Randomise", - default=0.0, - min=0.0, - precision=3, - description="Randomise spire" - ) - spline_name = StringProperty( - name="Name", - default="SpiroFit" - ) - spline_type = EnumProperty( - name="Spline", - default='BEZIER', - description="Spline type", - items=[('POLY', 'Poly', 'Poly spline'), - ('BEZIER', 'Bezier', 'Bezier spline')] - ) - resolution_u = IntProperty( - name="Resolution U", - default=12, - min=0, - max=64, - description="Curve resolution u" - ) - bevel = FloatProperty( - name="Bevel Radius", - default=0.0, - min=0.0, - precision=3, - description="Bevel depth" - ) - bevel_res = IntProperty( - name="Bevel Resolution", - default=0, - min=0, - max=32, - description="Bevel resolution" - ) - extrude = FloatProperty( - name="Extrude", - default=0.0, - min=0.0, - precision=3, - description="Extrude amount" - ) - twist_mode = EnumProperty( - name="Twisting", - default='MINIMUM', - description="Twist method, type of tilt calculation", - items=[('Z_UP', "Z-Up", 'Z Up'), - ('MINIMUM', "Minimum", 'Minimum'), - ('TANGENT', "Tangent", 'Tangent')] - ) - twist_smooth = FloatProperty( - name="Smooth", - default=0.0, - min=0.0, - precision=3, - description="Twist smoothing amount for tangents" - ) - tilt = FloatProperty( - name="Tilt", - default=0.0, - precision=3, - description="Spline handle tilt" - ) - random_radius = FloatProperty( - name="Randomise", - default=0.0, - min=0.0, - precision=3, - description="Randomise radius of spline controlpoints" - ) - x_ray = BoolProperty( - name="X-Ray", - default=False, - description="X-Ray - make the object draw in front of others" - ) - random_seed = IntProperty( - name="Random Seed", - default=1, - min=0, - description="Random seed number" - ) - origin_to_start = BoolProperty( - name="Origin at Start", - description="Set origin at first point of spline", - default=False - ) - refresh = BoolProperty( - name="Refresh", - description="Refresh spline", - default=False - ) - auto_refresh = BoolProperty( - name="Auto", - description="Auto refresh spline", - default=True - ) - - def draw(self, context): - layout = self.layout - col = layout.column(align=True) - row = col.row(align=True) - - if self.auto_refresh is False: - self.refresh = False - elif self.auto_refresh is True: - self.refresh = True - - row.prop(self, "auto_refresh", toggle=True, icon="AUTO", icon_only=True) - row.prop(self, "refresh", toggle=True, icon="FILE_REFRESH", icon_only=True) - row.operator("object.add_spirofit_spline", text="Add") - row.prop(self, "x_ray", toggle=True, icon_only=True, icon="RESTRICT_VIEW_OFF") - row.prop(self, "origin_to_start", toggle=True, icon="CURVE_DATA", icon_only=True) - - col = layout.column(align=True) - col.prop(self, "spline_name") - col.separator() - col.prop(self, "map_method") - col.separator() - col.prop(self, "spire_resolution") - row = col.row(align=True).split(0.9, align=True) - row.prop(self, "spires") - row.prop(self, "direction", toggle=True, text="", icon="ARROW_LEFTRIGHT") - col.prop(self, "offset") - col.prop(self, "waves") - col.prop(self, "wave_iscale") - col.prop(self, "rndm_spire") - col.prop(self, "random_seed") - draw_spline_settings(self) - - @classmethod - def poll(self, context): - ob = context.active_object - return ((ob is not None) and - (context.mode == 'OBJECT')) - - def invoke(self, context, event): - self.refresh = True - return self.execute(context) - - def execute(self, context): - if not self.refresh: - return {'PASS_THROUGH'} - - obj = context.active_object - if obj.type != 'MESH': - self.report({'WARNING'}, - "Active Object is not a Mesh. Operation Cancelled") - return {'CANCELLED'} - - undo = context.user_preferences.edit.use_global_undo - context.user_preferences.edit.use_global_undo = False - - bpy.ops.object.select_all(action='DESELECT') - - r.seed(self.random_seed) - - points = spirofit_spline( - obj, - self.spire_resolution, - self.spires, - self.offset, - self.waves, - self.wave_iscale, - self.rndm_spire, - self.direction, - self.map_method - ) - - add_curve_object( - points, - obj.matrix_world, - self.spline_name, - self.spline_type, - self.resolution_u, - self.bevel, - self.bevel_res, - self.extrude, - self.random_radius, - self.twist_mode, - self.twist_smooth, - self.tilt, - self.x_ray - ) - - if self.origin_to_start is True: - move_origin_to_start() - - if self.auto_refresh is False: - self.refresh = False - - context.user_preferences.edit.use_global_undo = undo - return {'FINISHED'} - - -# ------------------------------------------------------------ -# Bounce spline / Fiber mesh -# Original script by Liero and Atom -# https://blenderartists.org/forum/showthread.php?331750-Fiber-Mesh-Emulation -# ------------------------------------------------------------ -def noise(var=1): - rand = Vector((r.gauss(0, 1), r.gauss(0, 1), r.gauss(0, 1))) - vec = rand.normalized() * var - return vec - - -def bounce_spline(obj, - number=1000, - ang_noise=0.25, - offset=0.0, - extra=50, - active_face=False - ): - - dist, points = 1000, [] - poly = obj.data.polygons - - if active_face: - try: - n = poly.active - except: - print("No active face selected") - pass - else: - n = r.randint(0, len(poly) - 1) - - end = poly[n].normal.copy() * -1 - start = poly[n].center - points.append(start + offset * end) - - for i in range(number): - for ray in range(extra + 1): - end += noise(ang_noise) - try: - hit, nor, index = obj.ray_cast(start, end * dist)[-3:] - except: - index = -1 - if index != -1: - start = hit - nor / 10000 - end = end.reflect(nor).normalized() - points.append(hit + offset * nor) - break - if index == -1: - return points - return points - - -class BounceSpline(Operator): - bl_idname = "object.add_bounce_spline" - bl_label = "Bounce Spline" - bl_description = "Fill selected mesh with a spline" - bl_options = {'REGISTER', 'UNDO', 'PRESET'} - - bounce_number = IntProperty( - name="Bounces", - default=1000, - min=1, - max=100000, - soft_max=10000, - description="Number of bounces" - ) - ang_noise = FloatProperty( - name="Angular Noise", - default=0.25, - min=0.0, - precision=3, - description="Add some noise to ray direction" - ) - offset = FloatProperty( - name="Offset", - default=0.0, - precision=3, - description="Use normal direction to offset spline" - ) - extra = IntProperty( - name="Extra", - default=50, - min=0, - max=1000, - description="Number of extra tries if it fails to hit mesh" - ) - active_face = BoolProperty( - name="Active Face", - default=False, - description="Starts from active face or a random one" - ) - spline_name = StringProperty( - name="Name", - default="BounceSpline" - ) - spline_type = EnumProperty( - name="Spline", - default='BEZIER', - description="Spline type", - items=[('POLY', "Poly", "Poly spline"), - ('BEZIER', "Bezier", "Bezier spline")] - ) - resolution_u = IntProperty( - name="Resolution U", - default=12, - min=0, - max=64, - description="Curve resolution u" - ) - bevel = FloatProperty( - name="Bevel Radius", - default=0.0, - min=0.0, - precision=3, - description="Bevel depth" - ) - bevel_res = IntProperty( - name="Bevel Resolution", - default=0, - min=0, - max=32, - description="Bevel resolution" - ) - extrude = FloatProperty( - name="Extrude", - default=0.0, - min=0.0, - precision=3, - description="Extrude amount" - ) - twist_mode = EnumProperty( - name="Twisting", - default='MINIMUM', - description="Twist method, type of tilt calculation", - items=[('Z_UP', "Z-Up", 'Z Up'), - ('MINIMUM', "Minimum", 'Minimum'), - ('TANGENT', "Tangent", 'Tangent')] - ) - twist_smooth = FloatProperty( - name="Smooth", - default=0.0, - min=0.0, - precision=3, - description="Twist smoothing amount for tangents" - ) - tilt = FloatProperty( - name="Tilt", - default=0.0, - precision=3, - description="Spline handle tilt" - ) - random_radius = FloatProperty( - name="Randomise", - default=0.0, - min=0.0, - precision=3, - description="Randomise radius of spline controlpoints" - ) - x_ray = BoolProperty( - name="X-Ray", - default=False, - description="X-Ray - make the object draw in front of others" - ) - random_seed = IntProperty( - name="Random Seed", - default=1, - min=0, - description="Random seed number" - ) - origin_to_start = BoolProperty( - name="Origin at Start", - description="Set origin at first point of spline", - default=False - ) - refresh = BoolProperty( - name="Refresh", - description="Refresh spline", - default=False - ) - auto_refresh = BoolProperty( - name="Auto", - description="Auto refresh spline", - default=True - ) - - def draw(self, context): - layout = self.layout - col = layout.column(align=True) - row = col.row(align=True) - if self.auto_refresh is False: - self.refresh = False - elif self.auto_refresh is True: - self.refresh = True - - row.prop(self, "auto_refresh", toggle=True, icon="AUTO", icon_only=True) - row.prop(self, "refresh", toggle=True, icon="FILE_REFRESH", icon_only=True) - row.operator("object.add_bounce_spline", text="Add") - row.prop(self, "x_ray", toggle=True, icon_only=True, icon="RESTRICT_VIEW_OFF") - row.prop(self, "origin_to_start", toggle=True, icon="CURVE_DATA", icon_only=True) - - col = layout.column(align=True) - col.prop(self, "spline_name") - col.separator() - col.prop(self, "bounce_number") - row = col.row(align=True).split(0.9, align=True) - row.prop(self, "ang_noise") - row.prop(self, "active_face", toggle=True, text="", icon="SNAP_FACE") - col.prop(self, "offset") - col.prop(self, "extra") - col.prop(self, "random_seed") - draw_spline_settings(self) - - @classmethod - def poll(self, context): - ob = context.active_object - return ((ob is not None) and - (context.mode == 'OBJECT')) - - def invoke(self, context, event): - self.refresh = True - return self.execute(context) - - def execute(self, context): - if not self.refresh: - return {'PASS_THROUGH'} - - obj = context.active_object - if obj.type != 'MESH': - return {'CANCELLED'} - - undo = context.user_preferences.edit.use_global_undo - context.user_preferences.edit.use_global_undo = False - - bpy.ops.object.select_all(action='DESELECT') - - r.seed(self.random_seed) - - points = bounce_spline( - obj, - self.bounce_number, - self.ang_noise, - self.offset, - self.extra, - self.active_face - ) - - add_curve_object( - points, - obj.matrix_world, - self.spline_name, - self.spline_type, - self.resolution_u, - self.bevel, - self.bevel_res, - self.extrude, - self.random_radius, - self.twist_mode, - self.twist_smooth, - self.tilt, - self.x_ray - ) - - if self.origin_to_start is True: - move_origin_to_start() - - if self.auto_refresh is False: - self.refresh = False - - context.user_preferences.edit.use_global_undo = undo - return {'FINISHED'} - - -# ------------------------------------------------------------ -# Hang Catenary curve between two selected objects -# ------------------------------------------------------------ -def catenary_curve( - start=[-2, 0, 2], - end=[2, 0, 2], - steps=24, - a=2.0 - ): - - points = [] - lx = end[0] - start[0] - ly = end[1] - start[1] - lr = sqrt(pow(lx, 2) + pow(ly, 2)) - lv = lr / 2 - (end[2] - start[2]) * a / lr - zv = start[2] - pow(lv, 2) / (2 * a) - slx = lx / steps - sly = ly / steps - slr = lr / steps - i = 0 - while i <= steps: - x = start[0] + i * slx - y = start[1] + i * sly - z = zv + pow((i * slr) - lv, 2) / (2 * a) - points.append([x, y, z]) - i += 1 - return points - - -class CatenaryCurve(Operator): - bl_idname = "object.add_catenary_curve" - bl_label = "Catenary" - bl_description = "Hang a curve between two selected objects" - bl_options = {'REGISTER', 'UNDO', 'PRESET'} - - steps = IntProperty( - name="Steps", - description="Resolution of the curve", - default=24, - min=2, - max=1024, - ) - var_a = FloatProperty( - name="a", - description="Catenary variable a", - precision=3, - default=2.0, - min=0.01, - max=100.0 - ) - spline_name = StringProperty( - name="Name", - default="Catenary" - ) - spline_type = EnumProperty( - name="Spline", - default='BEZIER', - description="Spline type", - items=[('POLY', "Poly", "Poly spline"), - ('BEZIER', "Bezier", "Bezier spline")] - ) - resolution_u = IntProperty( - name="Resolution U", - default=12, - min=0, - max=64, - description="Curve resolution u" - ) - bevel = FloatProperty( - name="Bevel Radius", - default=0.0, - min=0.0, - precision=3, - description="Bevel depth" - ) - bevel_res = IntProperty( - name="Bevel Resolution", - default=0, - min=0, - max=32, - description="Bevel resolution" - ) - extrude = FloatProperty( - name="Extrude", - default=0.0, - min=0.0, - precision=3, - description="Extrude amount" - ) - twist_mode = EnumProperty( - name="Twisting", - default='MINIMUM', - description="Twist method, type of tilt calculation", - items=[('Z_UP', "Z-Up", 'Z Up'), - ('MINIMUM', "Minimum", "Minimum"), - ('TANGENT', "Tangent", "Tangent")] - ) - twist_smooth = FloatProperty( - name="Smooth", - default=0.0, - min=0.0, - precision=3, - description="Twist smoothing amount for tangents" - ) - tilt = FloatProperty( - name="Tilt", - default=0.0, - precision=3, - description="Spline handle tilt" - ) - random_radius = FloatProperty( - name="Randomise", - default=0.0, - min=0.0, - precision=3, - description="Randomise radius of spline controlpoints" - ) - x_ray = BoolProperty( - name="X-Ray", - default=False, - description="X-Ray - make the object draw in front of others" - ) - random_seed = IntProperty( - name="Random Seed", - default=1, - min=0, - description="Random seed number" - ) - origin_to_start = BoolProperty( - name="Origin at Start", - description="Set origin at first point of spline", - default=False - ) - refresh = BoolProperty( - name="Refresh", - description="Refresh spline", - default=False - ) - auto_refresh = BoolProperty( - name="Auto", - description="Auto refresh spline", - default=True - ) - - def draw(self, context): - layout = self.layout - col = layout.column(align=True) - row = col.row(align=True) - - if self.auto_refresh is False: - self.refresh = False - elif self.auto_refresh is True: - self.refresh = True - - row.prop(self, "auto_refresh", toggle=True, icon="AUTO", icon_only=True) - row.prop(self, "refresh", toggle=True, icon="FILE_REFRESH", icon_only=True) - row.operator("object.add_catenary_curve", text="Add") - row.prop(self, "x_ray", toggle=True, icon_only=True, icon="RESTRICT_VIEW_OFF") - row.prop(self, "origin_to_start", toggle=True, icon="CURVE_DATA", icon_only=True) - - col = layout.column(align=True) - col.prop(self, "spline_name") - col.separator() - col.prop(self, "steps") - col.prop(self, "var_a") - - draw_spline_settings(self) - col = layout.column(align=True) - col.prop(self, "random_seed") - - @classmethod - def poll(self, context): - ob = context.active_object - return ob is not None - - def invoke(self, context, event): - self.refresh = True - return self.execute(context) - - def execute(self, context): - if not self.refresh: - return {'PASS_THROUGH'} - - try: - ob1 = bpy.context.active_object - ob1.select = False - ob2 = bpy.context.selected_objects[0] - start = ob1.location - end = ob2.location - if (start[0] == end[0]) and (start[1] == end[1]): - self.report({"WARNING"}, - "Objects have the same X, Y location. Operation Cancelled") - - return {'CANCELLED'} - except: - self.report({"WARNING"}, - "Catenary could not be completed. Operation Cancelled") - return {'CANCELLED'} - - bpy.ops.object.select_all(action='DESELECT') - - undo = context.user_preferences.edit.use_global_undo - context.user_preferences.edit.use_global_undo = False - - r.seed(self.random_seed) - - points = catenary_curve( - start, - end, - self.steps, - self.var_a - ) - add_curve_object( - points, - Matrix(), - self.spline_name, - self.spline_type, - self.resolution_u, - self.bevel, - self.bevel_res, - self.extrude, - self.random_radius, - self.twist_mode, - self.twist_smooth, - self.tilt, - self.x_ray - ) - - if self.origin_to_start is True: - move_origin_to_start() - else: - bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY') - - if self.auto_refresh is False: - self.refresh = False - - context.user_preferences.edit.use_global_undo = undo - return {'FINISHED'} - - -# ------------------------------------------------------------ -# Generate curve object from given points -# ------------------------------------------------------------ -def add_curve_object( - verts, - matrix, - spline_name="Spline", - spline_type='BEZIER', - resolution_u=12, - bevel=0.0, - bevel_resolution=0, - extrude=0.0, - spline_radius=0.0, - twist_mode='MINIMUM', - twist_smooth=0.0, - tilt=0.0, - x_ray=False - ): - - curve = bpy.data.curves.new(spline_name, 'CURVE') - curve.dimensions = '3D' - spline = curve.splines.new(spline_type) - cur = bpy.data.objects.new(spline_name, curve) - - spline.radius_interpolation = 'BSPLINE' - spline.tilt_interpolation = 'BSPLINE' - - if spline_type == 'BEZIER': - spline.bezier_points.add(int(len(verts) - 1)) - for i in range(len(verts)): - spline.bezier_points[i].co = verts[i] - spline.bezier_points[i].handle_right_type = 'AUTO' - spline.bezier_points[i].handle_left_type = 'AUTO' - spline.bezier_points[i].radius += spline_radius * r.random() - spline.bezier_points[i].tilt = radians(tilt) - else: - spline.points.add(int(len(verts) - 1)) - for i in range(len(verts)): - spline.points[i].co = verts[i][0], verts[i][1], verts[i][2], 1 - - bpy.context.scene.objects.link(cur) - cur.data.use_uv_as_generated = True - cur.data.resolution_u = resolution_u - cur.data.fill_mode = 'FULL' - cur.data.bevel_depth = bevel - cur.data.bevel_resolution = bevel_resolution - cur.data.extrude = extrude - cur.data.twist_mode = twist_mode - cur.data.twist_smooth = twist_smooth - cur.matrix_world = matrix - bpy.context.scene.objects.active = cur - cur.select = True - if x_ray is True: - cur.show_x_ray = x_ray - return - - -def move_origin_to_start(): - active = bpy.context.active_object - spline = active.data.splines[0] - if spline.type == 'BEZIER': - start = active.matrix_world * spline.bezier_points[0].co - else: - start = active.matrix_world * spline.points[0].co - start = start[:-1] - cursor = bpy.context.scene.cursor_location.copy() - bpy.context.scene.cursor_location = start - bpy.ops.object.origin_set(type='ORIGIN_CURSOR') - bpy.context.scene.cursor_location = cursor - - -def draw_spline_settings(self): - layout = self.layout - col = layout.column(align=True) - - col.prop(self, "spline_type") - col.separator() - col.prop(self, "resolution_u") - col.prop(self, "bevel") - col.prop(self, "bevel_res") - col.prop(self, "extrude") - - if self.spline_type == 'BEZIER': - col.prop(self, "random_radius") - col.separator() - col.prop(self, "twist_mode") - col.separator() - - if self.twist_mode == 'TANGENT': - col.prop(self, "twist_smooth") - - if self.spline_type == 'BEZIER': - col.prop(self, "tilt") - - -# ------------------------------------------------------------ -# Tools Panel > Create -# ------------------------------------------------------------ -class SplinePanel(Panel): - bl_space_type = "VIEW_3D" - bl_context = "objectmode" - bl_region_type = "TOOLS" - bl_label = "Spline" - bl_category = "Create" - bl_options = {'DEFAULT_CLOSED'} - - def draw(self, context): - col = self.layout.column(align=True) - col.operator(SpiroFitSpline.bl_idname, icon="FORCE_MAGNETIC") - col.operator(BounceSpline.bl_idname, icon="FORCE_HARMONIC") - col.operator(CatenaryCurve.bl_idname, icon="FORCE_CURVE") - - -# ------------------------------------------------------------ -# Register -# ------------------------------------------------------------ -def register(): - bpy.utils.register_class(SplinePanel) - bpy.utils.register_class(SpiroFitSpline) - bpy.utils.register_class(BounceSpline) - bpy.utils.register_class(CatenaryCurve) - - -def unregister(): - bpy.utils.unregister_class(SplinePanel) - bpy.utils.unregister_class(SpiroFitSpline) - bpy.utils.unregister_class(BounceSpline) - bpy.utils.unregister_class(CatenaryCurve) - - -if __name__ == "__main__": - register() diff --git a/tests/test_helpers/addons/add_curve_extra_objects/add_curve_torus_knots.py b/tests/test_helpers/addons/add_curve_extra_objects/add_curve_torus_knots.py deleted file mode 100644 index e093257..0000000 --- a/tests/test_helpers/addons/add_curve_extra_objects/add_curve_torus_knots.py +++ /dev/null @@ -1,726 +0,0 @@ -# ##### 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_info = { - "name": "Torus Knots", - "author": "Marius Giurgi (DolphinDream), testscreenings", - "version": (0, 2), - "blender": (2, 76, 0), - "location": "View3D > Add > Curve", - "description": "Adds many types of (torus) knots", - "warning": "", - "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/" - "Scripts/Curve/Torus_Knot", - "category": "Add Curve"} -""" - -import bpy -from bpy.props import ( - BoolProperty, - EnumProperty, - FloatProperty, - IntProperty - ) -from math import ( - sin, cos, - pi, sqrt - ) -from mathutils import ( - Vector, - Matrix, - ) -from bpy_extras.object_utils import AddObjectHelper -from random import random -from bpy.types import Operator - -# Globals: -DEBUG = False - - -# greatest common denominator -def gcd(a, b): - if b == 0: - return a - else: - return gcd(b, a % b) - - -# ####################################################################### -# ###################### Knot Definitions ############################### -# ####################################################################### -def Torus_Knot(self, linkIndex=0): - p = self.torus_p # revolution count (around the torus center) - q = self.torus_q # spin count (around the torus tube) - - N = self.torus_res # curve resolution (number of control points) - -# use plus options only when they are enabled - if self.options_plus: - u = self.torus_u # p multiplier - v = self.torus_v # q multiplier - h = self.torus_h # height (scale along Z) - s = self.torus_s # torus scale (radii scale factor) - else: # don't use plus settings - u = 1 - v = 1 - h = 1 - s = 1 - - R = self.torus_R * s # major radius (scaled) - r = self.torus_r * s # minor radius (scaled) - - # number of decoupled links when (p,q) are NOT co-primes - links = gcd(p, q) # = 1 when (p,q) are co-primes - - # parametrized angle increment (cached outside of the loop for performance) - # NOTE: the total angle is divided by number of decoupled links to ensure - # the curve does not overlap with itself when (p,q) are not co-primes - da = 2 * pi / links / (N - 1) - - # link phase : each decoupled link is phased equally around the torus center - # NOTE: linkIndex value is in [0, links-1] - linkPhase = 2 * pi / q * linkIndex # = 0 when there is just ONE link - - # user defined phasing - if self.options_plus: - rPhase = self.torus_rP # user defined revolution phase - sPhase = self.torus_sP # user defined spin phase - else: # don't use plus settings - rPhase = 0 - sPhase = 0 - - rPhase += linkPhase # total revolution phase of the current link - - if DEBUG: - print("") - print("Link: %i of %i" % (linkIndex, links)) - print("gcd = %i" % links) - print("p = %i" % p) - print("q = %i" % q) - print("link phase = %.2f deg" % (linkPhase * 180 / pi)) - print("link phase = %.2f rad" % linkPhase) - - # flip directions ? NOTE: flipping both is equivalent to no flip - if self.flip_p: - p *= -1 - if self.flip_q: - q *= -1 - - # create the 3D point array for the current link - newPoints = [] - for n in range(N - 1): - # t = 2 * pi / links * n/(N-1) with: da = 2*pi/links/(N-1) => t = n * da - t = n * da - theta = p * t * u + rPhase # revolution angle - phi = q * t * v + sPhase # spin angle - - x = (R + r * cos(phi)) * cos(theta) - y = (R + r * cos(phi)) * sin(theta) - z = r * sin(phi) * h - - # append 3D point - # NOTE : the array is adjusted later as needed to 4D for POLY and NURBS - newPoints.append([x, y, z]) - - return newPoints - - -# ------------------------------------------------------------------------------ -# Calculate the align matrix for the new object (based on user preferences) - -def align_matrix(self, context): - if self.absolute_location: - loc = Matrix.Translation(Vector((0, 0, 0))) - else: - loc = Matrix.Translation(context.scene.cursor_location) - -# user defined location & translation - userLoc = Matrix.Translation(self.location) - userRot = self.rotation.to_matrix().to_4x4() - - obj_align = context.user_preferences.edit.object_align - if (context.space_data.type == 'VIEW_3D' and obj_align == 'VIEW'): - rot = context.space_data.region_3d.view_matrix.to_3x3().inverted().to_4x4() - else: - rot = Matrix() - - align_matrix = userLoc * loc * rot * userRot - return align_matrix - - -# ------------------------------------------------------------------------------ -# Set curve BEZIER handles to auto - -def setBezierHandles(obj, mode='AUTOMATIC'): - scene = bpy.context.scene - if obj.type != 'CURVE': - return - scene.objects.active = obj - bpy.ops.object.mode_set(mode='EDIT', toggle=True) - bpy.ops.curve.select_all(action='SELECT') - bpy.ops.curve.handle_type_set(type=mode) - bpy.ops.object.mode_set(mode='OBJECT', toggle=True) - - -# ------------------------------------------------------------------------------ -# Convert array of vert coordinates to points according to spline type - -def vertsToPoints(Verts, splineType): - # main vars - vertArray = [] - - # array for BEZIER spline output (V3) - if splineType == 'BEZIER': - for v in Verts: - vertArray += v - - # array for non-BEZIER output (V4) - else: - for v in Verts: - vertArray += v - if splineType == 'NURBS': - vertArray.append(1) # for NURBS w=1 - else: # for POLY w=0 - vertArray.append(0) - - return vertArray - - -# ------------------------------------------------------------------------------ -# Create the Torus Knot curve and object and add it to the scene - -def create_torus_knot(self, context): - # pick a name based on (p,q) parameters - aName = "Torus Knot %i x %i" % (self.torus_p, self.torus_q) - - # create curve - curve_data = bpy.data.curves.new(name=aName, type='CURVE') - - # setup materials to be used for the TK links - if self.use_colors: - addLinkColors(self, curve_data) - - # create torus knot link(s) - if self.multiple_links: - links = gcd(self.torus_p, self.torus_q) - else: - links = 1 - - for l in range(links): - # get vertices for the current link - verts = Torus_Knot(self, l) - - # output splineType 'POLY' 'NURBS' or 'BEZIER' - splineType = self.outputType - - # turn verts into proper array (based on spline type) - vertArray = vertsToPoints(verts, splineType) - - # create spline from vertArray (based on spline type) - spline = curve_data.splines.new(type=splineType) - if splineType == 'BEZIER': - spline.bezier_points.add(int(len(vertArray) * 1.0 / 3 - 1)) - spline.bezier_points.foreach_set('co', vertArray) - else: - spline.points.add(int(len(vertArray) * 1.0 / 4 - 1)) - spline.points.foreach_set('co', vertArray) - spline.use_endpoint_u = True - - # set curve options - spline.use_cyclic_u = True - spline.order_u = 4 - - # set a color per link - if self.use_colors: - spline.material_index = l - - curve_data.dimensions = '3D' - curve_data.resolution_u = self.segment_res - - # create surface ? - if self.geo_surface: - curve_data.fill_mode = 'FULL' - curve_data.bevel_depth = self.geo_bDepth - curve_data.bevel_resolution = self.geo_bRes - curve_data.extrude = self.geo_extrude - curve_data.offset = self.geo_offset - - new_obj = bpy.data.objects.new(aName, curve_data) - - # set object in the scene - scene = bpy.context.scene - scene.objects.link(new_obj) # place in active scene - new_obj.select = True # set as selected - scene.objects.active = new_obj # set as active - new_obj.matrix_world = self.align_matrix # apply matrix - - # set BEZIER handles - if splineType == 'BEZIER': - setBezierHandles(new_obj, self.handleType) - - return - - -# ------------------------------------------------------------------------------ -# Create materials to be assigned to each TK link - -def addLinkColors(self, curveData): - # some predefined colors for the torus knot links - colors = [] - if self.colorSet == "1": # RGBish - colors += [[0.0, 0.0, 1.0]] - colors += [[0.0, 1.0, 0.0]] - colors += [[1.0, 0.0, 0.0]] - colors += [[1.0, 1.0, 0.0]] - colors += [[0.0, 1.0, 1.0]] - colors += [[1.0, 0.0, 1.0]] - colors += [[1.0, 0.5, 0.0]] - colors += [[0.0, 1.0, 0.5]] - colors += [[0.5, 0.0, 1.0]] - else: # RainBow - colors += [[0.0, 0.0, 1.0]] - colors += [[0.0, 0.5, 1.0]] - colors += [[0.0, 1.0, 1.0]] - colors += [[0.0, 1.0, 0.5]] - colors += [[0.0, 1.0, 0.0]] - colors += [[0.5, 1.0, 0.0]] - colors += [[1.0, 1.0, 0.0]] - colors += [[1.0, 0.5, 0.0]] - colors += [[1.0, 0.0, 0.0]] - - me = curveData - links = gcd(self.torus_p, self.torus_q) - - for i in range(links): - matName = "TorusKnot-Link-%i" % i - matListNames = bpy.data.materials.keys() - # create the material - if matName not in matListNames: - if DEBUG: - print("Creating new material : %s" % matName) - mat = bpy.data.materials.new(matName) - else: - if DEBUG: - print("Material %s already exists" % matName) - mat = bpy.data.materials[matName] - - # set material color - if self.options_plus and self.random_colors: - mat.diffuse_color = random(), random(), random() - else: - cID = i % (len(colors)) # cycle through predefined colors - mat.diffuse_color = colors[cID] - - if self.options_plus: - mat.diffuse_color.s = self.saturation - else: - mat.diffuse_color.s = 0.75 - - me.materials.append(mat) - - -# ------------------------------------------------------------------------------ -# Main Torus Knot class - -class torus_knot_plus(Operator, AddObjectHelper): - bl_idname = "curve.torus_knot_plus" - bl_label = "Torus Knot +" - bl_options = {'REGISTER', 'UNDO', 'PRESET'} - bl_description = "Adds many types of tours knots" - bl_context = "object" - - def mode_update_callback(self, context): - # keep the equivalent radii sets (R,r)/(eR,iR) in sync - if self.mode == 'EXT_INT': - self.torus_eR = self.torus_R + self.torus_r - self.torus_iR = self.torus_R - self.torus_r - - # align_matrix for the invoke - align_matrix = None - - # GENERAL options - options_plus = BoolProperty( - name="Extra Options", - default=False, - description="Show more options (the plus part)", - ) - absolute_location = BoolProperty( - name="Absolute Location", - default=False, - description="Set absolute location instead of relative to 3D cursor", - ) - # COLOR options - use_colors = BoolProperty( - name="Use Colors", - default=False, - description="Show torus links in colors", - ) - colorSet = EnumProperty( - name="Color Set", - items=(('1', "RGBish", "RGBsish ordered colors"), - ('2', "Rainbow", "Rainbow ordered colors")), - ) - random_colors = BoolProperty( - name="Randomize Colors", - default=False, - description="Randomize link colors", - ) - saturation = FloatProperty( - name="Saturation", - default=0.75, - min=0.0, max=1.0, - description="Color saturation", - ) - # SURFACE Options - geo_surface = BoolProperty( - name="Surface", - default=True, - description="Create surface", - ) - geo_bDepth = FloatProperty( - name="Bevel Depth", - default=0.04, - min=0, soft_min=0, - description="Bevel Depth", - ) - geo_bRes = IntProperty( - name="Bevel Resolution", - default=2, - min=0, soft_min=0, - max=5, soft_max=5, - description="Bevel Resolution" - ) - geo_extrude = FloatProperty( - name="Extrude", - default=0.0, - min=0, soft_min=0, - description="Amount of curve extrusion" - ) - geo_offset = FloatProperty( - name="Offset", - default=0.0, - min=0, soft_min=0, - description="Offset the surface relative to the curve" - ) - # TORUS KNOT Options - torus_p = IntProperty( - name="p", - default=2, - min=1, soft_min=1, - description="Number of Revolutions around the torus hole before closing the knot" - ) - torus_q = IntProperty( - name="q", - default=3, - min=1, soft_min=1, - description="Number of Spins through the torus hole before closing the knot" - ) - flip_p = BoolProperty( - name="Flip p", - default=False, - description="Flip Revolution direction" - ) - flip_q = BoolProperty( - name="Flip q", - default=False, - description="Flip Spin direction" - ) - multiple_links = BoolProperty( - name="Multiple Links", - default=True, - description="Generate all links or just one link when q and q are not co-primes" - ) - torus_u = IntProperty( - name="Rev. Multiplier", - default=1, - min=1, soft_min=1, - description="Revolutions Multiplier" - ) - torus_v = IntProperty( - name="Spin Multiplier", - default=1, - min=1, soft_min=1, - description="Spin multiplier" - ) - torus_rP = FloatProperty( - name="Revolution Phase", - default=0.0, - min=0.0, soft_min=0.0, - description="Phase revolutions by this radian amount" - ) - torus_sP = FloatProperty( - name="Spin Phase", - default=0.0, - min=0.0, soft_min=0.0, - description="Phase spins by this radian amount" - ) - # TORUS DIMENSIONS options - mode = EnumProperty( - name="Torus Dimensions", - items=(("MAJOR_MINOR", "Major/Minor", - "Use the Major/Minor radii for torus dimensions."), - ("EXT_INT", "Exterior/Interior", - "Use the Exterior/Interior radii for torus dimensions.")), - update=mode_update_callback, - ) - torus_R = FloatProperty( - name="Major Radius", - min=0.00, max=100.0, - default=1.0, - subtype='DISTANCE', - unit='LENGTH', - description="Radius from the torus origin to the center of the cross section" - ) - torus_r = FloatProperty( - name="Minor Radius", - min=0.00, max=100.0, - default=.25, - subtype='DISTANCE', - unit='LENGTH', - description="Radius of the torus' cross section" - ) - torus_iR = FloatProperty( - name="Interior Radius", - min=0.00, max=100.0, - default=.75, - subtype='DISTANCE', - unit='LENGTH', - description="Interior radius of the torus (closest to the torus center)" - ) - torus_eR = FloatProperty( - name="Exterior Radius", - min=0.00, max=100.0, - default=1.25, - subtype='DISTANCE', - unit='LENGTH', - description="Exterior radius of the torus (farthest from the torus center)" - ) - torus_s = FloatProperty( - name="Scale", - min=0.01, max=100.0, - default=1.00, - description="Scale factor to multiply the radii" - ) - torus_h = FloatProperty( - name="Height", - default=1.0, - min=0.0, max=100.0, - description="Scale along the local Z axis" - ) - # CURVE options - torus_res = IntProperty( - name="Curve Resolution", - default=100, - min=3, soft_min=3, - description="Number of control vertices in the curve" - ) - segment_res = IntProperty( - name="Segment Resolution", - default=12, - min=1, soft_min=1, - description="Curve subdivisions per segment" - ) - SplineTypes = [ - ('POLY', "Poly", "Poly type"), - ('NURBS', "Nurbs", "Nurbs type"), - ('BEZIER', "Bezier", "Bezier type")] - outputType = EnumProperty( - name="Output splines", - default='BEZIER', - description="Type of splines to output", - items=SplineTypes, - ) - bezierHandles = [ - ('VECTOR', "Vector", "Bezier Hanles type - Vector"), - ('AUTOMATIC', "Auto", "Bezier Hanles type - Automatic"), - ] - handleType = EnumProperty( - name="Handle type", - default='AUTOMATIC', - items=bezierHandles, - description="Bezier handle type", - ) - adaptive_resolution = BoolProperty( - name="Adaptive Resolution", - default=False, - description="Auto adjust curve resolution based on TK length", - ) - - def draw(self, context): - layout = self.layout - - # extra parameters toggle - layout.prop(self, "options_plus") - - # TORUS KNOT Parameters - col = layout.column() - col.label(text="Torus Knot Parameters:") - - box = layout.box() - split = box.split(percentage=0.85, align=True) - split.prop(self, "torus_p", text="Revolutions") - split.prop(self, "flip_p", toggle=True, text="", - icon="ARROW_LEFTRIGHT") - - split = box.split(percentage=0.85, align=True) - split.prop(self, "torus_q", text="Spins") - split.prop(self, "flip_q", toggle=True, text="", - icon="ARROW_LEFTRIGHT") - - links = gcd(self.torus_p, self.torus_q) - info = "Multiple Links" - - if links > 1: - info += " ( " + str(links) + " )" - box.prop(self, 'multiple_links', text=info) - - if self.options_plus: - box = box.box() - col = box.column(align=True) - col.prop(self, "torus_u") - col.prop(self, "torus_v") - - col = box.column(align=True) - col.prop(self, "torus_rP") - col.prop(self, "torus_sP") - - # TORUS DIMENSIONS options - col = layout.column(align=True) - col.label(text="Torus Dimensions:") - box = layout.box() - col = box.column(align=True) - col.row().prop(self, "mode", expand=True) - - if self.mode == "MAJOR_MINOR": - col = box.column(align=True) - col.prop(self, "torus_R") - col.prop(self, "torus_r") - else: # EXTERIOR-INTERIOR - col = box.column(align=True) - col.prop(self, "torus_eR") - col.prop(self, "torus_iR") - - if self.options_plus: - box = box.box() - col = box.column(align=True) - col.prop(self, "torus_s") - col.prop(self, "torus_h") - - # CURVE options - col = layout.column(align=True) - col.label(text="Curve Options:") - box = layout.box() - - col = box.column() - col.label(text="Output Curve Type:") - col.row().prop(self, "outputType", expand=True) - - depends = box.column() - depends.prop(self, "torus_res") - # deactivate the "curve resolution" if "adaptive resolution" is enabled - depends.enabled = not self.adaptive_resolution - - box.prop(self, "adaptive_resolution") - box.prop(self, "segment_res") - - # SURFACE options - col = layout.column() - col.label(text="Geometry Options:") - box = layout.box() - box.prop(self, "geo_surface") - if self.geo_surface: - col = box.column(align=True) - col.prop(self, "geo_bDepth") - col.prop(self, "geo_bRes") - - col = box.column(align=True) - col.prop(self, "geo_extrude") - col.prop(self, "geo_offset") - - # COLOR options - col = layout.column() - col.label(text="Color Options:") - box = layout.box() - box.prop(self, "use_colors") - if self.use_colors and self.options_plus: - box = box.box() - box.prop(self, "colorSet") - box.prop(self, "random_colors") - box.prop(self, "saturation") - - # TRANSFORM options - col = layout.column() - col.label(text="Transform Options:") - box = col.box() - box.prop(self, "location") - box.prop(self, "absolute_location") - box.prop(self, "rotation") - - @classmethod - def poll(cls, context): - if context.mode != "OBJECT": - return False - return context.scene is not None - - def execute(self, context): - if self.mode == 'EXT_INT': - # adjust the equivalent radii pair : (R,r) <=> (eR,iR) - self.torus_R = (self.torus_eR + self.torus_iR) * 0.5 - self.torus_r = (self.torus_eR - self.torus_iR) * 0.5 - - if self.adaptive_resolution: - # adjust curve resolution automatically based on (p,q,R,r) values - p = self.torus_p - q = self.torus_q - R = self.torus_R - r = self.torus_r - links = gcd(p, q) - - # get an approximate length of the whole TK curve - # upper bound approximation - maxTKLen = 2 * pi * sqrt(p * p * (R + r) * (R + r) + q * q * r * r) - # lower bound approximation - minTKLen = 2 * pi * sqrt(p * p * (R - r) * (R - r) + q * q * r * r) - avgTKLen = (minTKLen + maxTKLen) / 2 # average approximation - - if DEBUG: - print("Approximate average TK length = %.2f" % avgTKLen) - - # x N factor = control points per unit length - self.torus_res = max(3, avgTKLen / links * 8) - - # update align matrix - self.align_matrix = align_matrix(self, context) - - # turn off undo - undo = bpy.context.user_preferences.edit.use_global_undo - bpy.context.user_preferences.edit.use_global_undo = False - - # create the curve - create_torus_knot(self, context) - - # restore pre operator undo state - bpy.context.user_preferences.edit.use_global_undo = undo - - return {'FINISHED'} - - def invoke(self, context, event): - self.execute(context) - - return {'FINISHED'} diff --git a/tests/test_helpers/addons/add_curve_extra_objects/add_surface_plane_cone.py b/tests/test_helpers/addons/add_curve_extra_objects/add_surface_plane_cone.py deleted file mode 100644 index dcbb5b5..0000000 --- a/tests/test_helpers/addons/add_curve_extra_objects/add_surface_plane_cone.py +++ /dev/null @@ -1,398 +0,0 @@ -# gpl: author Folkert de Vries - -bl_info = { - "name": "Surface: Plane / Cone/ Star / Wedge", - "description": "Create a NURBS surface plane", - "author": "Folkert de Vries", - "version": (1, 0, 1), - "blender": (2, 5, 9), - "location": "View3D > Add > Surface", - "warning": "", - "wiki_url": "", - "category": "Add Mesh" -} - -""" -Info: -to add a surface star, plane or cone, go to add Menu > Surface > Star, Plane or Cone -next parameters like scale and u and v resolution can be adjusted in the toolshelf - -have fun using this add-on -""" - -import bpy -from bpy.props import ( - FloatProperty, - IntProperty, - ) -from bpy.types import Operator - - -# generic class for inheritance -class MakeSurfaceHelpers: - # get input for size and resolution - size = FloatProperty( - name="Size", - description="Size of the object", - default=1.0, - min=0.01, - max=100.0, - unit="LENGTH", - ) - res_u = IntProperty( - name="Resolution U", - description="Surface resolution in u direction", - default=1, - min=1, - max=500, - ) - res_v = IntProperty( - name="Resolution V", - description="Surface resolution in v direction", - default=1, - min=1, - max=500, - ) - - @classmethod - def poll(cls, context): - return context.mode == 'OBJECT' - - def draw(self, context): - layout = self.layout - layout.prop(self, "size") - - col = layout.column(align=True) - col.prop(self, "res_u") - col.prop(self, "res_v") - - -class MakeSurfaceWedge(Operator, MakeSurfaceHelpers): - bl_idname = "object.add_surface_wedge" - bl_label = "Add Surface Wedge" - bl_description = "Construct a Surface Wedge" - bl_options = {'REGISTER', 'UNDO'} - - def execute(self, context): - # variables - size = self.size - res_u = self.res_u - res_v = self.res_v - - # add a surface Plane - bpy.ops.object.add_surface_plane() - # save some time, by getting instant acces to those values - ao = context.active_object - point = ao.data.splines[0].points - - # rotate 90 degrees on the z axis - ao.rotation_euler[0] = 0.0 - ao.rotation_euler[1] = 0.0 - ao.rotation_euler[2] = 1.570796 - - # go into edit mode and deselect - bpy.ops.object.mode_set(mode='EDIT') - bpy.ops.curve.select_all(action='DESELECT') - - # select points 0 and 1, and extrudde them - # declaring ao and point again seems necesary... - ao = context.active_object - point = ao.data.splines[0].points - point[0].select = True - ao = context.active_object - point = ao.data.splines[0].points - point[1].select = True - bpy.ops.curve.extrude() - # bring extruded points up 1 bu on the z axis, and toggle - # cyclic in V direction - bpy.ops.transform.translate(value=(0, 0, 1), constraint_axis=(False, False, True)) - bpy.ops.curve.cyclic_toggle(direction='CYCLIC_V') - - # get points to the right coords. - point[0].co = (1.0, 0.0, 1.0, 1.0) - point[1].co = (-1.0, 0.0, 1.0, 1.0) - point[2].co = (1.0, -0.5, 0.0, 1.0) - point[3].co = (-1.0, -0.5, 0.0, 1.0) - point[4].co = (1.0, 0.5, 0.0, 1.0) - point[5].co = (-1.0, 0.5, 0.0, 1.0) - - # go back to object mode - bpy.ops.object.mode_set(mode='OBJECT') - # get origin to geometry. - bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='MEDIAN') - # change name - context.active_object.name = 'SurfaceWedge' - # get the wedge to the 3d cursor. - context.active_object.location = context.scene.cursor_location - bpy.ops.transform.resize(value=(size, size, size)) - - # adjust resolution in u and v direction - context.active_object.data.resolution_u = res_u - context.active_object.data.resolution_v = res_v - - return{'FINISHED'} - - -class MakeSurfaceCone(Operator, MakeSurfaceHelpers): - bl_idname = "object.add_surface_cone" - bl_label = "Add Surface Cone" - bl_description = "Construct a Surface Cone" - bl_options = {'REGISTER', 'UNDO'} - - def execute(self, context): - size = self.size - res_u = self.res_u - res_v = self.res_v - - # add basemesh, a nurbs torus - bpy.ops.surface.primitive_nurbs_surface_torus_add(location=(0, 0, 0)) - # get active object and active object name - - ao = context.active_object - - # go to edit mode - bpy.ops.object.mode_set(mode='EDIT') - # deselect all - bpy.ops.curve.select_all(action='DESELECT') - # too shorten alot of lines - point = ao.data.splines[0].points - # get middle points - - for i in range(0, 63): - if point[i].co.z == 0.0: - point[i].select = True - - # select non-middle points and delete them - bpy.ops.curve.select_all(action='INVERT') - bpy.ops.curve.delete(type='VERT') - # declaring this again seems necesary... - point = ao.data.splines[0].points - # list of points to be in center, and 2 bu'' s higher - - ToKeep = [1, 3, 5, 7, 9, 11, 13, 15, 17] - for i in range(0, len(ToKeep) - 1): - point[ToKeep[i]].select = True - - bpy.ops.transform.resize(value=(0, 0, 0)) - bpy.ops.curve.cyclic_toggle(direction='CYCLIC_U') - bpy.ops.transform.translate(value=(0, 0, 2)) - - # to make cone visible - bpy.ops.object.editmode_toggle() - bpy.ops.object.editmode_toggle() - # change name - context.active_object.name = 'SurfaceCone' - # go back to object mode - bpy.ops.object.editmode_toggle() - # bring object to cursor - bpy.ops.object.mode_set(mode='OBJECT') - context.active_object.location = context.scene.cursor_location - # adjust size - bpy.ops.transform.resize(value=(size, size, size)) - - # adjust resolution in u and v direction - context.active_object.data.resolution_u = res_u - context.active_object.data.resolution_v = res_v - - return{'FINISHED'} - - -class MakeSurfaceStar(Operator, MakeSurfaceHelpers): - bl_idname = "object.add_surface_star" - bl_label = "Add Surface Star" - bl_description = "Contruct a Surface Star" - bl_options = {'REGISTER', 'UNDO'} - - def execute(self, context): - size = self.size - res_u = self.res_u - res_v = self.res_v - - # add surface circle: - bpy.ops.surface.primitive_nurbs_surface_circle_add(location=(0, 0, 0)) - # we got 8 points, we need 40 points. - # get active object - ao = context.active_object - # enter edtimode - bpy.ops.object.mode_set(mode='EDIT') - # deselect all - bpy.ops.curve.select_all(action='DESELECT') - # select point 0 and 1, and subdivide - point = ao.data.splines[0].points - - point[0].select = True - point[1].select = True - bpy.ops.curve.subdivide() - bpy.ops.curve.select_all(action='DESELECT') - - # select point 2 and 3, and subdivide - point[2].select = True - point[3].select = True - bpy.ops.curve.subdivide() - bpy.ops.curve.select_all(action='DESELECT') - - ListOfCoords = [ - (0.5, 0.0, 0.25, 1.0), - (0.80901700258255, 0.5877853035926819, 0.25, 1.0), - (0.1545085906982422, 0.4755282402038574, 0.25, 1.0), - (-0.30901703238487244, 0.9510565400123596, 0.25, 1.0), - (-0.4045085608959198, 0.293892502784729, 0.2499999850988388, 1.0), - (-1.0, 0.0, 0.25, 1.0), - (-0.4045085608959198, -0.293892502784729, 0.2499999850988388, 1.0), - (-0.30901703238487244, -0.9510565400123596, 0.25, 1.0), - (0.1545085906982422, -0.4755282402038574, 0.25, 1.0), - (0.8090166449546814, -0.5877856612205505, 0.2499999850988388, 1.0) - ] - for i in range(0, 10): - context.active_object.data.splines[0].points[i].co = ListOfCoords[i] - - # now select all, and subdivide till 40 points is reached: - bpy.ops.curve.select_all(action='SELECT') - bpy.ops.curve.subdivide() - bpy.ops.curve.subdivide() - bpy.ops.curve.subdivide() - - # extrude the star - bpy.ops.curve.extrude(mode='TRANSLATION') - # bring extruded part up - bpy.ops.transform.translate( - value=(0, 0, 0.5), - constraint_axis=(False, False, True) - ) - # flip normals - bpy.ops.curve.switch_direction() - # go back to object mode - bpy.ops.object.mode_set(mode='OBJECT') - # origin to geometry - bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='MEDIAN') - # get object to 3d cursor - context.active_object.location = context.scene.cursor_location - # change name - ao.name = 'SurfaceStar' - # adjust size - bpy.ops.transform.resize(value=(size, size, size)) - - # adjust resolution in u and v direction - context.active_object.data.resolution_u = res_u - context.active_object.data.resolution_v = res_v - - return{'FINISHED'} - - -class MakeSurfacePlane(Operator, MakeSurfaceHelpers): - bl_idname = "object.add_surface_plane" - bl_label = "Add Surface Plane" - bl_description = "Contruct a Surface Plane" - bl_options = {'REGISTER', 'UNDO'} - - def execute(self, context): - size = self.size - res_u = self.res_u - res_v = self.res_v - - bpy.ops.surface.primitive_nurbs_surface_surface_add() # add the base mesh, a NURBS Surface - - bpy.ops.transform.resize( - value=(1, 1, 0.0001), - constraint_axis=(False, False, True) - ) # make it flat - - # added surface has 16 points - - # deleting points to get plane shape - bpy.ops.object.mode_set(mode='EDIT') - bpy.ops.curve.select_all(action='DESELECT') - - context.active_object.data.splines[0].points[0].select = True - context.active_object.data.splines[0].points[1].select = True - context.active_object.data.splines[0].points[2].select = True - context.active_object.data.splines[0].points[3].select = True - bpy.ops.curve.delete(type='VERT') - - context.active_object.data.splines[0].points[8].select = True - context.active_object.data.splines[0].points[9].select = True - context.active_object.data.splines[0].points[10].select = True - context.active_object.data.splines[0].points[11].select = True - bpy.ops.curve.delete(type='VERT') - - context.active_object.data.splines[0].points[0].select = True - context.active_object.data.splines[0].points[4].select = True - bpy.ops.curve.delete(type='VERT') - context.active_object.data.splines[0].points[2].select = True - context.active_object.data.splines[0].points[5].select = True - bpy.ops.curve.delete(type='VERT') - - # assigning name - context.active_object.name = "SurfacePlane" - # select all - bpy.ops.curve.select_all(action='SELECT') - # bringing origin to center: - bpy.ops.object.mode_set(mode='OBJECT') - bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='MEDIAN') - # transform scale - bpy.ops.object.transform_apply(scale=True) - - # bring object to 3d cursor - bpy.ops.object.mode_set(mode='OBJECT') - context.active_object.location = context.scene.cursor_location - bpy.ops.transform.resize(value=(size, size, size)) - - # adjust resolution in u and v direction - context.active_object.data.resolution_u = res_u - context.active_object.data.resolution_v = res_v - - return{'FINISHED'} - - -class SmoothXtimes(Operator): - bl_idname = "curve.smooth_x_times" - bl_label = "Smooth X Times" - bl_space_type = "VIEW_3D" - bl_options = {'REGISTER', 'UNDO'} - - # use of this class: - # lets you smooth till a thousand times. this is normally difficult, because - # you have to press w, click, press w, click etc. - - # get values - times = IntProperty( - name="Smooth x Times", - min=1, - max=1000, - default=1, - description="Smooth amount" - ) - - @classmethod - def poll(cls, context): - return context.mode == 'EDIT_SURFACE' - - def execute(self, context): - # smooth times - times = self.times - for i in range(1, times): - bpy.ops.curve.smooth() - - return{'FINISHED'} - - -def register(): - bpy.utils.register_class(MakeSurfaceHelpers) - bpy.utils.register_class(MakeSurfacePlane) - bpy.utils.register_class(MakeSurfaceCone) - bpy.utils.register_class(MakeSurfaceStar) - bpy.utils.register_class(MakeSurfaceWedge) - bpy.utils.register_class(SmoothXtimes) - - -def unregister(): - bpy.utils.unregister_class(MakeSurfaceHelpers) - bpy.utils.unregister_class(MakeSurfacePlane) - bpy.utils.unregister_class(MakeSurfaceCone) - bpy.utils.unregister_class(MakeSurfaceStar) - bpy.utils.unregister_class(MakeSurfaceWedge) - bpy.utils.unregister_class(SmoothXtimes) - - -if __name__ == "__main__": - register() diff --git a/tests/test_helpers/addons/add_curve_extra_objects/beveltaper_curve.py b/tests/test_helpers/addons/add_curve_extra_objects/beveltaper_curve.py deleted file mode 100644 index f91eb8b..0000000 --- a/tests/test_helpers/addons/add_curve_extra_objects/beveltaper_curve.py +++ /dev/null @@ -1,422 +0,0 @@ -# ##### 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 3 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, see . -# -# ##### END GPL LICENSE BLOCK ##### - -# DevBo Task: https://developer.blender.org/T37377 - -bl_info = { - "name": "Bevel/Taper Curve", - "author": "Cmomoney", - "version": (1, 1), - "blender": (2, 69, 0), - "location": "View3D > Object > Bevel/Taper", - "description": "Adds bevel and/or taper curve to active curve", - "warning": "", - "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/" - "Py/Scripts/Curve/Bevel_-Taper_Curve", - "category": "Curve"} - - -import bpy -from bpy.types import ( - Operator, - Menu, - ) -from bpy.props import ( - BoolProperty, - FloatProperty, - IntProperty, - ) -from bpy_extras.object_utils import ( - AddObjectHelper, - object_data_add, - ) - - -def add_taper(self, context): - scale_ends1 = self.scale_ends1 - scale_ends2 = self.scale_ends2 - scale_mid = self.scale_mid - verts = [ - (-2.0, 1.0 * scale_ends1, 0.0, 1.0), - (-1.0, 0.75 * scale_mid, 0.0, 1.0), - (0.0, 1.5 * scale_mid, 0.0, 1.0), - (1.0, 0.75 * scale_mid, 0.0, 1.0), - (2.0, 1.0 * scale_ends2, 0.0, 1.0) - ] - make_path(self, context, verts) - - -def add_type5(self, context): - scale_x = self.scale_x - scale_y = self.scale_y - verts = [ - [0.0 * scale_x, 0.049549 * scale_y, - 0.0, 0.031603 * scale_x, 0.047013 * scale_y, - 0.0, 0.05 * scale_x, 0.0 * scale_y, 0.0, - 0.031603 * scale_x, -0.047013 * scale_y, - 0.0, 0.0 * scale_x, -0.049549 * scale_y, - 0.0, -0.031603 * scale_x, -0.047013 * scale_y, - 0.0, -0.05 * scale_x, -0.0 * scale_y, 0.0, - -0.031603 * scale_x, 0.047013 * scale_y, 0.0] - ] - lhandles = [ - [(-0.008804 * scale_x, 0.049549 * scale_y, 0.0), - (0.021304 * scale_x, 0.02119 * scale_y, 0.0), - (0.05 * scale_x, 0.051228 * scale_y, 0.0), - (0.036552 * scale_x, -0.059423 * scale_y, 0.0), - (0.008804 * scale_x, -0.049549 * scale_y, 0.0), - (-0.021304 * scale_x, -0.02119 * scale_y, 0.0), - (-0.05 * scale_x, -0.051228 * scale_y, 0.0), - (-0.036552 * scale_x, 0.059423 * scale_y, 0.0)] - ] - rhandles = [ - [(0.008803 * scale_x, 0.049549 * scale_y, 0.0), - (0.036552 * scale_x, 0.059423 * scale_y, 0.0), - (0.05 * scale_x, -0.051228 * scale_y, 0.0), - (0.021304 * scale_x, -0.02119 * scale_y, 0.0), - (-0.008803 * scale_x, -0.049549 * scale_y, 0.0), - (-0.036552 * scale_x, -0.059423 * scale_y, 0.0), - (-0.05 * scale_x, 0.051228 * scale_y, 0.0), - (-0.021304 * scale_x, 0.02119 * scale_y, 0.0)] - ] - make_curve(self, context, verts, lhandles, rhandles) - - -def add_type4(self, context): - scale_x = self.scale_x - scale_y = self.scale_y - verts = [ - [-0.0 * scale_x, 0.017183 * scale_y, - 0.0, 0.05 * scale_x, 0.0 * scale_y, - 0.0, 0.0 * scale_x, -0.017183 * scale_y, - 0.0, -0.05 * scale_x, -0.0 * scale_y, 0.0] - ] - lhandles = [ - [(-0.017607 * scale_x, 0.017183 * scale_y, 0.0), - (0.05 * scale_x, 0.102456 * scale_y, 0.0), - (0.017607 * scale_x, -0.017183 * scale_y, 0.0), - (-0.05 * scale_x, -0.102456 * scale_y, 0.0)] - ] - rhandles = [ - [(0.017607 * scale_x, 0.017183 * scale_y, 0.0), - (0.05 * scale_x, -0.102456 * scale_y, 0.0), - (-0.017607 * scale_x, -0.017183 * scale_y, 0.0), - (-0.05 * scale_x, 0.102456 * scale_y, 0.0)] - ] - make_curve(self, context, verts, lhandles, rhandles) - - -def add_type3(self, context): - scale_x = self.scale_x - scale_y = self.scale_y - verts = [ - [-0.017183 * scale_x, 0.0 * scale_y, - 0.0, 0.0 * scale_x, 0.05 * scale_y, - 0.0, 0.017183 * scale_x, 0.0 * scale_y, - 0.0, 0.0 * scale_x, -0.05 * scale_y, 0.0] - ] - lhandles = [ - [(-0.017183 * scale_x, -0.017607 * scale_y, 0.0), - (-0.102456 * scale_x, 0.05 * scale_y, 0.0), - (0.017183 * scale_x, 0.017607 * scale_y, 0.0), - (0.102456 * scale_x, -0.05 * scale_y, 0.0)] - ] - rhandles = [ - [(-0.017183 * scale_x, 0.017607 * scale_y, 0.0), - (0.102456 * scale_x, 0.05 * scale_y, 0.0), - (0.017183 * scale_x, -0.017607 * scale_y, 0.0), - (-0.102456 * scale_x, -0.05 * scale_y, 0.0)] - ] - make_curve(self, context, verts, lhandles, rhandles) - - -def add_type2(self, context): - scale_x = self.scale_x - scale_y = self.scale_y - verts = [ - [-0.05 * scale_x, 0.0 * scale_y, - 0.0, 0.0 * scale_x, 0.05 * scale_y, - 0.0, 0.05 * scale_x, 0.0 * scale_y, - 0.0, 0.0 * scale_x, -0.05 * scale_y, 0.0] - ] - lhandles = [ - [(-0.05 * scale_x, -0.047606 * scale_y, 0.0), - (-0.047606 * scale_x, 0.05 * scale_y, 0.0), - (0.05 * scale_x, 0.047607 * scale_y, 0.0), - (0.047606 * scale_x, -0.05 * scale_y, 0.0)] - ] - rhandles = [ - [(-0.05 * scale_x, 0.047607 * scale_y, 0.0), - (0.047607 * scale_x, 0.05 * scale_y, 0.0), - (0.05 * scale_x, -0.047607 * scale_y, 0.0), - (-0.047607 * scale_x, -0.05 * scale_y, 0.0)] - ] - make_curve(self, context, verts, lhandles, rhandles) - - -def add_type1(self, context): - scale_x = self.scale_x - scale_y = self.scale_y - verts = [ - [-0.05 * scale_x, 0.0 * scale_y, - 0.0, 0.0 * scale_x, 0.05 * scale_y, - 0.0, 0.05 * scale_x, 0.0 * scale_y, - 0.0, 0.0 * scale_x, -0.05 * scale_y, 0.0] - ] - lhandles = [ - [(-0.05 * scale_x, -0.027606 * scale_y, 0.0), - (-0.027606 * scale_x, 0.05 * scale_y, 0.0), - (0.05 * scale_x, 0.027606 * scale_y, 0.0), - (0.027606 * scale_x, -0.05 * scale_y, 0.0)] - ] - rhandles = [ - [(-0.05 * scale_x, 0.027607 * scale_y, 0.0), - (0.027607 * scale_x, 0.05 * scale_y, 0.0), - (0.05 * scale_x, -0.027607 * scale_y, 0.0), - (-0.027607 * scale_x, -0.05 * scale_y, 0.0)] - ] - make_curve(self, context, verts, lhandles, rhandles) - - -def make_path(self, context, verts): - target = bpy.context.scene.objects.active - bpy.ops.curve.primitive_nurbs_path_add( - view_align=False, enter_editmode=False, location=(0, 0, 0) - ) - target.data.taper_object = bpy.context.scene.objects.active - taper = bpy.context.scene.objects.active - taper.name = target.name + '_Taper' - bpy.context.scene.objects.active = target - points = taper.data.splines[0].points - - for i in range(len(verts)): - points[i].co = verts[i] - - -def make_curve(self, context, verts, lh, rh): - target = bpy.context.scene.objects.active - curve_data = bpy.data.curves.new( - name=target.name + '_Bevel', type='CURVE' - ) - curve_data.dimensions = '3D' - - for p in range(len(verts)): - c = 0 - spline = curve_data.splines.new(type='BEZIER') - spline.use_cyclic_u = True - spline.bezier_points.add(len(verts[p]) / 3 - 1) - spline.bezier_points.foreach_set('co', verts[p]) - - for bp in spline.bezier_points: - bp.handle_left_type = 'ALIGNED' - bp.handle_right_type = 'ALIGNED' - bp.handle_left.xyz = lh[p][c] - bp.handle_right.xyz = rh[p][c] - c += 1 - - object_data_add(context, curve_data, operator=self) - target.data.bevel_object = bpy.context.scene.objects.active - bpy.context.scene.objects.active = target - - -class add_tapercurve(Operator): - bl_idname = "curve.tapercurve" - bl_label = "Add Curve as Taper" - bl_description = ("Add taper curve to Active Curve\n" - "Needs an existing Active Curve") - bl_options = {'REGISTER', 'UNDO'} - - scale_ends1 = FloatProperty( - name="End Width Left", - description="Adjust left end taper", - default=0.0, - min=0.0 - ) - scale_ends2 = FloatProperty( - name="End Width Right", - description="Adjust right end taper", - default=0.0, - min=0.0 - ) - scale_mid = FloatProperty( - name="Center Width", - description="Adjust taper at center", - default=1.0, - min=0.0 - ) - link1 = BoolProperty( - name="Link Ends", - description="Link the End Width Left / Right settings\n" - "End Width Left will be editable ", - default=True - ) - link2 = BoolProperty( - name="Link Ends / Center", - description="Link the End Widths with the Center Width", - default=False - ) - diff = FloatProperty( - name="Difference", - default=1, - description="Difference between ends and center while linked" - ) - - @classmethod - def poll(cls, context): - obj = context.active_object - return context.mode == 'OBJECT' and obj and obj.type == "CURVE" - - def draw(self, context): - layout = self.layout - - col = layout.column(align=True) - col.label("Settings:") - split = layout.split(percentage=0.95, align=True) - split.active = not self.link2 - col = split.column(align=True) - col.prop(self, "scale_ends1") - - row = split.row(align=True) - row.scale_y = 2.0 - col_sub = col.column(align=True) - col_sub.active = not self.link1 - col_sub.prop(self, "scale_ends2") - row.prop(self, "link1", toggle=True, text="", icon="LINKED") - - split = layout.split(percentage=0.95, align=True) - col = split.column(align=True) - col.prop(self, "scale_mid") - - row = split.row(align=True) - row.scale_y = 2.0 - col_sub = col.column(align=True) - col_sub.active = self.link2 - row.prop(self, "link2", toggle=True, text="", icon="LINKED") - col_sub.prop(self, "diff") - - def execute(self, context): - if self.link1: - self.scale_ends2 = self.scale_ends1 - - if self.link2: - self.scale_ends2 = self.scale_ends1 = self.scale_mid - self.diff - - add_taper(self, context) - - return {'FINISHED'} - - -class add_bevelcurve(Operator, AddObjectHelper): - bl_idname = "curve.bevelcurve" - bl_label = "Add Curve as Bevel" - bl_description = ("Add bevel curve to Active Curve\n" - "Needs an existing Active Curve") - bl_options = {'REGISTER', 'UNDO'} - - types = IntProperty( - name="Type", - description="Type of bevel curve", - default=1, - min=1, max=5 - ) - scale_x = FloatProperty( - name="Scale X", - description="Scale on X axis", - default=1.0 - ) - scale_y = FloatProperty( - name="Scale Y", - description="Scale on Y axis", - default=1.0 - ) - link = BoolProperty( - name="Link XY", - description="Link the Scale on X/Y axis", - default=True - ) - - @classmethod - def poll(cls, context): - obj = context.active_object - return context.mode == 'OBJECT' and obj and obj.type == "CURVE" - - def draw(self, context): - layout = self.layout - - col = layout.column(align=True) - # AddObjectHelper props - col.prop(self, "view_align") - col.prop(self, "location") - col.prop(self, "rotation") - - col = layout.column(align=True) - col.label("Settings:") - col.prop(self, "types") - - split = layout.split(percentage=0.95, align=True) - col = split.column(align=True) - col.prop(self, "scale_x") - row = split.row(align=True) - row.scale_y = 2.0 - col.prop(self, "scale_y") - row.prop(self, "link", toggle=True, text="", icon="LINKED") - - def execute(self, context): - if self.link: - self.scale_y = self.scale_x - if self.types == 1: - add_type1(self, context) - if self.types == 2: - add_type2(self, context) - if self.types == 3: - add_type3(self, context) - if self.types == 4: - add_type4(self, context) - if self.types == 5: - add_type5(self, context) - - return {'FINISHED'} - - -class Bevel_Taper_Curve_Menu(Menu): - bl_label = "Bevel/Taper" - bl_idname = "OBJECT_MT_bevel_taper_curve_menu" - - def draw(self, context): - layout = self.layout - - layout.operator("curve.bevelcurve") - layout.operator("curve.tapercurve") - - -def menu_funcs(self, context): - if bpy.context.scene.objects.active.type == "CURVE": - self.layout.menu("OBJECT_MT_bevel_taper_curve_menu") - - -def register(): - bpy.utils.register_module(__name__) - bpy.types.VIEW3D_MT_object.append(menu_funcs) - - -def unregister(): - bpy.utils.unregister_module(__name__) - bpy.types.VIEW3D_MT_object.remove(menu_funcs) - - -if __name__ == "__main__": - register() diff --git a/tests/test_helpers/addons/dir_addon/123AA_sort_this_dir_first/__init__.py b/tests/test_helpers/addons/dir_addon/123AA_sort_this_dir_first/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_helpers/addons/add_curve_extra_objects/__init__.py b/tests/test_helpers/addons/dir_addon/__init__.py similarity index 100% rename from tests/test_helpers/addons/add_curve_extra_objects/__init__.py rename to tests/test_helpers/addons/dir_addon/__init__.py diff --git a/tests/test_helpers/addons/dir_addon/other.py b/tests/test_helpers/addons/dir_addon/other.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_helpers/addons/invalid_addon.py b/tests/test_helpers/addons/invalid_addon.py new file mode 100644 index 0000000..11388b1 --- /dev/null +++ b/tests/test_helpers/addons/invalid_addon.py @@ -0,0 +1,12 @@ +bl_info = { + "author": "testscreenings, PKHG, TrumanBlending", + "version": (0, 1, 2), + "blender": (2, 59, 0), + "location": "View3D > Add > Curve", + "description": "Adds generated ivy to a mesh object starting " + "at the 3D cursor", + "warning": "", + "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/" + "Scripts/Curve/Ivy_Gen", + "category": "Add Curve", +} diff --git a/tests/test_helpers/addons/not_an_addon.py b/tests/test_helpers/addons/not_an_addon.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_helpers/addons/add_curve_ivygen.py b/tests/test_helpers/addons/real_addon.py similarity index 100% rename from tests/test_helpers/addons/add_curve_ivygen.py rename to tests/test_helpers/addons/real_addon.py diff --git a/tests/test_helpers/addons/repo.json b/tests/test_helpers/addons/repo.json new file mode 100644 index 0000000..86db477 --- /dev/null +++ b/tests/test_helpers/addons/repo.json @@ -0,0 +1,70 @@ +{ + "packages": [ + { + "bl_info": { + "author": "Multiple Authors", + "blender": [ + 2, + 76, + 0 + ], + "category": "Add Curve", + "description": "Add extra curve object types", + "location": "View3D > Add > Curve > Extra Objects", + "name": "Extra Objects", + "version": [ + 0, + 1, + 2 + ], + "warning": "", + "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/Curve/Curve_Objects" + }, + "type": "addon" + }, + { + "bl_info": { + "author": "testscreenings, PKHG, TrumanBlending", + "blender": [ + 2, + 59, + 0 + ], + "category": "Add Curve", + "description": "Adds generated ivy to a mesh object starting at the 3D cursor", + "location": "View3D > Add > Curve", + "name": "IvyGen", + "version": [ + 0, + 1, + 2 + ], + "warning": "", + "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/Curve/Ivy_Gen" + }, + "type": "addon" + }, + { + "bl_info": { + "author": "Multiple Authors", + "blender": [ + 2, + 76, + 0 + ], + "category": "Add Curve", + "description": "Add extra curve object types", + "location": "View3D > Add > Curve > Extra Objects", + "name": "Extra Objects", + "version": [ + 0, + 1, + 2 + ], + "warning": "", + "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/Curve/Curve_Objects" + }, + "type": "addon" + } + ] +} \ No newline at end of file diff --git a/tests/test_helpers/addons/zipped_addon.zip b/tests/test_helpers/addons/zipped_addon.zip new file mode 100644 index 0000000..b7682c6 Binary files /dev/null and b/tests/test_helpers/addons/zipped_addon.zip differ diff --git a/tests/test_helpers/extra_objects_blinfo.txt b/tests/test_helpers/dir_addon_output similarity index 100% rename from tests/test_helpers/extra_objects_blinfo.txt rename to tests/test_helpers/dir_addon_output diff --git a/tests/test_helpers/ivy_gen_blinfo.txt b/tests/test_helpers/real_addon.py_output similarity index 100% rename from tests/test_helpers/ivy_gen_blinfo.txt rename to tests/test_helpers/real_addon.py_output diff --git a/tests/test_helpers/zipped_addon.zip_output b/tests/test_helpers/zipped_addon.zip_output new file mode 100644 index 0000000..f7a28bd --- /dev/null +++ b/tests/test_helpers/zipped_addon.zip_output @@ -0,0 +1 @@ +{'name': 'Extra Objects', 'author': 'Multiple Authors', 'version': (0, 1, 2), 'blender': (2, 76, 0), 'location': 'View3D > Add > Curve > Extra Objects', 'description': 'Add extra curve object types', 'warning': '', 'wiki_url': 'https://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/Curve/Curve_Objects', 'category': 'Add Curve'} \ No newline at end of file