from math import degrees, radians, atan, atan2, tan, asin, sin, acos, cos, sqrt, pi
# Use these to draw or suppress various parts of the Dial
Geometry            = True
General_Text        = True 
Motto               = True
EoT_Text            = True
Fecit               = True 
EoT                 = True 
Gnomon              = True
Outer_Time_Markers  = True
Big_Numbers         = True
Little_Numbers      = True
Outer_Time_Markers  = True
Circles             = True
Octagons            = True
Screws              = True

# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Parameter Definition
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
My_Latitude      = +(52. + 5/60.)  # Latitude in degress  +ve North of Equator
My_Longitude     = -(2. + 48./60.) # Longitude in degress +ve East of Greenwich
My_Time_Zone     = -1           # +ve East of Greenwich
My_Noon_Gap      = .5*cm        # Thickness of Gnomon
My_Style_Foot    = 4.425*cm     # Distance from Dial Centre to Foot of Style
My_Radius        = 143.75*mm    # Outer Radius

                                # Sets up the Various Text options for the Hour Numbers
Roman_Text       = ["-","I","II","III","IIII","V","VI","VII","VIII","IX","X","XI","XII","I","II","III","IIII","V","VI","VII","VIII","IX","X","XI","XII"]
Arabic_Text      = ["-","1","2","3","4","5","6","7","8","9","10","11","12","1","2","3","4","5","6","7","8","9","10","11","12"]
Symbol           = "o"
Alignment_Text1  = ["-",Symbol,Symbol,Symbol,Symbol,Symbol,Symbol,Symbol,Symbol,Symbol,Symbol,Symbol,Symbol,Symbol,Symbol,Symbol,Symbol,Symbol,Symbol,Symbol,Symbol,Symbol,Symbol,Symbol,Symbol]
Alignment_Text2  = ["-","|","|","|","|","|","|","|","|","|","|","|","|","|","|","|","|","|","|","|","|","|","|","|","|"]
All_Text         = [Roman_Text, Arabic_Text,Alignment_Text1,Alignment_Text2]
Which_Text       = 0            # 0=Roman, 1=Arabic, 2 = Symbol (see above) , 3=Alignment mark (|). 2 & 3 are used for debugging

My_Font          = "Times-Roman"
My_Font_Size     = 76           # Font Size for Main Hour Numerals
My_x_Stretch     = .5           # Stretches/Compresses the numbers in the horizontal direction
My_y_Stretch     = 1.           # Stretches/Compresses the numbers in the vertical direction
                                # My_Hour_Tweaks allows and hour number to the radially shifted by a value in degrees. 
                                # This allows some optical improvements in some fonts - esp they are 'over'-seriffed
My_Hour_Tweaks   = [0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.]
My_Fineness      = 5            # Number of segments the font curves are split into - higher numbers  > better curves, but try 1.
UpsideDown       = 1            # 1 for inward facing hour numbers, -1 for outward facing
Start_Hour       = 4
End_Hour         = 20

My_Start_Year    = 2012         # Used for EoT calculation: This MUST be a LEAP YEAR
My_Paper         = "A3"
My_Scale         = 1.           # General Scaling Factor
Want_Graph_Paper = False        # Prints an under-lying millimeter graph paper to help positioning
Coloured         = False        # If true, the EoT flame is in colour
My_Line_Width    = .6           # The guy who does the photo-etching suggests that lines should not be less ttan .5 points
My_Cutting       = False        # Set to True, if you want the outine cutting image for water-jet cutting


# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Draws a little cross - used for centre marking and for debugging purposes
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
def Mark(The_x_Centre,The_y_Centre,Mark_Size,Mark_Orient):
    push()
    ms = Mark_Size/2
    translate(The_x_Centre,The_y_Centre)
    #stroke(0.1)
    if (Mark_Orient == 0):
        line(-ms, -ms, ms, ms)
        line(-ms, ms, ms, -ms)
    else:
        line(-ms,0,ms,0)
        line(0,-ms,0,ms)
    pop()
Mark(0,0,20,1)

# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Defines background millimetre graph paper for debugging purposes
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
def Graph_Paper(The_Paper):
    push()
    if The_Paper == "A3":
        Graph_x_size = 14
        Graph_y_size = 20
    else:
        Graph_x_size = 10
        Graph_y_size = 14

    rr=-Graph_x_size *10
    while (rr <= Graph_x_size*10):
        qq = (float(rr)/10)*cm
        if (rr % 10 == 0):
            strokewidth(.3)
            stroke(color(1,0,0,1))
        elif(rr % 5 == 0):
            strokewidth(.2)
            stroke(color(1,0,0,.5))
        else:
            stroke(color(0,1,1,.5))
            strokewidth(.1)
        
        line(qq,-Graph_y_size*cm,qq, Graph_y_size*cm)
        #line(-Graph_x_size*cm,qq, Graph_x_size*cm,qq)
        rr = rr + 1
    
    rr=-Graph_y_size *10
    while (rr <= Graph_y_size*10):
        qq = (float(rr)/10)*cm
        if (rr % 10 == 0):
            strokewidth(.3)
            stroke(color(1,0,0,1))
        elif(rr % 5 == 0):
            strokewidth(.2)
            stroke(color(1,0,0,.5))
        else:
            stroke(color(0,1,1,.5))
            strokewidth(.1)
        
        line(-Graph_x_size*cm,qq, Graph_x_size*cm,qq)
        rr = rr + 1
    
    stroke(0)
    Mark(0,0,8,0)
    pop()
    
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Convert Font Outlines from  a series of Bezier Curves to a series of short line segments
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
def Lineate_Text(The_Text,The_x,The_y,Fineness,The_x_Stretch,The_y_Stretch,Switch,UpsideDown) :
    if Switch == -1 :
        Text_Reverse = -UpsideDown
    else:
        Text_Reverse = UpsideDown
    Original_Text_Path = textpath(The_Text,0,0,) #defined at the origin
    Lineated_Text_Path = [] # Lineated_Text_Path will hold Original_Text_Path transformed to strainght line segments
    autoclosepath(close=False)
    for point in Original_Text_Path :
        if point.cmd == MOVETO :
            Closing_x = point.x
            Closing_y = point.y
            Lineated_Text_Path.append(point)
        elif (point.cmd == LINETO or point.cmd == CURVETO or point.cmd == CLOSE)  :
            # Convert all non-MOVETO points into Bezier Curves. LINETO & CLOSE are beziers with control point on segment ends
            # This is done since there is a routine that will auto-split any beziers into multiple parts
            Not_Closed_Yet = True
            beginpath(Last_x,Last_y)
            if point.cmd == CURVETO :
                curveto(point.ctrl1.x,point.ctrl1.y,point.ctrl2.x,point.ctrl2.y,point.x,point.y)
            elif point.cmd == LINETO :
                curveto(Last_x,Last_y, point.x,point.y, point.x,point.y)
            else: # a CLOSE
                if Last_x == Closing_x and Last_y == Closing_y : # Check if a redundant CLOSE is present
                    Lineated_Text_Path.append(point)
                    Not_Closed_Yet = False
                else :  
                    curveto(Last_x,Last_y, Closing_x, Closing_y, Closing_x, Closing_y)
            This_Segment = endpath(draw=False)
            count = 1
            if Not_Closed_Yet :
                # Chop up the Bezier Curves into straight lines, the number of which is defined by Fineness
                while count <= Fineness :
                    This_Sub_Segment = This_Segment.point(count/float(Fineness))
                    This_Sub_Segment.cmd = LINETO
                    Lineated_Text_Path.append(This_Sub_Segment)
                    count = count + 1
            if point.cmd == CLOSE and Not_Closed_Yet :
                Lineated_Text_Path.append(point)
        Last_x = point.x
        Last_y = point.y
    # Find the lateral & vertical extent of the drawn points on the drawn character
    # excluding the initial & trailing MOVETOs that are used for spacing the next char
    Max_x = -9999999.
    Min_x = 9999999.
    Min_y = 9999999.
    counter = 0
    Last_Drawn_Point = len(Lineated_Text_Path) - 4
    for point in Lineated_Text_Path :
        if point.cmd <> 3 and counter < Last_Drawn_Point :
            if counter < Last_Drawn_Point :
                Max_x = max(Max_x,point.x)
                Min_x = min(Min_x,point.x)
                Min_y = min(Min_y,point.y)
        counter = counter + 1
    UpsideDown_offset = 0
    if UpsideDown == -1 :
        UpsideDown_offset = Min_y
    Text_Width = Max_x - Min_x
    Text_Off = Min_x + Text_Width/2.
    # Centre / Reverse / Upside-down /Stretch the text and move to the input x & y points
    for point in Lineated_Text_Path :
        point.x = Text_Reverse * The_x_Stretch * (point.x - Text_Off)
        point.y = UpsideDown * The_y_Stretch * point.y + The_y + UpsideDown_offset
    return Lineated_Text_Path
    
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Adjust a character point (x,y) with a transformation that 
#   makes vertical character lines point to the dial centre
#   makes horizonatal character lines into circular arcs
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
def Circularize (x,y, The_Radius) :
    if x <> 0 :
            Angle_Offset = x/The_Radius - pi + atan2(x , y)        
            cosAng = cos(Angle_Offset)
            sinAng = sin(Angle_Offset)
            x = x * cosAng - y * sinAng
            y = x * sinAng + y * cosAng
    return [x,y]

# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Adjust a character point (x,y) with a transformation that 
#   makes radial character lines point to the style foot
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
def Slant (x,y, HLA_Deg, The_Radius,Text_Switch,HNG,Style_Foot,Text_Tweak) :
    Point_Angle_Turn_deg = degrees(x / y)
    Total_Point_Turn = -Point_Angle_Turn_deg - Text_Switch * Text_Tweak
    Signer = 1
    if HLA_Deg > 90 : Signer = -1
    tanGamma = tan(radians(HLA_Deg))
    dd = Style_Foot * tanGamma + Text_Switch * HNG
    aaa = 1 + tanGamma**2
    bbb = 2 * dd * tanGamma
    ccc = dd * dd - y**2
    yy = (-bbb + Signer * sqrt(bbb**2 - 4 * aaa * ccc)) / (2 * aaa)
    xx = sqrt(y**2 - yy**2)
    
    beta_rad = radians(Total_Point_Turn)
    alpha_rad = atan2(yy,xx)
    NewSlope = -tan(alpha_rad - beta_rad)

    xxx = -Text_Switch * y / sqrt(1 + NewSlope**2)
    yyy =  Text_Switch * NewSlope * xxx
    return [xxx,  yyy]
        
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# For each Hour character, 
#   first convert bezier curves to multiple straight lines
#   second fit the character to the radius curve
#   slant the charcter so that it "points" to the appropriate side of the style foot
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
def Do_Chars (My_Chars, HLA_Deg,The_Radius,x_Stretch,y_Stretch, Text_Switch, UpsideDown, HNG,Style_Foot,Text_Tweak,My_Fineness) :
    push()
    Line_Text_Path  = Lineate_Text(My_Chars,0,-The_Radius, My_Fineness, x_Stretch,y_Stretch, Text_Switch, UpsideDown)
    Trans_Char_Path = []
    Point_Count = 0
    for point in Line_Text_Path :
        if Text_Switch <> 0 : # i.e not noon
            Circ_xy = Circularize(point.x,point.y,The_Radius)
            x = Circ_xy[0]
            y = Circ_xy[1]
            Slant_xy = Slant(x,y, HLA_Deg, The_Radius,Text_Switch,HNG,Style_Foot,Text_Tweak)
            point.x = Slant_xy[0]
            point.y = Slant_xy[1]
        Trans_Char_Path.append(point)
        Point_Count = Point_Count + 1
    stroke(0)
    strokewidth(.1)
    fill(0)

    drawpath(Trans_Char_Path)
    # Used for debugging - marks each of the short line segment ends
    if False :
        tt = 0
        Which_point = 7
        for point in Trans_Char_Path :
            #print point
            stroke(1,0,0)
            Mark_Type = 0
            Mark_Size = 2
            if tt == Which_point : 
                stroke(0,0,1)
                Mark_Type = 1
                Mark_Size = 10
            Mark(point.x,point.y,Mark_Size,Mark_Type)
            tt = tt + 1
    pop()
    
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Draw the Hour Numbers (or Half Hour Symbols)
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
def Do_the_Hour (The_Hour,The_Latitue_Deg,The_Noon_Gap,Style_Foot,The_Radius,UpsideDown,The_Text,The_Font,The_Font_Size,The_Font_X_Stretch,The_Font_Y_Stretch,The_Text_Angle_Tweak, My_Fineness) :
    font(The_Font)
    fontsize(The_Font_Size)

    HA_Deg = (The_Hour - 12) * 15
    HA_Rad = radians(abs(HA_Deg))
    HLA_Rad = atan(tan(HA_Rad) * sin(radians(abs(The_Latitue_Deg))))                      # HLA is Hour Line Angle being angle CSP
    if (HA_Deg > 90 or HA_Deg < -90): 
        HLA_Rad = HLA_Rad + pi
    HLA_Deg = degrees(HLA_Rad)
    
    if (The_Hour > 6 and The_Hour < 12) or The_Hour > 18 :
        HNG = -The_Noon_Gap/2.
    else :
        HNG = The_Noon_Gap/2.

    if The_Hour < 12 :
        Text_Switch = -1
    elif The_Hour > 12 :
        Text_Switch = 1
    else :
        Text_Switch = 0

    if False :
        if The_Hour <> 12 :
            push()
            translate(HNG, Style_Foot)
            rotate(90 - Text_Switch * HLA_Deg)
            strokewidth(My_Line_Width)
            stroke(0,1,1)
            line(0., 0., 50*cm, 0.)
            pop()    
    Do_Chars(The_Text,HLA_Deg,The_Radius,The_Font_X_Stretch, The_Font_Y_Stretch,Text_Switch, UpsideDown, HNG,Style_Foot, The_Text_Angle_Tweak, My_Fineness)


# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Transform for Long Curved String Definition
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
def Long_Text_Circ(x,y,R1,R2) :
    Base_x = x
    Base_y = R1
    Top_x = Base_x
    Top_y = R2

    Ht = Top_y - Base_y
    theta = atan(Base_x/R1)
    a = R1 * (1 - cos(theta))
    b = Base_x - R1 * sin(theta)
    c = sqrt(a*a + b*b)
    d = Ht - c
    e = d * sin(theta)
    f = d * cos(theta)
    Base_x_trans = Base_x - b
    Base_y_trans = Base_y - a

    Top_x_trans = Base_x + e
    Top_y_trans = Base_y + f

    frac = (y - R1) / Ht
    The_X_trans = Base_x_trans + frac * (Top_x_trans - Base_x_trans)
    The_Y_trans = Base_y_trans + frac * (Top_y_trans - Base_y_trans)

    return [-The_X_trans,-The_Y_trans]
    
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Print Curved String Definition
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
def Do_Curved_String(The_Text,R1,R2,The_Font_X_Stretch, The_Font_Y_Stretch,Text_Switch, UpsideDown, The_Text_Angle_Tweak, My_Fineness):
    push()
    Line_Text_Path  = Lineate_Text(The_Text,0,-R1, My_Fineness, The_Font_X_Stretch, The_Font_Y_Stretch, Text_Switch, UpsideDown)
    Trans_Char_Path = []
    Point_Count = 0
    for point in Line_Text_Path :
        if Text_Switch <> 0 : # i.e not noon
            Circ_xy = Long_Text_Circ(point.x,point.y,R1,R2)
            point.x = Circ_xy[0]
            point.y = Circ_xy[1]
        Trans_Char_Path.append(point)
        Point_Count = Point_Count + 1

    stroke(0)
    strokewidth(.1)
    fill(0)

    drawpath(Trans_Char_Path)
    if False :
        tt = 0
        Which_point = 7
        for point in Trans_Char_Path :
            #print point
            stroke(1,0,0)
            Mark_Type = 0
            Mark_Size = 2
            if tt == Which_point : 
                stroke(0,0,1)
                Mark_Type = 1
                Mark_Size = 10
            Mark(point.x,point.y,Mark_Size,Mark_Type)
            tt = tt + 1
    pop()

# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Print Straight String Definition
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
def Do_Straight_String(The_Text,x,y):
    push()
    Line_Text_Path = Lineate_Text(The_Text,x,y,My_Fineness,1,1,1,1)
    for point in Line_Text_Path :
        point.x = point.x + x
        point.y = point.y + y
    drawpath(Line_Text_Path)
    pop()

# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Tick Mark Definition
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
def Tick(The_Half_Minute,R1,R2,The_Noon_Gap,Style_Foot,The_Latitue_Deg):
    The_Hour = The_Half_Minute/120.
    HA_Deg = (The_Hour - 12.) * 15.
    HA_Rad = radians(abs(HA_Deg))
    HLA_Rad = atan(tan(HA_Rad) * sin(radians(abs(The_Latitue_Deg))))                      # HLA is Hour Line Angle being angle CSP
    if (HA_Deg > 90 or HA_Deg < -90): 
        HLA_Rad = HLA_Rad + pi
    HLA_Deg = degrees(HLA_Rad)
    
    if (The_Hour > 6 and The_Hour < 12) or The_Hour > 18 :
        HNG = -The_Noon_Gap/2.
    else :
        HNG = The_Noon_Gap/2.
        
    if The_Hour < 12 :
        Switch = -1
    elif The_Hour > 12 :
        Switch = 1
    else :
        Switch = 0

    Signer = 1
    if HLA_Deg > 90 : Signer = -1
    tanGamma = tan(radians(HLA_Deg))
    dd = Style_Foot * tanGamma + Switch * HNG
    aaa = 1 + tanGamma**2
    bbb = 2 * dd * tanGamma
    ccc = dd * dd - R1**2
    y1 = (-bbb + Signer * sqrt(bbb**2 - 4 * aaa * ccc)) / (2 * aaa)
    x1 = sqrt(R1**2 - y1**2)
    ccc = dd * dd - R2**2
    y2 = (-bbb + Signer * sqrt(bbb**2 - 4 * aaa * ccc)) / (2 * aaa)
    x2 = sqrt(R2**2 - y2**2)
    if The_Hour <> 12. :    
        line(Switch * x1,-y1,Switch * x2,-y2)
    else:
        line (HNG,-R1,HNG,-R2)
        line (-HNG,-R1,-HNG,-R2)
     
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Twinkle Definition
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
def Twinkle(The_x,The_y,H1,H2) :
    beginpath() 
    moveto(The_x-H1, The_y)
    lineto(The_x+H1, The_y)
    moveto(The_x,    The_y+H1)
    lineto(The_x,    The_y-H1)
    moveto(The_x-H2, The_y-H2)
    lineto(The_x+H2, The_y+H2)
    moveto(The_x-H2, The_y-H2)
    lineto(The_x+H2, The_y+H2)
    moveto(The_x+H2, The_y-H2)
    lineto(The_x-H2, The_y+H2)
    q = endpath(draw=False)
    return q

# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Polygon or Star Definition
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
def Polygon(The_x,The_y,Siz,Sides,Turns) :
    beginpath()
    counter = 0
    while counter < Sides + 1 :
        Ang = radians(Turns * counter*360./Sides)
        if counter == 0 :
            moveto(The_x + Siz*sin(Ang), The_y - Siz*cos(Ang))
        else :
            lineto(The_x + Siz*sin(Ang), The_y - Siz*cos(Ang))
        counter = counter + 1
    q = endpath(draw=False)
    return q

# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Pornbrokers Balls
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
def PawnBrokers_Balls(The_x,The_y, Rad) :
    x1 = 0
    y1 = -Rad
    x2 = Rad *sin(radians(60.))
    y2 = Rad *cos(radians(60.))
    x3 = -x2
    y3 = y2
    path1 = oval(The_x-x1-Rad/2, The_y-y1-Rad/2, Rad, Rad, draw= False)
    path2 = oval(The_x-x2-Rad/2, The_y-y2-Rad/2, Rad, Rad, draw=False)
    path3 = oval(The_x-x3-Rad/2, The_y-y3-Rad/2, Rad, Rad, draw=False)
    compound = path1.union(path2)
    compound = compound.union(path3)
    return compound

# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Draw Twinkles, Polygons or Stars
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
def Do_Shapes (Which,Shape_Size,Shape_Param1,Shape_Param2, HLA_Deg,The_Radius, Text_Switch, HNG,Style_Foot) :
    push()
    if Which == 1 :
        The_Shape_Path = Polygon(0.,0., Shape_Size, Shape_Param1,Shape_Param2)
    elif Which == 2 :
        The_Shape_Path = Twinkle(0.,0., Shape_Size,Shape_Size*.5)
    else :
        The_Shape_Path = PawnBrokers_Balls(0.,0., Shape_Size)

    stroke(0)
    strokewidth(My_Line_Width)
    fill(0)
    if Text_Switch <> 0 : # i.e not noon
        Trans_Shape_Path = []
        for point in The_Shape_Path :
            Trans_xy = Slant(point.x,point.y - The_Radius, HLA_Deg,The_Radius,Text_Switch,HNG,Style_Foot,0)
            point.x = Trans_xy[0]
            point.y = Trans_xy[1]
            Trans_Shape_Path.append(point)
        drawpath(Trans_Shape_Path)
    pop()
 
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# EoT Blob-Mark Definition
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
def Blob (xx,yy,siz,Mon_Kol):
    push()    
    if (siz == 0):
        strokewidth(.5)
        stroke(Mon_Kol)
        fill(1)
        ss = 2.5*mm
    elif(siz == 1):
        fill(Mon_Kol)
        nostroke()
        ss = 1*mm
    elif(siz == 2):
        fill(Mon_Kol)
        nostroke()
        ss = 1.9*mm
    else:
        fill(Mon_Kol)
        nostroke()
        ss = 2.2*mm
    ss = ss * .4
    oval(xx-ss/2, yy-ss/2, ss, ss)
    pop()

# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Dashed Line Definition
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
def Dash_Line(x1,y1,x2,y2,Dashes) :
    x_inc = (x2-x1)/Dashes
    y_inc = (y2-y1)/Dashes
    counter = 0
    while counter < Dashes-1 :
        if counter % 2 == 0 :
            xx = x1 + counter * x_inc
            yy = y1 + counter * y_inc
            line(xx,yy,xx + x_inc,yy + y_inc)
        counter = counter + 1

# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Gnomon Definition
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
def Draw_Gnomon(My_x,My_y,Latitude,My_Strokewidth):
    Base_Latitude = 52. + 5/60.
    beginpath(0,0)
    lineto(5600,0)
    lineto(5600,1700)
    lineto(32500,1700)
    lineto(32500,0)
    lineto(38100,0)
    lineto(36200,-3000)
    lineto(35300,-3000)
    curveto(33300,-3000,33000,-3200,34100,-4100)
    curveto(35200,-5000,40200,-7400,37900,-19400)
    curveto(37700,-20600,39900,-20200,39100,-21800)
    curveto(38400,-23200,37800,-21300,37100,-21300)
    curveto(36200,-21300,32300,-23500,32300,-29500)
    curveto(32300,-30100,32200,-33400,33800,-33400)
    curveto(34800,-33400,34700,-31500,36200,-31500)
    curveto(37200,-31500,38400,-33000,38400,-34200)
    curveto(38400,-34600,37900,-35700,37900,-35900)
    curveto(37800,-36500,41200,-39700,40900,-41700)
    curveto(40500,-44200,39300,-44100,38900,-44700)
    curveto(38700,-44900,39200,-46000,39900,-46900)
    lineto(41418.3,-48800)
    lineto(41418.3,-53172.2)
    lineto(0,0)
    pp = endpath(draw=False)
         
    beginpath(6944.8925,-4535.44)
    lineto(15533.882,-15590.575)
    curveto(17574.83,-18283.4925,18141.76,-18283.4925,18425.225,-18283.4925)
    curveto(19275.62,-18283.4925,19275.62,-15165.3775,21259.875,-13181.1225)
    curveto(22677.2,-11338.6,26362.245,-11196.8675,26362.245,-10913.4025)
    curveto(26645.71,-10629.9375,26645.71,-10488.205,26645.71,-9921.275)
    curveto(26645.71,-9411.038,26787.4425,-8787.415,24661.455,-8588.9895)
    curveto(22110.27,-8333.871,20126.015,-6236.23,20126.015,-4393.7075)
    curveto(20126.015,-3826.7775,20409.48,-3826.7775,20409.48,-3259.8475)
    curveto(20409.48,-2976.3825,20126.015,-2919.6895,19842.55,-2919.6895)
    lineto(7086.625,-2919.6895)
    curveto(5952.765,-2919.6895,6236.23,-3401.58,6944.8925,-4535.44)
    qq = endpath(draw=False)

    beginpath(27779.57,-2919.6895)
    lineto(22960.665,-2919.6895)
    curveto(22677.2,-2919.6895,22535.4675,-3401.58,22535.4675,-3685.045)
    curveto(22535.4675,-5385.835,21259.875,-4535.44,21259.875,-5102.37)
    curveto(21259.875,-7086.625,23244.13,-8220.485,24661.455,-8220.485)
    curveto(26929.175,-8220.485,28488.2325,-5669.3,28488.2325,-3826.7775)
    curveto(28488.2325,-3401.58,28063.035,-2919.6895,27779.57,-2919.6895)
    rr = endpath(draw=False)

    beginpath(20352.787,-17574.83)
    curveto(20352.787,-24661.455,35489.818,-24236.2575,35489.818,-14314.9825)
    curveto(35489.818,-12755.925,35291.3925,-11338.6,34440.9975,-9921.275)
    curveto(34015.8,-9070.88,33448.87,-9637.81,33307.1375,-9921.275)
    curveto(33307.1375,-9921.275,31748.08,-12188.995,30330.755,-12188.995)
    curveto(28913.43,-12188.995,30614.22,-15675.6145,27921.3025,-15675.6145)
    curveto(26560.6705,-15675.6145,26277.2055,-14740.18,26277.2055,-14173.25)
    curveto(26277.2055,-13889.785,26617.3635,-13379.548,26617.3635,-13096.083)
    curveto(26617.3635,-11678.758,20352.787,-12188.995,20352.787,-17574.83)
    ss = endpath(draw=False)

    beginpath(22166.963,-24094.525)
    lineto(27694.5305,-31181.15)
    curveto(28148.0745,-31748.08,28573.272,-32468.0811,29083.509,-32468.0811)
    curveto(29480.36,-32468.0811,30047.29,-31181.15,30047.29,-28346.5)
    curveto(30047.29,-24094.525,30982.7245,-24377.99,30982.7245,-23385.8625)
    curveto(30982.7245,-22960.665,30670.913,-22733.893,30387.448,-22733.893)
    curveto(29196.895,-22733.893,29196.895,-23300.823,26929.175,-23300.823)
    curveto(24944.92,-23300.823,23244.13,-22733.893,22393.735,-22733.893)
    curveto(21543.34,-22733.893,21996.884,-23811.06,22166.963,-24094.525)
    tt = endpath(draw=False)

    beginpath(33222.0979999999,-38267.775)
    lineto(35858.3225,-41669.355)
    curveto(36170.134,-42037.8595,36652.0245,-42463.057,36850.45,-42463.057)
    curveto(37133.915,-42463.057,37275.6475,-41726.048,38126.0425,-41726.048)
    curveto(38551.24,-41726.048,38267.775,-41726.048,39685.1,-42066.206)
    curveto(40535.495,-42066.206,39968.565,-40252.03,39685.1,-39543.3675)
    curveto(39118.17,-38409.5075,37417.38,-36566.985,34015.8,-36992.1825)
    curveto(32881.94,-37133.915,32768.554,-37700.845,33222.0979999999,-38267.775)
    uu = endpath(draw=False)

    compound = pp.difference(qq)
    compound = compound.difference(rr)
    compound = compound.difference(ss)
    compound = compound.difference(tt)
    compound = compound.difference(uu)

    push()
    translate(My_x,My_y)
    stroke(0)
    scale(.01,.01*tan(radians(abs(Latitude)))/tan(radians(abs(Base_Latitude))))
    strokewidth(My_Strokewidth/.01)
    if My_Cutting:
        fill(.9)
    else:
        nofill()
    drawpath(compound)
    pop()
    
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Calculate the EoT for a given day : This routine gives EoT accurate to +/- 1.5 second over th enext 50 years
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
def EoT_Calc (Days_2000) :
    # Input  : Days from Epoch 2000 (0:00 hrs on 31st Dec 1999)
    # Output : EOT in MINUTES
    
    # NOTA BENE
    # to get a more generally useful subroutine...
    # change the input parameters of this sub-routiner fromn Days_2000 to YYYY,DDD
    # and remove the comment characters in the two following code lines
    #
    #Days_2000 = int((YYYY - 2000) * 365.25) + DDD - Time_Zone/24
    #if YYYY % 4 <> 0 : Days_2000 = Days_2000 + 1
    
    Ang_Anom   = Days_2000 / 58.1329    
    Ang_Trop   = Days_2000 / 58.1301
    Av         = -0.006    
    Ecc_1      =  7.653    * sin(1 * Ang_Anom + 6.214)
    Ecc_2      =  0.081    * sin(2 * Ang_Anom + 6.154)
    Obl_1      =  0.329    * sin(1 * Ang_Trop + 3.532)
    Obl_2      =  9.848    * sin(2 * Ang_Trop + 0.314)
    Obl_3      =  0.316    * sin(3 * Ang_Trop + 0.217)
    Obl_4      =  0.219    * sin(4 * Ang_Trop + 0.609)
    
    return Av + Ecc_1 + Ecc_2 + Obl_1 + Obl_2 + Obl_3 + Obl_4

# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Gets the values of EoT and the coodinates requited for thre Flame Plot
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
def Get_Flame_Coords(The_Start_Year, The_Longitude, The_Time_Zone) :
    global EoT_Array, Flame_Array # these are the output from this subroutine
    EoT_Array = []
    Flame_Array = [0]
    The_Start_Day = 1.5 #(noon on 1st Jan)
    The_Day = int((The_Start_Year - 2000) * 365.25) + The_Start_Day - The_Time_Zone/24. # UTC at noon 1st Jan LOCAL Mean time
    Long_Adjust = (- The_Longitude + The_Time_Zone * 15. ) * 4.
    counter = 0
    Switch = 1.
    # This builds an EoT array covering a 366 day year (i.e. including 29th Feb)
    # in which each all non-leap days are the average EOT over a 4 year leap cycle
    # while 29 Feb stands alone
    # The output Flame curve thus has a tiny kink on 29th feb
    while counter < 366 :
        if counter == 59 : # 29th Feb
            EoT_Array.append(EoT_Calc(The_Day) + Long_Adjust)
            Switch = 1.
        else :
            Year_plus_1 = The_Day + 365. + Switch
            Year_plus_2 = Year_plus_1 + 365.
            Year_plus_3 = Year_plus_2 + 365.
            Av_EoT = (EoT_Calc(The_Day) + EoT_Calc(Year_plus_1) + EoT_Calc(Year_plus_2) + EoT_Calc(Year_plus_3))/4.
            EoT_Array.append(Av_EoT + Long_Adjust) 
        The_Day = The_Day + 1.
        counter += 1

    counter = 1
    Change_Array = [0]
    while counter < 366 :
        Change_Array.append(EoT_Array[counter] - EoT_Array[counter-1])
        counter += 1
    Max_Change = max(Change_Array)

    Fold_Day1 = 121 # 1st May    
    Fold_Day2 = 213 # 1st Aug
    Fold_Day3 = 274 # 1st Oct
    Fold_Day4 = 357 # 23rd Dec
    Tweak_Start_Day = 274 # 1st Oct
    Tweak_Factor = 1.0335

    counter = 1
    Direction_Changer = 1
    Intrinsic_Mod = 1
    while counter < 366 :
        if counter == Fold_Day1 or  counter == Fold_Day2 or counter == Fold_Day3 or counter == Fold_Day4 : Direction_Changer = - Direction_Changer
        if counter == Tweak_Start_Day : Intrinsic_Mod = Tweak_Factor 
        Flame_Array.append(Flame_Array[counter-1] +  Intrinsic_Mod * Direction_Changer * sqrt(Max_Change**2 - Change_Array[counter]**2) )
        counter += 1

# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Routine for Drawing the EoT Flame
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
def DrawFlame(xx,yy, squeezer, Chart_Width, Chart_Height, Coloured):
    global EoT_Array,Flame_Array # these calvulated in the Get_Flame_Coords subroiutine
    push()
    strokewidth(My_Line_Width)
    nofill()

    translate (xx,yy)
    # ===============
    # SCALE THE CHART
    # ===============
    up_scale = int(max(EoT_Array)) + 2
    down_scale  = int(min(EoT_Array)) -2
    
    Margin = .05 * max(Flame_Array)
    Max_Ys = Margin + max(Flame_Array) 
    Min_Ys = -Margin - min(Flame_Array) 
    Y_Range = Max_Ys - Min_Ys

    def EoT_to_Chart(EOT_val): return Chart_Width * (EOT_val - down_scale)/(up_scale - down_scale)
    def Ys_to_Chart(Y_val):    return  - 5 -Chart_Height * (Y_val- Min_Ys)/(Y_Range)
 
    # ==============
    # VERTICAL LINES
    # ==============
    counter = down_scale + 1 
    while counter <= up_scale - 1 :
        aa = EoT_to_Chart(float(counter))
        if (counter % 5 <> 0):
            if Coloured:
                 stroke(0,0,1)
            else:
                stroke(color(0))
            Dash_Line(aa, 0,aa,- Chart_Height,150)
        else:
            if Coloured:
                 stroke(1,0,0)
            else:
                 stroke(color(0))
            line(aa, 1*mm,aa,- Chart_Height-1*mm)
        counter = counter + 1

    # ===================================
    # LEFT, RIGHT, TOP AND BOTTOM MARGINS
    # ===================================
    if Coloured:
         stroke(1,0,0)
    else:
         stroke(color(0))
    aa = EoT_to_Chart(float(down_scale))
    line(aa, 0,aa,- Chart_Height)
    bb = EoT_to_Chart(float(up_scale) )
    line(bb, 0,bb,- Chart_Height)
    line(aa, - Chart_Height,bb,- Chart_Height)
    line(aa, 0,bb,0)

    # ====================
    # WHITE FILL FOR FLAME
    # ====================
    push()
    fill(1,1,1)
    nostroke()
    counter = -1
    while counter < 365:
        counter = counter + 1
        aa = EoT_to_Chart(EoT_Array[counter])
        bb = Ys_to_Chart (Flame_Array  [counter])
        nudge_size = 1.*mm
        ynudge = nudge_size
        if counter > 41 : ynudge = -nudge_size
        if counter > 132 : ynudge = nudge_size
        if counter > 205 : ynudge = -nudge_size
        if counter > 306 : ynudge = nudge_size
        xnudge = -nudge_size
        if counter < 120 or (counter > 208 and counter < 274) : xnudge = nudge_size
        if counter > 191 and counter < 212 :
            xnudge = -nudge_size * .7
            ynudge = nudge_size/2.
        if counter >= 212 and counter < 224 :
            xnudge = nudge_size * .8
            ynudge = nudge_size * .2
        if(counter == 0):
            beginpath(aa+xnudge,bb+ynudge)
        else:
            if counter < 200 or counter > 216 :
                lineto(aa+xnudge,bb+ynudge)
    whiteout = endpath(draw=False)
    push()
    stroke(0)
    nostroke()
    drawpath(whiteout)
    pop()
    #191 = 1st July
    #212 = bottom of spur
    #222 = 10th Aug
    #counter = 212
    #aa = EoT_to_Chart(EoT_Array[counter])
    #bb = Ys_to_Chart (Flame_Array  [counter])
        #push()
        #stroke(0)
        #Mark (aa,bb,13,0)
        #nostroke()
        #pop()
    pop()

    # ==============
    # MINUTE NUMBERS
    # ==============
    font(My_Font)
    fontsize(10)
    counter = 1
    #top_num_offset = [Minus_20_Nudge +EoT_Num_Y_Nudge, Minus_15_Nudge +EoT_Num_Y_Nudge, Minus_10_Nudge +EoT_Num_Y_Nudge, Minus_Five, Minus_Five, Minus_Five, Minus_Five, Minus_Five]

    counter = down_scale + 1 
    while counter <= up_scale - 1 :
        if counter % 5 == 0:
            textwid = 1.*textwidth (counter)
            textht  = textheight(counter) 
            xx = EoT_to_Chart(float(counter))
            fill(0)
            text(counter,xx - textwid/2,-Chart_Height - 2*mm)
            text(counter,xx - textwid/2, 4*mm)

        counter = counter + 1

    # ============
    # MONTH  NAMES
    # ============
    month_starts = [0,31,60,91,121,152,182,213,244,274,305,335,366]
    siz = [0,1,1,1,2,1,1,1,1,3,1,1,1,1,2,1,1,1,1,3,1,1,1,1,2,1,1,1,1,3,1]
    Aligner = [-1,-1,-1,-1,1,1,1,-1,1,1,1,1]
    Text_X_Offset = [ 1.5,
                     -6.0,
                     -10,
                     -9.5,
                     
                     -0.5,
                     +3.0,
                     +3.0,
                     -9.0,
                     
                     -9.4,
                     -3.0,
                     +1.5,
                     +4.2]
    Text_Y_Offset = [-4.0,
                     -4.0,
                     -1.5,
                     -.6,
                     
                     14.0,
                     +5.0,
                     +4.5,
                     -3.0,
                     
                     -0.7,
                     +7.0,
                     +6.0,
                     +1.0]
    Month_Names = ["Jan","Feb","Mar","Apr","My","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]

    font(My_Font)
    fontsize(12)
    counter = 0
    while counter < 12:
        This_Month = Month_Names[counter]
        if Coloured :
            if counter % 4 == 0 :
                Mon_Kol = color(1,0,0)
            elif counter % 4 == 1 :
                Mon_Kol = color(0,0,1)    
            elif counter % 4 == 2 :
                Mon_Kol = color(.9,0,.8)
            else:
                Mon_Kol = color(0,.6,0)
        else :
            Mon_Kol = color(0,0,0)
        Vert_Align = Text_Y_Offset[counter] * mm
        Hor_Align = Text_X_Offset[counter] * mm
        indexer = month_starts[counter]
        aa = EoT_to_Chart(EoT_Array[indexer])
        bb = Ys_to_Chart (Flame_Array  [indexer])
        push()
        fill(Mon_Kol)
        #fill(1,0,0)
        text(This_Month, aa + Hor_Align,bb + Vert_Align)
        pop()
        counter = counter + 1    
    
    # ==================
    # LITTLE BENT ARROWS
    # ==================
    L1 = 3*mm
    L2= 2*mm
    HW = .5*mm
    HS = .5*mm
    HL = 1.5*mm
    counter = 0
    while counter < 12 :
        len = 3*mm
        len2 = 2*mm
        the_index = month_starts[counter]
        x1 = EoT_to_Chart(EoT_Array[the_index])
        y1 = Ys_to_Chart(Flame_Array[the_index])
        x2 = EoT_to_Chart(EoT_Array[the_index+1])
        y2 = Ys_to_Chart(Flame_Array[the_index+1])
        turn = degrees(atan2((y2-y1),(x2-x1)))
        push()
        strokewidth(My_Line_Width)
        if Coloured :
            if counter % 4 == 0:
                Mon_Kol = color(1,0,0)
            elif counter % 4 == 1:
                Mon_Kol = color(0,0,1)
            elif counter % 4 == 2:
                Mon_Kol = color(.9,0,.8)
            else:
                Mon_Kol = color(0,.6,0)
        else:
            Mon_Kol = color(0,0,0)
        stroke(Mon_Kol)
        fill(Mon_Kol)
        translate(x1,y1)
        if counter <> 4:
            push()
            rotate(-turn)
            beginpath(0,0)
            lineto(0,-L1)
            lineto(L2,-L1)
            lineto(L2-HS,-L1-HW)
            lineto(L2+HS,-L1)
            lineto(L2-HS,-L1+HW)
            lineto(L2,-L1)
            lineto(0,-L1)
            lineto(0,0)
            endpath(draw=True)
            pop()
        else :
            rotate(-85)
            LL2 = 5*mm
            beginpath(0,0)
            lineto(LL2,0)
            lineto(LL2-HS,-HW)
            lineto(LL2+HS,0)
            lineto(LL2-HS,HW)
            lineto(LL2,0)
            lineto(0,0)
            endpath(draw=True)

        pop()
        counter = counter + 1
        
    # ===========================
    # MONTHLY LINES & DAILY BLOBS
    # ===========================
    counter = 0
    month_count = 0
    while month_count < 12 :
        the_index = month_starts[month_count]
        last_index = month_starts[month_count+1]
        day = 0 
        while the_index < last_index:
            kol = month_count % 4
            if (kol == 0):
                Mon_Kol = color(1,0,0)
            elif(kol == 1):
                Mon_Kol = color(0,0,1)    
            elif(kol == 2):
                Mon_Kol = color(.9,0,.8)
            else:
                Mon_Kol = color(0,.6,0)
            blob_size = siz[day]
        
            aa1 = EoT_to_Chart(EoT_Array[counter])
            bb1 = Ys_to_Chart (Flame_Array  [counter])
            if counter < last_index - 1:
                aa2 = EoT_to_Chart(EoT_Array[counter+1])
                bb2 = Ys_to_Chart (Flame_Array  [counter+1])
                stroke(Mon_Kol)
                stroke(0)
            #
            if Coloured :
                Blob(aa1, bb1, blob_size,Mon_Kol)        
            else:
                Blob(aa1, bb1, blob_size,color(0))        
            day = day + 1
            counter = counter + 1
            the_index = the_index + 1
        month_count = month_count + 1
    pop()

# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Set up Paper Size
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
if My_Paper == "A3" :
    size (29.7*cm, 42*cm) # A3 Paper Size
else :
    size (21.0*cm, 29.7*cm) # A4 Paper Size

translate (WIDTH/2,HEIGHT/2)
transform (CORNER)
if Want_Graph_Paper : Graph_Paper(My_Paper) 
push()
translate (0,-6*cm)
My_North_South   = 1
if My_Latitude < 0 :
    My_North_South   = -1

scale (My_Scale)
R1 = My_Radius
R2 = My_Radius -  1.75*mm
R3 = My_Radius -  3.75*mm
R4 = My_Radius -  8.00*mm
R5 = My_Radius - 28.25*mm
R6 = My_Radius - 30.25*mm
R7 = My_Radius - 32.25*mm
R8 = My_Radius - 40.00*mm
R9 = My_Radius - 65.60*mm
R9 = My_Radius - 60*mm

nofill()
strokewidth(My_Line_Width)
stroke(0)

# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Draw External Octagons
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
if Octagons :
    push()
    rotate (22.5)
    if not My_Cutting :
        nofill()
        drawpath(Polygon(0.,0.,R1+1.3*cm,8,1))
        drawpath(Polygon(0.,0.,R1+1.4*cm,8,1))
    else :
        fill (.9)
        drawpath(Polygon(0.,0.,R1+1.4*cm,8,1))
    pop()

# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Draw All the Circles
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
if Circles and not My_Cutting :
    oval (-R1,-R1,2*R1,2*R1)
    oval (-R2,-R2,2*R2,2*R2)
    oval (-R3,-R3,2*R3,2*R3)
    oval (-R4,-R4,2*R4,2*R4)
    oval (-R5,-R5,2*R5,2*R5)
    oval (-R6,-R6,2*R6,2*R6)
    oval (-R7,-R7,2*R7,2*R7)
    oval (-R8,-R8,2*R8,2*R8)
    oval (-R9,-R9,2*R9,2*R9)
    # Temporary Number Alignment Rings
    #stroke(1,0,0,.5)
    #R4a = R4 - 1*mm
    #R5a = R5 + 1*mm
    #oval (-R4a,-R4a,2*R4a,2*R4a)
    #oval (-R5a,-R5a,2*R5a,2*R5a)

# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Draw Outer Set of Minute Markers
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
if Outer_Time_Markers and not My_Cutting :
    stroke(0)
    strokewidth(My_Line_Width)
    Start_Minute = Start_Hour * 60
    End_Minute = End_Hour * 60
    The_Minute = Start_Minute
    while The_Minute <= End_Minute :
        if The_Minute % 60 == 0 :
            R_out = R1
            R_in = R3
            Tick(2.*The_Minute, R_in,R_out, My_Noon_Gap, My_Style_Foot, My_Latitude)
        elif The_Minute % 10 == 0 :
            R_out = R1
            R_in = R4
            Tick(2.*The_Minute, R_in,R_out, My_Noon_Gap, My_Style_Foot, My_Latitude)
        elif The_Minute % 5 == 0 :
            R_out = R2
            R_in = R3
            Tick(2.*The_Minute, R_in,R_out, My_Noon_Gap, My_Style_Foot, My_Latitude)
        elif The_Minute % 2 == 0 :
            R_out = R1
            R_in = R2
            Tick(2.*The_Minute, R_in,R_out, My_Noon_Gap, My_Style_Foot, My_Latitude)
        The_Minute = The_Minute + 1

# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Draw the little 10-min Numbers
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
if Little_Numbers and not My_Cutting :
    My_Chars = ["-","1","2","3","4","5"]
    The_Hour = Start_Hour
    The_10_Mins = Start_Hour * 6
    My_xx_Stretch = 1.
    Digit_Gap = .5 #degrees
    Big_Digit_Offset = 1.2*mm
    Little_Digit_Offset= 1.45*mm
    Little_Font_Size = 7
    while The_10_Mins <= End_Hour * 6 :
        if The_10_Mins % 72 == 0 :
            push()
            translate(My_Noon_Gap/2.,0)
            Do_the_Hour(The_10_Mins/6., My_Latitude, My_Noon_Gap, My_Style_Foot, R4 + Big_Digit_Offset   , UpsideDown, "0", My_Font, Little_Font_Size, My_xx_Stretch, My_y_Stretch, 0., My_Fineness)
            translate(-My_Noon_Gap,0)
            Do_the_Hour(The_10_Mins/6., My_Latitude, My_Noon_Gap, My_Style_Foot, R4 + Big_Digit_Offset   , UpsideDown, "0", My_Font, Little_Font_Size, My_xx_Stretch, My_y_Stretch, 0., My_Fineness)
            translate(My_Noon_Gap/2.,0)
            pop()
        elif The_10_Mins % 6 == 0 :
            Do_the_Hour(The_10_Mins/6., My_Latitude, My_Noon_Gap, My_Style_Foot, R4 + Big_Digit_Offset   , UpsideDown, "0", My_Font, Little_Font_Size, My_xx_Stretch, My_y_Stretch, 0., My_Fineness)
        else:
            This_Digit = The_10_Mins % 6
            if My_North_South == 1 :
                The_Char = My_Chars[This_Digit]
            else:
                The_Char = My_Chars[6 - This_Digit]

            Do_the_Hour(The_10_Mins/6., My_Latitude, My_Noon_Gap, My_Style_Foot, R4 + Big_Digit_Offset   , UpsideDown, The_Char, My_Font, Little_Font_Size, My_xx_Stretch, My_y_Stretch, Digit_Gap, My_Fineness)
            Do_the_Hour(The_10_Mins/6., My_Latitude, My_Noon_Gap, My_Style_Foot, R4 + Little_Digit_Offset, UpsideDown, "o", My_Font, Little_Font_Size, My_xx_Stretch, My_y_Stretch, -Digit_Gap, My_Fineness)
        The_10_Mins = The_10_Mins + 1

# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Draw Main Hour Number and Half Hour Symbols
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
if Big_Numbers and not My_Cutting :
    The_Text = All_Text[Which_Text]
    The_Hour = Start_Hour
    while (The_Hour <= End_Hour):
        if My_North_South == 1 :
            The_Chars = The_Text[The_Hour]
        else:
           The_Chars = The_Text[24 - The_Hour]
        
        Do_the_Hour(The_Hour, My_Latitude, My_Noon_Gap, My_Style_Foot, R5+1.2*mm, UpsideDown, The_Chars, My_Font, My_Font_Size, My_x_Stretch, My_y_Stretch, My_Hour_Tweaks[The_Hour], My_Fineness)
        The_Hour = The_Hour + 1

# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Draw Inner Set of Time Markers (7.5 min, 15 min, 30 min & hour ticks) & Markers (Twinkles & Pawnbrokers)
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
if Outer_Time_Markers and not My_Cutting  :
    Start_Half_Minute = Start_Hour * 120
    End_Half_Minute = End_Hour * 120
    The_Half_Minute = Start_Half_Minute
    stroke(0)
    strokewidth(My_Line_Width)
    R_out = R5
    while The_Half_Minute <= End_Half_Minute :
        if The_Half_Minute % 15 == 0 :
            R_in = R6
            if The_Half_Minute % 30 == 0 :
                R_in = R7
            if The_Half_Minute % 60 == 0 :
                R_in = (R8 + R9)/2.
            if The_Half_Minute % 120 == 0 :
                R_in = R9
            Tick(The_Half_Minute, R_in,R_out, My_Noon_Gap, My_Style_Foot, My_Latitude)

        if The_Half_Minute % 60 == 0 and The_Half_Minute % 120 <> 0 :
            The_Hour = The_Half_Minute/120.
            HA_Deg = (The_Hour - 12.) * 15.
            HA_Rad = radians(abs(HA_Deg))
            HLA_Rad = atan(tan(HA_Rad) * sin(radians(abs(My_Latitude))))                      # HLA is Hour Line Angle being angle CSP
            if (HA_Deg > 90 or HA_Deg < -90): 
                HLA_Rad = HLA_Rad + pi
            HLA_Deg = degrees(HLA_Rad)
    
            if (The_Hour > 6 and The_Hour < 12) or The_Hour > 18 :
                HNG = -My_Noon_Gap/2.
            else :
                HNG = My_Noon_Gap/2.
        
            if The_Hour < 12 :
                Switch = -1
            elif The_Hour > 12 :
                Switch = 1
            else :
                Switch = 0
            Do_Shapes (2, 5*mm ,30,1,HLA_Deg, (R4+R5)/2 ,Switch, HNG,My_Style_Foot)
            Do_Shapes (0, 2*mm ,30,1,HLA_Deg, R_in      ,Switch, HNG,My_Style_Foot)
        The_Half_Minute = The_Half_Minute + 1   

# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Draw in Straight Geometry lines
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
if Geometry  and not My_Cutting :
    stroke (0)
    Mark(0., 0.,8,0)
    line(My_Noon_Gap/2, My_Style_Foot,My_Noon_Gap/2,-R9)
    line(-My_Noon_Gap/2, My_Style_Foot,-My_Noon_Gap/2,-R9)
    line(-My_Noon_Gap/2, My_Style_Foot,My_Noon_Gap/2, My_Style_Foot)

# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Draw General Text
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
if General_Text  and not My_Cutting : 
    font(My_Font)
    fontsize(14)
    push()
    Do_Curved_String("To convert Sundial Time to Mean Time,",R6-2.7*cm,R5+1*cm,1,1,-1,-1,0,My_Fineness)
    Do_Curved_String("apply the Date Correction from the Graph.",R6-2.2*cm,R5+1*cm,1,1,-1,-1,0,My_Fineness)
    Do_Curved_String("Add 1 hour during BST.",R6-1.7*cm,R5+1*cm,1,1,-1,-1,0,My_Fineness)
    Do_Curved_String("The Old Rectory, Credenhill",R4-1.9*cm,R5+1*cm,1,1,-1,-1,0,My_Fineness)
    Do_Curved_String("Latitude 52 deg 05 min North : Longitude 2 deg 48 min West",R4-1.2*cm,R5+1*cm,1,1,-1,-1,0,My_Fineness)
    Do_Curved_String("ALK + BFG > PJK + GK > AELK & VEIK : EWK + CWN & EHK + ELB",R4-.5*cm,R5+1*cm,1,1,-1,-1,0,My_Fineness)
    pop()

# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Draw Motto
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
if Motto  and not My_Cutting :
    Line1 = "Horas non"
    Line2 = "numero nisi"
    Line3 = "serenas"
    push()
    font(My_Font)
    fill(0)
    nostroke()
    fontsize(40)
    translate(0,13*mm)
    Do_Straight_String(Line1,-4.2*cm,-1.3*cm)
    Do_Straight_String(Line2,-4.2*cm,-.5*cm)
    Do_Straight_String(Line3,-4.2*cm,.3*cm)
    pop()

# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Draw Fecit & Date Text
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
if Fecit and not My_Cutting :
    Line9 = "KWK fecit"
    Line10 = "August 2012"
    font(My_Font)
    fill(0)
    nostroke()
    fontsize(10)
    Do_Straight_String(Line9,-4.3*cm,7.15*cm)
    Do_Straight_String(Line10,4.3*cm,7.15*cm)

# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Draw EoT Explanatory Text
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
if EoT_Text and not My_Cutting :
    Line4 = "Longitude and"
    Line5 = "Equation-of-Time"
    Line6 = "Correction"
    Line7 = "in minutes"
    push()
    font(My_Font)
    fill(0)
    nostroke()
    fontsize(13)
    translate(3.5*cm,-6.3*cm)
    Do_Straight_String(Line4,0,-0)
    Do_Straight_String(Line5,0,.2*cm)
    Do_Straight_String(Line6,0,.4*cm)
    Do_Straight_String(Line7,0,.6*cm)
    pop()

# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Draws the EoT Flame
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
if EoT and not My_Cutting :
    Get_Flame_Coords (My_Start_Year, My_Longitude, My_Time_Zone)
    EoT_x = My_Noon_Gap/2. + 3*mm
    EoT_Ht = 8.85*cm
    EoT_Wid = 6.4*cm
    EoT_y = EoT_Ht/2
    DrawFlame(EoT_x, EoT_y,True,EoT_Wid, EoT_Ht, Coloured)

# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Draws the Screw Holes
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
if Screws and not My_Cutting :
    counter = 0
    Outer_Screw = 4*mm
    Inner_Screw = 1*mm
    push()
    rotate(22.5)
    while counter < 8 :
        stroke(0)
        strokewidth(My_Line_Width)
        push()
        translate (15*cm,0)
        nofill()
        oval(-Outer_Screw,-Outer_Screw, 2*Outer_Screw, 2*Outer_Screw)
        fill(0)
        oval(-Inner_Screw,-Inner_Screw, 2* Inner_Screw, 2* Inner_Screw)
        Mark(0.,0.,18,1)
        pop()
        rotate (45)
        counter = counter + 1
    pop()
pop()
   
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
# Draws the Gnomon
# •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
if Gnomon :
    Draw_Gnomon(-5*mm,20.*cm, My_Latitude,1.)

