1# vert class and overloading experiments
2import bpy
3# PKHG>NEEDED?
4import bmesh
5from math import acos, pi, sin, cos, atan, tan
6from mathutils import Vector
7from bpy_extras.object_utils import AddObjectHelper
8
9# PKHG>DBG change the DBG_info and use extra_DBG_info
10DBG_info = {"MeshInfo": False, "StrutMesh": False, "HubMesh": False}
11
12
13def extra_DBG_info(name="value from DBG_info", info_text="default\n", info_obj=None):
14    global DBG_info
15    DBG_keys = DBG_info.keys()
16    if name in DBG_keys:
17        if DBG_info[name]:
18            print(info_text, info_obj)
19
20sgn = lambda x: (x > 0) - (x < 0)  # missing signum function in Python
21
22
23def vefm_add_object(selfobj):
24    for i in range(len(selfobj.verts)):
25        selfobj.verts[i].index = i
26    v = [el.vector for el in selfobj.verts]
27
28    e = [[edge.a.index, edge.b.index] for edge in selfobj.edges]
29
30    if type(selfobj.faces[0]) == type([]):
31        # PKHG should be a list of vertices, which have an index
32        f = [[v.index for v in face] for face in selfobj.faces]
33    else:
34        f = [[v.index for v in face.vertices] for face in selfobj.faces]
35
36    m = bpy.data.meshes.new(name=selfobj.name)
37    m.from_pydata(v, e, f)
38    # useful for development when the mesh may be invalid.
39    m.validate(verbose=False)
40    return m
41
42
43# extra test phase
44
45class vertex:
46    def __init__(self, vec=(0, 0, 0)):  # default x = 0, y = 0, z = 0):
47        self.vector = Vector(vec)
48        self.length = self.vector.length
49        self.index = 0
50        self.normal = 0
51        self.edges = []
52        self.faces = []
53        self.boundary = 0
54
55    def findlength(self):
56        self.length = self.vector.length
57
58    def normalize(self):
59        self.findlength()
60        if self.length > 0:
61            tmp = 1.0 / self.length
62            self.vector = tmp * self.vector
63            self.length = 1.0
64
65    def findnormal(self):
66        target = []
67        if self.faces[:] == []:
68            print("vefm vertex L68 pkhg:*****ERROR**** findnormal has no faces")
69            return
70        for currentface in self.faces:
71            target.append(currentface.normal)
72        self.normal = average(target).centroid()
73        self.normal.findlength()
74        if self.length == 0:
75            print("******ERROR*** length zero in findnormal, j = (0,1,0) replaced")
76            self.normal = vertex((0, 1, 0))
77        self.normal.normalize()
78
79    def clockwise(self):  # PKHG self is a vertex
80        if self.boundary:
81            start = self.boundarystart()
82        else:
83            start = self.faces[0]
84
85        self.tempedges = []
86        self.tempfaces = []
87        for i in range(len(self.edges)):
88
89            self.tempfaces.append(start)
90            for corner in start.corners:
91                if corner[0] is not self:
92                    pass
93                elif corner[0] is self:
94                    self.tempedges.append(corner[1])
95                    nextedge = corner[2]
96            for facey in nextedge.faces:
97                if facey is not start:
98                    start = facey
99                    break
100        self.edges = self.tempedges
101        self.faces = self.tempfaces
102
103    def boundarystart(self):
104
105        pass
106
107    def __add__(self, other):
108        if isinstance(other, Vector):
109            tmp = self.vector + other
110        else:
111            tmp = self.vector + other.vector
112        return vertex(tmp)
113
114    def __sub__(self, other):
115        if isinstance(other, Vector):
116            tmp = self.vector - other
117        else:
118            tmp = self.vector - other.vector
119        return vertex(tmp)
120
121    def __mul__(self, other):
122        tmp = self.vector * other
123        return vertex(tmp)
124
125    def __truediv__(self, other):
126        denom = 1.0 / other
127        tmp = self.vector * denom
128        return (tmp)
129
130    def negative(self):
131        return vertex(-self.vector)
132
133
134class crossp:
135    # Takes in two vertices(vectors), returns the cross product.
136    def __init__(self, v1, v2):
137        self.v1 = v1
138        self.v2 = v2
139
140    def docrossproduct(self):
141        tmp = self.v1.vector.cross(self.v2.vector)
142        return vertex(tmp)
143
144
145class average:
146    # Takes a list of vertices and returns the average. If two verts are passed, returns midpoint.
147    def __init__(self, vertlist):
148        self.vertlist = vertlist
149
150    def centroid(self):
151        tmp = Vector()
152        # PKHG avoid emptylist problems
153        divisor = 1.0
154        nr_vertices = len(self.vertlist)
155        if nr_vertices > 1:
156            divisor = 1.0 / len(self.vertlist)
157        elif nr_vertices == 0:
158            print("\n***WARNING*** empty list in vefm_271.centroid! L158")
159        for vert in self.vertlist:
160            tmp = tmp + vert.vector
161        tmp = tmp * divisor
162        return vertex(tmp)
163
164
165class edge:
166    def __init__(self, a=0, b=0):
167        self.a = a
168        self.b = b
169        self.index = 0
170        self.normal = 0
171        self.cross = 0
172        self.unit = 0
173        self.faces = []
174        self.vect = 0   # PKHG becomes  b - a
175        self.vectb = 0  # PKHG becomes  a - b
176        self.boundary = 0
177        self.findvect()
178        self.findlength()
179
180    def findvect(self):
181        self.vect = self.b - self.a
182        self.vectb = self.a - self.b
183
184    def findlength(self):
185        self.vect.findlength()
186        self.vectb.length = self.vect.length
187
188    def findnormal(self):
189        if self.boundary:
190            self.normal = self.faces[0].normal    # average([self.a, self.b]).centroid()
191        else:
192            self.normal = average([self.faces[0].normal, self.faces[1].normal]).centroid()
193        self.normal.normalize()
194
195
196class face:
197    def __init__(self, vertices=[]):
198        # PKHG ok good for tri's at least
199        self.vertices = vertices    # List of vertex instances
200        self.edges = []             # Will be filled with the sides of the face
201        self.boundary = 0           # When set will have bool and id of edge concerned
202        self.normal = 0             # Face normal found through cross product
203        self.corners = []
204        self.spokes = []            # Vectors of the bisecting angles from each corner to the centre + dotproduct
205
206        self.index = 0
207
208    # dotproduct is misleading name, it is the hook between two vectors!
209    def dotproduct(self, v1, v2):
210        v1.findlength()
211        v2.findlength()
212        if v1.length == 0 or v2.length == 0:
213            print("\nPKHG warning, ===== vefm_271 dotproduct L212 ======"
214                  " at least one zero vector 0 used")
215            return 0
216        dot = v1.vector.dot(v2.vector)
217        costheta = dot / (v1.length * v2.length)
218        tmp = acos(costheta)
219        return tmp
220
221    def orderedges(self):
222        temp = []
223        finish = len(self.vertices)
224        for i in range(finish):
225            current = self.vertices[i]
226            if i == finish - 1:
227                next = self.vertices[0]
228            else:
229                next = self.vertices[i + 1]
230            for edge in face.edges:
231                if edge.a == current and edge.b == next:
232                    face.clockw.append(edge.vect)
233                    face.aclockw.append(edge.vectb)
234                    temp.append(edge)
235                if edge.b == current and edge.a == next:
236                    face.clockw.append(edge.vectb)
237                    face.aclockw.append(edge.vect)
238                    temp.append(edge)
239            for edge in face.edges:
240                if edge.a == current and edge.b == next:
241                    face.clockw.append(edge.vect)
242                    face.aclockw.append(edge.vectb)
243                    temp.append(edge)
244                if edge.b == current and edge.a == next:
245                    face.clockw.append(edge.vectb)
246                    face.aclockw.append(edge.vect)
247                    temp.append(edge)
248            face.vertices = temp
249
250    def docorners(self):
251        # This function identifies and stores the vectors coming from each vertex
252        # allowing easier calculation of cross and dot products.
253        finish = len(self.vertices)
254
255        for i in range(finish):
256            current = self.vertices[i]
257            if i == finish - 1:
258                next = self.vertices[0]
259            else:
260                next = self.vertices[i + 1]
261            if i == 0:
262                previous = self.vertices[-1]
263            else:
264                previous = self.vertices[i - 1]
265            corner = [current]  # PKHG new for each vertex = current
266            # corner = current
267            rightedge = None
268            leftedge = None
269            teller = -1
270            for edge in self.edges:
271                if finish == 3 and len(self.edges) == 2 and i == 2:
272                    return
273                teller += 1
274                # next and previous are vertex with respect to ith vertex
275                if edge.a is current or edge.b is current:    # does this edge contain our current vert
276                    if edge.a is current:
277                        if edge.b is next:
278                            rightedge = edge
279                            rightvect = edge.vect
280                        if edge.b is previous:
281                            leftedge = edge
282                            leftvect = edge.vect
283                    elif edge.b is current:
284                        if edge.a is next:
285                            rightedge = edge
286                            rightvect = edge.vectb
287                        if edge.a is previous:
288                            leftedge = edge
289                            leftvect = edge.vectb
290            corner.append(rightedge)
291            corner.append(leftedge)
292            if rightedge and leftedge:
293
294                dotty = self.dotproduct(rightvect, leftvect)
295                corner.append(dotty)
296            self.corners.append(corner)
297
298    def findnormal(self):
299        one = self.corners[1][2]
300        two = self.corners[1][1]
301        if one.a is self.corners[1][0]:
302            one = one.vect
303        elif one.b is self.corners[1][0]:
304            one = one.vectb
305        if two.a is self.corners[1][0]:
306            two = two.vect
307        elif two.b is self.corners[1][0]:
308            two = two.vectb
309        self.normal = crossp(one, two).docrossproduct()
310        self.normal.findlength()
311        self.normal.normalize()
312
313    def dospokes(self):
314        for corner in self.corners:
315            vert = corner[0]
316            right = corner[1]
317            left = corner[2]
318            if right.a is vert:
319                one = vertex(right.vect.vector)
320            elif right.b is vert:
321                one = vertex(right.vectb.vector)
322            if left.a is vert:
323                two = vertex(left.vect.vector)
324            elif left.b is vert:
325                two = vertex(left.vectb.vector)
326
327            one.normalize()
328            two.normalize()
329            spoke = one + two
330            spoke.normalize()
331            self.spokes.append(spoke)
332
333    def artspokes(self):
334        centre = average(self.vertices).centroid()
335        for point in self.vertices:
336            newedge = edge(point, centre)
337            self.spokes.append(newedge)
338
339
340class mesh:
341    def __init__(self, name="GD_mesh"):
342        self.name = name
343        self.verts = []
344        self.edges = []
345        self.faces = []
346        self.edgeflag = 0
347        self.faceflag = 0
348        self.vertexflag = 0
349        self.vertedgeflag = 0
350        self.vertfaceflag = 0
351        self.faceedgeflag = 0
352        self.boundaryflag = 0
353        self.vertnormalflag = 0
354        self.edgenormalflag = 0
355        self.facenormalflag = 0
356        self.a45 = pi * 0.25
357        self.a90 = pi * 0.5
358        self.a180 = pi
359        self.a270 = pi * 1.5
360        self.a360 = pi * 2
361
362    def power(self, a, b):  # Returns a power, including negative numbers
363        result = sgn(a) * (abs(a) ** b)
364        return result
365
366    def sign(self, d):      # Works out the sign of a number.
367        return sgn(d)
368
369    def ellipsecomp(self, efactor, theta):
370        if theta == self.a90:
371            result = self.a90
372        elif theta == self.a180:
373            result = self.a180
374        elif theta == self.a270:
375            result = self.a270
376        elif theta == self.a360:
377            result = 0.0
378        else:
379            result = atan(tan(theta) / efactor ** 0.5)
380            if result < 0.0:
381                if theta > self.a180:
382                    result = result + self.a180
383                elif theta < self.a180:
384                    result = result + self.a180
385
386            if result > 0.0:
387                if theta > self.a180:
388                    result = result + self.a180
389                elif theta < self.a180:
390                    result = result
391        return result
392
393    def connectivity(self):
394        self.dovertedge()
395        self.dovertface()
396        self.dofaceedge()
397        self.boundary()
398
399    def superell(self, n1, uv, turn):
400        t1 = sin(uv + turn)
401        t1 = abs(t1)
402        t1 = t1 ** n1
403        t2 = cos(uv + turn)
404        t2 = abs(t2)
405        t2 = t2 ** n1
406        r = self.power(1.0 / (t1 + t2), (1.0 / n1))
407        return r
408
409    def superform(self, m, n1, n2, n3, uv, a, b, twist):
410        t1 = cos(m * (uv + twist) * .25) * a
411        t1 = abs(t1)
412        t1 = t1 ** n2
413        t2 = sin(m * (uv + twist) * .25) * b
414        t2 = abs(t2)
415        t2 = t2 ** n3
416        r = self.power(1.0 / (t1 + t2), n1)
417        return r
418
419    def dovertedge(self):
420        if not self.vertedgeflag:
421            for vert in self.verts:
422                vert.edges = []
423            for currentedge in self.edges:
424                currentedge.a.edges.append(currentedge)
425                currentedge.b.edges.append(currentedge)
426        self.vertedgeflag = 1
427
428    def dovertface(self):
429        if not self.vertfaceflag:
430            for vert in self.verts:
431                vert.faces = []
432            for face in self.faces:
433                for vert in face.vertices:
434                    vert.faces.append(face)
435        self.vertfaceflag = 1
436
437    def dofaceedge(self):
438        self.dovertedge()    # just in case they haven't been done
439        self.dovertface()
440        if not self.faceedgeflag:
441            for edge in self.edges:
442                edge.faces = []
443            for face in self.faces:
444                face.edges = []
445            for face in self.faces:
446                finish = len(face.vertices)
447                for i in range(finish):
448                    current = face.vertices[i]
449                    if i == finish - 1:
450                        next = face.vertices[0]
451                    else:
452                        next = face.vertices[i + 1]
453                    for edge in current.edges:
454                        if edge.a is current or edge.b is current:
455                            if edge.b is next or edge.a is next:
456                                edge.faces.append(face)
457                                face.edges.append(edge)
458        self.faceedgeflag = 1
459
460    def boundary(self):
461        if not self.boundaryflag:
462            for edge in self.edges:
463                if len(edge.faces) < 2:
464                    edge.boundary = 1
465                    edge.faces[0].boundary = 1
466                    edge.a.boundary = 1
467                    edge.b.boundary = 1
468
469    # The functions below turn the basic triangular faces into
470    # hexagonal faces, creating the buckyball effect.
471    # PKHG seems to work only for meshes with tri's ;-)
472    def hexify(self):
473        self.hexverts = []
474        self.hexedges = []
475        self.hexfaces = []
476        # PKHG renumbering the index of the verts
477        for i in range(len(self.verts)):
478            self.verts[i].index = i
479        # PKHG renumbering the index of the edges
480        for i in range(len(self.edges)):
481            self.edges[i].index = i
482
483        self.connectivity()
484        hexvert_counter = 0
485        for edge in self.edges:
486
487            self.hexshorten(edge, hexvert_counter)
488            hexvert_counter += 2  # PKHG two new vertices done
489
490        for face in self.faces:
491            self.makehexfaces(face)
492
493        for vert in self.verts:
494            vert.clockwise()
495            self.hexvertface(vert)
496        self.verts = self.hexverts
497        self.edges = self.hexedges
498        self.faces = self.hexfaces
499        self.vertedgeflag = 0
500        self.vertfaceflag = 0
501        self.faceedgeflag = 0
502
503    def hexshorten(self, currentedge, hexvert_counter):
504        third = vertex(currentedge.vect / 3.0)
505        newvert1 = vertex(currentedge.a.vector)
506        newvert2 = vertex(currentedge.b.vector)
507        newvert1 = newvert1 + third
508        newvert1.index = hexvert_counter
509        newvert2 = newvert2 - third
510        newvert2.index = hexvert_counter + 1  # PKHG caller adjusts +=2
511        newedge = edge(newvert1, newvert2)
512        newedge.index = currentedge.index
513        self.hexverts.append(newvert1)
514        self.hexverts.append(newvert2)
515        self.hexedges.append(newedge)
516
517    def makehexfaces(self, currentface):
518        vertices = []
519        currentface.docorners()
520        for corner in currentface.corners:
521            vert = corner[0]
522            rightedge = corner[1]
523            leftedge = corner[2]
524            lid = leftedge.index
525            rid = rightedge.index
526
527            if leftedge.a is vert:
528                vertices.append(self.hexedges[lid].a)
529            elif leftedge.b is vert:
530                vertices.append(self.hexedges[lid].b)
531
532            if rightedge.a is vert:
533                vertices.append(self.hexedges[rid].a)
534            elif rightedge.b is vert:
535                vertices.append(self.hexedges[rid].b)
536
537        newface = face(vertices)
538        newedge1 = edge(vertices[0], vertices[1])
539        newedge2 = edge(vertices[2], vertices[3])
540        newedge3 = edge(vertices[4], vertices[5])
541        self.hexfaces.append(newface)
542        self.hexedges.append(newedge1)
543        self.hexedges.append(newedge2)
544        self.hexedges.append(newedge3)
545
546    def hexvertface(self, vert):
547        vertices = []
548        for edge in vert.edges:
549            eid = edge.index
550            if edge.a is vert:
551                vertices.append(self.hexedges[eid].a)
552            elif edge.b is vert:
553                vertices.append(self.hexedges[eid].b)
554        newface = face(vertices)
555        self.hexfaces.append(newface)
556
557    def starify(self):
558        self.starverts = []
559        self.staredges = []
560        self.starfaces = []
561        for i in range(len(self.verts)):
562            self.verts[i].index = i
563        for i in range(len(self.edges)):
564            self.edges[i].index = i
565        self.connectivity()
566        star_vert_counter = 0
567        for currentedge in self.edges:
568            newvert = average([currentedge.a, currentedge.b]).centroid()
569            newvert.index = star_vert_counter
570            star_vert_counter += 1
571            self.starverts.append(newvert)
572        star_face_counter = 0
573        star_edge_counter = 0
574        for currentface in self.faces:
575            currentface.docorners()
576            vertices = []
577            for corner in currentface.corners:
578                vert = self.starverts[corner[1].index]
579                vertices.append(vert)
580            newface = face(vertices)
581            newface.index = star_face_counter
582            star_face_counter += 1
583            newedge1 = edge(vertices[0], vertices[1])
584            newedge1.index = star_edge_counter
585            newedge2 = edge(vertices[1], vertices[2])
586            newedge2.index = star_edge_counter + 1
587            newedge3 = edge(vertices[2], vertices[0])
588            newedge3.index = star_edge_counter + 2
589            star_edge_counter += 3
590            self.starfaces.append(newface)
591            self.staredges.append(newedge1)
592            self.staredges.append(newedge2)
593            self.staredges.append(newedge3)
594        for vert in self.verts:
595            vertices = []
596            vert.clockwise()
597            for currentedge in vert.edges:
598                eid = currentedge.index
599                vertices.append(self.starverts[eid])
600            newface = face(vertices)
601            newface.index = star_face_counter
602            star_face_counter += 1
603            self.starfaces.append(newface)
604        self.verts = self.starverts
605        self.edges = self.staredges
606        self.faces = self.starfaces
607        self.vertedgeflag = 0
608        self.vertfaceflag = 0
609        self.faceedgeflag = 0
610
611    def class2(self):
612        self.class2verts = []
613        self.class2edges = []
614        self.class2faces = []
615
616        newvertstart = len(self.verts)
617        newedgestart = len(self.edges)
618        counter_verts = len(self.verts)
619        for i in range(counter_verts):
620            self.verts[i].index = i
621        for i in range(len(self.edges)):
622            self.edges[i].index = i
623        for i in range(len(self.faces)):
624            self.faces[i].index = i
625        self.connectivity()
626        for currentface in self.faces:
627            currentface.docorners()
628            newvert = average(currentface.vertices).centroid()
629            newvert.index = counter_verts
630
631            counter_verts += 1
632            self.verts.append(newvert)
633            newedge1 = edge(currentface.vertices[0], newvert)
634            newedge2 = edge(currentface.vertices[1], newvert)
635            newedge3 = edge(currentface.vertices[2], newvert)
636
637            self.edges.append(newedge1)
638            self.edges.append(newedge2)
639            self.edges.append(newedge3)
640        for currentedge in range(newedgestart):
641            self.edges[currentedge].a = self.verts[self.edges[currentedge].faces[0].index + newvertstart]
642            self.edges[currentedge].b = self.verts[self.edges[currentedge].faces[1].index + newvertstart]
643            self.edges[currentedge].findvect()
644
645        for currentvert in range(newvertstart):
646            vert = self.verts[currentvert]
647            vertices = []
648            vert.clockwise()
649            for currentface in vert.faces:
650                eid = currentface.index
651                vertices.append(self.verts[newvertstart + eid])
652
653            for i in range(len(vertices)):
654                if i == len(vertices) - 1:
655                    next = vertices[0]
656                else:
657                    next = vertices[i + 1]
658
659                newface = face([vert, vertices[i], next])
660                self.class2faces.append(newface)
661
662        self.faces = self.class2faces
663        self.vertedgeflag = 0
664        self.vertfaceflag = 0
665        self.faceedgeflag = 0
666
667    def dual(self):
668        self.dualverts = []
669
670        self.dualfaces = []
671
672        counter_verts = len(self.verts)
673        for i in range(counter_verts):
674            self.verts[i].index = i
675        for i in range(len(self.edges)):
676            self.edges[i].index = i
677        for i in range(len(self.faces)):
678            self.faces[i].index = i
679        self.connectivity()
680        counter_verts = 0
681        for currentface in self.faces:
682            currentface.docorners()
683            newvert = average(currentface.vertices).centroid()
684            newvert.index = counter_verts  # PKHG needed in >= 2.59
685            counter_verts += 1
686            self.dualverts.append(newvert)
687        for vert in self.verts:
688            vertices = []
689            vert.clockwise()
690            for currentface in vert.faces:
691                eid = currentface.index
692                vertices.append(self.dualverts[eid])
693            newface = face(vertices)
694            self.dualfaces.append(newface)
695        for currentedge in self.edges:
696            currentedge.a = self.dualverts[currentedge.faces[0].index]
697            currentedge.b = self.dualverts[currentedge.faces[1].index]
698        self.verts = self.dualverts
699
700        self.faces = self.dualfaces
701        self.vertedgeflag = 0
702        self.vertfaceflag = 0
703        self.faceedgeflag = 0
704
705
706class facetype(mesh):
707    def __init__(self, basegeodesic, parameters, width, height, relative):
708        mesh.__init__(self)
709        self.detach = parameters[0]
710        self.endtype = parameters[1]
711        self.coords = parameters[2]
712        self.base = basegeodesic
713        self.relative = relative
714        self.width = width
715
716        if not self.relative:
717            newwidth = self.findrelative()
718            self.width = width * newwidth
719        self.height = height
720        self.base.connectivity()
721        for coord in self.coords:
722            coord[0] = coord[0] * self.width
723            coord[1] = coord[1] * self.height
724        if not self.base.facenormalflag:
725            for currentface in self.base.faces:
726
727                currentface.docorners()
728                currentface.findnormal()
729
730            self.base.facenormalflag = 1
731        if self.endtype == 4 and not self.base.vertnormalflag:
732            for currentvert in self.base.verts:
733                currentvert.findnormal()
734            self.base.vertnormalflag = 1
735        self.createfaces()
736
737    def findrelative(self):
738        centre = average(self.base.faces[0].vertices).centroid()
739        edgelist = []
740        for point in self.base.faces[0].vertices:
741            newedge = edge(centre, point)
742            edgelist.append(newedge)
743        length = 0
744        for edg in edgelist:
745            extra = edg.vect.length
746            length = length + extra
747
748        length = length / len(edgelist)
749
750        return length
751
752    def createfaces(self):
753        if not self.detach:
754            for point in self.base.verts:
755                self.verts.append(point)
756        if self.endtype == 4:
757            self.createghostverts()
758        for currentface in self.base.faces:
759            self.doface(currentface)
760
761    def createghostverts(self):
762        self.ghoststart = len(self.verts)
763        for vert in self.base.verts:
764            newvert = vert + (vert.normal * self.coords[-1][1])
765            self.verts.append(newvert)
766
767    def doface(self, candidate):
768        grid = []
769        candidate.dospokes()
770
771        if not self.detach:
772            line = []
773            for vert in candidate.vertices:
774                line.append(vert)
775            grid.append(line)
776        else:
777            line = []
778            for point in candidate.vertices:
779                newvert = vertex(point.vector)
780                self.verts.append(newvert)
781                line.append(newvert)
782            grid.append(line)
783        finish = len(self.coords)
784        if self.endtype == 1 or self.endtype == 4:
785            finish = finish - 1
786        for i in range(finish):
787            up = candidate.normal * self.coords[i][1]
788            line = []
789            for j in range(len(candidate.vertices)):
790                dotfac = candidate.corners[j][3] * 0.5
791                vec = (candidate.spokes[j] * (self.coords[i][0] / sin(dotfac)))
792
793                newvert = candidate.vertices[j] + vec + up
794                line.append(newvert)
795                self.verts.append(newvert)
796            grid.append(line)
797        if self.endtype == 4:
798            line = []
799            for i in range(len(candidate.vertices)):
800                vert = self.verts[candidate.vertices[i].index + self.ghoststart]
801                line.append(vert)
802
803            grid.append(line)
804        for line in grid:
805            line.append(line[0])
806        if self.endtype == 3:
807            grid.append(grid[0])
808        for i in range(len(grid) - 1):
809            for j in range(len(grid[i]) - 1):
810                one = grid[i][j]
811                two = grid[i][j + 1]
812                three = grid[i + 1][j + 1]
813                four = grid[i + 1][j]
814                newface = face([one, two, three, four])
815                self.faces.append(newface)
816        if self.endtype == 2:
817            finalfaceverts = grid[-1]
818            newface = face(finalfaceverts[:-1])
819            self.faces.append(newface)
820        if self.endtype == 1:
821            lastvert = average(candidate.vertices).centroid()
822            up = candidate.normal * self.coords[-1][1]
823            newvert = lastvert + up
824            self.verts.append(newvert)
825            ring = grid[-1]
826            for i in range(len(ring) - 1):
827                newface = face([newvert, ring[i], ring[i + 1]])
828                self.faces.append(newface)
829
830
831class importmesh(mesh):
832    def __init__(self, meshname, breakquadflag):
833        mesh.__init__(self)
834
835        obj = bpy.data.objects[meshname]
836        bpy.context.view_layer.objects.active = obj
837        obj.select_set(True)
838        impmesh = None
839        if not breakquadflag:
840            bpy.ops.object.mode_set(mode='EDIT')
841            impmesh = bmesh.new()           # create an empty BMesh
842            impmesh.from_mesh(obj.data)     # fill it in from a Mesh
843            bpy.ops.object.mode_set(mode='OBJECT')
844
845        if breakquadflag:
846            bpy.ops.object.mode_set(mode='EDIT')
847            bpy.ops.mesh.quads_convert_to_tris()
848            impmesh = bmesh.new()         # create an empty BMesh
849            impmesh.from_mesh(obj.data)   # fill it in from a Mesh
850            bpy.ops.object.mode_set(mode='OBJECT')
851
852        for v in impmesh.verts:
853            vert = vertex(v.co)
854            vert.index = v.index
855            self.verts.append(vert)
856            # PKHG verts is now a list of vertex, so to say a copy of the Vectors
857
858        # PKHG edges
859        for e in impmesh.edges:
860            tmp = []
861            for vert in e.verts:
862                a = self.verts[vert.index]
863                tmp.append(a)
864            newedge = edge(tmp[0], tmp[1])
865            newedge.index = e.index
866            self.edges.append(newedge)
867        # PKHG faces
868        extra_DBG_info("MeshInfo", "vefm L868 the mesh impmesh", impmesh.faces[:])
869
870        for f in impmesh.faces:
871            temp = []
872            for vert in f.verts:            # PKHG a list! of indices ??? PKHG>???
873                a = self.verts[vert.index]  # PKHG verts contains already vertex objects
874                temp.append(a)
875            newface = face(temp)
876            newface.index = f.index  # indexcount
877            self.faces.append(newface)
878        self.dovertedge()
879        self.dovertface()
880        self.temp = []
881
882        for i in range(len(self.verts)):
883            self.temp.append([])
884            self.verts[i].index = i
885        for i in range(len(self.verts)):
886            target = self.surroundingverts(self.verts[i])
887            for j in range(len(target)):                    # go through those verts
888                temptarg = self.temp[target[j].index]
889                flag = 0                                    # set a flag up
890
891                for k in range(len(temptarg)):              # go through temp list for each of those verts
892
893                    if temptarg[k] == i:                    # if we find a match to the current vert...
894                        flag = 1                            # raise the flag
895
896                if flag == 0:                               # if there is no flag after all that...
897                    self.temp[target[j].index].append(i)    # add current vert to temp list of this surrounding vert
898                    self.temp[i].append(target[j].index)    # add this surrounding vert to the current temp list
899                    newedge = edge(self.verts[i], self.verts[target[j].index])
900                    self.edges.append(newedge)              # add the newly found edge to the edges list
901
902        for edg in self.edges:
903            edg.findvect()
904        self.vertedgeflag = 0
905        self.vertedgeflag = 0
906        self.connectivity()
907
908    def surroundingverts(self, vert):
909        ''' Find the verts surrounding vert'''
910        surround = []                       # list to be filled and returned
911        for faces in vert.faces:            # loop through faces attached to vert
912            finish = len(faces.vertices)
913            for i in range(finish):
914                if i == finish - 1:
915                    next = faces.vertices[0]
916                else:
917                    next = faces.vertices[i + 1]
918                if vert == faces.vertices[i]:
919                    surround.append(next)
920        return surround
921
922    def breakquad(self, quad_face):
923        ''' turn quads into triangles'''
924        distance1 = quad_face.vertices[0] - quad_face.vertices[2]
925        distance2 = quad_face.vertices[1] - quad_face.vertices[3]
926        distance1.findlength()
927        distance2.findlength()
928        if abs(distance1.length) < abs(distance2.length):
929            self.faces[quad_face.index] = face([quad_face.vertices[0], quad_face.vertices[1], quad_face.vertices[2]])
930            self.faces.append(face([quad_face.vertices[0], quad_face.vertices[2], quad_face.vertices[3]]))
931        else:
932            self.faces[quad_face.index] = face([quad_face.vertices[0], quad_face.vertices[1], quad_face.vertices[3]])
933            self.faces.append(face([quad_face.vertices[1], quad_face.vertices[2], quad_face.vertices[3]]))
934
935
936class strut(mesh):
937    def __init__(self, base, struttype, width, height, length, widthtog, heighttog,
938                 lengthtog, meshname, stretchflag, lift):
939
940        extra_DBG_info(name="StrutMesh", info_text="vefm L940\nstrut called: ",
941                        info_obj=[base, struttype, width, height, length, widthtog,
942                        heighttog, lengthtog, meshname, stretchflag, lift])
943        mesh.__init__(self)
944        # put in strut prep stuff here
945        if struttype is None:
946            return
947        total = 0
948        divvy = len(base.faces[0].edges)
949        for lengf in base.faces[0].edges:
950            lengf.vect.findlength()
951            total = total + lengf.vect.length
952        yardstick = total / divvy
953        if widthtog:
954            self.width = width
955        else:
956            self.width = width * yardstick
957        if heighttog:
958            self.height = height
959        else:
960            self.height = height * yardstick
961        if lengthtog:
962            self.shrink = length
963        else:
964            self.shrink = length * yardstick
965        if not base.facenormalflag:
966            for currentface in base.faces:
967                currentface.docorners()
968                currentface.findnormal()
969            base.facenormalflag = 1
970        for edj in base.edges:
971            edj.findnormal()
972            side = edge(edj.a, edj.b)
973            edj.unit = side.vect
974            edj.unit.normalize()
975            edj.cross = crossp(edj.normal, edj.unit).docrossproduct()
976        template = importmesh(meshname, 0)
977        maxx = 0
978        minx = 0
979        for vert in template.verts:
980            if vert.vector.x > maxx:
981                maxx = vert.vector.x
982            if vert.vector.x < minx:
983                minx = vert.vector.x
984        for edj in base.edges:
985            start = len(self.verts)
986            centre = average([edj.a, edj.b]).centroid()
987            split = edj.vect.length / 2
988            # PKHG no division by zero!!
989            tmp = 1.0
990            if maxx != minx:
991                tmp = 1.0 / (maxx - minx)
992            dubbl = edj.vect.length * tmp
993            # PKHG end no division by zero!!
994            diffplus = split - maxx
995            diffminus = -split - minx
996            for point in template.verts:
997                ay = (edj.normal * point.vector.z * self.height) + (edj.normal * lift)
998                ce = edj.cross * point.vector.y * self.width
999
1000                if stretchflag:
1001                    be = edj.unit * self.shrink * dubbl * point.vector.x
1002                else:
1003                    if point.vector.x > 0.0:
1004                        be = edj.unit * self.shrink * (point.vector.x + diffplus)
1005                    elif point.vector.x < 0.0:
1006                        be = edj.unit * self.shrink * (point.vector.x + diffminus)
1007                    elif point.vector.x == 0.0:
1008                        be = edj.unit * self.shrink * point.vector.x
1009                de = ay + be + ce
1010                newvert = centre + de
1011                self.verts.append(newvert)
1012            for edjy in template.edges:
1013                one = edjy.a.index + start
1014                two = edjy.b.index + start
1015                newedge = edge(self.verts[one], self.verts[two])
1016                self.edges.append(newedge)
1017            for facey in template.faces:
1018                faceverts = []
1019                for verty in facey.vertices:
1020                    index = verty.index + start
1021                    faceverts.append(self.verts[index])
1022                newface = face(faceverts)
1023                self.faces.append(newface)
1024        self.vertedgeflag = 0
1025        self.vertedgeflag = 0
1026        self.connectivity()
1027
1028
1029class hub(mesh):
1030    def __init__(self, base, hubtype, width, height, length,
1031                 widthtog, heighttog, lengthtog, meshname):
1032        mesh.__init__(self)
1033        self.width = 1.0
1034        self.height = 1.0
1035        self.shrink = 1.0
1036        # put in strut prep stuff here
1037        extra_DBG_info("vefm L1037 HubMesh", "base is ", str(dir(base)) + "\n and meshname = " + meshname)
1038        if hubtype is None:
1039            return
1040        total = 0
1041        divvy = len(base.faces[0].edges)
1042        for lengf in base.verts[0].edges:
1043            lengf.vect.findlength()
1044            total = total + lengf.vect.length
1045        yardstick = total / divvy
1046        if widthtog:
1047            self.width = width
1048        else:
1049            self.width = width * yardstick
1050        if heighttog:
1051            self.height = height
1052        else:
1053            self.height = height * yardstick
1054        if lengthtog:
1055            self.shrink = length
1056        else:
1057            self.shrink = length * yardstick
1058
1059        if not base.facenormalflag:
1060            for currentface in base.faces:
1061                currentface.docorners()
1062                currentface.findnormal()
1063            base.facenormalflag = 1
1064
1065        for apex in base.verts:
1066            apex.findnormal()
1067            side = edge(apex.edges[0].a, apex.edges[0].b)
1068            apex.unit = side.vect  # PKHG is Vector: b - a
1069            apex.unit.normalize()
1070            apex.cross = crossp(apex.normal, apex.unit).docrossproduct()
1071            apex.unit = crossp(apex.cross, apex.normal).docrossproduct()
1072
1073        template = importmesh(meshname, 0)
1074        for apex in base.verts:
1075            start = len(self.verts)
1076            centre = apex
1077            for point in template.verts:
1078                ay = apex.normal * point.vector.z * self.height
1079                ce = apex.cross * point.vector.y * self.width
1080                be = apex.unit * point.vector.x * self.shrink
1081                de = ay + be + ce
1082                newvert = centre + de
1083                self.verts.append(newvert)
1084            for edjy in template.edges:
1085                one = edjy.a.index + start
1086                two = edjy.b.index + start
1087                newedge = edge(self.verts[one], self.verts[two])
1088                self.edges.append(newedge)
1089            for facey in template.faces:
1090                faceverts = []
1091                for verty in facey.vertices:
1092                    index = verty.index + start
1093                    faceverts.append(self.verts[index])
1094                newface = face(faceverts)
1095                self.faces.append(newface)
1096        self.vertedgeflag = 0
1097        self.vertedgeflag = 0
1098        self.connectivity()
1099
1100
1101# ???PKHG TODO Nmesh used yet wrong!
1102def finalfill(source, target):
1103    if source == target:  # PKHG: otherwise >infinite< loop
1104        print("\n***WARNING*** vefm_271.finalfill L1104 source == target empty mesh used")
1105        target = mesh()
1106    # PKHG_??? maybe renumverting and checking faces with >=4 5 vertices?
1107    count = 0
1108
1109    for point in source.verts:
1110        newvert = vertex(point.vector)
1111        newvert.index = count
1112        target.verts.append(newvert)
1113        point.index = count  # PKHG_INFO source renumbered too!
1114
1115        count += 1
1116
1117    for facey in source.faces:
1118        row = len(facey.vertices)
1119        if row >= 5:
1120            tmp = Vector()
1121            for el in facey.vertices:
1122                tmp = tmp + target.verts[el.index].vector
1123            tmp = tmp / row
1124            centre = vertex(tmp)
1125            centre.index = count  # PKHG_??? give it a good index
1126            count += 1
1127
1128            target.verts.append(centre)
1129            for i in range(row):
1130                if i == row - 1:
1131                    a = target.verts[facey.vertices[-1].index]
1132                    b = target.verts[facey.vertices[0].index]
1133                else:
1134                    a = target.verts[facey.vertices[i].index]
1135                    b = target.verts[facey.vertices[i + 1].index]
1136                target.faces.append([a, b, centre])
1137        else:
1138            f = []
1139
1140            for j in range(len(facey.vertices)):
1141                a = facey.vertices[j]
1142                f.append(target.verts[a.index])
1143
1144            target.faces.append(f)
1145