File Coverage

blib/lib/Math/VectorReal.pm
Criterion Covered Total %
statement 120 177 67.8
branch 25 70 35.7
condition 14 46 30.4
subroutine 28 36 77.7
pod 14 18 77.7
total 201 347 57.9


line stmt bran cond sub pod time code
1             #
2             # Math::VectorReal Vector Mathematics
3             #
4             #
5             # Copyright (c) 2001 Anthony Thyssen. All rights reserved. This program
6             # is free software; you can redistribute it and/or modify it under the
7             # same terms as Perl itself.
8             #
9             package Math::VectorReal;
10              
11             =head1 NAME
12              
13             Math::VectorReal - Module to handle 3D Vector Mathematics
14              
15             =head1 SYNOPSIS
16              
17             #!/usr/bin/perl
18             use Math::VectorReal;
19              
20             $a = vector( 1, 2, .5 );
21             print "Vector as string (MatrixReal default format)\n\$a => ", $a;
22              
23             print $a->stringify("Formated Output \$a => { %g, %g, %g }\n");
24              
25             # I hate newline in the default output format (defined as MatrixReal)
26             $Math::VectorReal::FORMAT = "[ %.5f %.5f %.5f ]";
27             print "Modified default output format \$a => $a\n";
28              
29             print 'length => ', $a->length, "\n";
30             print 'normalised => ', $a->norm, "\n";
31              
32             use Math::VectorReal qw(:all); # Include O X Y Z axis constant vectors
33             print 'string concat $a."**" = ', $a."**", "\n";
34             print 'vector constant X = ', X, "\n";
35             print 'subtraction $a - Z = ', $a - Z, "\n";
36             print 'scalar divide $a / 3 = ', $a / 3, "\n";
37             print 'dot product $a . Y = ', $a . Y, "\n";
38             print 'cross product $a x Y = ', $a x Y, "\n";
39              
40             print "Plane containing points X, \$a, Z (in anti-clockwise order)\n";
41             ($n,$d) = plane( X, $a, Z ); # return normal and disance from O
42             print ' normal = $n = ', $n, "\n";
43             print ' disance from O = $d = ', $d, "\n";
44             print ' Y axis intersect = $d/($n.Y) = ', $d/($n.Y), "\n";
45              
46             print "VectorReal and MatrixReal interaction\n\n";
47             use Math::MatrixReal; # Not required for pure vector math as above
48              
49             $r = $a->vector2matrix_row; # convert to MatrixReal Row Vector
50             $c = $a->vector2matrix_col; # convert to MatrixReal Column Vector
51             print 'Vector as a MatrixReal Row $r (vector -> matrix) => ', "\n", $r;
52             print 'Vector as a MatrixReal Col $c (vector -> matrix) => ', "\n", $c;
53              
54             $nx = $a->norm; $ny = $nx x Z; $nz = $nx x $ny; # orthogonal vectors
55             $R = vector_matrix( $nx, $ny, $nz ); # make the rotation matrix
56             print 'Rotation Matrix from 3 Vectors $R => ',"\n", $R, "\n";
57              
58             print "Extract the Y row from the matrix as a VectorReal..\n";
59             print '$R->matrix_row2vector(1) => ', $R->matrix_row2vector(1), "\n";
60              
61             print "Rotate a vector with above rotation matrix\n";
62             print '$a * $R (vector -> vector)',"\n", $a * $R, "\n";
63              
64             print "Rotate a MatrixReal column (post multiply)...\n";
65             print "(NB: matrix must be transposed (~) to match column format)\n";
66             print '~$R * $c (col_matrix -> col_matrix) =>',"\n", ~$R * $c, "\n";
67              
68             =head1 DESCRIPTION
69              
70             The C package defines a 3D mathematical "vector", in a way
71             that is compatible with the previous CPAN module C. However
72             it provides a more vector oriented set of mathematical functions and overload
73             operators, to the C package. For example the normal perl string
74             functions "x" and "." have been overloaded to allow vector cross and dot
75             product operations. Vector math formula thus looks like vector math formula in
76             perl programs using this package.
77              
78             While this package is compatible with Math::MatrixReal, you DO NOT need to
79             have that package to perform purely vector orientated calculations. You will
80             need it however if you wish to do matrix operations with these vectors. The
81             interface has been designed with this package flexibility in mind.
82              
83             The vectors are defined in the same way as a "row" C matrix,
84             instead of that packages choice of "column" definition for vector operations.
85             Such vectors are multiplied to matices with the vector on the left and the
86             matrix on the right. EG: v * M -> 'v
87              
88             Not only is this the way I prefer to handle vectors, but it is the way most
89             graphics books use vectors. As a bonus it results in no overload conflicts
90             between this package and that of Math::MatrixReal, (the left objects overload
91             operator is called to do the mathematics). It also is a lot simpler than
92             C column vector methods, which were designed for equation solving
93             rather than 3D geometry operations.
94              
95             The vector_matrix() function provided, simplifies the creation a
96             C object from 3 (usually orthogonal) vectors. This with its vector
97             orientated math operators makes it very easy to define orthogonal rotation
98             matrices from C objects. See a rough example in the
99             synopsis above, or in the file "matrix_test" in the packages source.
100              
101             NOTE: the 6th element the C array object is used to hold the
102             length of the vector so that it can be re-used without needing to be
103             re-calculated all the time. This means the expensive sqrt() function, need not
104             be called unless nessary. This usage should not effect the direct use of
105             these objects in the C functions.
106              
107             =cut
108              
109 2     2   956 use strict;
  2         4  
  2         85  
