[SOLVED] Using definition on elements of a list to decide which give smallest answer

Issue

In the code below I have calculated which triangles cover a certain point. Now I am trying to let the function perimeter calculate the perimeter of the left over triangles which can be found in triangle_fit. And when I know the perimeters of these triangles I want to chose the smallest triangle. I did some attempts but the function will only recognize x1, y1, x2, ....

import itertools
import math

def area(x1, y1, x2, y2, x3, y3):
    return abs((x1 * (y2 - y3) + x2 * (y3 - y1)
                + x3 * (y1 - y2)) / 2.0)


def isInside(x1, y1, x2, y2, x3, y3, x, y):
    A = area (x1, y1, x2, y2, x3, y3)
    A1 = area (x, y, x2, y2, x3, y3)
    A2 = area (x1, y1, x, y, x3, y3)
    A3 = area (x1, y1, x2, y2, x, y)
    if(A == A1 + A2 + A3):
        return True
    else:
        return False


def perimeter (x1, y1, x2, y2, x3, y3):
    return abs(math.sqrt((x1-x2)**2+(y1-y2)**2)+math.sqrt((x2-x3)^2
               +(y2-y3)**2)+math.sqrt((x3-x1)**2+(y3-y1)**2))


points = [(0,10), (0,0), (10,0), (10,10), (5,2), (2,2)]
P = (5,1)
triangle_fit = []

for triangle in itertools.combinations(points, 3):
    p1, p2, p3 = triangle
    if isInside(*p1, *p2, *p3, *P):
       triangle_fit.append(triangle)

print(triangle_fit)

Solution

You can do it by sorting the list of triangles by their perimeter which will move the smaller ones to the beginning (note there can be more than one that is smallest if they have the same perimeter).

To make doing this easier I changed the calling sequence of your perimeter() function to accept a sequence of three points to match the format of the contents of the triangle_fit list. I also changed it to use the math.hypot() function to compute the Euclidean-distance between each pair points. Doing this not only makes it a little faster, it also fixed a bug in your code I noticed where you used ^ instead of ** for exponentiation.

import itertools
import math

def area(x1, y1, x2, y2, x3, y3):
    return abs((x1 * (y2 - y3) +
                x2 * (y3 - y1) +
                x3 * (y1 - y2)) / 2.0)


def is_inside(x1, y1, x2, y2, x3, y3, x, y):
    A = area(x1, y1, x2, y2, x3, y3)
    A1 = area(x, y, x2, y2, x3, y3)
    A2 = area(x1, y1, x, y, x3, y3)
    A3 = area(x1, y1, x2, y2, x, y)
    return A == A1 + A2 + A3


def perimeter(points):
    (x1, y1), (x2, y2), (x3, y3) = points
    return (math.hypot(x1-x2, y1-y2) +
            math.hypot(x2-x3, y2-y3) +
            math.hypot(x3-x1, y3-y1))


points = [(0,10), (0,0), (10,0), (10,10), (5,2), (2,2)]
P = (5,1)
triangle_fit = []

for triangle in itertools.combinations(points, 3):
    p1, p2, p3 = triangle
    if is_inside(*p1, *p2, *p3, *P):
       triangle_fit.append(triangle)

triangle_fit.sort(key=perimeter)  # Sort by perimeter.

for points in triangle_fit:
    print(f'{points}: area={area(*points[0], *points[1], *points[2]):.2f}')

Answered By – martineau

Answer Checked By – Katrina (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published.