concurrency.py

Created by james-wysocki

Created on February 18, 2026

7.34 KB

Given three vertices of a triangle, this program will calculate the circumcenter, orthocenter, incenter, and centroid of the triangle - provided none of the sides are vertical.


## J Wysocki
## Computes the circumcenter, orthocenter, and centroid of a triangle given the three vertices.
## Notes for a future update: make it work with sides (or medians or perpendicular lines) that are vertical

from math import *

def distance(point1, point2):
    """
    Calculates the distance between two points
    :param point1 the first point
    :param point2 the second point
    :return: distance between them, as a float
    """
    return sqrt((point1[0] - point2[0])**2 + (point1[1] - point2[1])**2)

def find_slope(point1, point2):
    """
    Calculate the slope between two points
    :param point1: first point
    :param point2: second point
    :return: slope or 'vertical'
    """
    if point1[0] == point2[0]:
        return 'vertical'
    else:
        return (point1[1] - point2[1]) / (point1[0] - point2[0])

def find_midpoint(point1, point2):
    """
    Calculates the midpoint between two points
    :param point1: first point
    :param point2: second point
    """
    return ((point1[0] + point2[0]) / 2, (point1[1] + point2[1]) / 2)

def y_intercept(slope, point):
    """
    Calculates the y-intercept of a line given the slope and a point
    :param slope: slope of the line
    :param point: point on the line
    :return: the y-intercept
    """
    return -1 * slope * point[0] + point[1]

def solve_system(slope1, point1, slope2, point2):
    """
    Solve a system of two linear equations, returns the intersection point    
    :param slope1: slope of the first line
    :param point1: point on the first line
    :param slope2: slope of the second line
    :param point2: point on the second line
    :return: intersection point
    """
    x = (slope1*point1[0] - slope2*point2[0] + point2[1] - point1[1]) / (slope1 - slope2)
    y = slope1 * (x - point1[0]) + point1[1]
    return x,y

def ratio_of_sides(common_point, endpoint1, endpoint2):
    """
    Calculates the ratio of segment lengths
    :param common_point point connected to both endpoints
    :param endpoint1 first endpoint
    :param endpoint2 second endpoint
    :return ratio of sides as a float
    """
    distance1 = distance(common_point, endpoint1)
    distance2 = distance(common_point, endpoint2)
    return distance2 / distance1


def round_tuple(point, digits_to_round):
    """
    Rounds the values in a tuple to a specified value
    :param point: the point to be rounded
    :param digits_to_round: the decimal place to round to
    :return: the point with rounded values
    """
    return round(point[0], digits_to_round) + 0, round(point[1], digits_to_round) + 0

def input_coord():
    """
    inputs the coordinates for three points
    :return: the three points of the triangle
    """
    labels = ['A', 'B', 'C']
    points = []
    for item, label in enumerate(labels):
        pt1 = float(input("x-coordinate of " + label + ": "))
        pt2 = float(input("y-coordinate of " + label + ": "))
        points.append((pt1, pt2))
    return points

def slopes(point_list):
    """
    Creates the slopes of the sides of a triangle
    :param point_list: list of vertices of the triangle (A,B,C)
    :return: a list of the slopes (AB, BC, CA)
    """
    new_points = point_list[:]
    new_points.append(point_list[0])
    slope_list = []
    for i in range(len(new_points)-1):
        slope_list.append(find_slope(new_points[i],new_points[i+1]))
    return slope_list


def perp_slopes(slope_list):
    """
    calculate perpendicular slopes
    :param slope_list list of slopes
    :return list of slopes perpendicular
    """
    p_slopes = []
    for i in range(len(slope_list)):
        if slope_list[i] == 'vertical':
            p_slopes.append(0)
        elif slope_list[i] == 0:
            p_slopes.append('vertical')
        else:
            p_slopes.append(-1 / slope_list[i])
    return p_slopes

