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 )