| 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 |
|
|---|