Construction Toy : find the x-coordinate of rightmost point of chained triangles using Python

Question:

There is a programming challenge to which I would like to submit a solution using Python as programming language. The challenge is to calculate the maximum distance from a wall of corner points of chained triangles formed from a set of sticks with different lengths ( see here for the full description of the challenge).

enter image description here

Up to now I have managed to calculate the heights in a triangle given the lengths of its sides solving this way the first input sample of the challenge. Now I am stuck on how can I calculate the distance if more segments are added? Added segments will form a chain of triangles stick to each other and I have no idea how approach this and make further progress. So my question is: How can I calculate the maximum distance of the rightmost point of a chain of triangles in case there are more than 3 sticks/segments?

Asked By: Komal batool

||

Answers:

How can I calculate the maximum distance with more than 3 segments?

Calculation of the maximum distance from the ‘wall’ with only 3 segments comes down to calculation of heights of a triangle with given side lengths.

The algorithm for this calculation is easily found on the Internet. In the Python code below available as

heights_triangle(sides)

function which takes the side lengths (a,b,c) and outputs the triangle heights from side x to corner X (i.e. from a to A, b to B, c to C, see conventions in the provided code ).

The maximum distance is then the greatest height i.e. expressen in terms of Python code: max(heights_triangle(sides)).

Adding next two sticks forms another triangle which shares a side with the first one. Calculation of its heights does not help here to calculate the distance the free corner of this triangle is away from the wall. In order to be able to know the x coordinate of the free corner of a triangle it is necessary to be able to calculate its (x,y) coordinates from given coordinates of the two other corners and the side lengths.

In case of the first triangle put at the wall there are on Internet ready to use solutions for finding the x,y coordinates of its free corner, but the next triangle usually doesn’t have any side which is horizontal or vertical, so a rotation is involved and requires additional calculations.

In the code below there are two functions which cope with rotation:

line_angle(Axy, Bxy)
rotate_point(Origin, Point, theta)

with help of these two functions which algorithms you find on Internet I wrote the function:

get_Cxy( Axy, Bxy, abc )

from scratch as I failed to find such one quickly on the Internet.

get_Cxy( Axy, Bxy, abc)

is all you need to calculate the maximum distance with any number of segments. For the first three segments you choose as triangle corner coordinates Axy=(0,0) and Bxy=(0,c). From this coordinates you can calculate then Cxy knowing the side lengths a, b and c. Adding the next two sticks you know this way the position of two of the corner points of the new triangle as it share them with the previous one.

The maximum distance is then the maximum of the x-coordinates of every point Cxy you got along the way using next two sticks to form the next triangle i.e. max( x for x,y in [Cxy1, Cxy2, Cxy3, Cxy4]) or if you use a list LCxy for storing all the C points max(x for x,y in LCxy).

Hope this answers your question. Does it?

"""
Conventions: 

    ah = Ah = height from corner A down to side a
    bh = Bh = height from corner B down to side b
    ch = Ch = height from corner C down to side c

    aa = Aa = angle at corner A opposite to side a
    ba = Ba = angle at corner B opposite to side b
    ca = Ca = angle at corner C opposite to side a

    suffix xy in Axy means (Ax, Ay) x,y coordinates of point A
    
          B xy
          |
          |  
          |     a=BC 
          |      
          |           
     c=AB |         > C xy   
          |        /
          |      /  
          |    /  b=AC
          |  /
          |/
    Ay--  A xy
          !         
        Ax=Bx      Cx

"""

from math import acos, atan2, degrees, radians, sin, cos, sqrt

def is_valid_triangle(sides):
    # given by its side lengths a, b, c
    a,b,c = sides
    return True if a+b>=c and b+c>=a and c+a>=b else False    

def heights_triangle(sides):
    # returns height build upon the triangle side    
    a,b,c = sidelengths
    tA = triangleArea= 0.25 * sqrt((a + b + c) * (-a + b + c) * (a - b + c) * (a + b - c))
    ah = Ah = height_at_A = 2.0 * tA / a    
    bh = Bh = height_at_B = 2.0 * tA / b    
    ch = Ch = height_at_C = 2.0 * tA / c
    return (Ah, Bh, Ch)   
