root/trunk/RBRapier/RBRapier/Tools/Geometry/Synthesis/VertexNormals.py

Revision 432, 5.1 kB (checked in by sholloway, 6 years ago)

*** empty log message ***

Line 
1 #!/usr/bin/env python
2 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3 ##~ License
4 ##~
5 ##- The RuneBlade Foundation library is intended to ease some
6 ##- aspects of writing intricate Jabber, XML, and User Interface (wxPython, etc.)
7 ##- applications, while providing the flexibility to modularly change the
8 ##- architecture. Enjoy.
9 ##~
10 ##~ Copyright (C) 2002  TechGame Networks, LLC.
11 ##~
12 ##~ This library is free software; you can redistribute it and/or
13 ##~ modify it under the terms of the BSD style License as found in the
14 ##~ LICENSE file included with this distribution.
15 ##~
16 ##~ TechGame Networks, LLC can be reached at:
17 ##~ 3578 E. Hartsel Drive #211
18 ##~ Colorado Springs, Colorado, USA, 80920
19 ##~
20 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
21
22 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23 #~ Imports
24 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25
26 import weakref
27 import Numeric
28 from RBRapier.Tools.Vector import Vector3
29 from RBFoundation.Aspects.FlyweightGroup import FlyweightGroupObject
30
31 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
32 #~ Definitions
33 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
34
35 class Vertex(FlyweightGroupObject):
36     def __init__(self, idx):
37         self.idx = idx
38         self.Normals = {}
39
40     def IntegrateNormal(self, normal, cosToler=2.):
41         if cosToler is not None:
42             for idx, (value, blendable) in self.Normals.iteritems():
43                 if not blendable: continue
44                 cosAngle = normal.Dot(value)
45                 #if not (-1.000001 <= cosAngle <= 1.000001):
46                 #    print cosAngle
47                 assert -1.000001 <= cosAngle <= 1.000001
48                 #divisor = abs(value) * abs(normal)
49                 #cosAngle = normal.Dot(value) / divisor
50                 #try:
51                 #    print 180./Numeric.pi * Numeric.arccos(cosAngle)
52                 #except ValueError:
53                 #    print "ValueError", cosAngle
54                 if cosAngle >= cosToler:
55                     # Found one within tolerance... average them
56                     self.Normals[idx] = ((normal + value).Normalize(), blendable)
57                     return idx
58             blendable = 1
59         else: blendable = 0
60
61         # Well, let's make a new normal then
62         if not self.Normals: idx = self.idx
63         else: idx = self.owner._GetNextValue()
64         self.Normals[idx] = normal.Normalize(), blendable
65         return idx
66
67     def SetResults(self, VertexData, NormalData):
68         srcVertex = self.owner.VertexData[self.idx]
69         for idx, (normal, blendable) in self.Normals.iteritems():
70             VertexData[idx] = srcVertex
71             NormalData[idx] = normal.Normalize().asarray()
72
73 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
74
75 class VertexNormalSynthesisMgr(object):
76     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
77     #~ Public Methods
78     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
79
80     def __init__(self, VertexData, tolerance=None):
81         self._VertexClass = Vertex.FlyweightGroup('VertexNormalSynthesisMgr', owner=weakref.proxy(self))
82         self.VertexData = VertexData
83         self.NextVertexIdx = len(VertexData)
84         self.Vertices = [self._VertexClass(i) for i in xrange(self.NextVertexIdx)]
85         self.SetTolerance(tolerance)
86
87     def SetTolerance(self, tolerance):
88         if tolerance is None: self._cosToler = None
89         else: self._cosToler = Numeric.cos(tolerance)
90        
91     def GetResultantArrays(self):
92         defval = (0.,0.,0.)
93         self.NormalData = [defval for i in xrange(self.NextVertexIdx)]
94         self.VertexData.extend(self.NormalData[len(self.VertexData):])
95         for vertex in self.Vertices:
96             vertex.SetResults(self.VertexData, self.NormalData)
97         return self.VertexData, self.NormalData
98
99     def VisitTriangle(self, vi0, vi1, vi2):
100         if vi0==vi1 or vi1==vi2 or vi2==vi0:
101             print "Degenerate triangle found"
102             return None
103         normal = self._CalculateNormal(vi0, vi1, vi2)
104         if normal is None:
105             return None
106         else:
107             vi0 = self.Vertices[vi0].IntegrateNormal(normal, self._cosToler)
108             vi1 = self.Vertices[vi1].IntegrateNormal(normal, self._cosToler)
109             vi2 = self.Vertices[vi2].IntegrateNormal(normal, self._cosToler)
110             return vi0, vi1, vi2
111
112     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
113     #~ Protected Methods
114     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
115
116     def _GetNextValue(self):
117         result = self.NextVertexIdx
118         self.NextVertexIdx = result + 1
119         return result
120
121     def _CalculateNormal(self, vi0, vi1, vi2):
122         vector0 = Vector3(self.VertexData[vi0])
123         e01 = (Vector3(self.VertexData[vi1]) - vector0).Normalize()
124         e02 = (Vector3(self.VertexData[vi2]) - vector0).Normalize()
125         normal = e01.Cross3(e02)
126         if normal.Magnitude(0) <= 1e-9:
127             return e01
128         else:
129             return normal.Normalize()
130
131 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
132 #~ Optimization
133 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
134
135 try: import psyco
136 except ImportError: pass
137 else:
138     psyco.bind(Vertex)
139     psyco.bind(VertexNormalSynthesisMgr)
140
Note: See TracBrowser for help on using the browser.