File Coverage

blib/lib/Math/Vectors2.pm
Criterion Covered Total %
statement 182 196 92.8
branch 23 40 57.5
condition 10 21 47.6
subroutine 57 60 95.0
pod 32 35 91.4
total 304 352 86.3


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -I/home/phil/perl/cpan/DataTableText/lib/
2             #-------------------------------------------------------------------------------
3             # Vectors in two dimensions
4             # Philip R Brenan at gmail dot com, Appa Apps Ltd Inc., 2017-2020
5             #-------------------------------------------------------------------------------
6             # podDocumentation
7             package Math::Vectors2;
8             require v5.16;
9             our $VERSION = 20231002;
10 1     1   1553 use warnings FATAL => qw(all);
  1         7  
  1         42  
11 1     1   6 use strict;
  1         2  
  1         24  
12 1     1   5 use Carp qw(confess);
  1         1  
  1         85  
13 1     1   1088 use Data::Dump qw(dump);
  1         7937  
  1         64  
14 1     1   6398 use Data::Table::Text qw(genHash);
  1         148233  
  1         350  
15 1     1   3463 use Math::Trig;
  1         15368  
  1         2855  
16              
17             my $nearness = 1e-6; # Definition of near
18              
19             sub near($$) # Check two scalars are near each other.
20 393     393 0 3496 {my ($o, $p) = @_;
21 393         1283 abs($p-$o) < $nearness
22             }
23              
24             sub near2($$) # Check two vectors are near each other.
25 45     45 0 1145 {my ($o, $p) = @_;
26 45         111 $o->d($p) < $nearness
27             }
28              
29             #D1 Methods # Vector methods.
30              
31             sub new($$) #S Create new vector from components.
32 643     643 1 10704 {my ($x, $y) = @_; # X component, Y component
33 643         1658 genHash(__PACKAGE__, # Attributes of a vector
34             x => $x, # X coordinate
35             y => $y, # Y coordinate
36             );
37             }
38              
39             sub zeroAndUnits() #S Create the useful vectors: zero=(0,0), x=(1,0), y=(0,1).
40 12     12 1 40 {map {&new(@$_)} ([0, 0], [1, 0], [0, 1])
  36         967  
41             }
42              
43             sub eq($$) # Whether two vectors are equal to within the accuracy of floating point arithmetic.
44 13     13 1 20 {my ($o, $p) = @_; # First vector, second vector
45 13         28 near2($o, $p)
46             }
47              
48             sub zero($) # Whether a vector is equal to zero within the accuracy of floating point arithmetic.
49 3     3 1 8 {my ($o) = @_; # Vector
50 3 100       85 near($o->x, 0) && near($o->y, 0)
51             }
52              
53             sub print($@) # Print one or more vectors.
54 13     13 1 23 {my ($p, @p) = @_; # Vector to print, more vectors to print
55 13         25 join ', ', map {'('.$_->x.','.$_->y.')'} @_
  13         212  
56             }
57              
58             sub clone($) # Clone a vector.
59 139     139 1 260 {my ($o) = @_; # Vector to clone
60 139         2466 new($o->x, $o->y)
61             }
62              
63             sub Plus($@) # Add zero or more other vectors to the first vector and return the result.
64 37     37 1 1240 {my ($o, @p) = @_; # First vector, other vectors
65 37         68 for(@p)
66 37         642 {$o->x += $_->x;
67 37         720 $o->y += $_->y;
68             }
69             $o
70 37         354 }
71              
72             sub plus($@) # Add zero or more other vectors to a copy of the first vector and return the result.
73 35     35 1 61 {my ($o, @p) = @_; # First vector, other vectors
74 35         72 $o->clone->Plus(@p)
75             }
76              
77             sub Minus($@) # Subtract zero or more vectors from the first vector and return the result.
78 61     61 1 1929 {my ($o, @p) = @_; # First vector, other vectors
79 61         97 for(@p)
80 61         1060 {$o->x -= $_->x;
81 61         1175 $o->y -= $_->y;
82             }
83             $o
84 61         875 }
85              
86             sub minus($@) # Subtract zero or more vectors from a copy of the first vector and return the result.
87 59     59 1 102 {my ($o, @p) = @_; # First vector, other vectors
88 59         108 $o->clone->Minus(@p)
89             }
90              
91             sub Multiply($$) # Multiply a vector by a scalar and return the result.
92 41     41 1 1263 {my ($o, $m) = @_; # Vector, scalar to multiply by
93 41         741 $o->x *= $m; $o->y *= $m;
  41         835  
94 41         218 $o
95             }
96              
97             sub multiply($$) # Multiply a copy of a vector by a scalar and return the result.
98 39     39 1 65 {my ($o, $m) = @_; # Vector, scalar to multiply by
99 39         73 $o->clone->Multiply($m)
100             }
101              
102             sub Divide($$) # Divide a vector by a scalar and return the result.
103 7     7 1 173 {my ($o, $d) = @_; # Vector, scalar to multiply by
104 7         130 $o->x /= $d; $o->y /= $d;
  7         137  
105 7         36 $o
106             }
107              
108             sub divide($$) # Divide a copy of a vector by a scalar and return the result.
109 5     5 1 8 {my ($o, $d) = @_; # Vector, scalar to divide by
110 5         12 $o->clone->Divide($d)
111             }
112              
113             sub l($) # Length of a vector.
114 1563     1563 1 40625 {my ($o) = @_; # Vector
115 1563         23761 sqrt($o->x**2 + $o->y**2)
116             }
117              
118             sub l2($) # Length squared of a vector.
119 2     2 1 9 {my ($o) = @_; # Vector
120 2         34 $o->x**2 + $o->y**2
121             }
122              
123             sub d($$) # Distance between the points identified by two vectors when placed on the same point.
124 46     46 1 78 {my ($o, $p) = @_; # Vector 1, vector 2
125 46         896 sqrt(($o->x-$p->x)**2 + ($o->y-$p->y)**2)
126             }
127              
128             sub d2($$) # Distance squared between the points identified by two vectors when placed on the same point.
129 1     1 1 13 {my ($o, $p) = @_; # Vector 1, vector 2
130 1         23 ($o->x-$p->x)**2 + ($o->y-$p->y)**2
131             }
132              
133             sub n($) # Return a normalized a copy of a vector.
134 1     1 1 3 {my ($o) = @_; # Vector
135 1         2 my $l = $o->l;
136 1 50       30 $l == 0 and confess;
137 1         19 new($o->x / $l, $o->y / $l)
138             }
139              
140             sub dot($$) # Dot product of two vectors.
141 393     393 1 594 {my ($o, $p) = @_; # Vector 1, vector 2
142 393         8577 $o->x * $p->x + $o->y * $p->y
143             }
144              
145             sub area($$) # Signed area of the parallelogram defined by the two vectors. The area is negative if the second vector appears to the right of the first if they are both placed at the origin and the observer stands against the z-axis in a left handed coordinate system.
146 399     399 1 608 {my ($o, $p) = @_; # Vector 1, vector 2
147 399         6347 $o->x * $p->y - $o->y * $p->x
148             }
149              
150             sub cosine($$) # Cos(angle between two vectors).
151 389     389 1 700 {my ($o, $p) = @_; # Vector 1, vector 2
152 389         741 $o->dot($p) / $o->l / $p->l
153             }
154              
155             sub sine($$) # Sin(angle between two vectors).
156 391     391 1 702 {my ($o, $p) = @_; # Vector 1, vector 2
157 391         808 $o->area($p) / $o->l / $p->l
158             }
159              
160             sub angle($$) # Angle in radians anticlockwise that the first vector must be rotated to point along the second vector normalized to the range: -pi to +pi.
161 384     384 1 846 {my ($o, $p) = @_; # Vector 1, vector 2
162 384         758 my $c = $o->cosine($p);
163 384         8879 my $s = $o->sine($p);
164 384         8236 my $a = Math::Trig::acos($c);
165 384 100       3695 $s > 0 ? $a : -$a
166             }
167              
168             sub smallestAngleToNormalPlane($$) # The smallest angle between the second vector and a plane normal to the first vector.
169 9     9 1 47 {my ($a, $b) = @_; # Vector 1, vector 2
170 9         21 my $r = abs $a->angle($b);
171 9         23 my $p = Math::Trig::pi / 2;
172 9 100       49 $r < $p ? $p - $r : $r - $p
173             }
174              
175             sub r90($) # Rotate a vector by 90 degrees anticlockwise.
176 12     12 1 211 {my ($o) = @_; # Vector to rotate
177 12         238 new(-$o->y, $o->x)
178             }
179              
180             sub r180($) # Rotate a vector by 180 degrees.
181 0     0 1 0 {my ($o) = @_; # Vector to rotate
182 0         0 new(-$o->x, -$o->y)
183             }
184              
185             sub r270($) # Rotate a vector by 270 degrees anticlockwise.
186 0     0 1 0 {my ($o) = @_; # Vector to rotate
187 0         0 new($o->y, -$o->x)
188             }
189              
190             sub rotate($$$$) # Rotate a vector about another vector through an angle specified by its values as sin, and cos.
191 6     6 1 171 {my ($p, $o, $sin, $cos) = @_; # Vector to rotate, center of rotation, sin of the angle of rotation, cosine of the angle of rotation
192 6         16 my $q = $p - $o;
193 6         99 $o + new($cos*$q->x-$sin*$q->y, $sin*$q->x+$cos*$q->y)
194             }
195              
196             my sub min(@) #P Find the minimum number in a list of numbers
197 16     16   107 {my (@m) = @_; # Numbers
198 16         23 my $M = shift @m;
199 16         28 for(@m)
200 16 100       38 {$M = $_ if $_ < $M;
201             }
202             $M
203 16         31 }
204            
205             my sub max(@) #P Find the maximum number in a list of numbers
206 16     16   93 {my (@m) = @_; # Numbers
207 16         24 my $M = shift @m;
208 16         27 for(@m)
209 16 100       70 {$M = $_ if $_ > $M;
210             }
211             $M
212 16         34 }
213              
214             sub intersection($$$$) # Find the intersection of two line segments delimited by vectors if such a point exists.
215 4     4 1 65 {my ($a, $b, $c, $d) = @_; # Start of first line segment, end of first line segment, start of second line segment, end of second line segment
216              
217 4         93 my $abx = min($a->x, $b->x); my $abX = max($a->x, $b->x);
  4         74  
218 4         66 my $aby = min($a->y, $b->y); my $abY = max($a->y, $b->y);
  4         62  
219 4         63 my $cdx = min($c->x, $d->x); my $cdX = max($c->x, $d->x);
  4         64  
220 4         70 my $cdy = min($c->y, $d->y); my $cdY = max($c->y, $d->y);
  4         64  
221            
222 4 50       9 return undef if $abX < $cdx; # Quick reject
223 4 50       9 return undef if $abY < $cdy;
224 4 50       10 return undef if $abx > $cdX;
225 4 50       8 return undef if $aby > $cdY;
226            
227             # $a + $l * ($b - $a) == $c + $m * ($d - $c)
228             # $a - $c == $m * ($d - $c) - $l * ($b - $a)
229             # $ac == $m * ($dc) - $l * ($ba)
230             #
231             # $acx = $m * $dcx - $l * $bax
232             # $acy = $m * $dcy - $l * $bay
233             #
234             # $acx * $dcy = $m * $dcx * $dcy - $l * $bax * $dcy
235             # $acy * $dcx = $m * $dcx * $dcy - $l * $dcx * $bay
236             #
237             # $acx * $dcy - $acy * $dcx = $l($dcx * $bay - $bax * $dcy)
238             #
239             # $l = ($acx * $dcy - $acy * $dcx) / ($dcx * $bay - $bax * $dcy)
240            
241 4         25 my $l = (($a-$c)->x * ($d-$c)->y - ($a-$c)->y * ($d-$c)->x) / (($d-$c)->x * ($b-$a)->y - ($b-$a)->x * ($d-$c)->y);
242 4         38 $a + $l * ($b - $a)
243             }
244              
245             sub triangulate($@) # Find a set of triangles that cover a shape whose boundary points are represented by an array of vectors. The points along the boundary must be given in such away that the interior of the shape is always on the same side for each pair of successive points as indicated by the clockwise parameter.
246 2     2 1 60 {my ($clockwise, @boundary) = @_; # If true then the interior of the shape is on the left as the boundary of the shape is traversed otherwise on the right, vectors representing the boundary of the shape
247              
248 2 50       9 @boundary >= 3 or confess "Need at least 3 points to outline the shape.";
249              
250 2         5 my @t; my @b = @boundary; # Generated triangles. Current boundary
  2         5  
251            
252 2         16 while(@b > 3) # Reduce the boundary by one point by triangulating four consecutive points.
253 2         7 {my @B; # New boundary
254 2         9 for(my $i = 0; $i < @b; ++$i) # Move around border filling in where possible to establish a new inner boundary that is smaller than the outer boundary
255 2         5 {my $A = $b[$i % @b];
256 2         8 my ($B, $C, $D) = ($b[($i+1) % @b], $b[($i+2) % @b], $b[($i+3) % @b]);
257 2 50       6 if (defined(my $X = intersection($A, $C, $B, $D))) # Located the intersection
258 2         5 {my $a = area($X - $A, $B - $A); # Area of triangle made by first pair and intersection
259 2         89 my $b = area($X - $B, $C - $B); # Area of triangle made by second pair and intersection
260 2         122 my $c = area($X - $C, $D - $C); # Area of triangle made by third pair and intersection
261 2 50 66     113 if ($a < 0 && $b < 0 && $c < 0 && $clockwise or
      66        
      33        
      33        
      33        
      33        
      66        
262             $a > 0 && $b > 0 && $c > 0 && !$clockwise) # All of the triangles are on the expected side
263 2         20 {push @t, [$X, $A, $B], [$X, $B, $C], [$X, $C, $D];
264 2         8 push @B, $A, $X, $D;
265 2         11 $i += 3;
266             }
267             else # One or more of the triangles is outside the shape
268 0         0 {push @B, $A;
269             }
270             }
271             }
272 2 50       7 if (@B == @b) # Unable to make any reductions
273 0 0       0 {my $c = $clockwise ? 0 : 1;
274 0         0 confess <
275             No reductions available yet shape not filled. You might want to try again with
276             the clockwise parameter set to $c.
277             END
278             }
279 2         7 @b = @B; # New boundary
280             }
281 2 50       8 push @t, [@b] if @b == 3; # Last triangle
282             @t # Triangulation
283 2         7 }
284              
285             sub swap($) # Swap the components of a vector.
286 1     1 1 2 {my ($o) = @_; # Vector
287 1         23 new($o->y, $o->x)
288             }
289              
290             use overload
291 13     13   149 '==' => sub {my ($o, $p) = @_; $o->eq ($p)},
  13         32  
