Peter’s solutions: week 101 — 22 February 2021
THE WEEKLY CHALLENGE
Spiral triangle
You are given three points in the plane, as a list of six co-ordinates: A=(x1,y1), B=(x2,y2) and C=(x3,y3).
Write a script to find out if the triangle formed by the given three co-ordinates contains the origin (0,0).
Print 1 if found, otherwise 0.
Example 1 Input: A=(0,1), B=(1,0) and C=(2,2) Output: 0 because that triangle does not contain (0,0). Example 2 Input: A=(1,1), B=(-1,1) and C=(0,-3) Output: 1 because that triangle contains (0, 0) in its interior. Example 3 Input: A=(0,1), B=(2,0) and C=(-6,0) Output: 1 because (0,0) is on the edge connecting B and C.
This is a well-known mathematical problem, for which there are a number of established solutions. The one that appeals to me most uses barycentric coordinates.
In the current context, the 3 barycentric coordinates of the point at the cartesian origin are the signed proportions of lines from each vertex of the triangle which pass through the origin and end when they meet the opposite side of the triangle.
If the point is within the triangle, the barycentric coordinates will thus all be in the range 0 to +1.
If any of them is exactly 1 then the point lies on one of the triangle's edges, and if any is 0, the point is at a vertex. I have chosen to regard these as lying within the triangle - ie returned a 1 response.
Like almost every method, the answer for points very close to or on the triangle's sides depends on floating point arithmetic, so may be marginally inaccurate. However, this is arguably less likely than in a solution based on cartesian coordinates, where lines with infinite or near infinite gradient (eg x = 0) require treatment as exceptions.
#!/usr/bin/perl # Blog: http://ccgi.campbellsmiths.force9.co.uk/challenge use v5.26; # The Weekly Challenge - 2021-02-22 use utf8; # Week 101 - task 2 - Origin-containing triangle use warnings; # Peter Campbell Smith binmode STDOUT, ':utf8'; use Encode; origin_in_triangle(0, 1, 1, 0, 2, 2); origin_in_triangle(1, 1, -1, 1, 0, -3); origin_in_triangle(0, 1, 2, 0, -6, 0); sub origin_in_triangle { my ($x1, $y1, $x2, $y2, $x3, $y3, $a, $b, $c); # initialise ($x1, $y1, $x2, $y2, $x3, $y3) = @_; # calculate barycentric coordinates $a = (($y2 - $y3) * (0 - $x3) + ($x3 - $x2) * (0 - $y3)) / (($y2 - $y3) * ($x1 - $x3) + ($x3 - $x2) * ($y1 - $y3)); $b = (($y3 - $y1) * (0 - $x3) + ($x1 - $x3) * (0 - $y3)) / (($y2 - $y3) * ($x1 - $x3) + ($x3 - $x2) * ($y1 - $y3)); $c = 1 - $a - $b; # report say qq[\nInput: ($x1, $y1), ($x2, $y2), ($x3, $y3)]; say qq[Output: ] . ((0 <= $a && $a <= 1 && 0 <= $b && $b <= 1 && 0 <= $c && $c <= 1) ? 1 : 0); }
10 lines of code
Completed after the closing date and not submitted to GitHub
Input: (0, 1), (1, 0), (2, 2) Output: 0 Input: (1, 1), (-1, 1), (0, -3) Output: 1 Input: (0, 1), (2, 0), (-6, 0) Output: 1
Any content of this website which has been created by Peter Campbell Smith is in the public domain