Math-Project3D

 view release on metacpan or  search on metacpan

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

   # $dimension == 0 => one solution
   # $dimension == 1 => straight line
   # $dimension == 2 => plane (impossible :) )
   # ...
   # $dimension == 1 is possible (point and projection_vector part
   # of the plane). Hence: !!!FIXME!!!

   return $p_vector->element(2,1), # coefficient 1
          $p_vector->element(3,1), # coefficient 2
          $p_vector->element(1,1); # distance in lengths of the projection vector
}


# Method project_range_callback
# 
# Does the projection calculations for ranges of function parameters.
# Takes an code reference and a number array refs of ranges as argument.
# Ranges are specified using three values:
# [lower_bound, upper_bound, increment].
# Alternatively, one may specify only one element in any of the array
# references. This will then be a static parameter.
# The number of ranges (array references) corresponds to the number of
# parameters to the vectorial function.
# The callback is called for every set of result values with an array
# reference of parameters and the list of the three result values.

sub project_range_callback {
   my  $self     = shift;

   croak "You need to assign a function before projecting it."
     if not defined $self->get_function();

   # Argument checking
   my  $callback = shift;
   ref $callback eq 'CODE' or
     croak "Invalid code reference passed to project_range_callback.";

   my @ranges    = @_;

   croak "Invalid range parameters passed to project_range_callback"
     if grep { ref $_ ne 'ARRAY' } @ranges;


   my $function = $self->get_function();

   # Replace all ranges that consist of a single number with ranges
   # that iterate from that number to itself.
   foreach (@ranges) {
      $_ = [$_->[0], $_->[0], 1] if @$_ == 1;
   }

   # Calculate every range's length and store it in @lengths.
   my @lengths   = map {
                         #      upper  - lower    / increment
                         int( ($_->[1] - $_->[0]) / $_->[2] ),
                       } @ranges;

   # Prepare counters for every range.
   my @counters  = (0) x scalar(@ranges);

   # Calculate the number if iterations needed.
   # It is $_+1 and not $_ because the lengths are the lengths we
   # need for the comparisons inside the long for loop. We save one
   # op in there that way.
   my $iterations = 1;
   $iterations *= ( $_ + 1 ) for @lengths;
   
   # For all possible combinations of parameters...
   for (my $i = 1; $i <= $iterations; $i++) {
      
      # Get current function parameters
      my @params;

      # Get one parameter for every range
      for (my $range_no = 0; $range_no < @ranges; $range_no++) {
         # lower + increment * current_count
         push @params, $ranges[$range_no][0] +
                       $ranges[$range_no][2] * $counters[$range_no];
      }
      
      # Increment outermost range by one. If it got out of bounds,
      # make it 0 and increment the next range, etc.
      my $j = 0;
      while (defined $ranges[$j] and ++$counters[$j] > $lengths[$j]) {
         $counters[$j] = 0;
         $j++;
      }

      # Apply function
      my $point = _new_from_cols(
                    [
                      [ $function->(@params) ],
                    ]
      );

      # Generate result_vector
      my $result_vector = _new_from_cols(
                            [
                              $self->{plane_basis_vector} + $point
                            ]
      );

      # Solve the l_e_s.
      my ($dimension, $p_vector, undef) = $self->{lr_matrix}->solve_LR($result_vector);
   
      # Did we find a solution?
      croak "Could not project $result_vector."
        if not defined $dimension;

      # $dimension == 0 => one solution
      # $dimension == 1 => straight line
      # $dimension == 2 => plane (impossible :) )
      # ...
      # $dimension == 1 is possible (point and projection_vector part
      # of the plane). Hence: !!!FIXME!!!
      
      $callback->(
             $p_vector->element(2,1), # coefficient 1
             $p_vector->element(3,1), # coefficient 2
             $p_vector->element(1,1), # distance in lengths of the projection vector
             $j,                      # how many ranges did we increment?
      );
   }
   
   return();
}


# Method project_list



( run in 0.465 second using v1.01-cache-2.11-cpan-71847e10f99 )