292 34     34   297 '+' => sub {my ($o, $p) = @_; $o->plus ($p)},
  34         74  
293 1     1   40 '+=' => sub {my ($o, $p) = @_; $o->Plus ($p)},
  1         5  
294 72 100   72   383 '-' => sub {my ($o, $p) = @_; ref($p) ? $o->minus($p) : $o->multiply(-1)},
  72         198  
295 1     1   43 '-=' => sub {my ($o, $p) = @_; $o->Minus ($p)},
  1         5  
296 24     24   105 '*' => sub {my ($o, $p) = @_; $o->multiply($p)},
  24         60  
297 1     1   4 '*=' => sub {my ($o, $p) = @_; $o->Multiply($p)},
  1         15  
298 4     4   8 '/' => sub {my ($o, $p) = @_; $o->divide ($p)},
  4         13  
299 1     1   8 '/=' => sub {my ($o, $p) = @_; $o->Divide ($p)},
  1         4  
300 4     4   9 '.' => sub {my ($o, $p) = @_; $o->dot ($p)},
  4         11  
301 0     0   0 'x' => sub {my ($o, $p) = @_; $o->area ($p)},
  0         0  
302 367     367   13385 '<' => sub {my ($o, $p) = @_; $o->angle ($p)},
  367         774  
303 12     12   26 '""' => sub {my ($o) = @_; $o->print },
  12         29  