assert heights_triangle((3,4,5))==(4.0, 3.0, 2.4)
assert heights_triangle((1,1,sqrt(2)))== (0.9999999999999999, 0.9999999999999999, 0.7071067811865474)
assert heights_triangle((1,  1,   1)) == (0.8660254037844386, 0.8660254037844386, 0.8660254037844386)

def triangle_angles(sides):
    # returns the angle in degrees opposite to the side    
    a,b,c = sides
    Aa = a_a = triangle_angle_opposite_to_side_a = degrees(acos((b**2+c**2-a**2)/(2.0*b*c)))
    Ba = b_a = triangle_angle_opposite_to_side_b = degrees(acos((a**2+c**2-b**2)/(2.0*a*c)))
    Ca = c_a = triangle_angle_opposite_to_side_c = degrees(acos((a**2+b**2-c**2)/(2.0*a*b)))
    return (Aa, Ba, Ca)
assert triangle_angles((3,4,5) )            == (36.86989764584401, 53.13010235415599, 90.0)
assert triangle_angles((1,0.5,sqrt(0.75)) ) == (90.00000000000001, 29.999999999999993, 59.99999999999999)

def line_angle(Axy, Bxy):
    # https://stackoverflow.com/questions/34372480/rotate-point-about-another-point-in-degrees-python
    """ get angle of the line AB in degrees with point A as origin:""" 
    Ax, Ay = Axy
    Bx, By = Bxy
    return degrees(atan2(By-Ay, Bx-Ax)) # (-180 to 180) with no zero problems
        
def rotate_point(Origin, Point, theta):
    # https://stackoverflow.com/questions/34372480/rotate-point-about-another-point-in-degrees-python
    """ Rotate a point counterclockwise around a given origin.
    The angle should be given in degrees (not radians).
    """
    sin_ = sin(radians(theta))
    cos_ = cos(radians(theta))
    Ox, Oy = Origin
    Px, Py = Point
    RPx = Ox + (Px - Ox) * cos_ - (Py - Oy) * sin_ 
    RPy = Oy + (Px - Ox) * sin_ + (Py - Oy) * cos_
    return (RPx, RPy)

def get_Cxy(Axy,Bxy,abc):
    # https://math.stackexchange.com/questions/543961/determine-third-point-of-triangle-when-two-points-and-all-sides-are-known
    # Return both the possible points and get the another two by 
    # switching the position of Axy,Bxy in the parameter list.
    a,b,c = abc
    Ax,Ay = Axy
    Bx,By = Bxy
    BC = a; AC = b; AB = c
    """Given (Ax,Ay),(Bx,By) of A and B and lengths c=AB, b=AC and a=BC 
    we want to find coordinates (Cx,Cy) i.e. Cxy of C. 
    Let's assume that A is at (0, 0) and B is at (0, c=AB)""" 
    Axy__ = (Ax__, Ay__) = (0, 0)
    Bxy__ = (Bx__, By__) = (0, c) # Cxy_ = (?, ?)
    """ i.e. in the y-direction. 
    B
    |
    | *
    |  *
    |   *
    |    * C -- y
    |  *   |
    A      x
    Let's also assume the point C is in the positive x-direction 
    The solution is then:"""
    Cy__ = (AB**2 + AC**2 - BC**2)/ 2* AB
    Cx__ = sqrt( AC**2 - Cy**2 )
    """ Now it's time to transpose this solution Cxy__ = (Cx__,Cy__) to
    the actual position given by Axy and Bxy
    Let's first move the coordinates of Cxy__ by Axy - Axy__:""" 
    Cx_ = Cx__ + Ax  
    Cy_ = Cy__ + Ay
    """Now it's time to rotate the Cxy_ around Axy_ so that Bxy_ == Bxy
    Therefore it is necessary to know the rotation angle. 
    """
    theta   = line_angle(Axy, Bxy)
    Origin  = Axy
    Point   = Cxy_ = (Cx_, Cy_)
    Cxy = (Cx,Cy) = rotate_point(Origin, Point, theta)
    return Cxy
Answered By: Claudio