Sun position: remove unused prop in HDRI mode
[blender-addons.git] / archipack / panel.py
blob7339cc3a2c3462ccbcff7d2156c40a1186ba0647
1 # -*- coding:utf-8 -*-
3 # ##### BEGIN GPL LICENSE BLOCK #####
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software Foundation,
17 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110- 1301, USA.
19 # ##### END GPL LICENSE BLOCK #####
21 # <pep8 compliant>
23 # ----------------------------------------------------------
24 # Author: Stephen Leger (s-leger)
26 # ----------------------------------------------------------
28 from math import cos, sin, tan, sqrt, atan2, pi
29 from mathutils import Vector
32 class Panel():
33 """
34 Define a bevel profil
35 index: array associate each y with a coord circle and a x
36 x = array of x of unique points in the profil relative to origin (0, 0) is bottom left
37 y = array of y of all points in the profil relative to origin (0, 0) is bottom left
38 idmat = array of material index for each segment
39 when path is not closed, start and end caps are generated
41 shape is the loft profile
42 path is the loft path
44 Open shape:
46 x = [0,1]
47 y = [0,1,1, 0]
48 index = [0, 0,1,1]
49 closed_shape = False
51 1 ____2
52 | |
53 | |
54 | |
55 0 3
57 Closed shape:
59 x = [0,1]
60 y = [0,1,1, 0]
61 index = [0, 0,1,1]
62 closed_shape = True
64 1 ____2
65 | |
66 | |
67 |____|
68 0 3
70 Side Caps (like glass for window):
72 x = [0,1]
73 y = [0,1,1, 0.75, 0.25, 0]
74 index = [0, 0,1,1,1,1]
75 closed_shape = True
76 side_caps = [3,4]
78 1 ____2 ____
79 | 3|__cap__| |
80 | 4|_______| |
81 |____| |____|
82 0 5
84 """
85 def __init__(self, closed_shape, index, x, y, idmat, side_cap_front=-1, side_cap_back=-1, closed_path=True,
86 subdiv_x=0, subdiv_y=0, user_path_verts=0, user_path_uv_v=None):
88 self.closed_shape = closed_shape
89 self.closed_path = closed_path
90 self.index = index
91 self.x = x
92 self.y = y
93 self.idmat = idmat
94 self.side_cap_front = side_cap_front
95 self.side_cap_back = side_cap_back
96 self.subdiv_x = subdiv_x
97 self.subdiv_y = subdiv_y
98 self.user_path_verts = user_path_verts
99 self.user_path_uv_v = user_path_uv_v
101 @property
102 def n_pts(self):
103 return len(self.y)
105 @property
106 def profil_faces(self):
108 number of faces for each section
110 if self.closed_shape:
111 return len(self.y)
112 else:
113 return len(self.y) - 1
115 @property
116 def uv_u(self):
118 uvs of profil (absolute value)
120 x = [self.x[i] for i in self.index]
121 x.append(x[0])
122 y = [y for y in self.y]
123 y.append(y[0])
124 uv_u = []
125 uv = 0
126 uv_u.append(uv)
127 for i in range(len(self.index)):
128 dx = x[i + 1] - x[i]
129 dy = y[i + 1] - y[i]
130 uv += sqrt(dx * dx + dy * dy)
131 uv_u.append(uv)
132 return uv_u
134 def path_sections(self, steps, path_type):
136 number of verts and faces sections along path
138 n_path_verts = 2
139 if path_type in ['QUADRI', 'RECTANGLE']:
140 n_path_verts = 4 + self.subdiv_x + 2 * self.subdiv_y
141 if self.closed_path:
142 n_path_verts += self.subdiv_x
143 elif path_type in ['ROUND', 'ELLIPSIS']:
144 n_path_verts = steps + 3
145 elif path_type == 'CIRCLE':
146 n_path_verts = steps
147 elif path_type == 'TRIANGLE':
148 n_path_verts = 3
149 elif path_type == 'PENTAGON':
150 n_path_verts = 5
151 elif path_type == 'USER_DEFINED':
152 n_path_verts = self.user_path_verts
153 if self.closed_path:
154 n_path_faces = n_path_verts
155 else:
156 n_path_faces = n_path_verts - 1
157 return n_path_verts, n_path_faces
159 def n_verts(self, steps, path_type):
160 n_path_verts, n_path_faces = self.path_sections(steps, path_type)
161 return self.n_pts * n_path_verts
163 ############################
164 # Geomerty
165 ############################
167 def _intersect_line(self, center, basis, x):
168 """ upper intersection of line parallel to y axis and a triangle
169 where line is given by x origin
170 top by center, basis size as float
171 return float y of upper intersection point
173 center.x and center.y are absolute
174 a 0 center.x lie on half size
175 a 0 center.y lie on basis
177 if center.x > 0:
178 dx = x - center.x
179 else:
180 dx = center.x - x
181 p = center.y / basis
182 return center.y + dx * p
184 def _intersect_triangle(self, center, basis, x):
185 """ upper intersection of line parallel to y axis and a triangle
186 where line is given by x origin
187 top by center, basis size as float
188 return float y of upper intersection point
190 center.x and center.y are absolute
191 a 0 center.x lie on half size
192 a 0 center.y lie on basis
194 if x > center.x:
195 dx = center.x - x
196 sx = 0.5 * basis - center.x
197 else:
198 dx = x - center.x
199 sx = 0.5 * basis + center.x
200 if sx == 0:
201 sx = basis
202 p = center.y / sx
203 return center.y + dx * p
205 def _intersect_circle(self, center, radius, x):
206 """ upper intersection of line parallel to y axis and a circle
207 where line is given by x origin
208 circle by center, radius as float
209 return float y of upper intersection point, float angle
211 dx = x - center.x
212 d = (radius * radius) - (dx * dx)
213 if d <= 0:
214 if x > center.x:
215 return center.y, 0
216 else:
217 return center.y, pi
218 else:
219 y = sqrt(d)
220 return center.y + y, atan2(y, dx)
222 def _intersect_elipsis(self, center, radius, x):
223 """ upper intersection of line parallel to y axis and an ellipsis
224 where line is given by x origin
225 circle by center, radius.x and radius.y semimajor and seminimor axis (half width and height) as float
226 return float y of upper intersection point, float angle
228 dx = x - center.x
229 d2 = dx * dx
230 A = 1 / radius.y / radius.y
231 C = d2 / radius.x / radius.x - 1
232 d = - 4 * A * C
233 if d <= 0:
234 if x > center.x:
235 return center.y, 0
236 else:
237 return center.y, pi
238 else:
239 y0 = sqrt(d) / 2 / A
240 d = (radius.x * radius.x) - d2
241 y = sqrt(d)
242 return center.y + y0, atan2(y, dx)
244 def _intersect_arc(self, center, radius, x_left, x_right):
245 y0, a0 = self._intersect_circle(center, radius.x, x_left)
246 y1, a1 = self._intersect_circle(center, radius.x, x_right)
247 da = (a1 - a0)
248 if da < -pi:
249 da += 2 * pi
250 if da > pi:
251 da -= 2 * pi
252 return y0, y1, a0, da
254 def _intersect_arc_elliptic(self, center, radius, x_left, x_right):
255 y0, a0 = self._intersect_elipsis(center, radius, x_left)
256 y1, a1 = self._intersect_elipsis(center, radius, x_right)
257 da = (a1 - a0)
258 if da < -pi:
259 da += 2 * pi
260 if da > pi:
261 da -= 2 * pi
262 return y0, y1, a0, da
264 def _get_ellispe_coords(self, steps, offset, center, origin, size, radius, x, pivot, bottom_y=0):
266 Rectangle with single arc on top
268 x_left = size.x / 2 * (pivot - 1) + x
269 x_right = size.x / 2 * (pivot + 1) - x
270 cx = center.x - origin.x
271 cy = offset.y + center.y - origin.y
272 y0, y1, a0, da = self._intersect_arc_elliptic(center, radius, origin.x + x_left, origin.x + x_right)
273 da /= steps
274 coords = []
275 # bottom left
276 if self.closed_path:
277 coords.append((offset.x + x_left, offset.y + x + bottom_y))
278 else:
279 coords.append((offset.x + x_left, offset.y + bottom_y))
280 # top left
281 coords.append((offset.x + x_left, offset.y + y0 - origin.y))
282 for i in range(1, steps):
283 a = a0 + i * da
284 coords.append((offset.x + cx + cos(a) * radius.x, cy + sin(a) * radius.y))
285 # top right
286 coords.append((offset.x + x_right, offset.y + y1 - origin.y))
287 # bottom right
288 if self.closed_path:
289 coords.append((offset.x + x_right, offset.y + x + bottom_y))
290 else:
291 coords.append((offset.x + x_right, offset.y + bottom_y))
292 return coords
294 def _get_arc_coords(self, steps, offset, center, origin, size, radius, x, pivot, bottom_y=0):
296 Rectangle with single arc on top
298 x_left = size.x / 2 * (pivot - 1) + x
299 x_right = size.x / 2 * (pivot + 1) - x
300 cx = offset.x + center.x - origin.x
301 cy = offset.y + center.y - origin.y
302 y0, y1, a0, da = self._intersect_arc(center, radius, origin.x + x_left, origin.x + x_right)
303 da /= steps
304 coords = []
306 # bottom left
307 if self.closed_path:
308 coords.append((offset.x + x_left, offset.y + x + bottom_y))
309 else:
310 coords.append((offset.x + x_left, offset.y + bottom_y))
312 # top left
313 coords.append((offset.x + x_left, offset.y + y0 - origin.y))
315 for i in range(1, steps):
316 a = a0 + i * da
317 coords.append((cx + cos(a) * radius.x, cy + sin(a) * radius.x))
319 # top right
320 coords.append((offset.x + x_right, offset.y + y1 - origin.y))
322 # bottom right
323 if self.closed_path:
324 coords.append((offset.x + x_right, offset.y + x + bottom_y))
325 else:
326 coords.append((offset.x + x_right, offset.y + bottom_y))
328 return coords
330 def _get_circle_coords(self, steps, offset, center, origin, radius):
332 Full circle
334 cx = offset.x + center.x - origin.x
335 cy = offset.y + center.y - origin.y
336 a = -2 * pi / steps
337 return [(cx + cos(i * a) * radius.x, cy + sin(i * a) * radius.x) for i in range(steps)]
339 def _get_rectangular_coords(self, offset, size, x, pivot, bottom_y=0):
340 coords = []
342 x_left = offset.x + size.x / 2 * (pivot - 1) + x
343 x_right = offset.x + size.x / 2 * (pivot + 1) - x
345 if self.closed_path:
346 y0 = offset.y + x + bottom_y
347 else:
348 y0 = offset.y + bottom_y
349 y1 = offset.y + size.y - x
351 dy = (y1 - y0) / (1 + self.subdiv_y)
352 dx = (x_right - x_left) / (1 + self.subdiv_x)
354 # bottom left
355 # coords.append((x_left, y0))
357 # subdiv left
358 for i in range(self.subdiv_y + 1):
359 coords.append((x_left, y0 + i * dy))
361 # top left
362 # coords.append((x_left, y1))
364 # subdiv top
365 for i in range(self.subdiv_x + 1):
366 coords.append((x_left + dx * i, y1))
368 # top right
369 # coords.append((x_right, y1))
370 # subdiv right
371 for i in range(self.subdiv_y + 1):
372 coords.append((x_right, y1 - i * dy))
374 # subdiv bottom
375 if self.closed_path:
376 for i in range(self.subdiv_x + 1):
377 coords.append((x_right - dx * i, y0))
378 else:
379 # bottom right
380 coords.append((x_right, y0))
382 return coords
384 def _get_vertical_rectangular_trapezoid_coords(self, offset, center, origin, size, basis, x, pivot, bottom_y=0):
386 Rectangular trapezoid vertical
387 basis is the full width of a triangular area the trapezoid lie into
388 center.y is the height of triagular area from top
389 center.x is the offset from basis center
393 |__|
395 coords = []
396 x_left = size.x / 2 * (pivot - 1) + x
397 x_right = size.x / 2 * (pivot + 1) - x
398 sx = x * sqrt(basis * basis + center.y * center.y) / basis
399 dy = size.y + offset.y - sx
400 y0 = self._intersect_line(center, basis, origin.x + x_left)
401 y1 = self._intersect_line(center, basis, origin.x + x_right)
402 # bottom left
403 if self.closed_path:
404 coords.append((offset.x + x_left, offset.y + x + bottom_y))
405 else:
406 coords.append((offset.x + x_left, offset.y + bottom_y))
407 # top left
408 coords.append((offset.x + x_left, dy - y0))
409 # top right
410 coords.append((offset.x + x_right, dy - y1))
411 # bottom right
412 if self.closed_path:
413 coords.append((offset.x + x_right, offset.y + x + bottom_y))
414 else:
415 coords.append((offset.x + x_right, offset.y + bottom_y))
416 return coords
418 def _get_horizontal_rectangular_trapezoid_coords(self, offset, center, origin, size, basis, x, pivot, bottom_y=0):
420 Rectangular trapeze horizontal
421 basis is the full width of a triangular area the trapezoid lie into
422 center.y is the height of triagular area from top to basis
423 center.x is the offset from basis center
426 |____\
428 TODO: correct implementation
430 raise NotImplementedError
432 def _get_pentagon_coords(self, offset, center, origin, size, basis, x, pivot, bottom_y=0):
434 TODO: correct implementation
438 |____|
440 raise NotImplementedError
442 def _get_triangle_coords(self, offset, center, origin, size, basis, x, pivot, bottom_y=0):
443 coords = []
444 x_left = offset.x + size.x / 2 * (pivot - 1) + x
445 x_right = offset.x + size.x / 2 * (pivot + 1) - x
447 # bottom left
448 if self.closed_path:
449 coords.append((x_left, offset.y + x + bottom_y))
450 else:
451 coords.append((x_left, offset.y + bottom_y))
452 # top center
453 coords.append((center.x, offset.y + center.y))
454 # bottom right
455 if self.closed_path:
456 coords.append((x_right, offset.y + x + bottom_y))
457 else:
458 coords.append((x_right, offset.y + bottom_y))
459 return coords
461 def _get_horizontal_coords(self, offset, size, x, pivot):
462 coords = []
463 x_left = offset.x + size.x / 2 * (pivot - 1)
464 x_right = offset.x + size.x / 2 * (pivot + 1)
465 # left
466 coords.append((x_left, offset.y + x))
467 # right
468 coords.append((x_right, offset.y + x))
469 return coords
471 def _get_vertical_coords(self, offset, size, x, pivot):
472 coords = []
473 x_left = offset.x + size.x / 2 * (pivot - 1) + x
474 # top
475 coords.append((x_left, offset.y + size.y))
476 # bottom
477 coords.append((x_left, offset.y))
478 return coords
480 def choose_a_shape_in_tri(self, center, origin, size, basis, pivot):
482 Choose which shape inside either a tri or a pentagon
484 cx = (0.5 * basis + center.x) - origin.x
485 cy = center.y - origin.y
486 x_left = size.x / 2 * (pivot - 1)
487 x_right = size.x / 2 * (pivot + 1)
488 y0 = self.intersect_triangle(cx, cy, basis, x_left)
489 y1 = self.intersect_triangle(cx, cy, basis, x_right)
490 if (y0 == 0 and y1 == 0) or ((y0 == 0 or y1 == 0) and (y0 == cy or y1 == cy)):
491 return 'TRIANGLE'
492 elif x_right <= cx or x_left >= cx:
493 # single side of triangle
494 # may be horizontal or vertical rectangular trapezoid
495 # horizontal if size.y < center.y
496 return 'QUADRI'
497 else:
498 # both sides of triangle
499 # may be horizontal trapezoid or pentagon
500 # horizontal trapezoid if size.y < center.y
501 return 'PENTAGON'
503 ############################
504 # Vertices
505 ############################
507 def vertices(self, steps, offset, center, origin, size, radius,
508 angle_y, pivot, shape_z=None, path_type='ROUND', axis='XZ'):
510 verts = []
511 if shape_z is None:
512 shape_z = [0 for x in self.x]
513 if path_type == 'ROUND':
514 coords = [self._get_arc_coords(steps, offset, center, origin,
515 size, Vector((radius.x - x, 0)), x, pivot, shape_z[i]) for i, x in enumerate(self.x)]
516 elif path_type == 'ELLIPSIS':
517 coords = [self._get_ellispe_coords(steps, offset, center, origin,
518 size, Vector((radius.x - x, radius.y - x)), x, pivot, shape_z[i]) for i, x in enumerate(self.x)]
519 elif path_type == 'QUADRI':
520 coords = [self._get_vertical_rectangular_trapezoid_coords(offset, center, origin,
521 size, radius.x, x, pivot) for i, x in enumerate(self.x)]
522 elif path_type == 'HORIZONTAL':
523 coords = [self._get_horizontal_coords(offset, size, x, pivot)
524 for i, x in enumerate(self.x)]
525 elif path_type == 'VERTICAL':
526 coords = [self._get_vertical_coords(offset, size, x, pivot)
527 for i, x in enumerate(self.x)]
528 elif path_type == 'CIRCLE':
529 coords = [self._get_circle_coords(steps, offset, center, origin, Vector((radius.x - x, 0)))
530 for i, x in enumerate(self.x)]
531 else:
532 coords = [self._get_rectangular_coords(offset, size, x, pivot, shape_z[i])
533 for i, x in enumerate(self.x)]
534 # vertical panel (as for windows)
535 if axis == 'XZ':
536 for i in range(len(coords[0])):
537 for j, p in enumerate(self.index):
538 x, z = coords[p][i]
539 y = self.y[j]
540 verts.append((x, y, z))
541 # horizontal panel (table and so on)
542 elif axis == 'XY':
543 for i in range(len(coords[0])):
544 for j, p in enumerate(self.index):
545 x, y = coords[p][i]
546 z = self.y[j]
547 verts.append((x, y, z))
548 return verts
550 ############################
551 # Faces
552 ############################
554 def _faces_cap(self, faces, n_path_verts, offset):
555 if self.closed_shape and not self.closed_path:
556 last_point = offset + self.n_pts * n_path_verts - 1
557 faces.append(tuple([offset + i for i in range(self.n_pts)]))
558 faces.append(tuple([last_point - i for i in range(self.n_pts)]))
560 def _faces_closed(self, n_path_faces, offset):
561 faces = []
562 n_pts = self.n_pts
563 for i in range(n_path_faces):
564 k0 = offset + i * n_pts
565 if self.closed_path and i == n_path_faces - 1:
566 k1 = offset
567 else:
568 k1 = k0 + n_pts
569 for j in range(n_pts - 1):
570 faces.append((k1 + j, k1 + j + 1, k0 + j + 1, k0 + j))
571 # close profile
572 faces.append((k1 + n_pts - 1, k1, k0, k0 + n_pts - 1))
573 return faces
575 def _faces_open(self, n_path_faces, offset):
576 faces = []
577 n_pts = self.n_pts
578 for i in range(n_path_faces):
579 k0 = offset + i * n_pts
580 if self.closed_path and i == n_path_faces - 1:
581 k1 = offset
582 else:
583 k1 = k0 + n_pts
584 for j in range(n_pts - 1):
585 faces.append((k1 + j, k1 + j + 1, k0 + j + 1, k0 + j))
586 return faces
588 def _faces_side(self, faces, n_path_verts, start, reverse, offset):
589 n_pts = self.n_pts
590 vf = [offset + start + n_pts * f for f in range(n_path_verts)]
591 if reverse:
592 faces.append(tuple(reversed(vf)))
593 else:
594 faces.append(tuple(vf))
596 def faces(self, steps, offset=0, path_type='ROUND'):
597 n_path_verts, n_path_faces = self.path_sections(steps, path_type)
598 if self.closed_shape:
599 faces = self._faces_closed(n_path_faces, offset)
600 else:
601 faces = self._faces_open(n_path_faces, offset)
602 if self.side_cap_front > -1:
603 self._faces_side(faces, n_path_verts, self.side_cap_front, False, offset)
604 if self.side_cap_back > -1:
605 self._faces_side(faces, n_path_verts, self.side_cap_back, True, offset)
606 self._faces_cap(faces, n_path_verts, offset)
607 return faces
609 ############################
610 # Uvmaps
611 ############################
613 def uv(self, steps, center, origin, size, radius, angle_y, pivot, x, x_cap, path_type='ROUND'):
614 uvs = []
615 n_path_verts, n_path_faces = self.path_sections(steps, path_type)
616 if path_type in ['ROUND', 'ELLIPSIS']:
617 x_left = size.x / 2 * (pivot - 1) + x
618 x_right = size.x / 2 * (pivot + 1) - x
619 if path_type == 'ELLIPSIS':
620 y0, y1, a0, da = self._intersect_arc_elliptic(center, radius, x_left, x_right)
621 else:
622 y0, y1, a0, da = self._intersect_arc(center, radius, x_left, x_right)
623 uv_r = abs(da) * radius.x / steps
624 uv_v = [uv_r for i in range(steps)]
625 uv_v.insert(0, y0 - origin.y)
626 uv_v.append(y1 - origin.y)
627 uv_v.append(size.x)
628 elif path_type == 'USER_DEFINED':
629 uv_v = self.user_path_uv_v
630 elif path_type == 'CIRCLE':
631 uv_r = 2 * pi * radius.x / steps
632 uv_v = [uv_r for i in range(steps + 1)]
633 elif path_type == 'QUADRI':
634 dy = 0.5 * tan(angle_y) * size.x
635 uv_v = [size.y - dy, size.x, size.y + dy, size.x]
636 elif path_type == 'HORIZONTAL':
637 uv_v = [size.y]
638 elif path_type == 'VERTICAL':
639 uv_v = [size.y]
640 else:
641 dx = size.x / (1 + self.subdiv_x)
642 dy = size.y / (1 + self.subdiv_y)
643 uv_v = []
644 for i in range(self.subdiv_y + 1):
645 uv_v.append(dy * (i + 1))
646 for i in range(self.subdiv_x + 1):
647 uv_v.append(dx * (i + 1))
648 for i in range(self.subdiv_y + 1):
649 uv_v.append(dy * (i + 1))
650 for i in range(self.subdiv_x + 1):
651 uv_v.append(dx * (i + 1))
652 # uv_v = [size.y, size.x, size.y, size.x]
654 uv_u = self.uv_u
655 if self.closed_shape:
656 n_pts = self.n_pts
657 else:
658 n_pts = self.n_pts - 1
659 v0 = 0
660 # uvs parties rondes
661 for i in range(n_path_faces):
662 v1 = v0 + uv_v[i]
663 for j in range(n_pts):
664 u0 = uv_u[j]
665 u1 = uv_u[j + 1]
666 uvs.append([(u0, v1), (u1, v1), (u1, v0), (u0, v0)])
667 v0 = v1
668 if self.side_cap_back > -1 or self.side_cap_front > -1:
669 if path_type == 'ROUND':
670 # rectangle with top part round
671 coords = self._get_arc_coords(steps, Vector((0, 0, 0)), center,
672 origin, size, Vector((radius.x - x_cap, 0)), x_cap, pivot, x_cap)
673 elif path_type == 'CIRCLE':
674 # full circle
675 coords = self._get_circle_coords(steps, Vector((0, 0, 0)), center,
676 origin, Vector((radius.x - x_cap, 0)))
677 elif path_type == 'ELLIPSIS':
678 coords = self._get_ellispe_coords(steps, Vector((0, 0, 0)), center,
679 origin, size, Vector((radius.x - x_cap, radius.y - x_cap)), x_cap, pivot, x_cap)
680 elif path_type == 'QUADRI':
681 coords = self._get_vertical_rectangular_trapezoid_coords(Vector((0, 0, 0)), center,
682 origin, size, radius.x, x_cap, pivot)
683 # coords = self._get_trapezoidal_coords(0, origin, size, angle_y, x_cap, pivot, x_cap)
684 else:
685 coords = self._get_rectangular_coords(Vector((0, 0, 0)), size, x_cap, pivot, 0)
686 if self.side_cap_front > -1:
687 uvs.append(list(coords))
688 if self.side_cap_back > -1:
689 uvs.append(list(reversed(coords)))
691 if self.closed_shape and not self.closed_path:
692 coords = [(self.x[self.index[i]], y) for i, y in enumerate(self.y)]
693 uvs.append(coords)
694 uvs.append(list(reversed(coords)))
695 return uvs
697 ############################
698 # Material indexes
699 ############################
701 def mat(self, steps, cap_front_id, cap_back_id, path_type='ROUND'):
702 n_path_verts, n_path_faces = self.path_sections(steps, path_type)
703 n_profil_faces = self.profil_faces
704 idmat = []
705 for i in range(n_path_faces):
706 for f in range(n_profil_faces):
707 idmat.append(self.idmat[f])
708 if self.side_cap_front > -1:
709 idmat.append(cap_front_id)
710 if self.side_cap_back > -1:
711 idmat.append(cap_back_id)
712 if self.closed_shape and not self.closed_path:
713 idmat.append(self.idmat[0])
714 idmat.append(self.idmat[0])
715 return idmat