aboutsummaryrefslogtreecommitdiff
path: root/src/Math/Path.pm
diff options
context:
space:
mode:
Diffstat (limited to 'src/Math/Path.pm')
-rw-r--r--src/Math/Path.pm171
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;
+}