import math


def solve_tilted_rectangle(xend, yend, length, width, angle, padding=0.0,
                           pad_upper=True):
    """
    
    Given a rectangle of a certain length, width and orientation,
    knowing the coordinates of the centre of one end of the
    rectangle, return the coordinates of the corners.

    :Parameters:
    
    xend: float
        X coordinate of the centre of the upper edge (at the extremity
        of the length) of the rectangle.
    yend: float
        Y coordinate of the centre of the same edge of the rectangle.
    length: float
        Length of the rectangle
    width: float
        Width of the rectangle
    angle: float
        Angle of the rectangle (radians).
    padding: float (optional)
        An optional padding to be applied to the edges of the
        rectangle, increasing the length and the width by
        2 * padding. This parameter can be used to determine the
        corners of a new rectangle which avoids the edges of the
        original rectangle by at least this amount.
        By default the padding is zero and the corners of the
        original rectangle are returned.
    pad_upper: boolean (optional)
        Set True (the default) to pad the upper edge of the rectangle.
        Setting this to False allows one end of the rectangle to
        have a much smaller padding.

    :Returns:
    
    quad: tuple of ((x1,y1),(x2,y2),(x3,y3),(x4,y4))
        The corner coordinates of the rectangle
   
    """
    assert float(length) > 0.0
    assert float(width) > 0.0
    
    # The coordinates of the other edge of the rectangle can be calculated
    # from the length and orientation.
    xlength = length * math.cos(angle)
    ylength = length * math.sin(angle)
    xother = xend - xlength
    yother = yend - ylength
    
    # The X and Y increments of the corners from these ends depend on
    # the width and orientation
    xwidth2 = width * math.sin(angle) / 2.0
    ywidth2 = width * math.cos(angle) / 2.0
        
    x1 = xother + xwidth2
    y1 = yother - ywidth2
    x2 = xother - xwidth2
    y2 = yother + ywidth2
    x3 = xend - xwidth2
    y3 = yend + ywidth2
    x4 = xend + xwidth2
    y4 = yend - ywidth2
    
    # If required, apply a padding to the corner coordinates.
    if padding > 0.0:
        xlength_pad = padding * math.cos(angle)
        ylength_pad = padding * math.sin(angle)
        xwidth_pad = padding * math.sin(angle)
        ywidth_pad = padding * math.cos(angle)
        
        x1 = x1 - xlength_pad + xwidth_pad
        y1 = y1 - ylength_pad - ywidth_pad
        x2 = x2 - xlength_pad - xwidth_pad
        y2 = y2 - ylength_pad + ywidth_pad
        if pad_upper:
            x3 = x3 + xlength_pad - xwidth_pad
            y3 = y3 + ylength_pad + ywidth_pad
            x4 = x4 + xlength_pad + xwidth_pad
            y4 = y4 + ylength_pad - ywidth_pad
        else:
            # Only pad the width at the upper end of the rectangle
            x3 = x3 - xwidth_pad
            y3 = y3 + ywidth_pad
            x4 = x4 + xwidth_pad
            y4 = y4 - ywidth_pad
     
    quad = [(x1,y1), (x2,y2), (x3,y3), (x4,y4)]
    return quad