aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad S Anwar <Mohammad.Anwar@yahoo.com>2022-05-23 09:19:02 +0100
committerGitHub <noreply@github.com>2022-05-23 09:19:02 +0100
commit29bd962c8142282c38743cddc2d2171a27187e77 (patch)
treebf794bb938fc13be699ec4172ae78741e3caa2aa
parentd59a9d3fcc9051aaec60dd56b2ea38be29141c94 (diff)
parent38000c6f72163eba496485b2eb4cc542ed2f0734 (diff)
downloadperlweeklychallenge-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-xchallenge-165/e-choroba/perl/ch-1.pl105
-rwxr-xr-xchallenge-165/e-choroba/perl/ch-2.pl60
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