diff options
Diffstat (limited to 'src/Math/Path.pm')
-rw-r--r-- | src/Math/Path.pm | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/src/Math/Path.pm b/src/Math/Path.pm new file mode 100644 index 0000000..d7afc20 --- /dev/null +++ b/src/Math/Path.pm @@ -0,0 +1,171 @@ +package Math::Path; +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU LGPL Libray General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA, +# or refer to http://www.gnu.org/copyleft/lgpl.html +# +################################################################## + +use strict; +our $recursive_depth = 2; + +sub new { + my ($class, @coords) = @_; + my $self = {}; + bless $self, $class; + $self -> {content} = (); + my @path = (); + my $tmp = []; + + for (my $i = 0; $i < @coords; $i ++) + { + my @arr = @{$coords [$i]}; + if (@arr == 3) + { + push (@{$tmp}, \@arr); + } + else + { + push (@{$tmp}, \@arr); + push (@path, $tmp); + $tmp = []; + } + } + $self -> {curves} = \@path; + $self -> {lastPoint} = undef; + $self -> {lenght} = 0; + $self -> update (); + return $self; +} + +sub drawLine { + my ($self, $x0, $y0, $x1, $y1) = @_; + if (!defined $self -> {content} || @{$self -> {content}} == 0) + { + push (@{$self -> {content}}, [$x0, $y0]); + } + push (@{$self -> {content}}, [$x1, $y1]); +} + +sub _calcul_lenght { + my ($self) = @_; + my @content = @{$self -> {content}}; + my $x = $content [0] -> [0]; + my $y = $content [0] -> [1]; + my $lenght = 0; + for (my $i = 0; $i < @content; $i ++) + { + my $dx = $content [$i] -> [0] - $x; + my $dy = $content [$i] -> [1] - $y; + my $d = sqrt (($dx) ** 2 + ($dy) ** 2); + $lenght += $d; + $x = $content [$i] -> [0]; + $y = $content [$i] -> [1]; + } + $self -> {lenght} = $lenght; +} + +sub drawBezierRecursive { + my ($self, $p0, $p1, $p2, $p3, $level) = @_; + if ($level <= 0) + { + $self -> drawLine ($p0 -> [0] + 0.5, $p0 -> [1] + 0.5, $p3 -> [0] + 0.5, $p3 -> [1] + 0.5); + } + else + { + my $left0 = [$p0 -> [0], $p0 -> [1]]; + my $left1 = [($p0 -> [0] + $p1 -> [0]) / 2, ($p0 -> [1] + $p1 -> [1]) / 2]; + my $left2 = [($p0 -> [0] + 2*$p1 -> [0] + $p2 -> [0]) / 4, ($p0 -> [1] + 2*$p1 -> [1] + $p2 -> [1]) / 4]; + my $left3 = [($p0 -> [0] + 3*$p1 -> [0] + 3*$p2 -> [0] + $p3 -> [0]) / 8, ($p0 -> [1] + 3*$p1 -> [1] + 3*$p2 -> [1] + $p3 -> [1]) / 8]; + my $right0 = [$left3 -> [0], $left3 -> [1]]; + my $right1 = [($p1 -> [0] + 2*$p2 -> [0] + $p3 -> [0]) / 4, ($p1 -> [1] + 2*$p2 -> [1] + $p3 -> [1]) / 4]; + my $right2 = [($p2 -> [0] + $p3 -> [0]) / 2, ($p2 -> [1] + $p3 -> [1]) / 2]; + my $right3 = [$p3 -> [0],$p3 -> [1]]; + $self -> drawBezierRecursive ($left0, $left1, $left2, $left3, $level -1); + $self -> drawBezierRecursive ($right0, $right1, $right2, $right3, $level -1); + } +} + +sub update { + my ($self) = @_; + my @curr_curve = (); + $self -> {content} = (); + $self -> {lastPoint} = undef; + my @curves = @{$self -> {curves}}; + for (my $i = 0; $i < @curves; $i++) + { + @curr_curve = @{$curves [$i]}; + if (@curr_curve == 1) + { + push (@{$self -> {content}}, $curr_curve [0]); + $self -> {lastPoint} = $curr_curve [0]; + } + elsif (@curr_curve == 2) + { + push (@{$self -> {content}}, $curr_curve [0]); + push (@{$self -> {content}}, $curr_curve [1]); + $self -> {lastPoint} = $curr_curve [1]; + } + elsif (@curr_curve == 3) + { + $self -> drawBezierRecursive ($self -> {lastPoint}, $curr_curve [0], $curr_curve [1], $curr_curve [2], $recursive_depth); + $self -> {lastPoint} = $curr_curve [2]; + } + elsif (@curr_curve == 4) + { + $self -> drawBezierRecursive ($curr_curve [0], $curr_curve [1], $curr_curve [2], $curr_curve [3], $recursive_depth); + $self -> {lastPoint} = $curr_curve [3]; + } + } + $self -> _calcul_lenght (); +} + +sub getRegularPoints { + my ($self, $nb) = @_; + my @points = (); + my $troncon = $self -> {lenght} / $nb; + my @content = @{$self -> {content}}; + my $current_troncon = 0; + my $x = $content [0] -> [0]; + my $y = $content [0] -> [1]; + my $dx = 1; + my $dy = 1; + my $lenght = 0; + for (my $i = 0; $i < @content; $i ++) + { + $dx = $content [$i] -> [0] - $x; + $dy = $content [$i] -> [1] - $y; + + my $d = sqrt (($dx) ** 2 + ($dy) ** 2); + $lenght += $d; + $current_troncon += $d; + while ($current_troncon >= $troncon) + { + my $dtp = $troncon - ($current_troncon - $d); + my $px = $x + $dx * $dtp / $d; + my $py = $y + $dy * $dtp / $d; + $x = $px; + $y = $py; + $d -= $dtp; + $dx = $content [$i] -> [0] - $x; + $dy = $content [$i] -> [1] - $y; + $current_troncon -= $troncon; + push (@points, [$x, $y, atan2 ($dx, $dy)]); + } + + $x = $content [$i] -> [0]; + $y = $content [$i] -> [1]; + } + push (@points, [$x, $y, atan2 ($dx, $dy)]); + return @points; +} |