Skip Menu |

This queue is for tickets about the Math-Quaternion CPAN distribution.

Report information
The Basics
Id: 89907
Status: resolved
Priority: 0/
Queue: Math-Quaternion

People
Owner: Nobody in particular
Requestors: djerius [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Critical
Broken in: 0.06
Fixed in: (no value)



Subject: incorrect quaternion generated when passed parallel but opposite vectors
rotation() incorrectly generates a non-rotating quaternion when passed two vectors which are parallel but opposite. For example, rotation( [1,0,0], [-1,0,0 ] ) returns [ 1, 0, 0, 0] rather than [ 0, 0, 0, 1 ]. This is caused by the new parallel vector code, which doesn't distinguish the sign of the dot product. Attached is a patch against 0.06 which fixes the code (and removes some of the comments in that section which are no longer pertinent, as one no longer has the choice of choosing a random rotation vector, since the rotation is not always zero). Test added as well. Diab
Subject: Math-Quaternion-0.06.patch
# This is a patch for Math-Quaternion-0.06.orig to update it to Math-Quaternion-0.06 # # To apply this patch: # STEP 1: Chdir to the source directory. # STEP 2: Run the 'applypatch' program with this patch file as input. # # If you do not have 'applypatch', it is part of the 'makepatch' package # that you can fetch from the Comprehensive Perl Archive Network: # http://www.perl.com/CPAN/authors/Johan_Vromans/makepatch-x.y.tar.gz # In the above URL, 'x' should be 2 or higher. # # To apply this patch without the use of 'applypatch': # STEP 1: Chdir to the source directory. # STEP 2: Run the 'patch' program with this file as input. # #### End of Preamble #### #### Patch data follows #### diff -c 'Math-Quaternion-0.06.orig/lib/Math/Quaternion.pm' 'Math-Quaternion-0.06/lib/Math/Quaternion.pm' Index: ./lib/Math/Quaternion.pm *** ./lib/Math/Quaternion.pm Sat Aug 24 07:52:47 2013 --- ./lib/Math/Quaternion.pm Wed Oct 30 16:45:30 2013 *************** *** 678,698 **** if (($x == 0) and ($y == 0) and ($z == 0)) { ! # Vectors a and b are parallel, such that rotation vector ! # is the zero-length vector (0,0,0), with theta 0. To ! # remove round-off errors in theta, set it to 0 ! $theta = 0; # Such a zero-length rotation vector is annoying (e.g. # division by 0 on normalization, and problems combining ! # rotations) Simple solution would be to set a random ! # rotation vector (e.g. 1,0,0) to go with the zero rotation ! # angle. This would satisfy as a quaternion that rotates ! # the first vector on the second, by a zero degree ! # rotation. ! # ! # A more elegant solution is to select a random rotation # vector that is also perpendicular to both parallel # vectors a and b. This satisfies the rotation requirement, # and helps programs relying on the logic that the rotation --- 678,694 ---- if (($x == 0) and ($y == 0) and ($z == 0)) { ! # Vectors a and b are parallel, such that rotation ! # vector is the zero-length vector (0,0,0), with ! # theta either 0 or pi (if vectors are opposite). ! # To remove round-off errors in theta, explicitly ! # set it. ! $theta = $dotprod > 0 ? 0 : pi; # Such a zero-length rotation vector is annoying (e.g. # division by 0 on normalization, and problems combining ! # rotations). To solve this, select a random rotation # vector that is also perpendicular to both parallel # vectors a and b. This satisfies the rotation requirement, # and helps programs relying on the logic that the rotation *************** *** 724,731 **** $z = $ax*$by-$ay*$bx; # ($x,$y,$z) is now a random yet valid rotation vector ! # perpendicular to the two original vectors. theta is still ! # 0. } } else { --- 720,726 ---- $z = $ax*$by-$ay*$bx; # ($x,$y,$z) is now a random yet valid rotation vector ! # perpendicular to the two original vectors. } } else { diff -c 'Math-Quaternion-0.06.orig/t/001_basic.t' 'Math-Quaternion-0.06/t/001_basic.t' Index: ./t/001_basic.t *** ./t/001_basic.t Sat Aug 24 07:35:51 2013 --- ./t/001_basic.t Wed Oct 30 16:42:59 2013 *************** *** 1,4 **** ! use Test::More tests => 82; use Math::Trig; use strict; use Carp; --- 1,4 ---- ! use Test::More tests => 83; use Math::Trig; use strict; use Carp; *************** *** 59,64 **** --- 59,81 ---- } } + # take two vectors as array refs; return true if they are equivalent + sub check_vector { + croak("Wrong number of args") unless (2==@_); + + my ($v1, $v2) = @_; + + if ( + equal_fuzz ($v1->[0] , $v2->[0]) + && equal_fuzz ($v1->[1] , $v2->[1]) + && equal_fuzz ($v1->[2] , $v2->[2]) + ) { + return 1; + } else { + return undef; + } + } + sub quatequal_fuzz { my ($q1,$q2) = @_; *************** *** 512,514 **** --- 529,547 ---- }); ok( checkquat($uq,1,0,0,0), "Creating Quaternion from two parallel vectors does not crash"); + + + # quaternion from parallel but opposite vectors + { + my $v1 = [ 1, 0, 0 ]; + my $v2 = [ -1, 0, 0 ]; + + my $q = Math::Quaternion->new({ v1 => $v1, v2 => $v2 }); + + my $v1_v2 = [ $q->rotate_vector( @$v1 ) ]; + + ok( check_vector( $v2, $v1_v2 ), + "Rotate opposite but parallel vectors" ); + + + } #### End of Patch data #### #### ApplyPatch data follows #### # Data version : 1.0 # Date generated : Wed Oct 30 16:48:37 2013 # Generated by : makepatch 2.05 # Recurse directories : Yes # Excluded files : (\A|/).*\~\Z # (\A|/).*\.a\Z # (\A|/).*\.bak\Z # (\A|/).*\.BAK\Z # (\A|/).*\.elc\Z # (\A|/).*\.exe\Z # (\A|/).*\.gz\Z # (\A|/).*\.ln\Z # (\A|/).*\.o\Z # (\A|/).*\.obj\Z # (\A|/).*\.olb\Z # (\A|/).*\.old\Z # (\A|/).*\.orig\Z # (\A|/).*\.rej\Z # (\A|/).*\.so\Z # (\A|/).*\.Z\Z # (\A|/)\.del\-.*\Z # (\A|/)\.make\.state\Z # (\A|/)\.nse_depinfo\Z # (\A|/)core\Z # (\A|/)tags\Z # (\A|/)TAGS\Z # p 'lib/Math/Quaternion.pm' 27300 1383165930 0100644 # p 't/001_basic.t' 16070 1383165779 0100644 #### End of ApplyPatch data #### #### End of Patch kit [created: Wed Oct 30 16:48:37 2013] #### #### Patch checksum: 161 5621 38014 #### #### Checksum: 179 6328 31229 ####
Thanks, fixed in 0.0.7.