ICC-Profile
view release on metacpan or search on metacpan
lib/ICC/Support/geo2.pm view on Meta::CPAN
# create new object from parameter hash
_new_from_hash($self, @_);
}
# bless object
bless($self, $class);
# return object reference
return($self);
}
# compute distance and offset
# optional hash keys:
# 'limit0' limits offset to values >= 0
# 'limit1' limits offset to values <= 1
# parameters: (ref_to_input_array, [hash])
# returns: (distance, offset)
sub transform {
# get parameters
my ($self, $in, $hash) = @_;
# local variables
my ($v01, $v21, $vx, $s, $t);
# compute (x0 - x1) and (x2 - x1)
$v01 = [$in->[0] - $self->[1][0][0], $in->[1] - $self->[1][0][1], $in->[2] - $self->[1][0][2]];
$v21 = [$self->[1][1][0] - $self->[1][0][0], $self->[1][1][1] - $self->[1][0][1], $self->[1][1][2] - $self->[1][0][2]];
# compute |(x2 - x1)|^2
if ($s = $v21->[0]**2 + $v21->[1]**2 + $v21->[2]**2) {
# compute offset
$t = ICC::Shared::dotProduct($v01, $v21)/$s;
# if offset limited >= 0 and t < 0
if ($hash->{'limit0'} && $t < 0) {
# return distance and offset
return(sqrt(($in->[0] - $self->[1][0][0])**2 + ($in->[1] - $self->[1][0][1])**2 + ($in->[2] - $self->[1][0][2])**2), 0);
# if offset limited <= 0 and t > 1
} elsif ($hash->{'limit1'} && $t > 1) {
# return distance and offset
return(sqrt(($in->[0] - $self->[1][1][0])**2 + ($in->[1] - $self->[1][1][1])**2 + ($in->[2] - $self->[1][1][2])**2), 1);
} else {
# compute (x0 - x1) x (x2 - x1)
$vx = ICC::Shared::crossProduct($v01, $v21);
# return distance and offset
return(sqrt(($vx->[0]**2 + $vx->[1]**2 + $vx->[2]**2)/$s), $t);
}
# identical endpoints
} else {
# return distance and offset
return(sqrt(($in->[0] - $self->[1][0][0])**2 + ($in->[1] - $self->[1][0][1])**2 + ($in->[2] - $self->[1][0][2])**2), 0);
}
}
# compute Jacobian matrix
# optional hash keys:
# 'limit0' limits offset to values >= 0
# 'limit1' limits offset to values <= 1
# parameters: (ref_to_input_array, [hash])
# returns: (Jacobian_matrix, [distance, offset])
sub jacobian {
# get parameters
my ($self, $in, $hash) = @_;
# local variables
my ($v01, $v21, $vx, $vr, $s, $t, $d, $jac, $wx);
# compute (x0 - x1) and (x2 - x1)
$v01 = [$in->[0] - $self->[1][0][0], $in->[1] - $self->[1][0][1], $in->[2] - $self->[1][0][2]];
$v21 = [$self->[1][1][0] - $self->[1][0][0], $self->[1][1][1] - $self->[1][0][1], $self->[1][1][2] - $self->[1][0][2]];
# compute |(x2 - x1)|^2
if ($s = $v21->[0]**2 + $v21->[1]**2 + $v21->[2]**2) {
# compute offset
$t = ICC::Shared::dotProduct($v01, $v21)/$s;
# if offset limited >= 0 and t < 0
if ($hash->{'limit0'} && $t < 0) {
# set offset
$t = 0;
# compute Jacobian vector and radius
($jac->[0], $d) = _radjac($self->[1][0], $in);
# complete Jacobian
$jac->[1] = [0, 0, 0];
# if offset limited <= 0 and t > 1
} elsif ($hash->{'limit1'} && $t > 1) {
# set offset
$t = 1;
# compute Jacobian vector and radius
($jac->[0], $d) = _radjac($self->[1][1], $in);
# complete Jacobian
$jac->[1] = [0, 0, 0];
} else {
# compute (x0 - x1) x (x2 - x1)
$vx = ICC::Shared::crossProduct($v01, $v21);
# compute distance
$d = sqrt(($vx->[0]**2 + $vx->[1]**2 + $vx->[2]**2)/$s);
# compute offset partial derivatives
$jac->[1] = [$v21->[0]/$s, $v21->[1]/$s, $v21->[2]/$s];
# compute cross product matrix
$wx = [
[0, $jac->[1][2]/$d, -$jac->[1][1]/$d],
[-$jac->[1][2]/$d, 0, $jac->[1][0]/$d],
[$jac->[1][1]/$d, -$jac->[1][0]/$d, 0]
];
# compute distance partial derivatives
$jac->[0] = ICC::Support::Lapack::vec_xplus($wx, $vx, {'trans' => 'T'});
}
# identical endpoints
} else {
# set offset
$t = 0;
# compute Jacobian vector and radius
($jac->[0], $d) = _radjac($self->[1][0], $in);
# complete Jacobian
$jac->[1] = [0, 0, 0];
}
# bless Jacobian as Math::Matrix object
bless($jac, 'Math::Matrix');
# if array wanted
if (wantarray) {
# return Jacobian, distance and offset
return($jac, $d, $t);
} else {
# return Jacobian
return($jac);
}
}
# get/set points array
# parameters: ([ref_to_points_array])
# returns: (ref_to_points_array)
sub points {
# get parameters
my ($self, $points) = @_;
# if parameter supplied
if (defined($points)) {
# verify a 2-D array
(ref($points) eq 'ARRAY' && @{$points} == grep {ref() eq 'ARRAY'} @{$points}) || croak('\'points\' parameter not a 2-D array');
# verify array has 2 rows
(@{$points} == 2) || croak('\'points\' parameter must contain 2 points');
# verify point 0 contains 3 coordinates
(@{$points->[0]} == 3 && 3 == grep {Scalar::Util::looks_like_number($_)} @{$points->[0]}) || croak('\'points\' parameter has invalid point 0');
# verify point 1 contains 3 coordinates
(@{$points->[1]} == 3 && 3 == grep {Scalar::Util::looks_like_number($_)} @{$points->[1]}) || croak('\'points\' parameter has invalid point 1');
# verify points are unique
($points->[0][0] != $points->[1][0] || $points->[0][1] != $points->[1][1] || $points->[0][2] != $points->[1][2]) || carp('\'points\' parameter contains identical points');
# copy points array
$self->[1] = Storable::dclone($points);
( run in 0.349 second using v1.01-cache-2.11-cpan-524268b4103 )