98bea954ace44289ec2e2d4d019cd5b70a2599ea
[blender-addons-contrib.git] / add_mesh_space_tree / simplefork.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
3 #  SCA Tree Generator,  a Blender addon
4 #  (c) 2013 Michel J. Anders (varkenvarken)
5 #
6 #  This program is free software; you can redistribute it and/or
7 #  modify it under the terms of the GNU General Public License
8 #  as published by the Free Software Foundation; either version 2
9 #  of the License,  or (at your option) any later version.
10 #
11 #  This program is distributed in the hope that it will be useful,
12 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 #  GNU General Public License for more details.
15 #
16 #  You should have received a copy of the GNU General Public License
17 #  along with this program; if not,  write to the Free Software Foundation,
18 #  Inc.,  51 Franklin Street,  Fifth Floor,  Boston,  MA 02110-1301,  USA.
19 #
20 # ##### END GPL LICENSE BLOCK #####
21
22 # <pep8 compliant>
23
24 from math import pi
25 from mathutils import Quaternion
26
27 rot120 = 2 * pi / 3
28
29
30 def rot(point, axis, angle):
31     q = Quaternion(axis, angle)
32     P = point.copy()
33     P.rotate(q)
34     #print(point, P)
35     return P
36
37
38 def vertexnormal(d1, d2, d3):
39     n1 = d1.cross(d2).normalized()
40     n2 = d2.cross(d3).normalized()
41     n3 = d3.cross(d1).normalized()
42     n = (n1 + n2 + n3).normalized()
43     if (d1 + d2 + d3).dot(n) > 0:
44         return -n
45     return n
46
47
48 def simplefork2(p0, p1, p2, p3, r0, r1, r2, r3):
49     d1 = p1 - p0
50     d2 = p2 - p0
51     d3 = p3 - p0
52     #print(d1, d2, d3)
53     n = vertexnormal(d1, d2, d3)
54     #print(n)
55
56     pp1 = p0 + d1 / 3
57     n1a = r1 * n
58     n1b = rot(n1a, d1, rot120)
59     n1c = rot(n1a, d1, -rot120)
60     v1a = pp1 + n1a
61     v1b = pp1 + n1b
62     v1c = pp1 + n1c
63
64     pp2 = p0 + d2 / 3
65     n2a = r2 * n
66     n2b = rot(n2a, d2, rot120)
67     n2c = rot(n2a, d2, -rot120)
68     v2a = pp2 + n2a
69     v2b = pp2 + n2b
70     v2c = pp2 + n2c
71
72     pp3 = p0 + d3 / 3
73     n3a = r3 * n
74     n3b = rot(n3a, d3, rot120)
75     n3c = rot(n3a, d3, -rot120)
76     v3a = pp3 + n3a
77     v3b = pp3 + n3b
78     v3c = pp3 + n3c
79
80     n0a = n * r0
81     v0a = p0 + n0a
82     v0c = p0 - d3.normalized() * r0 - n0a / 3
83     v0d = p0 - d1.normalized() * r0 - n0a / 3
84     v0b = p0 - d2.normalized() * r0 - n0a / 3
85
86     #v0b=p0+(n1b+n2c)/2
87     #v0d=p0+(n2b+n3c)/2
88     #v0c=p0+(n3b+n1c)/2
89
90     verts = (v1a, v1b, v1c, v2a, v2b, v2c, v3a, v3b, v3c, v0a, v0b, v0c, v0d)
91     faces = ((0, 1, 10, 9), (1, 2, 11, 10), (2, 0, 9, 11),  # chck
92         (3, 4, 11, 9), (4, 5, 12, 11), (5, 3, 9, 12),  # chck
93
94         (6, 7, 12, 9),
95         (7, 8, 10, 12),
96         (8, 6, 9, 10),
97
98         (10, 11, 12))
99
100     return verts, faces
101
102
103 def simplefork(p0, p1, p2, p3, r0, r1, r2, r3):
104     d1 = p1 - p0
105     d2 = p2 - p0
106     d3 = p3 - p0
107     #print(d1, d2, d3)
108     n = -vertexnormal(d1, d2, d3)
109     #print(n)
110
111     # the central tetrahedron
112     n0a = n * r0 * 0.3
113     v0a = n0a
114     v0b = -d1 / 6 - n0a / 2
115     v0c = -d2 / 6 - n0a / 2
116     v0d = -d3 / 6 - n0a / 2
117
118     n1 = v0a + v0c + v0d
119     n2 = v0a + v0b + v0d
120     n3 = v0a + v0b + v0c
121
122     q1 = n1.rotation_difference(d1)
123     q2 = n2.rotation_difference(d2)
124     q3 = n3.rotation_difference(d3)
125
126     pp1 = p0 + d1 / 3
127     v1a = v0a.copy()
128     v1b = v0c.copy()
129     v1c = v0d.copy()
130     v1a.rotate(q1)
131     v1b.rotate(q1)
132     v1c.rotate(q1)
133     v1a += pp1
134     v1b += pp1
135     v1c += pp1
136
137     pp2 = p0 + d2 / 3
138     v2a = v0a.copy()
139     v2b = v0b.copy()
140     v2c = v0d.copy()
141     v2a.rotate(q2)
142     v2b.rotate(q2)
143     v2c.rotate(q2)
144     v2a += pp2
145     v2b += pp2
146     v2c += pp2
147
148     pp3 = p0 + d3 / 3
149     v3a = v0a.copy()
150     v3b = v0b.copy()
151     v3c = v0c.copy()
152     v3a.rotate(q3)
153     v3b.rotate(q3)
154     v3c.rotate(q3)
155     v3a += pp3
156     v3b += pp3
157     v3c += pp3
158
159     v0a += p0
160     v0b += p0
161     v0c += p0
162     v0d += p0
163
164     verts = (v1a, v1b, v1c, v2a, v2b, v2c, v3a, v3b, v3c, v0a, v0b, v0c, v0d)
165     faces = (
166         #(1, 2, 12, 11),
167         #(9, 12, 2, 0),
168         #(11, 9, 0, 1),
169
170         #(5, 4, 10, 12),
171         #(4, 3, 9, 10),
172         #(3, 5, 12, 9),
173
174         (8, 7, 11, 10),
175         (7, 5, 9, 11),
176         (6, 8, 10, 9),
177
178         (10, 11, 12))
179
180     return verts, faces
181
182
183 def bridgequads(aquad, bquad, verts):
184     "return faces,  aloop,  bloop"
185     ai, bi, _ = min([(ai, bi, (verts[a] - verts[b]).length_squared) for ai, a in enumerate(aquad) for bi, b in enumerate(bquad)], key=lambda x: x[2])
186     n = len(aquad)
187     #print([(aquad[(ai+i)%n],  aquad[(ai+i+1)%n],  bquad[(bi+i+1)%n],  bquad[(bi+i)%n]) for i in range(n)], "\n",  [aquad[(ai+i)%n] for i in range(n)], "\n",   [aquad[(bi+i)%n] for i in range(n)])
188
189     #print('bridgequads', aquad, bquad, ai, bi)
190
191     return ([(aquad[(ai + i) % n], aquad[(ai + i + 1) % n], bquad[(bi + i + 1) % n], bquad[(bi + i) % n]) for i in range(n)], [aquad[(ai + i) % n] for i in range(n)], [bquad[(bi + i) % n] for i in range(n)])
192
193
194 def quadfork(p0, p1, p2, p3, r0, r1, r2, r3):
195     d1 = p1 - p0
196     d2 = p2 - p0
197     d3 = p3 - p0
198     a = (d3 - d2).normalized()
199     n = d2.cross(d3).normalized()
200     pp1 = p0 + d1 / 3
201     pp2 = p0 + d2 / 3
202     pp3 = p0 + d3 / 3
203
204     v2a = pp2 + (n + a) * r2
205     v2b = pp2 + (n - a) * r2
206     v2c = pp2 + (-n - a) * r2
207     v2d = pp2 + (-n + a) * r2
208
209     v3a = pp3 + (n + a) * r3
210     v3b = pp3 + (n - a) * r3
211     v3c = pp3 + (-n - a) * r3
212     v3d = pp3 + (-n + a) * r3
213
214     a = d1.cross(n).normalized()
215     n = a.cross(d1).normalized()
216     v1a = pp1 + (n + a) * r1
217     v1b = pp1 + (n - a) * r1
218     v1c = pp1 + (-n - a) * r1
219     v1d = pp1 + (-n + a) * r1
220
221     #the top of the connecting block consist of two quads
222     v0a = p0 + (n + a) * r0
223     v0b = p0 + (n - a) * r0
224     v0c = p0 + (-n - a) * r0
225     v0d = p0 + (-n + a) * r0
226     v0ab = p0 + n * r0
227     v0cd = p0 - n * r0
228     #the bottom is a single quad (which means the front and back are 5gons)
229     d = d1.normalized() * r0 * 0.1
230     vb0a = v0a + d
231     vb0b = v0b + d
232     vb0c = v0c + d
233     vb0d = v0d + d
234
235     verts = [v1a, v1b, v1c, v1d,             # 0 1 2 3
236         v2a, v2b, v2c, v2d,             # 4 5 6 7
237         v3a, v3b, v3c, v3d,             # 8 9 10 11
238         v0a, v0ab, v0b, v0c, v0cd, v0d,   # 12 13 14 15 16 17
239         vb0a, vb0b, vb0c, vb0d]        # 18 19 20 21
240
241     faces = [(0, 1, 19, 18),        # p1->p0 bottom
242         (1, 2, 20, 19),
243         (2, 3, 21, 20),
244         (3, 0, 18, 21),
245
246         #(4, 5, 14, 13),        # p2 -> p0 top right
247         #(5, 6, 15, 14),
248         #(6, 7, 16, 15),
249         #(7, 4, 13, 16),
250
251         (13, 14, 5, 4),
252         (14, 15, 6, 5),
253         (15, 16, 7, 6),
254         (16, 13, 4, 7),
255
256         #(8, 9, 13, 12),        # p3 -> p0 top left
257         #(9, 10, 16, 13),
258         #(10, 11, 17, 16),
259         #(11, 8, 12, 17),
260
261         (12, 13, 9, 8),
262         (13, 16, 10, 9),
263         (16, 17, 11, 10),
264         (17, 12, 8, 11),
265
266         #(12, 17, 21, 18),      # connecting block
267         #(14, 15, 20, 19),
268         #(12, 13, 14, 19, 18),
269         #(15, 16, 17, 21, 20)]
270
271         (12, 17, 21, 18),      # connecting block
272         (19, 20, 15, 14),
273         (18, 19, 14, 13, 12),
274         (20, 21, 17, 16, 15)]
275
276     return verts, faces