110             #require Math::MatrixReal; # not required!
111              
112 2     2   11 use strict;
  2         5  
  2         80  
113 2     2   18 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION);
  2         3  
  2         514  
114             require Exporter;
115              
116             @ISA = qw(Exporter);
117              
118             @EXPORT = qw( vector plane vector_matrix );
119              
120             @EXPORT_OK = qw( O X Y Z );
121              
122             %EXPORT_TAGS = (
123             axis => [ qw( O X Y Z ) ], # Unix Axis Vector Constants
124             all => [@EXPORT, @EXPORT_OK]
125             );
126              
127             $VERSION = '1.0';
128              
129 2     2   13 use Carp;
  2         3  
  2         174  
130 2     2   11 use vars qw( $FORMAT $TRACE );
  2         4  
  2         2093  
131             $TRACE = 0;
132             $FORMAT = "[ %#19.12E %#19.12E %#19.12E ]\n"; # output format (as MatrixReal)
133              
134             =head1 CONSTANTS
135              
136             Four constant vectors are available for export (using an ":all" tag).
137             these are
138              
139             0 = [ 0 0 0 ] the zero vector or origin
140             X = [ 1 0 0 ] |
141             Y = [ 0 1 0 ] > Unit axis vectors
142             Z = [ 0 0 1 ] |
143              
144             =cut
145              
146             # Constant Vector Functions
147             # The format is as per a Math::MatrixReal object, with extra length item
148 2     2 0 20 sub O() { bless [ [[0,0,0]], 1,3, undef,undef,undef, 0 ], __PACKAGE__; }
149 4     4 0 24 sub X() { bless [ [[1,0,0]], 1,3, undef,undef,undef, 1 ], __PACKAGE__; }
150 4     4 0 25 sub Y() { bless [ [[0,1,0]], 1,3, undef,undef,undef, 1 ], __PACKAGE__; }
151 8     8 0 44 sub Z() { bless [ [[0,0,1]], 1,3, undef,undef,undef, 1 ], __PACKAGE__; }
152              
153             =head1 CONSTRUCTORS
154              
155             =over 4
156              
157             =item new(x,y,z)
158              
159             Create a new vector with the values of C, C, C returning the
160             appropriate object.
161              
162             =item vector(x,y,z)
163              
164             As C but is a exported function which does not require a package
165             reference to create a C object.
166              
167             =item clone()
168              
169             Return a completely new copy of the referring C object.
170              
171             =cut
172              
173             sub new { # typical object creation (not many checks)
174 30 50   30 1 56 croak "Usage: \$vector = ".__PACKAGE__."->new(x,y,z);\n" unless @_;
175 30         33 my $ref = shift;
176 30   66     150 return bless [ [[ @_ ]], 1,3 ], ref $ref || $ref;
177             }
178              
179              
180             sub vector { # normal way to create a vector - Exported function
181             # This works as both a Object Method or Exported Function
182 1 0 0 1 1 5 croak "Usage: \$vector = ".__PACKAGE__."->vector(x,y,z);\n".
      33        
183             " or \$vector = vector(x,y,z);\n"
184             unless @_ == 3 || @_ == 4 && ref $_[0];
185 1         2 my $class = __PACKAGE__;
186 1 50       4 $class = ref shift if @_ == 4;
187 1         26 return $class->new(@_);
188             }
189              
190             sub clone {
191 25 50   25 1 53 croak "Usage: \$vector_copy = \$vector->clone;\n" unless @_ == 1;
192 25         32 my $v = shift;
193 25         41 my $c = $v->new( $v->array ); # create a new vector using values
194 25 100       80 $c->[6] = $v->[6] if defined $v->[6]; # also note its length (if known)
195 25         38 return $c;
196             }
197              
198             =head1 METHODS
199              
200             =item array()
201              
202             Return the x,y,z elements of the referring vector are an array of values.
203              
204             =item x()
205              
206             Return the x element of the referring vector.
207              
208             =item y()
209              
210             Return the y element of the referring vector.
211              
212             =item z()
213              
214             Return the z element of the referring vector.
215              
216             =item stringify( [ FORMAT ] )
217              
218             Return the referring verctor as a string. The C if given is used
219             to sprintf format the vector. This is used for all VectorReal to String
220             conversions.
221              
222             By default this format is the same as it would be for a C
223             object, "[ %#19.12E %#19.12E %#19.12E ]\n". Note that this includes a newline
224             character!.
225              
226             However unlike C you can assign a new default sprintf
227             format by assigning it to the packages C<$FORMAT> variable. For Example
228              
229             $Math::VectorReal::FORMAT = "{ %g, %g, %g }"
230              
231             Which is a good format to output vectors for use by the POVray (Persistance of
232             Vision Raytracer) program.
233              
234             =item length()
235              
236             Return the length of the given vector. As a side effect the length is saved
237             into that vectors object to avoid the use of the expensive sqrt() function.
238              
239             =item norm()
240              
241             Normalise the Vector. That is scalar divide the vector by its length, so that
242             it becomes of length one. Normal vectors are commonly use to define
243             directions, without scale, or orientation of a 3 dimensional plane.
244              
245             =cut
246              
247             sub array { # return vector as an array of values
248 72     72 1 83 my $v = shift;
249 72         67 return @{$v->[0][0]};
  72         565  
250             }
251              
252             sub x {
253 0     0 1 0 my $v = shift;
254 0         0 return ($v->array)[0];
255             }
256              
257             sub y {
258 0     0 1 0 my $v = shift;
259 0         0 return ($v->array)[1];
260             }
261              
262             sub z {
263 0     0 1 0 my $v = shift;
264 0         0 return ($v->array)[2];
265             }
266              
267             sub stringify { # convert a vector to a string (with optional format)
268 39     39 1 52 my( $v, $fmt ) = @_;
269 39 50       86 $fmt = $FORMAT unless defined $fmt; # if not given use current default
270 39         69 return sprintf $fmt, $v->array;
271             }
272              
273             sub length { # convert a vector to a string
274 5     5 1 7 my $v = shift;
275 5 100       17 return $v->[6] if defined $v->[6];
276 3         5 return $v->[6] = sqrt( $v.$v );
277             }
278              
279             sub norm { # scale vector to a length of one
280 3     3 1 5 my $v = shift;
281 3         5 return $v / $v->length;
282             }
283              
284             =item plane( v1, v2, v3 )
285              
286             Given three points defined counter clockwise on a plane, return an array in
287             which the first element is the planes normal unit vector, and the second its
288             distance from the origin, along that vector. NOTE: the distance may be
289             negitive, in which case the origon is above the defined plane in 3d space.
290              
291             =cut
292              
293             sub plane { # Given three points on the plane (right-hand rule)
294             # return a normal vector and distance from origin for a plane
295 1 50   1 1 5 croak "Usage: (\$normal, \$distance) = plane(\$p1,\$p2,\$p3);\n"
296             unless @_ == 3;
297 1         2 my ($a, $b, $c) = @_;
298 1         2 my $normal = (($b - $a) x ($c - $b))->norm;
299 1         7 return ( $normal, $a . $normal );
300             }
301              
302             =item vector_matrix( nx, ny, nz )
303              
304             Given the new location for the X, Y and Z vectors, concatanate them together
305             (row wise) to create a C translation matrix. For example
306             if the 3 vectors are othogonal to each other, the matrix created will be
307             a rotation matrix to rotate the X, Y and Z axis to the given vectors. See
308             above for an example.
309              
310             =cut
311              
312             sub vector_matrix {
313 0     0 1 0 my( $nx, $ny, $nz ) = @_;
314 0         0 bless [ [[$nx->array],
315             [$ny->array],
316             [$nz->array]], 3, 3 ], "Math::MatrixReal";
317             }
318              
319             # ------------------------------------------------------------------
320             # Convertsions between Math::MatrixReal and Math::VectorReal packages
321              
322             =back
323              
324             =head1 VECTOR/MATRIX CONVERSION
325              
326             The following functions provide links between the C and
327             C packages.
328              
329             NOTE: While this package is closely related to C, it does
330             NOT require that that package to be installed unless you actually want to
331             perform matrix operations.
332              
333             Also the overload operations will automatically handle vector/matrix
334             mathematics (See below).
335              
336             =head2 Vector to Matrix Conversion
337              
338             =over 4
339              
340             =item vector2matrix_row( [CLASS] )
341              
342             =item vector2matrix_col( [CLASS] )
343              
344             Convert C objects to a C objects.
345             Optional argument defines the object class to be returned (defaults to
346             C).
347              
348             Note that as a C is internally equivelent to a
349             C row matrix, C is essentually just a
350             bless operation, which is NOT required to use with C
351             functions.
352              
353             The C performs the required transpose to convert the
354             C object into a C version of a vector (a
355             column matrix).
356              
357             =cut
358              
359             sub vector2matrix_row {
360 0     0 1 0 my( $v, $ref ) = @_;
361 0   0     0 $ref ||= "Math::MatrixReal";
362 0   0     0 bless $v->clone, ref $ref || $ref; # clone and bless (object unchanged)
363             }
364              
365             sub vector2matrix_col {
366 0     0 1 0 my( $v, $ref ) = @_;
367 0   0     0 $ref ||= "Math::MatrixReal";
368 0         0 my @v = $v->array;
369 0   0     0 bless [ [[$v[0]],[$v[1]],[$v[2]]], 3, 1 ], ref $ref || $ref;
370             }
371              
372             =head2 Matrix to Vector Conversion
373              
374             =item matrix_row2vector( [ROW] )
375              
376             =item matrix_col2vector( [COLUMN] )
377              
378             When referred to by a C object, extracts the vector
379             from the matrix. the optional argument defines which row or column of the
380             matrix is to be extracted as a C vector.
381              
382             =cut
383              
384             { # Enclose MartixReal package in a block
385             package Math::MatrixReal; # Fake a change into the Math::MatrixReal package
386 2     2   12 use Carp; # import carp into this package
  2         5  
  2         795  
387              
388             sub matrix_row2vector {
389 0     0   0 my $m = shift; my($rows,$cols) = ($m->[1],$m->[2]);
  0         0  
390 0         0 my $r = shift; # optional, which column from matrix
391 0 0       0 croak "Error: matrix does not have 3D rows" unless ($cols == 3);
392 0 0       0 if ( defined $r ) {
393 0 0       0 croak "Error: matrix does not have that row" unless ( $r < $rows);
394             }
395             else { # if no option, it must be a Math::MatrixReal Row Vector
396 0 0       0 croak "Error: matrix given to matrix_row2vector is not a 3D row matrix"
397             unless ($rows == 1);
398 0         0 $r = 0;
399             }
400 0         0 return Math::VectorReal->new(@{$m->[0][$r]}); # same result, only cleaned up
  0         0  
401             }
402              
403             sub matrix_col2vector {
404 0     0   0 my $m = shift; my($rows,$cols) = ($m->[1],$m->[2]);
  0         0  
405 0         0 my $c = shift; # optional, which column from matrix
406 0 0       0 croak "Error: matrix does not have 3D rows" unless ($rows == 3);
407 0 0       0 if ( defined $c ) {
408 0 0       0 croak "Error: matrix does not have that column" unless ( $c < $cols);
409             }
410             else { # if no option, it must be a Math::MatrixReal Column Vector
411 0 0       0 croak "Error: matrix given to matrix_col2vector is not a 3D column matrix"
412             unless ($cols == 1);
413 0         0 $c = 0;
414             }
415 0         0 return Math::VectorReal->new($m->[0][0][$c], $m->[0][1][$c], $m->[0][2][$c]);
416             }
417              
418             } # Return to the Math::VectorReal package we are really defining
419              
420             # ------------------------------------------------------------------
421             # Overloaded Math functions
422              
423             =back
424              
425             =head1 OPERATOR OVERLOADING
426              
427             Overload operations are provided to perform the usual string conversion,
428             addition, subtraction, unary minus, scalar multiplation & division. On top of
429             this however the multiply have been expanded to look for and execute
430             C multiplation.
431              
432             The Main purpose of this package however was to provide the special vector
433             product operations: dot product "." and cross product "x". In perl these
434             operations are normally used for string operations, but if either argument
435             is a C object, the operation will attempt the approprate
436             vector math operation instead.
437              
438             Note however that if one side of the dot "." operator is already a string,
439             then the vector will be converted to a sting and a string concatantion will be
440             performed. The cross operator "x" will just croak() as it is non-sensical to
441             either repeat the string conversion of a vector, OR to repeat a string,
442             vector, times!
443              
444             Overloaded operator summery...
445             neg unary minus - multiply vector by -1
446             "" automatic string conversion using stringify() function
447             + vector addition
448             - vector subtraction
449             / scalar division (left argument must be the vector)
450             * scalar multiplication OR MatrixReal multiplication
451             x vector/cross product of two vectors
452             . dot product of two vectors OR vector/string concatanation
453              
454             Posible future addition '~' to transpose a C into a
455             C column vector (as per that operator on C objects).
456             It was not added as it just did not seem to be needed.
457              
458             =cut
459              
460             use overload
461 2         35 'neg' => \&_negate,
462             '""' => \&_stringify,
463             '+' => \&_addition,
464             '-' => \&_subtract,
465             '*' => \&_multiply,
466             '/' => \&_scalar_divide,
467             'x' => \&_cross_product, # Redefination of the string function
468             '.' => \&_dot_product, # These includes stingify/concatanation
469 2     2   1990 'fallback' => undef;
  2         1403  
