pricecharts

track prices of consumer electronics
Log | Files | Refs | README

commit 5cfb7d471001264e573e86cbd8027e9c5e2043d9
parent 2a08c834aab71af59167c60f71aa060bafc67c96
Author: Kyle Milz <kyle@getaddrinfo.net>
Date:   Mon,  4 May 2015 23:41:21 -0600

pc_html: use matrix multiplication instead of hand rolling

Diffstat:
MDEPS | 1+
Mpc_html | 75++++++++++++++++++++++++++++++++++-----------------------------------------
2 files changed, 35 insertions(+), 41 deletions(-)

diff --git a/DEPS b/DEPS @@ -7,6 +7,7 @@ p5-Getopt-Std p5-HTML-Grabber p5-IO-Tee p5-Lingua-EN-Inflect +p5-Math-MatrixReal p5-SVG p5-Template p5-Term-ReadKey diff --git a/pc_html b/pc_html @@ -6,6 +6,7 @@ use warnings; use Config::Grammar; use Getopt::Std; use Lingua::EN::Inflect qw(PL); +use Math::MatrixReal; use POSIX; use PriceChart; use SVG; @@ -35,6 +36,13 @@ my $where_stale = $args{a} ? "" : "where svg_stale = 1"; my $part_equality = qq{prices.manufacturer = products.manufacturer and prices.part_num = products.part_num}; +# catmull-rom to cubic bezier conversion matrix +my $catrom_to_bezier = Math::MatrixReal->new_from_rows([[0, 1, 0, 0], + [-1/6, 1, 1/6, 0], + [0, 1/6, 1, -1/6], + [0, 0, 1, 0]]); +my $m_t = ~$catrom_to_bezier; + # # manufacturers # @@ -358,22 +366,20 @@ sub make_svg my $retailer_id = lc($retailer); $retailer_id =~ s/ /_/; - my (@xs, @ys, @pts); + my (@xs, @ys); for (sort keys %{$values}) { my ($x, $y) = ($_, $values->{$_}{price}); push @xs, sprintf "%.3f", ($x - $x_min) * $x_scale + $left; push @ys, sprintf "%.3f", $height - $bottom - ($y - $y_min) * $y_scale; - push @pts, $xs[-1]; - push @pts, $ys[-1]; } - if (@pts < 6) { + if (@xs < 3) { my $points = $svg->get_path(x => \@xs, y => \@ys, -type => "path"); $defs->path(%$points, id => "path_$retailer_id"); } else { # catmull rom time - my $d = catmullrom_to_bezier(\@pts); + my $d = catmullrom_to_bezier(\@xs, \@ys); $defs->tag("path", "d" => $d, id => "path_$retailer_id"); } @@ -426,47 +432,34 @@ sub make_svg # sub catmullrom_to_bezier { - my $pts_ref = shift; - my @pts = @$pts_ref; - - # catmull-rom to cubic bezier conversion matrix - # 0 1 0 0 - # -1/6 1 1/6 0 - # 0 1/6 1 -1/6 - # 0 0 1 0 - - my $d = "M $pts[0], $pts[1] "; - my $iLen = @pts; - for (my $i = 0; $iLen - 2 > $i; $i += 2) { - my (@xs, @ys); + my $xs_ref = shift; + my $ys_ref = shift; + + my $d = "M $xs_ref->[0], $ys_ref->[0] "; + my $iLen = @$xs_ref; + for (my $i = 0; $iLen - 1 > $i; $i++) { + + my @offsets = (-1, 0, 1, 2); if ($i == 0) { - push @xs, $pts[$i]; push @ys, $pts[$i + 1]; - push @xs, $pts[$i]; push @ys, $pts[$i + 1]; - push @xs, $pts[$i + 2]; push @ys, $pts[$i + 3]; - push @xs, $pts[$i + 4]; push @ys, $pts[$i + 5]; + @offsets = (0, 0, 1, 2); + } elsif ($i == ($iLen - 2)) { + @offsets = (-1, 0, 1, 1); } - elsif ($i == ($iLen - 4)) { - push @xs, $pts[$i - 2]; push @ys, $pts[$i - 1]; - push @xs, $pts[$i]; push @ys, $pts[$i + 1]; - push @xs, $pts[$i + 2]; push @ys, $pts[$i + 3]; - push @xs, $pts[$i + 2]; push @ys, $pts[$i + 3]; - } - else { - push @xs, $pts[$i - 2]; push @ys, $pts[$i - 1]; - push @xs, $pts[$i]; push @ys, $pts[$i + 1]; - push @xs, $pts[$i + 2]; push @ys, $pts[$i + 3]; - push @xs, $pts[$i + 4]; push @ys, $pts[$i + 5]; + + my (@xs, @ys); + for my $idx (@offsets) { + push @xs, $xs_ref->[$i + $idx]; + push @ys, $ys_ref->[$i + $idx]; } - my (@bp_x, @bp_y); - push @bp_x, $xs[1]; push @bp_y, $ys[1]; - push @bp_x, ((-$xs[0] + 6*$xs[1] + $xs[2]) / 6); - push @bp_y, ((-$ys[0] + 6*$ys[1] + $ys[2]) / 6); - push @bp_x, (($xs[1] + 6*$xs[2] - $xs[3]) / 6); - push @bp_y, (($ys[1] + 6*$ys[2] - $ys[3]) / 6); - push @bp_x, $xs[2]; push @bp_y, $ys[2]; + my $x_row = Math::MatrixReal->new_from_rows([[@xs]]); + my $y_row = Math::MatrixReal->new_from_rows([[@ys]]); + + $x_row = $x_row * $m_t; + $y_row = $y_row * $m_t; - $d .= "C $bp_x[1], $bp_y[1] $bp_x[2], $bp_y[2] $bp_x[3], $bp_y[3] "; + my ($x, $y) = ($x_row->[0][0], $y_row->[0][0]); + $d .= "C $x->[1], $y->[1] $x->[2], $y->[2] $x->[3], $y->[3] "; } return $d;