Math-Vectors2

 view release on metacpan or  search on metacpan

lib/Math/Vectors2.pm  view on Meta::CPAN

#!/usr/bin/perl -I/home/phil/perl/cpan/DataTableText/lib/
#-------------------------------------------------------------------------------
# Vectors in two dimensions
# Philip R Brenan at gmail dot com, Appa Apps Ltd Inc., 2017-2020
#-------------------------------------------------------------------------------
# podDocumentation
package Math::Vectors2;
require v5.16;
our $VERSION = 20231002;
use warnings FATAL => qw(all);
use strict;
use Carp qw(confess);
use Data::Dump qw(dump);
use Data::Table::Text qw(genHash);
use Math::Trig;

my $nearness = 1e-6;                                                            # Definition of near

sub near($$)                                                                    # Check two scalars are near each other.
 {my ($o, $p) = @_;
  abs($p-$o) < $nearness
 }

sub near2($$)                                                                   # Check two vectors are near each other.
 {my ($o, $p) = @_;
  $o->d($p) < $nearness
 }

#D1 Methods                                                                     # Vector methods.

sub new($$)                                                                     #S Create new vector from components.
 {my ($x, $y) = @_;                                                             # X component, Y component
  genHash(__PACKAGE__,                                                          # Attributes of a vector
   x => $x,                                                                     # X coordinate
   y => $y,                                                                     # Y coordinate
  );
 }

sub zeroAndUnits()                                                              #S Create the useful vectors: zero=(0,0), x=(1,0), y=(0,1).
 {map {&new(@$_)} ([0, 0], [1, 0], [0, 1])
 }

sub eq($$)                                                                      # Whether two vectors are equal to within the accuracy of floating point arithmetic.
 {my ($o, $p) = @_;                                                             # First vector, second vector
  near2($o, $p)
 }

sub zero($)                                                                     # Whether a vector is equal to zero within the accuracy of floating point arithmetic.
 {my ($o) = @_;                                                                 # Vector
  near($o->x, 0) && near($o->y, 0)
 }

sub print($@)                                                                   # Print one or more vectors.
 {my ($p, @p) = @_;                                                             # Vector to print, more vectors to print
  join ', ', map {'('.$_->x.','.$_->y.')'} @_
 }

sub clone($)                                                                    # Clone a vector.
 {my ($o) = @_;                                                                 # Vector to clone
  new($o->x, $o->y)
 }

sub Plus($@)                                                                    # Add zero or more other vectors to the first vector and return the result.
 {my ($o, @p) = @_;                                                             # First vector, other vectors
  for(@p)
   {$o->x += $_->x;
    $o->y += $_->y;
   }
  $o
 }

sub plus($@)                                                                    # Add zero or more other vectors to a copy of the first vector and return the result.
 {my ($o, @p) = @_;                                                             # First vector, other vectors
  $o->clone->Plus(@p)
 }

sub Minus($@)                                                                   # Subtract zero or more vectors from the first vector and return the result.
 {my ($o, @p) = @_;                                                             # First vector, other vectors
  for(@p)
   {$o->x -= $_->x;
    $o->y -= $_->y;
   }
  $o
 }

sub minus($@)                                                                   # Subtract zero or more vectors from a copy of the first vector and return the result.
 {my ($o, @p) = @_;                                                             # First vector, other vectors
  $o->clone->Minus(@p)
 }

sub Multiply($$)                                                                # Multiply a vector by a scalar and return the result.
 {my ($o, $m) = @_;                                                             # Vector, scalar to multiply by
  $o->x *= $m; $o->y *= $m;
  $o
 }

sub multiply($$)                                                                # Multiply a copy of a vector by a scalar and return the result.
 {my ($o, $m) = @_;                                                             # Vector, scalar to multiply by
  $o->clone->Multiply($m)
 }

sub Divide($$)                                                                  # Divide a vector by a scalar and return the result.
 {my ($o, $d) = @_;                                                             # Vector, scalar to multiply by
  $o->x /= $d; $o->y /= $d;
  $o
 }

sub divide($$)                                                                  # Divide a copy of a vector by a scalar and return the result.
 {my ($o, $d) = @_;                                                             # Vector, scalar to divide by
  $o->clone->Divide($d)
 }

sub l($)                                                                        # Length of a vector.
 {my ($o) = @_;                                                                 # Vector
  sqrt($o->x**2 + $o->y**2)
 }

sub l2($)                                                                       # Length squared of a vector.
 {my ($o) = @_;                                                                 # Vector
  $o->x**2 + $o->y**2
 }

sub d($$)                                                                       # Distance between the points identified by two vectors when placed on the same point.
 {my ($o, $p) = @_;                                                             # Vector 1, vector 2
  sqrt(($o->x-$p->x)**2 + ($o->y-$p->y)**2)
 }

sub d2($$)                                                                      # Distance squared between the points identified by two vectors when placed on the same point.
 {my ($o, $p) = @_;                                                             # Vector 1, vector 2
  ($o->x-$p->x)**2 + ($o->y-$p->y)**2
 }

sub n($)                                                                        # Return a normalized a copy of a vector.
 {my ($o) = @_;                                                                 # Vector
  my $l = $o->l;
  $l == 0 and confess;
  new($o->x / $l, $o->y / $l)
 }

sub dot($$)                                                                     # Dot product of two vectors.
 {my ($o, $p) = @_;                                                             # Vector 1, vector 2
  $o->x * $p->x + $o->y * $p->y
 }

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 ...
 {my ($o, $p) = @_;                                                             # Vector 1, vector 2
  $o->x * $p->y - $o->y * $p->x
 }

sub cosine($$)                                                                  # Cos(angle between two vectors).
 {my ($o, $p) = @_;                                                             # Vector 1, vector 2
  $o->dot($p) / $o->l / $p->l
 }

sub sine($$)                                                                    # Sin(angle between two vectors).
 {my ($o, $p) = @_;                                                             # Vector 1, vector 2
  $o->area($p) / $o->l / $p->l
 }

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.
 {my ($o, $p) = @_;                                                             # Vector 1, vector 2
  my $c = $o->cosine($p);
  my $s = $o->sine($p);
  my $a = Math::Trig::acos($c);
  $s > 0 ? $a : -$a
 }

sub smallestAngleToNormalPlane($$)                                              # The smallest angle between the second vector and a plane normal to the first vector.
 {my ($a, $b) = @_;                                                             # Vector 1, vector 2
  my $r = abs $a->angle($b);
  my $p = Math::Trig::pi / 2;
  $r < $p ? $p - $r : $r - $p
 }

sub r90($)                                                                      # Rotate a vector by 90 degrees anticlockwise.
 {my ($o) = @_;                                                                 # Vector to rotate
  new(-$o->y, $o->x)
 }

sub r180($)                                                                     # Rotate a vector by 180 degrees.
 {my ($o) = @_;                                                                 # Vector to rotate
  new(-$o->x, -$o->y)
 }

sub r270($)                                                                     # Rotate a vector by 270 degrees anticlockwise.
 {my ($o) = @_;                                                                 # Vector to rotate
  new($o->y, -$o->x)
 }



( run in 0.726 second using v1.01-cache-2.11-cpan-524268b4103 )