470              
471              
472             sub _trace {
473 73 50   73   155 return unless $TRACE;
474 0         0 my($text,$object,$argument,$flip) = @_;
475 0 0       0 unless (defined $object) { $object = 'undef'; };
  0         0  
476 0 0       0 unless (defined $argument) { $argument = 'undef'; };
  0         0  
477 0 0       0 unless (defined $flip) { $flip = 'undef'; };
  0         0  
478 0 0       0 if (ref($object)) { $object = ref($object); }
  0         0  
479 0 0       0 if (ref($argument)) { $argument = ref($argument); }
  0         0  
480 0         0 $argument =~ s/\n/\\n/g;
481 0         0 print "$text: \$obj='$object' \$arg='$argument' \$flip='$flip'\n";
482             }
483              
484              
485             sub _negate {
486 3     3   7 my($object,$argument,$flip) = @_;
487 3         7 _trace("'neg'",$object,$argument,$flip);
488 3         6 my $v = $object->clone;
489 3         6 for ( 0 .. 2 ) { $v->[0][0][$_] = -$v->[0][0][$_]; }
  9         19  
490             # $v->[6]; does not change.
491 3         10 return $v
492             }
493              
494             sub _stringify {
495 33     33   54 my($object,$argument,$flip) = @_;
496 33         61 _trace("'\"\"'",$object,$argument,$flip);
497 33         55 return $object->stringify;
498             }
499              
500              
501             sub _addition {
502             # Operation on two vectors, as such $flip will be undefined or false
503             # The operation is also communitive - order does not matter.
504 5     5   9 my($object,$argument,$flip) = @_;
505 5         11 _trace("'+'",$object,$argument,$flip);
506 5 50 33     64 if ( (defined $argument) && ref($argument) &&
      33        
507             (ref($argument) !~ /^SCALAR$|^ARRAY$|^HASH$|^CODE$|^REF$/) ) {
508 5         13 my $v = $object->clone;
509 5         9 for ( 0 .. 2 ) { $v->[0][0][$_] += $argument->[0][0][$_]; }
  15         38  
510 5         7 $#{$v} = 2; # any cached vector length is now invalid
  5         13  
511 5         26 return $v;
512             }
513 0         0 croak("non-vector argument for '+'");
514             }
515              
516              
517             sub _subtract {
518 8     8   13 my($object,$argument,$flip) = @_;
519 8         22 _trace("'-'",$object,$argument,$flip);
520             # Operation on two vectors, as such $flip will be undefined or false
521             # Note; however this is not communitive - order matters
522 8 50 33     117 if ( (defined $argument) && ref($argument) &&
      33        
523             (ref($argument) !~ /^SCALAR$|^ARRAY$|^HASH$|^CODE$|^REF$/) ) {
524 8         14 my $v = $object->clone;
525 8         12 for ( 0 .. 2 ) { $v->[0][0][$_] -= $argument->[0][0][$_]; }
  24         50  
526 8         11 $#{$v} = 2; # any cached vector length is now invalid
  8         27  
527 8         21 return $v;
528             }
529 0         0 croak("non-vector argument for '-'");
530             }
531              
532              
533             sub _multiply {
534 3     3   5 my($object,$argument,$flip) = @_;
535 3         7 _trace("'*'",$object,$argument,$flip);
536 3 50       11 if ( ref($argument) ) {
    50          
537             # Assume multiply by Math::MatrixReal object EG: $v * $M --> $new_v
538             # Order is communicative, but $flip should NOT be true
539 0 0       0 if ( ! $flip ) {
540 0         0 return ( $object->vector2matrix_row($argument)
541             * $argument )->matrix_row2vector;
542             } else { # just in case flip is true..
543 0         0 return ( $argument *
544             $object->vector2matrix_row($argument) )->matrix_row2vector;
545             }
546             }
547             elsif ( defined $argument ) {
548             # defined $argument must be a scalar, so Scalar Multiply
549             # Communitive - order does not matter, $flip can be ignored
550 3         6 my $v = $object->clone;
551 3         6 for ( 0 .. 2 ) { $v->[0][0][$_] *= $argument; }
  9         19  
552 3 50       9 $v->[6] *= abs($argument) if defined $v->[6]; # multiply vector length
553 3         8 return $v;
554             }
555 0         0 croak("undefined argument given for vector multiply");
556             }
557              
558              
559             sub _scalar_divide {
560 6     6   10 my($object,$argument,$flip) = @_;
561 6         12 _trace("'/'",$object,$argument,$flip);
562             # The order is very important, you can NOT divide a scalar by a vector
563 6 50       12 croak("You can not divide a scalar by a vector") if $flip;
564             # The provided $argument must be a defined scalar
565 6 50 33     34 if ( (defined $argument) && ! ref($argument) ) {
566 6         11 my $v = $object->clone;
567 6         10 for ( 0 .. 2 ) { $v->[0][0][$_] /= $argument; }
  18         37  
568 6 100       18 $v->[6] /= abs($argument) if defined $v->[6]; # do vector length
569 6         19 return $v;
570             }
571 0         0 croak("non-scalar given for vector scalar divide");
572             }
573              
574              
575             sub _cross_product {
576 4     4   9 my($object,$argument,$flip) = @_;
577             # Operation on two vectors, as such $flip will be undefined or false
578             # Note: however this is not communitive - order does matters
579 4         9 _trace("'x'",$object,$argument,$flip);
580 4 50 33     53 if ( (defined $argument) && ref($argument) &&
      33        
581             (ref($argument) !~ /^SCALAR$|^ARRAY$|^HASH$|^CODE$|^REF$/) ) {
582 4         9 my $v = $object->new;
583 4         9 my @o = $object->array;
584 4         10 my @a = $argument->array;
585 4         14 @{$v->[0][0]} = ( $o[1]*$a[2] - $o[2]*$a[1],
  4         9  
586             $o[2]*$a[0] - $o[0]*$a[2],
587             $o[0]*$a[1] - $o[1]*$a[0] );
588 4         4 $#{$v} = 2; # any cached vector length is now invalid
  4         9  
589 4         15 return $v;
590             }
591 0         0 croak("string 'x' with a vector does not make sense!");
592             }
593              
594              
595             sub _dot_product {
596 11     11   21 my($object,$argument,$flip) = @_;
597 11 100 66     104 if ( (defined $argument) && ref($argument) &&
    50 66        
598             (ref($argument) !~ /^SCALAR$|^ARRAY$|^HASH$|^CODE$|^REF$/) ) {
599             # Operation on two vectors, and communitive - order does not matter
600 6         12 _trace("'.'",$object,$argument,$flip);
601 6         8 my $v = 0; # result is NOT an object, but a scalar
602 6         10 for ( 0 .. 2 ) { $v += $object->[0][0][$_] * $argument->[0][0][$_]; }
  18         44  
603 6         33 return $v;
604             }
605             # Argument is NOT a vector! Assume String concatenation wanted
606             elsif ( defined $flip ) {
607 5 100       11 if ( $flip ) {
608 3         13 _trace("'.\"\"'",$object,$argument,$flip);
609 3         10 return $argument . $object->stringify;
610             } else {
611 2         5 _trace("'\"\".'",$object,$argument,$flip);
612 2         5 return $object->stringify . $argument;
613             }
614             }
615             # concatenate a string to a vector
616 0           _trace("'.='",$object,$argument,$flip);
617 0           return $object->stringify . $argument;
618             # Concatenate a vector to string is handled automatically with '""' operator
619             }
620              
621             1;
622             # ------------------------------------------------------------------
623              
624             =head1 SEE ALSO
625              
626             The C CPAN Module by Steffen Beyer
627             and the C CPAN extension by Mike South
628              
629             =head1 AUTHOR
630              
631             Anthony Thyssen EFE
632              
633             =head1 COPYRIGHT
634              
635             Copyright (c) 2001 Anthony Thyssen. All rights reserved. This program is free
636             software; you can redistribute it and/or modify it under the same terms as
637             Perl itself. I would appreciate any suggestions however.
638              
639             =cut
640