def seg_midpoints(point_list):
    """
    List of midpoints
    :param point_list: list of vertices in triangle
    :return list of midpoints
    """
    points2 = point_list[:]
    points2.append(point_list[0])
    mdpts = []
    for i in range(len(points2)-1):
        mdpts.append(find_midpoint(points2[i], points2[i+1]))
    mdpts = mdpts[1:] + mdpts[:1]
    return mdpts

def two_point_slopes(point_list, second_list):
    """
    Calculate the slopes between two lists of points
    :param point_list: list of vertices in triangle
    :param second_list: list of other points
    """
    seconds = second_list[:]
    seconds.append(second_list[0])
    new_slopes = []
    for i in range(len(point_list)):
        new_slopes.append(find_slope(seconds[i], point_list[i]))
    return new_slopes

def angle_bisector_points(point_list):
    """
    Calculates a point for each of the vertices that would then create
    a line that represents the angle bisector of the angle at that point
    :param point_list: list of vertices in triangle
    :return: the points that would create angle bisectors
    """
    points2 = point_list[:]
    points2.append(point_list[0])
    points2.append(point_list[1])
    angle_points = []
    for i in range(len(point_list)):
        scale = ratio_of_sides(points2[i], points2[i+1], points2[i+2])
        delta_x = points2[i+1][0] - points2[i][0]
        delta_y = points2[i+1][1] - points2[i][1]
        point = (points2[i][0] + scale * delta_x, points2[i][1] + scale * delta_y)
        second_point = find_midpoint(points2[i+2],point)
        angle_points.append(second_point)
    return angle_points


def main():
    # program summary
    print("Program Summary: This program will prompt the user to enter the coordinates of the vertices of a triangle ABC.")
    print("It will then calculate the points of concurrency of the triangle.\n")

    coords = input_coord()
    # check for distinct points
    if len(coords) <= 2:
        print("These are not distinct points. No triangle.")
        exit()
    
    line_slopes = slopes(coords)
    if len(set(line_slopes)) <= 2:
        print("These points are all on the the same line. No triangle.")
        exit()

    perpendicular_slopes = perp_slopes(line_slopes)

    midpoints = seg_midpoints(coords)

    medians = two_point_slopes(coords, midpoints)

    bisectors = angle_bisector_points(coords)

    bisector_slopes = two_point_slopes(coords, bisectors)

    # calculate circumcenter
    circumcenter = solve_system(perpendicular_slopes[0], midpoints[2], perpendicular_slopes[1], midpoints[0])

    # calculate incenter
    incenter = solve_system(bisector_slopes[0], coords[0], bisector_slopes[1], coords[1])

    # calculate orthocenter
    orthocenter = solve_system(perpendicular_slopes[0], coords[2], perpendicular_slopes[1], coords[0])

    # calculate centroid
    centroid = solve_system(medians[0], coords[0], medians[1], coords[1])

    # calculate Euler line
    euler_slope = find_slope(circumcenter, orthocenter)
    euler_intercept = y_intercept(euler_slope, circumcenter)

    # print results
    print("Triangle ABC with \nA = " + str(coords[0]) + "\nB = " + str(coords[1]) + "\nC = " + str(coords[2]) + " has")
    print("-------------------------------")
    print("its circumcenter at:\n" + str(round_tuple(circumcenter, 2)))
    print("its incenter at:\n" + str(round_tuple(incenter, 2)))
    print("its centroid at:\n" + str(round_tuple(centroid, 2)))
    print("its orthocenter at:\n" + str(round_tuple(orthocenter, 2)))
    print("The Euler line is\n y = " + str(round(euler_slope, 2)) + "x + " + str(round(euler_intercept, 2)))

During your visit to our site, NumWorks needs to install "cookies" or use other technologies to collect data about you in order to:

With the exception of Cookies essential to the operation of the site, NumWorks leaves you the choice: you can accept Cookies for audience measurement by clicking on the "Accept and continue" button, or refuse these Cookies by clicking on the "Continue without accepting" button or by continuing your browsing. You can update your choice at any time by clicking on the link "Manage my cookies" at the bottom of the page. For more information, please consult our cookies policy.