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