diff options
| author | Mohammad S Anwar <Mohammad.Anwar@yahoo.com> | 2022-05-23 09:19:02 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-05-23 09:19:02 +0100 |
| commit | 29bd962c8142282c38743cddc2d2171a27187e77 (patch) | |
| tree | bf794bb938fc13be699ec4172ae78741e3caa2aa | |
| parent | d59a9d3fcc9051aaec60dd56b2ea38be29141c94 (diff) | |
| parent | 38000c6f72163eba496485b2eb4cc542ed2f0734 (diff) | |
| download | perlweeklychallenge-club-29bd962c8142282c38743cddc2d2171a27187e77.tar.gz perlweeklychallenge-club-29bd962c8142282c38743cddc2d2171a27187e77.tar.bz2 perlweeklychallenge-club-29bd962c8142282c38743cddc2d2171a27187e77.zip | |
Merge pull request #6147 from choroba/ech165
Solve 165: Scalable Vector Graphics (SVG) & Line of Best Fit
| -rwxr-xr-x | challenge-165/e-choroba/perl/ch-1.pl | 105 | ||||
| -rwxr-xr-x | challenge-165/e-choroba/perl/ch-2.pl | 60 |
2 files changed, 165 insertions, 0 deletions
diff --git a/challenge-165/e-choroba/perl/ch-1.pl b/challenge-165/e-choroba/perl/ch-1.pl new file mode 100755 index 0000000000..9a22702560 --- /dev/null +++ b/challenge-165/e-choroba/perl/ch-1.pl @@ -0,0 +1,105 @@ +#!/usr/bin/perl +use warnings; +use strict; + +use Template; + +my $HELP = << '__HELP__'; +Usage: $0 input_file [width height] + +Use - for input_file to read standard input. +Width and height default to 400x300. +__HELP__ + +my $TEMPLATE = << '__SVG__'; +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<svg height="[% height %]" width="[% width %]" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +[% IF lines -%] + <g id="lines" stroke="#369" stroke-width="4"> + [%- FOREACH line IN lines %] + <line x1="[% line.0 %]" x2="[% line.2 %]" y1="[% line.1 %]" y2="[% line.3 %]" /> + [%- END %] + </g> +[% END- %] +[%- IF points -%] + <g fill="#f73" id="points"> + [%- FOREACH point IN points %] + <circle cx="[% point.0 %]" cy="[% point.1 %]" r="3" /> + [%- END %] + </g> +[%- END %] +</svg> +__SVG__ + +my $file = shift; +if (! defined $file || $file =~ /^(?:-h|--help)$/) { + print $HELP; + exit ! defined $file +} + +my $width = shift || 400; +my $height = shift || 300; + +my ($min_x, $max_x, $min_y, $max_y); +my (@points, @lines); +my $FLOAT = qr/-?(?:[0-9]*(?:\.[0-9]+)?+)/; + +my $in; +if ('-' eq $file) { + $in = *STDIN; +} else { + open $in, '<', $file or die "$file: $!"; +} + +while (<$in>) { + if (/^($FLOAT),($FLOAT),($FLOAT),($FLOAT)$/) { + my ($x0, $y0, $x1, $y1) = ($1, $2, $3, $4); + push @lines, [$x0, $y0, $x1, $y1]; + for my $x ($x0, $x1) { + $min_x = $x if ! defined $min_x || $x < $min_x; + $max_x = $x if ! defined $max_x || $x > $max_x; + } + for my $y ($y0, $y1) { + $min_y = $y if ! defined $min_y || $y < $min_y; + $max_y = $y if ! defined $max_y || $y > $max_y; + } + + } elsif (/^($FLOAT),($FLOAT)$/) { + my ($x, $y) = ($1, $2); + push @points, [$x, $y]; + $min_x = $x if ! defined $min_x || $x < $min_x; + $max_x = $x if ! defined $max_x || $x > $max_x; + $min_y = $y if ! defined $min_y || $y < $min_y; + $max_y = $y if ! defined $max_y || $y > $max_y; + + } else { + warn "WARN: Ignoring: $_"; + } +} + +my $scale_x = ($max_x - $min_x) / $width; +my $scale_y = ($max_y - $min_y) / $height; +$_ ||= 1 for $scale_x, $scale_y; + +for my $point (@points) { + $point->[0] = ($point->[0] - $min_x) / $scale_x; + $point->[1] = ($point->[1] - $min_y) / $scale_y; +} +for my $line (@lines) { + $line->[$_] = ($line->[$_] - $min_x) / $scale_x for 0, 2; + $line->[$_] = ($line->[$_] - $min_y) / $scale_y for 1, 3; +} + +my $template = 'Template'->new; +$template->process(\$TEMPLATE, + {height => $height, + width => $width, + points => \@points, + lines => \@lines} +) or die $template->error; + +__DATA__ +53,10 +53,10,23,30 +23,30 diff --git a/challenge-165/e-choroba/perl/ch-2.pl b/challenge-165/e-choroba/perl/ch-2.pl new file mode 100755 index 0000000000..700420a82c --- /dev/null +++ b/challenge-165/e-choroba/perl/ch-2.pl @@ -0,0 +1,60 @@ +#!/usr/bin/perl +use warnings; +use strict; +use feature qw{ say }; + +use ARGV::OrDATA; +use List::Util qw{ sum }; + +=head1 Usage + +ch-2.pl input_file | ch-1.pl - > out.svg + +=cut + +my @points; +while (<>) { + push @points, map [split /,/], split; +} + +my ($min_x, $max_x, $min_y, $max_y) + = (($points[0][0]) x 2, ($points[0][1]) x 2); +for my $point (@points[1 .. $#points]) { + $min_x = $point->[0] if $point->[0] < $min_x; + $min_y = $point->[1] if $point->[1] < $min_y; + $max_x = $point->[0] if $point->[0] > $max_x; + $max_y = $point->[1] if $point->[1] > $max_y; +} + +my $sum_x = sum(map $_->[0], @points); +my $sum_y = sum(map $_->[1], @points); +my $sum_x_square = sum(map $_->[0] * $_->[0], @points); +my $sum_xy = sum(map $_->[0] * $_->[1], @points); + +my $divisor = @points * $sum_x_square - $sum_x * $sum_x; +my $slope = (@points * $sum_xy - $sum_x * $sum_y) + / ($divisor || 1); + +my $intercept = ($sum_y - $slope * $sum_x) / @points; + +my @line; +push @line, ($_, $intercept + $_ * $slope) for $min_x, $max_x; + +# Vertical. +if ($line[0] == $line[2] && $line[1] == $line[3]) { + $line[1] = $points[0][1]; + $line[3] = $points[1][1]; +} + +{ local $, = ','; + say @$_ for @points; + say @line; +} + +__DATA__ +333,129 39,189 140,156 292,134 393,52 160,166 362,122 13,193 +341,104 320,113 109,177 203,152 343,100 225,110 23,186 282,102 +284,98 205,133 297,114 292,126 339,112 327,79 253,136 61,169 +128,176 346,72 316,103 124,162 65,181 159,137 212,116 337,86 +215,136 153,137 390,104 100,180 76,188 77,181 69,195 92,186 +275,96 250,147 34,174 213,134 186,129 189,154 361,82 363,89 |
