Cleanup: trailing space
[blender-addons.git] / add_mesh_extra_objects / add_mesh_menger_sponge.py
blobbf723441b7ba10f7c646c916dabaf9c2e8816bbf
1 # SPDX-License-Identifier: MIT
2 # Copyright 2015 Sugiany
4 import bpy
6 from bpy_extras.object_utils import (
7 AddObjectHelper,
8 object_data_add,
11 from bpy.props import (
12 IntProperty,
13 BoolProperty,
14 BoolVectorProperty,
15 FloatVectorProperty,
16 FloatProperty,
19 import mathutils
20 import copy
23 class MengerSponge(object):
24 FACE_INDICES = [
25 [3, 7, 4, 0],
26 [5, 6, 2, 1],
27 [1, 2, 3, 0],
28 [7, 6, 5, 4],
29 [4, 5, 1, 0],
30 [2, 6, 7, 3],
33 def __init__(self, level):
34 self.__level = level
35 self.__max_point_number = 3 ** level
36 self.__vertices_map = {}
37 self.__indices = []
38 self.__face_visibility = {}
39 self.__faces = []
41 for x in range(3):
42 for y in range(3):
43 for z in range(3):
44 self.__face_visibility[(x, y, z)] = [
45 x == 0 or x == 2 and (y == 1 or z == 1),
46 x == 2 or x == 0 and (y == 1 or z == 1),
47 y == 0 or y == 2 and (x == 1 or z == 1),
48 y == 2 or y == 0 and (x == 1 or z == 1),
49 z == 0 or z == 2 and (y == 1 or x == 1),
50 z == 2 or z == 0 and (y == 1 or x == 1),
53 def create(self, width, height):
54 m = self.__max_point_number
55 points = [
56 (0, 0, 0),
57 (m, 0, 0),
58 (m, 0, m),
59 (0, 0, m),
60 (0, m, 0),
61 (m, m, 0),
62 (m, m, m),
63 (0, m, m),
65 self.__make_sub_sponge(points, None, self.__level)
66 vertices = self.__make_vertices(width, height)
67 return vertices, self.__faces
69 def __get_vindex(self, p):
70 if p in self.__vertices_map:
71 return self.__vertices_map[p]
72 index = len(self.__vertices_map)
73 self.__vertices_map[p] = index
74 return index
76 def __make_vertices(self, width, height):
77 vertices = [None] * len(self.__vertices_map)
78 w2 = width / 2
79 h2 = height / 2
80 w_step = width / self.__max_point_number
81 h_step = height / self.__max_point_number
82 for p, i in sorted(self.__vertices_map.items(), key=lambda x: x[1]):
83 vertices[i] = mathutils.Vector([
84 p[0] * w_step - w2,
85 p[1] * w_step - w2,
86 p[2] * h_step - h2,
88 return vertices
90 def __make_sub_sponge(self, cur_points, face_vis, depth):
91 if depth <= 0:
92 if not face_vis:
93 face_vis = [True] * 6
94 cur_point_indices = []
95 for p in cur_points:
96 cur_point_indices.append(self.__get_vindex(p))
97 for i, vis in enumerate(face_vis):
98 if vis:
99 f = []
100 for vi in self.FACE_INDICES[i]:
101 f.append(cur_point_indices[vi])
102 self.__faces.append(f)
103 return
105 base = cur_points[0]
106 width = (cur_points[1][0] - base[0]) / 3
107 local_vert_map = {}
108 for z in range(4):
109 for y in range(4):
110 for x in range(4):
111 local_vert_map[(x, y, z)] = (
112 width * x + base[0],
113 width * y + base[1],
114 width * z + base[2],
117 for x in range(3):
118 for y in range(3):
119 for z in range(3):
120 if [x, y, z].count(1) > 1:
121 continue
122 next_points = [
123 local_vert_map[(x, y, z)],
124 local_vert_map[(x + 1, y, z)],
125 local_vert_map[(x + 1, y, z + 1)],
126 local_vert_map[(x, y, z + 1)],
127 local_vert_map[(x, y + 1, z)],
128 local_vert_map[(x + 1, y + 1, z)],
129 local_vert_map[(x + 1, y + 1, z + 1)],
130 local_vert_map[(x, y + 1, z + 1)],
132 visibility = copy.copy(self.__face_visibility[(x, y, z)])
133 if face_vis:
134 visibility[0] = visibility[0] and (face_vis[0] or x != 0)
135 visibility[1] = visibility[1] and (face_vis[1] or x != 2)
136 visibility[2] = visibility[2] and (face_vis[2] or y != 0)
137 visibility[3] = visibility[3] and (face_vis[3] or y != 2)
138 visibility[4] = visibility[4] and (face_vis[4] or z != 0)
139 visibility[5] = visibility[5] and (face_vis[5] or z != 2)
140 self.__make_sub_sponge(
141 next_points,
142 visibility,
143 depth - 1)
146 class AddMengerSponge(bpy.types.Operator, AddObjectHelper):
147 bl_idname = "mesh.menger_sponge_add"
148 bl_label = "Menger Sponge"
149 bl_description = "Construct a menger sponge mesh"
150 bl_options = {'REGISTER', 'UNDO'}
152 level: IntProperty(
153 name="Level",
154 description="Sponge Level",
155 min=0, max=4,
156 default=1,
158 radius: FloatProperty(
159 name="Width",
160 description="Sponge Radius",
161 min=0.01, max=100.0,
162 default=1.0,
164 layers: BoolVectorProperty(
165 name="Layers",
166 size=20,
167 subtype='LAYER',
168 options={'HIDDEN', 'SKIP_SAVE'},
171 def execute(self, context):
172 sponger = MengerSponge(self.level)
173 vertices, faces = sponger.create(self.radius * 2, self.radius * 2)
174 del sponger
176 mesh = bpy.data.meshes.new(name='Sponge')
177 mesh.from_pydata(vertices, [], faces)
178 uvs = [(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)]
179 mesh.uv_layers.new()
180 for i, uvloop in enumerate(mesh.uv_layers.active.data):
181 uvloop.uv = uvs[i % 4]
183 object_data_add(context, mesh, operator=self)
185 return {'FINISHED'}