304 1     1   9 "fallback" => 1;
  1         1  
  1         40  
305              
306             #D0
307             #-------------------------------------------------------------------------------
308             # Export - eeee
309             #-------------------------------------------------------------------------------
310              
311 1     1   190 use Exporter qw(import);
  1         2  
  1         44  
312              
313 1     1   7 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  1         1  
  1         385  
314              
315             # containingFolder
316              
317             @ISA = qw(Exporter);
318             @EXPORT = qw();
319             @EXPORT_OK = qw();
320             %EXPORT_TAGS = (all=>[@EXPORT, @EXPORT_OK]);
321              
322             # podDocumentation
323              
324             =encoding utf-8
325              
326             =head1 Name
327              
328             Math::Vectors2 - Vectors in two dimensions
329              
330             =head1 Synopsis
331              
332             use Math::Vectors2;
333              
334             my ($zero, $x, $y) = Math::Vectors2::zeroAndUnits;
335              
336             ok near deg2rad(-60), $x + $y * sqrt(3) < $x;
337             ok near deg2rad(+30), ($x + $y * sqrt(3))->angle($y);
338              
339             =head1 Description
340              
341             Vectors in two dimensions
342              
343              
344             Version 20231001.
345              
346              
347             The following sections describe the methods in each functional area of this
348             module. For an alphabetic listing of all methods by name see L.
349              
350              
351              
352             =head1 Methods
353              
354             Vector methods.
355              
356             =head2 new($x, $y)
357              
358             Create new vector from components.
359              
360             Parameter Description
361             1 $x X component
362             2 $y Y component
363              
364             B
365              
366              
367             my ($zero, $x, $y) = zeroAndUnits;
368            
369             ok near $y->angle(new(+1, -1)), deg2rad(-135); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
370              
371            
372             ok near $y->angle(new(+1, 0)), deg2rad(-90); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
373              
374            
375             ok near $y->angle(new(+1, +1)), deg2rad(-45); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
376              
377            
378             ok near $y->angle(new( 0, +1)), deg2rad(+0); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
379              
380            
381             ok near $y->angle(new(-1, +1)), deg2rad(+45); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
382              
383            
384             ok near $y->angle(new(-1, 0)), deg2rad(+90); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
385              
386            
387             ok near $y->angle(new(-1, -1)), deg2rad(+135); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
388              
389            
390            
391             ok near new(1,1) < new( 0, -1), deg2rad(-135); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
392              
393            
394             ok near new(1,1) < new( 1, -1), deg2rad(-90); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
395              
396            
397             ok near new(1,1) < new( 1, 0), deg2rad(-45); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
398              
399            
400             ok near new(1,1) < new( 1, 1), deg2rad(0); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
401              
402            
403             ok near new(1,1) < new( 0, 1), deg2rad(+45); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
404              
405            
406             ok near new(1,1) < new(-1, 1), deg2rad(+90); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
407              
408            
409             ok near new(1,1) < new(-1, 0), deg2rad(+135); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
410              
411            
412             ok near deg2rad(-60), $x + $y * sqrt(3) < $x;
413             ok near deg2rad(+30), ($x + $y * sqrt(3))->angle($y);
414            
415             ok near deg2rad( 0), $y->smallestAngleToNormalPlane( $x); # First vector is y, second vector is 0 degrees anti-clockwise from x axis
416             ok near deg2rad(+45), $y->smallestAngleToNormalPlane( $x + $y);
417             ok near deg2rad(+90), $y->smallestAngleToNormalPlane( $y);
418             ok near deg2rad(+45), $y->smallestAngleToNormalPlane(-$x + -$y);
419             ok near deg2rad( 0), $y->smallestAngleToNormalPlane(-$x);
420             ok near deg2rad(+45), $y->smallestAngleToNormalPlane(-$x + -$y);
421             ok near deg2rad(+90), $y->smallestAngleToNormalPlane( -$y);
422             ok near deg2rad(+45), $y->smallestAngleToNormalPlane(-$x + -$y);
423             ok near deg2rad( 0), $y->smallestAngleToNormalPlane( $x);
424            
425             for my $i(-179..179)
426            
427             {ok near $x < new(cos(deg2rad($i)), sin(deg2rad($i))), deg2rad($i); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
428              
429             }
430            
431              
432             This is a static method and so should either be imported or invoked as:
433              
434             Math::Vectors2::new
435              
436              
437             =head2 zeroAndUnits()
438              
439             Create the useful vectors: zero=(0,0), x=(1,0), y=(0,1).
440              
441              
442             B
443              
444              
445            
446             my ($z, $x, $y) = zeroAndUnits; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
447              
448             ok $x + $y + $z == $x->plus($y);
449             ok $x - $y == $x->minus($y);
450             ok $x * 3 == $x->multiply(3);
451             ok $y / 2 == $y->divide(2);
452             ok $x + $y eq '(1,1)';
453             ok $x - $y eq '(1,-1)';
454             ok $x * 3 eq '(3,0)';
455             ok $y / 2 eq '(0,0.5)';
456             ok (($x * 2 + $y * 3)-> print eq '(2,3)');
457            
458              
459             This is a static method and so should either be imported or invoked as:
460              
461             Math::Vectors2::zeroAndUnits
462              
463              
464             =head2 eq($o, $p)
465              
466             Whether two vectors are equal to within the accuracy of floating point arithmetic.
467              
468             Parameter Description
469             1 $o First vector
470             2 $p Second vector
471              
472             B
473              
474              
475             my ($z, $x, $y) = zeroAndUnits;
476             ok $x + $y + $z == $x->plus($y);
477             ok $x - $y == $x->minus($y);
478             ok $x * 3 == $x->multiply(3);
479             ok $y / 2 == $y->divide(2);
480            
481             ok $x + $y eq '(1,1)'; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
482              
483            
484             ok $x - $y eq '(1,-1)'; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
485              
486            
487             ok $x * 3 eq '(3,0)'; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
488              
489            
490             ok $y / 2 eq '(0,0.5)'; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
491              
492            
493             ok (($x * 2 + $y * 3)-> print eq '(2,3)'); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
494              
495            
496              
497             =head2 zero($o)
498              
499             Whether a vector is equal to zero within the accuracy of floating point arithmetic.
500              
501             Parameter Description
502             1 $o Vector
503              
504             B
505              
506              
507            
508             my ($zero, $x, $y) = zeroAndUnits; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
509              
510            
511             ok $zero->zero; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
512              
513            
514             ok !$x->zero; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
515              
516            
517             ok !$y->zero; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
518              
519            
520              
521             =head2 print($p, @p)
522              
523             Print one or more vectors.
524              
525             Parameter Description
526             1 $p Vector to print
527             2 @p More vectors to print
528              
529             B
530              
531              
532             my ($z, $x, $y) = zeroAndUnits;
533             ok $x + $y + $z == $x->plus($y);
534             ok $x - $y == $x->minus($y);
535             ok $x * 3 == $x->multiply(3);
536             ok $y / 2 == $y->divide(2);
537             ok $x + $y eq '(1,1)';
538             ok $x - $y eq '(1,-1)';
539             ok $x * 3 eq '(3,0)';
540             ok $y / 2 eq '(0,0.5)';
541            
542             ok (($x * 2 + $y * 3)-> print eq '(2,3)'); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
543              
544            
545              
546             =head2 clone($o)
547              
548             Clone a vector.
549              
550             Parameter Description
551             1 $o Vector to clone
552              
553             B
554              
555              
556             my ($z, $x, $y) = zeroAndUnits;
557             ok $x->swap == $y;
558            
559             ok $x->clone == $x; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
560              
561            
562              
563             =head2 Plus($o, @p)
564              
565             Add zero or more other vectors to the first vector and return the result.
566              
567             Parameter Description
568             1 $o First vector
569             2 @p Other vectors
570              
571             B
572              
573              
574             my ($zero, $x, $y) = zeroAndUnits;
575            
576             $x->Plus(new(1,1)); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
577              
578             ok $x eq '(2,1)';
579             $y += new(1,1);
580             ok $y eq '(1,2)';
581            
582            
583              
584             =head2 plus($o, @p)
585              
586             Add zero or more other vectors to a copy of the first vector and return the result.
587              
588             Parameter Description
589             1 $o First vector
590             2 @p Other vectors
591              
592             B
593              
594              
595             my ($z, $x, $y) = zeroAndUnits;
596            
597             ok $x + $y + $z == $x->plus($y); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
598              
599             ok $x - $y == $x->minus($y);
600             ok $x * 3 == $x->multiply(3);
601             ok $y / 2 == $y->divide(2);
602             ok $x + $y eq '(1,1)';
603             ok $x - $y eq '(1,-1)';
604             ok $x * 3 eq '(3,0)';
605             ok $y / 2 eq '(0,0.5)';
606             ok (($x * 2 + $y * 3)-> print eq '(2,3)');
607            
608              
609             =head2 Minus($o, @p)
610              
611             Subtract zero or more vectors from the first vector and return the result.
612              
613             Parameter Description
614             1 $o First vector
615             2 @p Other vectors
616              
617             B
618              
619              
620             my ($zero, $x, $y) = zeroAndUnits;
621            
622             $x->Minus(new(0, 1)); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
623              
624             ok $x eq '(1,-1)';
625             $y -= new(1,1);
626             ok $y eq '(-1,0)';
627            
628              
629             =head2 minus($o, @p)
630              
631             Subtract zero or more vectors from a copy of the first vector and return the result.
632              
633             Parameter Description
634             1 $o First vector
635             2 @p Other vectors
636              
637             B
638              
639              
640             my ($z, $x, $y) = zeroAndUnits;
641             ok $x + $y + $z == $x->plus($y);
642            
643             ok $x - $y == $x->minus($y); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
644              
645             ok $x * 3 == $x->multiply(3);
646             ok $y / 2 == $y->divide(2);
647             ok $x + $y eq '(1,1)';
648             ok $x - $y eq '(1,-1)';
649             ok $x * 3 eq '(3,0)';
650             ok $y / 2 eq '(0,0.5)';
651             ok (($x * 2 + $y * 3)-> print eq '(2,3)');
652            
653              
654             =head2 Multiply($o, $m)
655              
656             Multiply a vector by a scalar and return the result.
657              
658             Parameter Description
659             1 $o Vector
660             2 $m Scalar to multiply by
661              
662             B
663              
664              
665             my ($zero, $x, $y) = zeroAndUnits;
666            
667             $x->Multiply(2); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
668              
669             ok $x eq '(2,0)';
670             $y *= 2;
671             ok $y eq '(0,2)';
672            
673            
674              
675             =head2 multiply($o, $m)
676              
677             Multiply a copy of a vector by a scalar and return the result.
678              
679             Parameter Description
680             1 $o Vector
681             2 $m Scalar to multiply by
682              
683             B
684              
685              
686             my ($z, $x, $y) = zeroAndUnits;
687             ok $x + $y + $z == $x->plus($y);
688             ok $x - $y == $x->minus($y);
689            
690             ok $x * 3 == $x->multiply(3); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
691              
692             ok $y / 2 == $y->divide(2);
693             ok $x + $y eq '(1,1)';
694             ok $x - $y eq '(1,-1)';
695             ok $x * 3 eq '(3,0)';
696             ok $y / 2 eq '(0,0.5)';
697             ok (($x * 2 + $y * 3)-> print eq '(2,3)');
698            
699              
700             =head2 Divide($o, $d)
701              
702             Divide a vector by a scalar and return the result.
703              
704             Parameter Description
705             1 $o Vector
706             2 $d Scalar to multiply by
707              
708             B
709              
710              
711             my ($zero, $x, $y) = zeroAndUnits;
712            
713             $x->Divide(1/2); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
714              
715             ok $x eq '(2,0)';
716             $y /= 1/2;
717             ok $y eq '(0,2)';
718            
719            
720              
721             =head2 divide($o, $d)
722              
723             Divide a copy of a vector by a scalar and return the result.
724              
725             Parameter Description
726             1 $o Vector
727             2 $d Scalar to divide by
728              
729             B
730              
731              
732             my ($z, $x, $y) = zeroAndUnits;
733             ok $x + $y + $z == $x->plus($y);
734             ok $x - $y == $x->minus($y);
735             ok $x * 3 == $x->multiply(3);
736            
737             ok $y / 2 == $y->divide(2); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
738              
739             ok $x + $y eq '(1,1)';
740             ok $x - $y eq '(1,-1)';
741             ok $x * 3 eq '(3,0)';
742             ok $y / 2 eq '(0,0.5)';
743             ok (($x * 2 + $y * 3)-> print eq '(2,3)');
744            
745              
746             =head2 l($o)
747              
748             Length of a vector.
749              
750             Parameter Description
751             1 $o Vector
752              
753             B
754              
755              
756             my ($z, $x, $y) = zeroAndUnits;
757            
758            
759             ok 5 == ($x * 3 + $y * 4)->l; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
760              
761             ok 25 == ($x * 3 + $y * 4)->l2;
762            
763            
764             ok 2 * ($x + $y)->l == ($x + $y)->d (-$x - $y); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
765              
766             ok 4 * ($x + $y)->l2 == ($x + $y)->d2(-$x - $y);
767            
768              
769             =head2 l2($o)
770              
771             Length squared of a vector.
772              
773             Parameter Description
774             1 $o Vector
775              
776             B
777              
778              
779             my ($z, $x, $y) = zeroAndUnits;
780            
781             ok 5 == ($x * 3 + $y * 4)->l;
782            
783             ok 25 == ($x * 3 + $y * 4)->l2; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
784              
785            
786             ok 2 * ($x + $y)->l == ($x + $y)->d (-$x - $y);
787            
788             ok 4 * ($x + $y)->l2 == ($x + $y)->d2(-$x - $y); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
789              
790            
791              
792             =head2 d($o, $p)
793              
794             Distance between the points identified by two vectors when placed on the same point.
795              
796             Parameter Description
797             1 $o Vector 1
798             2 $p Vector 2
799              
800             B
801              
802              
803             my ($z, $x, $y) = zeroAndUnits;
804            
805             ok 5 == ($x * 3 + $y * 4)->l;
806             ok 25 == ($x * 3 + $y * 4)->l2;
807            
808            
809             ok 2 * ($x + $y)->l == ($x + $y)->d (-$x - $y); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
810              
811             ok 4 * ($x + $y)->l2 == ($x + $y)->d2(-$x - $y);
812            
813              
814             =head2 d2($o, $p)
815              
816             Distance squared between the points identified by two vectors when placed on the same point.
817              
818             Parameter Description
819             1 $o Vector 1
820             2 $p Vector 2
821              
822             B
823              
824              
825             my ($z, $x, $y) = zeroAndUnits;
826            
827             ok 5 == ($x * 3 + $y * 4)->l;
828             ok 25 == ($x * 3 + $y * 4)->l2;
829            
830             ok 2 * ($x + $y)->l == ($x + $y)->d (-$x - $y);
831            
832             ok 4 * ($x + $y)->l2 == ($x + $y)->d2(-$x - $y); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
833              
834            
835              
836             =head2 n($o)
837              
838             Return a normalized a copy of a vector.
839              
840             Parameter Description
841             1 $o Vector
842              
843             B
844              
845              
846             my ($z, $x, $y) = zeroAndUnits;
847            
848             ok (($x * 3 + $y * 4)->n == $x * 3/5 + $y * 4/5); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
849              
850            
851             ok 0 == $x . $y;
852             ok 1 == $x . $x;
853             ok 1 == $y . $y;
854             ok 8 == ($x * 1 + $y * 2) .($x * 2 + $y * 3);
855            
856              
857             =head2 dot($o, $p)
858              
859             Dot product of two vectors.
860              
861             Parameter Description
862             1 $o Vector 1
863             2 $p Vector 2
864              
865             B
866              
867              
868             my ($z, $x, $y) = zeroAndUnits;
869             ok (($x * 3 + $y * 4)->n == $x * 3/5 + $y * 4/5);
870            
871             ok 0 == $x . $y;
872             ok 1 == $x . $x;
873             ok 1 == $y . $y;
874             ok 8 == ($x * 1 + $y * 2) .($x * 2 + $y * 3);
875            
876              
877             =head2 area($o, $p)
878              
879             Signed area of the parallelogram defined by the two vectors. The area is negative if the second vector appears to the right of the first if they are both placed at the origin and the observer stands against the z-axis in a left handed coordinate system.
880              
881             Parameter Description
882             1 $o Vector 1
883             2 $p Vector 2
884              
885             B
886              
887              
888             my ($z, $x, $y) = zeroAndUnits;
889             ok +1 == $x->cosine($x);
890             ok +1 == $y->cosine($y);
891             ok 0 == $x->cosine($y);
892             ok 0 == $y->cosine($x);
893            
894             ok 0 == $x->sine($x);
895             ok 0 == $y->sine($y);
896             ok +1 == $x->sine($y);
897             ok -1 == $y->sine($x);
898            
899             ok near -sqrt(1/2), ($x + $y)->sine($x);
900             ok near +sqrt(1/2), ($x + $y)->sine($y);
901            
902             ok near -2, ($x + $y)->area($x * 2); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
903              
904            
905             ok near +2, ($x + $y)->area($y * 2); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
906              
907            
908              
909             =head2 cosine($o, $p)
910              
911             Cos(angle between two vectors).
912              
913             Parameter Description
914             1 $o Vector 1
915             2 $p Vector 2
916              
917             B
918              
919              
920             my ($z, $x, $y) = zeroAndUnits;
921            
922             ok +1 == $x->cosine($x); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
923              
924            
925             ok +1 == $y->cosine($y); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
926              
927            
928             ok 0 == $x->cosine($y); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
929              
930            
931             ok 0 == $y->cosine($x); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
932              
933            
934             ok 0 == $x->sine($x);
935             ok 0 == $y->sine($y);
936             ok +1 == $x->sine($y);
937             ok -1 == $y->sine($x);
938            
939             ok near -sqrt(1/2), ($x + $y)->sine($x);
940             ok near +sqrt(1/2), ($x + $y)->sine($y);
941             ok near -2, ($x + $y)->area($x * 2);
942             ok near +2, ($x + $y)->area($y * 2);
943            
944              
945             =head2 sine($o, $p)
946              
947             Sin(angle between two vectors).
948              
949             Parameter Description
950             1 $o Vector 1
951             2 $p Vector 2
952              
953             B
954              
955              
956             my ($z, $x, $y) = zeroAndUnits;
957             ok +1 == $x->cosine($x);
958             ok +1 == $y->cosine($y);
959             ok 0 == $x->cosine($y);
960             ok 0 == $y->cosine($x);
961            
962            
963             ok 0 == $x->sine($x); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
964              
965            
966             ok 0 == $y->sine($y); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
967              
968            
969             ok +1 == $x->sine($y); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
970              
971            
972             ok -1 == $y->sine($x); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
973              
974            
975            
976             ok near -sqrt(1/2), ($x + $y)->sine($x); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
977              
978            
979             ok near +sqrt(1/2), ($x + $y)->sine($y); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
980              
981             ok near -2, ($x + $y)->area($x * 2);
982             ok near +2, ($x + $y)->area($y * 2);
983            
984              
985             =head2 angle($o, $p)
986              
987             Angle in radians anticlockwise that the first vector must be rotated to point along the second vector normalized to the range: -pi to +pi.
988              
989             Parameter Description
990             1 $o Vector 1
991             2 $p Vector 2
992              
993             B
994              
995              
996             my ($zero, $x, $y) = zeroAndUnits;
997            
998             ok near $y->angle(new(+1, -1)), deg2rad(-135); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
999              
1000            
1001             ok near $y->angle(new(+1, 0)), deg2rad(-90); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1002              
1003            
1004             ok near $y->angle(new(+1, +1)), deg2rad(-45); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1005              
1006            
1007             ok near $y->angle(new( 0, +1)), deg2rad(+0); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1008              
1009            
1010             ok near $y->angle(new(-1, +1)), deg2rad(+45); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1011              
1012            
1013             ok near $y->angle(new(-1, 0)), deg2rad(+90); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1014              
1015            
1016             ok near $y->angle(new(-1, -1)), deg2rad(+135); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1017              
1018            
1019             ok near new(1,1) < new( 0, -1), deg2rad(-135);
1020             ok near new(1,1) < new( 1, -1), deg2rad(-90);
1021             ok near new(1,1) < new( 1, 0), deg2rad(-45);
1022             ok near new(1,1) < new( 1, 1), deg2rad(0);
1023             ok near new(1,1) < new( 0, 1), deg2rad(+45);
1024             ok near new(1,1) < new(-1, 1), deg2rad(+90);
1025             ok near new(1,1) < new(-1, 0), deg2rad(+135);
1026            
1027             ok near deg2rad(-60), $x + $y * sqrt(3) < $x;
1028            
1029             ok near deg2rad(+30), ($x + $y * sqrt(3))->angle($y); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1030              
1031            
1032             ok near deg2rad( 0), $y->smallestAngleToNormalPlane( $x); # First vector is y, second vector is 0 degrees anti-clockwise from x axis
1033             ok near deg2rad(+45), $y->smallestAngleToNormalPlane( $x + $y);
1034             ok near deg2rad(+90), $y->smallestAngleToNormalPlane( $y);
1035             ok near deg2rad(+45), $y->smallestAngleToNormalPlane(-$x + -$y);
1036             ok near deg2rad( 0), $y->smallestAngleToNormalPlane(-$x);
1037             ok near deg2rad(+45), $y->smallestAngleToNormalPlane(-$x + -$y);
1038             ok near deg2rad(+90), $y->smallestAngleToNormalPlane( -$y);
1039             ok near deg2rad(+45), $y->smallestAngleToNormalPlane(-$x + -$y);
1040             ok near deg2rad( 0), $y->smallestAngleToNormalPlane( $x);
1041            
1042             for my $i(-179..179)
1043             {ok near $x < new(cos(deg2rad($i)), sin(deg2rad($i))), deg2rad($i);
1044             }
1045            
1046              
1047             =head2 smallestAngleToNormalPlane($a, $b)
1048              
1049             The smallest angle between the second vector and a plane normal to the first vector.
1050              
1051             Parameter Description
1052             1 $a Vector 1
1053             2 $b Vector 2
1054              
1055             =head2 r90($o)
1056              
1057             Rotate a vector by 90 degrees anticlockwise.
1058              
1059             Parameter Description
1060             1 $o Vector to rotate
1061              
1062             B
1063              
1064              
1065             my ($z, $x, $y) = zeroAndUnits;
1066            
1067             ok $x->r90 == $y; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1068              
1069            
1070             ok $y->r90 == -$x; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1071              
1072            
1073             ok $x->r90->r90 == -$x; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1074              
1075            
1076             ok $y->r90->r90 == -$y; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1077              
1078            
1079             ok $x->r90->r90->r90 == -$y; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1080              
1081            
1082             ok $y->r90->r90->r90 == $x; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1083              
1084            
1085              
1086             =head2 r180($o)
1087              
1088             Rotate a vector by 180 degrees.
1089              
1090             Parameter Description
1091             1 $o Vector to rotate
1092              
1093             B
1094              
1095              
1096             my ($z, $x, $y) = zeroAndUnits;
1097             ok $x->r90 == $y;
1098             ok $y->r90 == -$x;
1099             ok $x->r90->r90 == -$x;
1100             ok $y->r90->r90 == -$y;
1101             ok $x->r90->r90->r90 == -$y;
1102             ok $y->r90->r90->r90 == $x;
1103            
1104              
1105             =head2 r270($o)
1106              
1107             Rotate a vector by 270 degrees anticlockwise.
1108              
1109             Parameter Description
1110             1 $o Vector to rotate
1111              
1112             B
1113              
1114              
1115             my ($z, $x, $y) = zeroAndUnits;
1116             ok $x->r90 == $y;
1117             ok $y->r90 == -$x;
1118             ok $x->r90->r90 == -$x;
1119             ok $y->r90->r90 == -$y;
1120             ok $x->r90->r90->r90 == -$y;
1121             ok $y->r90->r90->r90 == $x;
1122            
1123              
1124             =head2 rotate($p, $o, $sin, $cos)
1125              
1126             Rotate a vector about another vector through an angle specified by its values as sin, and cos.
1127              
1128             Parameter Description
1129             1 $p Vector to rotate
1130             2 $o Center of rotation
1131             3 $sin Sin of the angle of rotation
1132             4 $cos Cosine of the angle of rotation
1133              
1134             B
1135              
1136              
1137            
1138             ok near2 new(1, 0)->rotate(new(0,0), 1, 0), new( 0, 1); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1139              
1140            
1141             ok near2 new(1, 1)->rotate(new(0,0), 1, 0), new(-1, 1); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1142              
1143            
1144             ok near2 new(0, 1)->rotate(new(0,0), 1, 0), new(-1, 0); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1145              
1146            
1147             ok near2 new(2, 2)->rotate(new(1,1), -1/sqrt(2), 1/sqrt(2)), new(1+sqrt(2), 1); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1148              
1149            
1150             ok near2 new(3, 1)->rotate(new(1,1), sqrt(3)/2, 1/2), new(2, 1+sqrt(3)); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1151              
1152            
1153            
1154             ok near2 new(3, 1)->rotate(new(1,1), # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1155              
1156             new(1, 0)->sine (new(1,1)),
1157             new(1, 0)->cosine(new(1,1))),
1158             new(1+sqrt(2), 1+sqrt(2));
1159            
1160              
1161             =head2 intersection($a, $b, $c, $d)
1162              
1163             Find the intersection of two line segments delimited by vectors if such a point exists.
1164              
1165             Parameter Description
1166             1 $a Start of first line segment
1167             2 $b End of first line segment
1168             3 $c Start of second line segment
1169             4 $d End of second line segment
1170              
1171             B
1172              
1173              
1174            
1175             ok near2 intersection(new(0,0), new(2,2), new(0,2),new(2,0)), new(1,1); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1176              
1177            
1178             ok near2 intersection(new(1,1), new(3,3), new(1,3),new(3,1)), new(2,2); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1179              
1180            
1181              
1182             =head2 triangulate($clockwise, @boundary)
1183              
1184             Find a set of triangles that cover a shape whose boundary points are represented by an array of vectors. The points along the boundary must be given in such away that the interior of the shape is always on the same side for each pair of successive points as indicated by the clockwise parameter.
1185              
1186             Parameter Description
1187             1 $clockwise If true then the interior of the shape is on the left as the boundary of the shape is traversed otherwise on the right
1188             2 @boundary Vectors representing the boundary of the shape
1189              
1190             B
1191              
1192              
1193            
1194             my @t = triangulate(1, new(0,0), new(2,0), new(2,2), new(0,2)); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1195              
1196            
1197             ok near2 $t[0][0], new(1, 1);
1198             ok near2 $t[0][1], new(0, 0);
1199             ok near2 $t[0][2], new(2, 0);
1200            
1201             ok near2 $t[1][0], new(1, 1);
1202             ok near2 $t[1][1], new(2, 0);
1203             ok near2 $t[1][2], new(2, 2);
1204            
1205             ok near2 $t[2][0], new(1, 1);
1206             ok near2 $t[2][1], new(2, 2);
1207             ok near2 $t[2][2], new(0, 2);
1208            
1209             ok near2 $t[3][0], new(0, 0);
1210             ok near2 $t[3][1], new(1, 1);
1211             ok near2 $t[3][2], new(0, 2);
1212            
1213            
1214             my @t = triangulate(0, new(2,2), new(2, 4), new(4,4), new(4, 2)); # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1215              
1216            
1217             ok near2 $t[0][0], new(3, 3);
1218             ok near2 $t[0][1], new(2, 2);
1219             ok near2 $t[0][2], new(2, 4);
1220            
1221             ok near2 $t[1][0], new(3, 3);
1222             ok near2 $t[1][1], new(2, 4);
1223             ok near2 $t[1][2], new(4, 4);
1224            
1225             ok near2 $t[2][0], new(3, 3);
1226             ok near2 $t[2][1], new(4, 4);
1227             ok near2 $t[2][2], new(4, 2);
1228            
1229             ok near2 $t[3][0], new(2, 2);
1230             ok near2 $t[3][1], new(3, 3);
1231             ok near2 $t[3][2], new(4, 2);
1232            
1233              
1234             =head2 swap($o)
1235              
1236             Swap the components of a vector.
1237              
1238             Parameter Description
1239             1 $o Vector
1240              
1241             B
1242              
1243              
1244             my ($z, $x, $y) = zeroAndUnits;
1245            
1246             ok $x->swap == $y; # 𝗘𝘅𝗮𝗺𝗽𝗹𝗲
1247              
1248             ok $x->clone == $x;
1249            
1250              
1251              
1252             =head1 Hash Definitions
1253              
1254              
1255              
1256              
1257             =head2 Math::Vectors2 Definition
1258              
1259              
1260             Attributes of a vector
1261              
1262              
1263              
1264              
1265             =head3 Output fields
1266              
1267              
1268             =head4 x
1269              
1270             X coordinate
1271              
1272             =head4 y
1273              
1274             Y coordinate
1275              
1276              
1277              
1278             =head1 Index
1279              
1280              
1281             1 L - Angle in radians anticlockwise that the first vector must be rotated to point along the second vector normalized to the range: -pi to +pi.
1282              
1283             2 L - Signed area of the parallelogram defined by the two vectors.
1284              
1285             3 L - Clone a vector.
1286              
1287             4 L - Cos(angle between two vectors).
1288              
1289             5 L - Distance between the points identified by two vectors when placed on the same point.
1290              
1291             6 L - Distance squared between the points identified by two vectors when placed on the same point.
1292              
1293             7 L - Divide a vector by a scalar and return the result.
1294              
1295             8 L - Divide a copy of a vector by a scalar and return the result.
1296              
1297             9 L - Dot product of two vectors.
1298              
1299             10 L - Whether two vectors are equal to within the accuracy of floating point arithmetic.
1300              
1301             11 L - Find the intersection of two line segments delimited by vectors if such a point exists.
1302              
1303             12 L - Length of a vector.
1304              
1305             13 L - Length squared of a vector.
1306              
1307             14 L - Subtract zero or more vectors from the first vector and return the result.
1308              
1309             15 L - Subtract zero or more vectors from a copy of the first vector and return the result.
1310              
1311             16 L - Multiply a copy of a vector by a scalar and return the result.
1312              
1313             17 L - Multiply a vector by a scalar and return the result.
1314              
1315             18 L - Return a normalized a copy of a vector.
1316              
1317             19 L - Create new vector from components.
1318              
1319             20 L - Add zero or more other vectors to a copy of the first vector and return the result.
1320              
1321             21 L - Add zero or more other vectors to the first vector and return the result.
1322              
1323             22 L - Print one or more vectors.
1324              
1325             23 L - Rotate a vector by 180 degrees.
1326              
1327             24 L - Rotate a vector by 270 degrees anticlockwise.
1328              
1329             25 L - Rotate a vector by 90 degrees anticlockwise.
1330              
1331             26 L - Rotate a vector about another vector through an angle specified by its values as sin, and cos.
1332              
1333             27 L - Sin(angle between two vectors).
1334              
1335             28 L - The smallest angle between the second vector and a plane normal to the first vector.
1336              
1337             29 L - Swap the components of a vector.
1338              
1339             30 L - Find a set of triangles that cover a shape whose boundary points are represented by an array of vectors.
1340              
1341             31 L - Whether a vector is equal to zero within the accuracy of floating point arithmetic.
1342              
1343             32 L - Create the useful vectors: zero=(0,0), x=(1,0), y=(0,1).
1344              
1345             =head1 Installation
1346              
1347             This module is written in 100% Pure Perl and, thus, it is easy to read,
1348             comprehend, use, modify and install via B:
1349              
1350             sudo cpan install Math::Vectors2
1351              
1352             =head1 Author
1353              
1354             L
1355              
1356             L
1357              
1358             =head1 Copyright
1359              
1360             Copyright (c) 2016-2023 Philip R Brenan.
1361              
1362             This module is free software. It may be used, redistributed and/or modified
1363             under the same terms as Perl itself.
1364              
1365             =cut
1366              
1367              
1368              
1369             # Tests and documentation
1370              
1371             sub test
1372 1     1 0 84 {my $p = __PACKAGE__;
1373 1         11 binmode($_, ":utf8") for *STDOUT, *STDERR;
1374 1 50       63 return if eval "eof(${p}::DATA)";
1375 0           my $s = eval "join('', <${p}::DATA>)";
1376 0 0         $@ and die $@;
1377 0           eval $s;
1378 0 0         $@ and die $@;
1379 0           1
1380             }
1381              
1382             test unless caller;
1383              
1384             1;
1385             # podDocumentation
1386             #__DATA__
1387 1     1   750 use Test::More tests => 465;
  1         81368  
  1         8  
