Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | #!/usr/local/bin/perl -w |
2 | # | |
3 | # Filename : Math/Geometry.pm | |
4 | # Description : General Geometry maths functions | |
5 | # Author : Greg McCarroll (greg@mccarroll.demon.co.uk) | |
6 | # Date Created : 22/10/99 | |
7 | # | |
8 | ||
9 | =head1 NAME | |
10 | ||
11 | Math::Geometry - Geometry related functions | |
12 | ||
13 | =head1 SYNOPSIS | |
14 | ||
15 | use Math::Geometry; | |
16 | ||
17 | @P2=rotx(@P1,$angle); | |
18 | @P3=rotx(@P1,$angle); | |
19 | @N =triangle_normal(@P1,@P2,@P3); | |
20 | @ZP=zplane_project(@P1,$d); | |
21 | ||
22 | ||
23 | =head1 NOTES | |
24 | ||
25 | This is about to get a massive overhaul, but first im adding tests, | |
26 | lots of lovely lovely tests. | |
27 | ||
28 | Currently for zplane_project onto a plane with normal of the z axis and z=0, | |
29 | the function returns the orthographic projections as opposed to a perspective | |
30 | projection. I'm currently looking into how to properly handle z=0 and will | |
31 | update it shortly. | |
32 | ||
33 | =head1 DESCRIPTION | |
34 | ||
35 | This package implements classic geometry methods. It should be considered alpha | |
36 | software and any feedback at all is greatly appreciated. The following methods | |
37 | are available: | |
38 | ||
39 | =head2 vector_product. | |
40 | ||
41 | Also known as the cross product, given two vectors in Geometry space, the | |
42 | vector_product of the two vectors, is a vector which is perpendicular | |
43 | to the plane of AB with length equal to the length of A multiplied | |
44 | by the length of B, multiplied by the sin of @, where @ is the angle | |
45 | between the two vectors. | |
46 | ||
47 | =head2 triangle_normal | |
48 | ||
49 | Given a triangle ABC that defines a plane P. This function will return | |
50 | a vector N, which is a normal to the plane P. | |
51 | ||
52 | ($Nx,$Ny,$Nz) = | |
53 | triangle_normal(($Ax,$Ay,$Az),($Bx,$By,$Bz),($Cx,$Cy,$Cz)); | |
54 | ||
55 | =head2 zplane_project | |
56 | ||
57 | Project a point in Geometry space onto a plane with the z-axis as the normal, | |
58 | at a distance d from z=0. | |
59 | ||
60 | ($x2,$y2,$z2) = zplane_project ($x1,$y1,$z1,$d); | |
61 | ||
62 | =head2 rotx | |
63 | ||
64 | Rotate about the x axis r radians. | |
65 | ||
66 | ($x2,$y2,$z2) = rotx ($x1,$y1,$z1,$r); | |
67 | ||
68 | =head2 roty | |
69 | ||
70 | Rotate about the y axis r radians. | |
71 | ||
72 | ($x2,$y2,$z2) = roty ($x1,$y1,$z1,$r); | |
73 | ||
74 | =head2 rotz | |
75 | ||
76 | Rotate about the z axis r radians. | |
77 | ||
78 | ($x2,$y2,$z2) = rotz ($x1,$y1,$z1,$r); | |
79 | ||
80 | =head2 deg2rad | |
81 | ||
82 | Convert degree's to radians. | |
83 | ||
84 | =head2 rad2deg | |
85 | ||
86 | Convert radians to degree's. | |
87 | ||
88 | =head2 pi | |
89 | ||
90 | Returns an approximate value of Pi, the code has been cribed from Pg146, Programming Perl | |
91 | 2nd Ed. | |
92 | ||
93 | =head1 EXAMPLE | |
94 | ||
95 | use Math::Geometry; | |
96 | ||
97 | =head1 AUTHOR | |
98 | ||
99 | Greg McCarroll <greg@mccarroll.demon.co.uk> | |
100 | ||
101 | =cut | |
102 | ||
103 | package Math::Geometry; | |
104 | ||
105 | require Exporter; | |
106 | @ISA='Exporter'; | |
107 | @EXPORT = qw/zplane_project triangle_normal rotx roty rotz rad2deg deg2rad pi/; | |
108 | ||
109 | use Math::Matrix; | |
110 | ||
111 | $VERSION='0.03'; | |
112 | ||
113 | sub version { | |
114 | return "Math::Geometry $VERSION"; | |
115 | } | |
116 | ||
117 | ||
118 | sub vector_product { | |
119 | my($a,$b,$c,$d,$e,$f)=@_; | |
120 | return($b*$f-$c*$e,$c*$d-$a*$f,$a*$e-$b*$d); | |
121 | } | |
122 | ||
123 | sub triangle_normal { | |
124 | my(($ax,$ay,$az),($bx,$by,$bz),($cx,$cy,$cz))=@_; | |
125 | my(@AB)=($bx-$ax,$by-$ay,$bz-$az); | |
126 | my(@AC)=($cx-$ax,$cy-$ay,$cz-$az); | |
127 | return(vector_product(@AB,@AC)); | |
128 | } | |
129 | ||
130 | sub zplane_project { | |
131 | my($x,$y,$z,$d)=@_; | |
132 | my($w); | |
133 | my($xp,$yp,$zp); | |
134 | if ($d == 0) { | |
135 | my($trans)=new Math::Matrix ([ 1, 0, 0, 0], | |
136 | [ 0, 1, 0, 0], | |
137 | [ 0, 0, 0, 0], | |
138 | [ 0, 0, 0, 1]); | |
139 | my($orig) =new Math::Matrix ([ $x], | |
140 | [ $y], | |
141 | [ $z], | |
142 | [ 1]); | |
143 | my($prod) =$trans->multiply($orig); | |
144 | $x=$prod->[0][0]; | |
145 | $y=$prod->[1][0]; | |
146 | $z=$prod->[2][0]; | |
147 | $w=$prod->[3][0]; | |
148 | } else { | |
149 | my($trans)=new Math::Matrix ([ 1, 0, 0, 0], | |
150 | [ 0, 1, 0, 0], | |
151 | [ 0, 0, 1, 0], | |
152 | [ 0, 0, 1/$d, 0]); | |
153 | my($orig) =new Math::Matrix ([ $x], | |
154 | [ $y], | |
155 | [ $z], | |
156 | [ 1]); | |
157 | my($prod) =$trans->multiply($orig); | |
158 | $x=$prod->[0][0]; | |
159 | $y=$prod->[1][0]; | |
160 | $z=$prod->[2][0]; | |
161 | $w=$prod->[3][0]; | |
162 | $x=$x/$w; | |
163 | $y=$y/$w; | |
164 | $z=$z/$w; | |
165 | } | |
166 | return ($x,$y,$z); | |
167 | } | |
168 | ||
169 | ||
170 | sub rotx { | |
171 | my($x,$y,$z,$rot)=@_; | |
172 | my($cosr)=cos $rot; | |
173 | my($sinr)=sin $rot; | |
174 | my($trans)=new Math::Matrix ([ 1, 0, 0, 0], | |
175 | [ 0, $cosr,-1*$sinr, 0], | |
176 | [ 0, $sinr, $cosr, 0], | |
177 | [ 0, 0, 0, 1]); | |
178 | ||
179 | my($orig) =new Math::Matrix ([ $x], | |
180 | [ $y], | |
181 | [ $z], | |
182 | [ 1]); | |
183 | ||
184 | my($prod) =$trans->multiply($orig); | |
185 | $x=$prod->[0][0]; | |
186 | $y=$prod->[1][0]; | |
187 | $z=$prod->[2][0]; | |
188 | return ($x,$y,$z); | |
189 | } | |
190 | ||
191 | sub roty { | |
192 | my($x,$y,$z,$rot)=@_; | |
193 | my($cosr)=cos $rot; | |
194 | my($sinr)=sin $rot; | |
195 | my($trans)=new Math::Matrix ([ $cosr, 0, $sinr, 0], | |
196 | [ 0, 1, 0, 0], | |
197 | [-1*$sinr, 0, $cosr, 0], | |
198 | [ 0, 0, 0, 1]); | |
199 | ||
200 | my($orig) =new Math::Matrix ([ $x], | |
201 | [ $y], | |
202 | [ $z], | |
203 | [ 1]); | |
204 | ||
205 | my($prod) =$trans->multiply($orig); | |
206 | $x=$prod->[0][0]; | |
207 | $y=$prod->[1][0]; | |
208 | $z=$prod->[2][0]; | |
209 | return ($x,$y,$z); | |
210 | } | |
211 | ||
212 | sub rotz { | |
213 | my($x,$y,$z,$rot)=@_; | |
214 | my($cosr)=cos $rot; | |
215 | my($sinr)=sin $rot; | |
216 | my($trans)=new Math::Matrix ([ $cosr,-1*$sinr, 0, 0], | |
217 | [ $sinr, $cosr, 0, 0], | |
218 | [ 0, 0, 1, 0], | |
219 | [ 0, 0, 0, 1]); | |
220 | ||
221 | my($orig) =new Math::Matrix ([ $x], | |
222 | [ $y], | |
223 | [ $z], | |
224 | [ 1]); | |
225 | ||
226 | my($prod) =$trans->multiply($orig); | |
227 | $x=$prod->[0][0]; | |
228 | $y=$prod->[1][0]; | |
229 | $z=$prod->[2][0]; | |
230 | return ($x,$y,$z); | |
231 | } | |
232 | ||
233 | ||
234 | sub deg2rad ($) { | |
235 | my($deg)=@_; | |
236 | return ($deg*pi())/180; | |
237 | } | |
238 | ||
239 | sub rad2deg ($) { | |
240 | my($rad)=@_; | |
241 | return ($rad*180)/pi(); | |
242 | } | |
243 | { | |
244 | my($PI); | |
245 | sub pi() { | |
246 | $PI ||= atan2(1,1)*4; | |
247 | return $PI; | |
248 | } | |
249 | } | |
250 | ||
251 | 1; | |
252 | ||
253 | ||
254 | ||
255 | ||
256 | ||
257 | ||
258 | ||
259 | ||
260 | ||
261 |