SVG picture and least squares
Weekly challenge 165 — 16 May 2022
Week 165: 16 May 2022
Using Scalable Vector Graphics (SVG) accept a series of points and lines in the following format, one per line, in arbitrary order:
Point: x,y
Line: x1,y1,x2,y2
and create the corresponding graphic.
Example 1: 53,10 53,10,23,30 23,30
SVG has always been a popular technology with me. Amongst other things, I've used it for making scale drawings for alterations to my house, and for making easily scalable or re-colourable logos for websites. For images which don't contain photographic material SVG files are often tiny in size when compared to compressed bitmaps like JPEG or PNG. But although most web browsers can render them, it's quite unusual to find them in use.
In my experience, Inkscape is the best GUI editor for generating SVG graphics from scratch, though its output is rather more verbose than that from the Perl SVG module.
Both tasks this week require us to draw lines and points in a 2-dimensional space. Once you've mastered the syntax required, the task is fairly simple, although there is one catch to be surmounted, which is that SVG's geometry is 'left-handed'. The normal convention for Cartesian (ie x and y) coordinates is that the positive direction of the y axis is 90 degrees anti-clockwise from the positive x axis. So in a rectangular container, if you place the origin (x = y = 0) at the bottom left, every point within the container has a positive x and y.
SVG uses the convention that the positive direction of the y axis is 90 degrees clockwise from that of the x axis. That means that in order to get the positive x and y valued points within a rectangle, the origin has to be at the top left, which is upside down to the normal convention.
So, I chose to write my code so that, in SVG terms, it transforms every (x, y) to (x, height - y) where 'height' is the height of the container, which draws the diagram in the way we were all taught at school.
#!/usr/bin/perl # Peter Campbell Smith - 2022-05-16 # PWC 165 task 1 use v5.28; use strict; use warnings; use utf8; use SVG; my ($grp, $grp1, $grp2, $i, $object, $size, $svg, $x1, $x2, $y1, $y2, @objects); # data @objects = ([20, 20], [20, 20, 20, 50], [20, 50], [20, 50, 50, 75], [50, 75], [80, 50], [20, 50, 80, 50], [50, 75, 80, 50], [80, 20], [80, 50, 80, 20], [80, 20, 20, 20]); # create bounding box $size = 100; $svg = SVG->new(width => $size, height => $size); # define groups $grp1 = $svg->group(id => 'line_group', style => {stroke => 'blue', fill => 'blue'}); $grp2 = $svg->group(id => 'dot_group', style => {stroke => 'orange', fill => 'orange'}); # process lines and points - nb - SVG space has y axis zero at top # so we have to use (height - y) to show in a right-handed space for $object (@objects) { $i ++; # a point if (scalar(@$object) == 2) { ($x1, $y1) = @$object; $grp2->circle(id => "dot$i", cx => $x1, cy => $size - $y1, r => 2); # a line } elsif (scalar(@$object) == 4) { ($x1, $y1, $x2, $y2) = @$object; $grp1->line(id => "line$i", x1 => $x1, y1 => $size - $y1, x2 => $x2, y2 => $size - $y2); } } # export the svg code open OUT, '>utf8:', qq[/var/www/pwc/public_html/images/svg_165_1.svg] or die $!; print OUT $svg->xmlify; close OUT;
Any content of this website which has been created by Peter Campbell Smith is in the public domain