1388              
1389             eval "goto latest";
1390              
1391             if (1) { #TzeroAndUnits #Tplus #Tminus #Tmultiply #Tdivide #Teq #Tprint
1392             my ($z, $x, $y) = zeroAndUnits;
1393             ok $x + $y + $z == $x->plus($y);
1394             ok $x - $y == $x->minus($y);
1395             ok $x * 3 == $x->multiply(3);
1396             ok $y / 2 == $y->divide(2);
1397             ok $x + $y eq '(1,1)';
1398             ok $x - $y eq '(1,-1)';
1399             ok $x * 3 eq '(3,0)';
1400             ok $y / 2 eq '(0,0.5)';
1401             ok (($x * 2 + $y * 3)-> print eq '(2,3)');
1402             }
1403              
1404             if (1) { #Tclone #Tswap
1405             my ($z, $x, $y) = zeroAndUnits;
1406             ok $x->swap == $y;
1407             ok $x->clone == $x;
1408             }
1409              
1410             if (1) { #Td #Td2 #Tl #Tl2
1411             my ($z, $x, $y) = zeroAndUnits;
1412              
1413             ok 5 == ($x * 3 + $y * 4)->l;
1414             ok 25 == ($x * 3 + $y * 4)->l2;
1415              
1416             ok 2 * ($x + $y)->l == ($x + $y)->d (-$x - $y);
1417             ok 4 * ($x + $y)->l2 == ($x + $y)->d2(-$x - $y);
1418             }
1419              
1420             if (1) { #Tn #Tdot
1421             my ($z, $x, $y) = zeroAndUnits;
1422             ok (($x * 3 + $y * 4)->n == $x * 3/5 + $y * 4/5);
1423              
1424             ok 0 == $x . $y;
1425             ok 1 == $x . $x;
1426             ok 1 == $y . $y;
1427             ok 8 == ($x * 1 + $y * 2) .($x * 2 + $y * 3);
1428             }
1429              
1430              
1431             if (1) { #Tr90 #Tr180 #Tr270
1432             my ($z, $x, $y) = zeroAndUnits;
1433             ok $x->r90 == $y;
1434             ok $y->r90 == -$x;
1435             ok $x->r90->r90 == -$x;
1436             ok $y->r90->r90 == -$y;
1437             ok $x->r90->r90->r90 == -$y;
1438             ok $y->r90->r90->r90 == $x;
1439             }
1440              
1441              
1442             if (1) { #Tsine #Tcosine #Tarea
1443             my ($z, $x, $y) = zeroAndUnits;
1444             ok +1 == $x->cosine($x);
1445             ok +1 == $y->cosine($y);
1446             ok 0 == $x->cosine($y);
1447             ok 0 == $y->cosine($x);
1448              
1449             ok 0 == $x->sine($x);
1450             ok 0 == $y->sine($y);
1451             ok +1 == $x->sine($y);
1452             ok -1 == $y->sine($x);
1453              
1454             ok near -sqrt(1/2), ($x + $y)->sine($x);
1455             ok near +sqrt(1/2), ($x + $y)->sine($y);
1456             ok near -2, ($x + $y)->area($x * 2);
1457             ok near +2, ($x + $y)->area($y * 2);
1458             }
1459              
1460             if (1) { #Tangle #Tnew
1461             my ($zero, $x, $y) = zeroAndUnits;
1462             ok near $y->angle(new(+1, -1)), deg2rad(-135);
1463             ok near $y->angle(new(+1, 0)), deg2rad(-90);
1464             ok near $y->angle(new(+1, +1)), deg2rad(-45);
1465             ok near $y->angle(new( 0, +1)), deg2rad(+0);
1466             ok near $y->angle(new(-1, +1)), deg2rad(+45);
1467             ok near $y->angle(new(-1, 0)), deg2rad(+90);
1468             ok near $y->angle(new(-1, -1)), deg2rad(+135);
1469              
1470             ok near new(1,1) < new( 0, -1), deg2rad(-135);
1471             ok near new(1,1) < new( 1, -1), deg2rad(-90);
1472             ok near new(1,1) < new( 1, 0), deg2rad(-45);
1473             ok near new(1,1) < new( 1, 1), deg2rad(0);
1474             ok near new(1,1) < new( 0, 1), deg2rad(+45);
1475             ok near new(1,1) < new(-1, 1), deg2rad(+90);
1476             ok near new(1,1) < new(-1, 0), deg2rad(+135);
1477              
1478             ok near deg2rad(-60), $x + $y * sqrt(3) < $x;
1479             ok near deg2rad(+30), ($x + $y * sqrt(3))->angle($y);
1480              
1481             ok near deg2rad( 0), $y->smallestAngleToNormalPlane( $x); # First vector is y, second vector is 0 degrees anti-clockwise from x axis
1482             ok near deg2rad(+45), $y->smallestAngleToNormalPlane( $x + $y);
1483             ok near deg2rad(+90), $y->smallestAngleToNormalPlane( $y);
1484             ok near deg2rad(+45), $y->smallestAngleToNormalPlane(-$x + -$y);
1485             ok near deg2rad( 0), $y->smallestAngleToNormalPlane(-$x);
1486             ok near deg2rad(+45), $y->smallestAngleToNormalPlane(-$x + -$y);
1487             ok near deg2rad(+90), $y->smallestAngleToNormalPlane( -$y);
1488             ok near deg2rad(+45), $y->smallestAngleToNormalPlane(-$x + -$y);
1489             ok near deg2rad( 0), $y->smallestAngleToNormalPlane( $x);
1490              
1491             for my $i(-179..179)
1492             {ok near $x < new(cos(deg2rad($i)), sin(deg2rad($i))), deg2rad($i);
1493             }
1494             }
1495              
1496             if (1) { #TPlus
1497             my ($zero, $x, $y) = zeroAndUnits;
1498             $x->Plus(new(1,1));
1499             ok $x eq '(2,1)';
1500             $y += new(1,1);
1501             ok $y eq '(1,2)';
1502              
1503             }
1504             if (1) { #TMinus
1505             my ($zero, $x, $y) = zeroAndUnits;
1506             $x->Minus(new(0, 1));
1507             ok $x eq '(1,-1)';
1508             $y -= new(1,1);
1509             ok $y eq '(-1,0)';
1510             }
1511             if (1) { #TMultiply
1512             my ($zero, $x, $y) = zeroAndUnits;
1513             $x->Multiply(2);
1514             ok $x eq '(2,0)';
1515             $y *= 2;
1516             ok $y eq '(0,2)';
1517              
1518             }
1519             if (1) { #TDivide
1520             my ($zero, $x, $y) = zeroAndUnits;
1521             $x->Divide(1/2);
1522             ok $x eq '(2,0)';
1523             $y /= 1/2;
1524             ok $y eq '(0,2)';
1525              
1526             }
1527              
1528             if (1) { #Tzero
1529             my ($zero, $x, $y) = zeroAndUnits;
1530             ok $zero->zero;
1531             ok !$x->zero;
1532             ok !$y->zero;
1533             }
1534              
1535             #latest:;
1536             if (1) { #Trotate
1537             ok near2 new(1, 0)->rotate(new(0,0), 1, 0), new( 0, 1);
1538             ok near2 new(1, 1)->rotate(new(0,0), 1, 0), new(-1, 1);
1539             ok near2 new(0, 1)->rotate(new(0,0), 1, 0), new(-1, 0);
1540             ok near2 new(2, 2)->rotate(new(1,1), -1/sqrt(2), 1/sqrt(2)), new(1+sqrt(2), 1);
1541             ok near2 new(3, 1)->rotate(new(1,1), sqrt(3)/2, 1/2), new(2, 1+sqrt(3));
1542              
1543             ok near2 new(3, 1)->rotate(new(1,1),
1544             new(1, 0)->sine (new(1,1)),
1545             new(1, 0)->cosine(new(1,1))),
1546             new(1+sqrt(2), 1+sqrt(2));
1547             }
1548              
1549             #latest:;
1550             if (1) { #Tintersection
1551             ok near2 intersection(new(0,0), new(2,2), new(0,2),new(2,0)), new(1,1);
1552             ok near2 intersection(new(1,1), new(3,3), new(1,3),new(3,1)), new(2,2);
1553             }
1554              
1555             #latest:;
1556             if (1) { #Ttriangulate
1557             my @t = triangulate(1, new(0,0), new(2,0), new(2,2), new(0,2));
1558            
1559             ok near2 $t[0][0], new(1, 1);
1560             ok near2 $t[0][1], new(0, 0);
1561             ok near2 $t[0][2], new(2, 0);
1562            
1563             ok near2 $t[1][0], new(1, 1);
1564             ok near2 $t[1][1], new(2, 0);
1565             ok near2 $t[1][2], new(2, 2);
1566            
1567             ok near2 $t[2][0], new(1, 1);
1568             ok near2 $t[2][1], new(2, 2);
1569             ok near2 $t[2][2], new(0, 2);
1570            
1571             ok near2 $t[3][0], new(0, 0);
1572             ok near2 $t[3][1], new(1, 1);
1573             ok near2 $t[3][2], new(0, 2);
1574             }
1575              
1576             #latest:;
1577             if (1) { #Ttriangulate
1578             my @t = triangulate(0, new(2,2), new(2, 4), new(4,4), new(4, 2));
1579            
1580             ok near2 $t[0][0], new(3, 3);
1581             ok near2 $t[0][1], new(2, 2);
1582             ok near2 $t[0][2], new(2, 4);
1583            
1584             ok near2 $t[1][0], new(3, 3);
1585             ok near2 $t[1][1], new(2, 4);
1586             ok near2 $t[1][2], new(4, 4);
1587            
1588             ok near2 $t[2][0], new(3, 3);
1589             ok near2 $t[2][1], new(4, 4);
1590             ok near2 $t[2][2], new(4, 2);
1591            
1592             ok near2 $t[3][0], new(2, 2);
1593             ok near2 $t[3][1], new(3, 3);
1594             ok near2 $t[3][2], new(4, 2);
1595             }