1 |
gross |
905 |
# $Id:$ |
2 |
|
|
""" |
3 |
|
|
transformations |
4 |
|
|
|
5 |
|
|
@var __author__: name of author |
6 |
|
|
@var __copyright__: copyrights |
7 |
|
|
@var __license__: licence agreement |
8 |
|
|
@var __url__: url entry point on documentation |
9 |
|
|
@var __version__: version |
10 |
|
|
@var __date__: date of the version |
11 |
|
|
@var DEG: unit of degree |
12 |
|
|
@var RAD: unit of radiant |
13 |
|
|
""" |
14 |
|
|
|
15 |
|
|
__author__="Lutz Gross, l.gross@uq.edu.au" |
16 |
|
|
__copyright__=""" Copyright (c) 2006 by ACcESS MNRF |
17 |
|
|
http://www.access.edu.au |
18 |
|
|
Primary Business: Queensland, Australia""" |
19 |
|
|
__license__="""Licensed under the Open Software License version 3.0 |
20 |
|
|
http://www.opensource.org/licenses/osl-3.0.php""" |
21 |
|
|
__url__="http://www.iservo.edu.au/esys/escript" |
22 |
|
|
__version__="$Revision:$" |
23 |
|
|
__date__="$Date:$" |
24 |
|
|
|
25 |
|
|
import numarray |
26 |
|
|
import math |
27 |
|
|
|
28 |
|
|
_TYPE=numarray.Float64 |
29 |
|
|
DEG=math.pi/180. |
30 |
|
|
RAD=1. |
31 |
|
|
class Transformation(object): |
32 |
|
|
""" |
33 |
|
|
general class to define an affine transformation x->Ax+b |
34 |
|
|
""" |
35 |
|
|
def __init__(self): |
36 |
|
|
""" |
37 |
|
|
create a linear transformation |
38 |
|
|
""" |
39 |
|
|
pass |
40 |
|
|
def __call__(self,x=numarray.zeros((3,))): |
41 |
|
|
""" |
42 |
|
|
applies transformation to x |
43 |
|
|
""" |
44 |
|
|
raise NotImplementeError() |
45 |
|
|
class Translation(Transformation): |
46 |
|
|
""" |
47 |
|
|
defines a translation x->x+b |
48 |
|
|
""" |
49 |
|
|
def __init__(self,b=numarray.zeros((3,),type=_TYPE)): |
50 |
|
|
""" |
51 |
|
|
create linear transformation x->x+b |
52 |
|
|
""" |
53 |
|
|
super(Translation, self).__init__() |
54 |
|
|
self.__b=numarray.array(b,_TYPE) |
55 |
|
|
def __call__(self,x=numarray.zeros((3,))): |
56 |
|
|
""" |
57 |
|
|
applies translation to x |
58 |
|
|
""" |
59 |
|
|
return numarray.array(x,_TYPE)+self.__b |
60 |
|
|
class Rotatation(Transformation): |
61 |
|
|
""" |
62 |
|
|
defines a rotation |
63 |
|
|
""" |
64 |
|
|
def __init__(self,point0=numarray.zeros((3,),type=_TYPE),point1=numarray.ones((3,),type=_TYPE),angle=0.*RAD): |
65 |
|
|
""" |
66 |
|
|
creates a rotation using to points to define the axis and a rotation angle |
67 |
|
|
""" |
68 |
|
|
self.__point0=numarray.array(point0,type=_TYPE) |
69 |
|
|
self.__point1=numarray.array(point1,type=_TYPE) |
70 |
|
|
self.__axis=self.__point1-self.__point0 |
71 |
gross |
907 |
lax=numarray.dot(self.__axis,self.__axis) |
72 |
gross |
905 |
if not lax>0: |
73 |
|
|
raise ValueError("points must be distinct.") |
74 |
|
|
self.__axis/=math.sqrt(lax) |
75 |
|
|
self.__angle=float(angle) |
76 |
|
|
def __call__(self,x=numarray.zeros((3,))): |
77 |
|
|
""" |
78 |
|
|
applies rotatation to x |
79 |
|
|
""" |
80 |
|
|
x=numarray.array(x,_TYPE) |
81 |
|
|
z=x-self.__point0 |
82 |
|
|
z0=numarray.dot(z,self.__axis) |
83 |
|
|
z_per=z-z0*self.__axis |
84 |
gross |
907 |
lz_per=numarray.dot(z_per,z_per) |
85 |
|
|
if lz_per>0: |
86 |
|
|
axis1=z_per/math.sqrt(lz_per) |
87 |
|
|
axis2=_cross(self.__axis,axis1) |
88 |
|
|
lax2=numarray.dot(axis2,axis2) |
89 |
|
|
axis2/=math.sqrt(lax2) |
90 |
|
|
return z0*self.__axis+math.sqrt(lz_per)*(math.cos(self.__angle)*axis1-math.sin(self.__angle)*axis2)+self.__point0 |
91 |
gross |
905 |
else: |
92 |
|
|
return x |
93 |
gross |
907 |
def _cross(x, y): |
94 |
gross |
905 |
""" |
95 |
|
|
Returns the cross product of x and y |
96 |
|
|
""" |
97 |
gross |
907 |
return numarray.array([x[1] * y[2] - x[2] * y[1], x[2] * y[0] - x[0] * y[2], x[0] * y[1] - x[1] * y[0]], _TYPE) |
98 |
gross |
905 |
|
99 |
|
|
class Dilation(Transformation): |
100 |
|
|
""" |
101 |
|
|
defines a dilation |
102 |
|
|
""" |
103 |
|
|
def __init__(self,factor=1.,center=numarray.zeros((3,),type=_TYPE)): |
104 |
|
|
""" |
105 |
|
|
creates a dilation with a center an a given expansion/contraction factor |
106 |
|
|
""" |
107 |
|
|
if not factor>0: |
108 |
|
|
raise ValueError("factor must be positive.") |
109 |
|
|
self.__factor=factor |
110 |
|
|
self.__center=numarray.array(center,type=_TYPE) |
111 |
|
|
def __call__(self,x=numarray.zeros((3,))): |
112 |
|
|
""" |
113 |
|
|
applies dilation to x |
114 |
|
|
""" |
115 |
|
|
x=numarray.array(x,_TYPE) |
116 |
|
|
return self.__factor*(x-self.__center)+self.__center |
117 |
|
|
|
118 |
|
|
class Reflection(Transformation): |
119 |
|
|
""" |
120 |
|
|
defines a reflection on a plain |
121 |
|
|
""" |
122 |
|
|
def __init__(self,normal=numarray.ones((3,),type=_TYPE),offset=0.): |
123 |
|
|
""" |
124 |
|
|
defines a reflection on a plain defined in normal form |
125 |
|
|
""" |
126 |
|
|
self.__normal=numarray.array(normal,type=_TYPE) |
127 |
|
|
ln=math.sqrt(numarray.dot(self.__normal,self.__normal)) |
128 |
|
|
if not ln>0.: |
129 |
|
|
raise ValueError("normal must have positive length.") |
130 |
|
|
self.__normal/=ln |
131 |
|
|
if isinstance(offset,float) or isinstance(offset,int): |
132 |
|
|
self.__offset=offset/ln |
133 |
|
|
else: |
134 |
|
|
self.__offset=numarray.dot(numarray.array(offset,type=_TYPE),self.__normal) |
135 |
|
|
def __call__(self,x=numarray.zeros((3,))): |
136 |
|
|
""" |
137 |
|
|
applies reflection to x |
138 |
|
|
""" |
139 |
|
|
x=numarray.array(x,_TYPE) |
140 |
|
|
return x - 2*(numarray.dot(x,self.__normal)-self.__offset)*self.__normal |