from math import degrees, radians, atan, atan2, tan, asin, sin, acos, cos, sqrt, pi import sys # Use these to draw or suppress various parts of the Dial Most = True Geometry = True General_Text = Most Motto = True EoT_Text = True Fecit = Most EoT = True Gnomon = False Gnomon_Supporters = False Big_Numbers = Most Little_Numbers = Most Inner_Time_Markers = Most Outer_Time_Markers = Most Circles = True Octagons = Most Screws = Most My_Cutting = False # Set to True, if you want the outine cutting image for water-jet cutting #def Mark(The_x_Centre,The_y_Centre,Mark_Size,Mark_Orient): #def Graph_Paper(The_Paper): #def Lineate_Text(The_Text_Path,The_x,The_y,Fineness,Switch,UpsideDown) : #def Slant_Shape (x,y, HLA_Deg, The_Radius,Text_Switch,HNG,Style_Foot,Text_Tweak) : #def Long_Text_Circ(x,y,R1,R2) : #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): #def Do_Straight_String(The_Text,x,y): #def Slant_Text(The_Radi,The_Height,The_HLA,The_Ang,The_Gap,The_Foot,The_Gap_Switch,The_Direction_Switch) : #def Do_the_Hour (The_Hour,The_Latitue_Deg,The_Noon_Gap,Style_Foot, #def Tick(The_Half_Minute,R1,R2,The_Noon_Gap,Style_Foot,The_Latitue_Deg): #def Hour_Lines(The_Hour,R1,The_Noon_Gap,Style_Foot,The_Latitue_Deg): #def Twinkle(The_x,The_y,H1,H2) : #def Polygon(The_x,The_y,Siz,Sides,Turns) : #def PawnBrokers_Balls(The_x,The_y, Radius) : #def Do_Shapes (Which,Shape_Size,Shape_Param1,Shape_Param2, HLA_Deg,The_Radius, Text_Switch, HNG,Style_Foot) : #def Draw_Gnomon(My_x,My_y,Latitude,My_Strokewidth): #def Dash_Line(x1,y1,x2,y2,Dashes) : #def Blob (xx,yy,siz,Mon_Kol,The_Scale): #def EoT_Calc (YYYY,DDD,The_Time_Zone,The_Longitude) : #def Get_Flame_Coords(The_Start_Year, The_Longitude, The_Time_Zone,This_Tweak) : #def DrawFlame(xx,yy, Chart_Width,Chart_Height,Coloured,Header,The_Font,The_Start_Year,The_Longitude,The_Time_Zone,The_Place,The_Tweak): #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 - Plot_Height * (Y_val- Min_Ys) /(Y_Range) #def Draw_Gnomon_Supporters(xx,yy,rot,Supporter_Thickness, Supporter_Length): # ================================================================================================================================= # Parameter Definition # ================================================================================================================================= My_Latitude = 52.090991 # Latitude in degress +ve North of Equator My_Longitude = -2.801763 # Longitude in degress +ve East of Greenwich My_Time_Zone = 0 # +ve East of Greenwich My_Noon_Gap = .5*cm # Thickness of Gnomon My_Style_Foot = 4.5*cm # Distance from Dial Centre to Foot of Style My_Radius = 143.75*mm # Outer Radius My_Place ="Credenhill" # 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","IV","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 = "4" 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 = 79 # Font Size for Main Hour Numerals My_x_Stretch =.42 # Stretches/Compresses the numbers in the horizontal direction My_y_Stretch = .956 # 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 = 8 # 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 if My_Start_Year % 4 <> 0 : sys.exit("! ! ! " + str(My_Start_Year) + " is not a Leap Year ! ! !") My_Big_Number_Fill = color(0) My_Big_Number_Stroke = color(0) My_Big_Number_Stroke_Width = 0 My_Small_Number_Fill = color(0) My_Small_Number_Stroke = color(0) My_Small_Number_Stroke_Width = 0 Temporary_Number_Alignment_Rings = False Norm = True # set to false for Single Large Hour Number # ================================================================================================================================= # Thissection just to show the big number transformations # ================================================================================================================================= Picked_Hour = 16 Which = 4 Show_Text_1 = False # Original Text Show_Text_2 = False # Stretched Text Show_Text_3 = False # Lineated Text Show_Text_4 = False # Circularised Text Show_Text_5 = False # Rotated Text Show_Text_6 = False # Slanted Text if not Norm : if Which == 1 : Show_Text_1 = True elif Which == 2 : Show_Text_2 = True elif Which == 3 : Show_Text_3 = True elif Which == 4 : Show_Text_4 = True elif Which == 5 : Show_Text_5 = True elif Which == 6 : Show_Text_6 = True # ================================================================================================================================= # 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_Path,The_x,The_y,Fineness,Switch,UpsideDown) : if Switch == -1 : Text_Reverse = -UpsideDown else: Text_Reverse = UpsideDown Lineated_Text_Path = [] # Lineated_Text_Path will hold Original_Text_Path transformed to strainght line segments autoclosepath(close=False) for point in The_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 * (point.x - Text_Off) point.y = UpsideDown * point.y + The_y + UpsideDown_offset return Lineated_Text_Path ## ================================================================================================================================= ## Adjust a shape point (x,y) with a transformation that ## makes radial character lines point to the style foot ## ================================================================================================================================= def Slant_Shape (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] # ================================================================================================================================= # 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() The_Text_Path = textpath(The_Text,0,0) Line_Text_Path = Lineate_Text(The_Text_Path,0,-R1, My_Fineness, 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() The_Text_Path = textpath(The_Text,0,0) Line_Text_Path = Lineate_Text(The_Text_Path,x,y,My_Fineness,1,1) for point in Line_Text_Path : point.x = point.x + x point.y = point.y + y drawpath(Line_Text_Path) pop() # ================================================================================================================================= # Draw the Hour Numbers (or Half Hour Symbols) # ================================================================================================================================= def Slant_Text(The_Radi,The_Height,The_HLA,The_Ang,The_Gap,The_Foot,The_Gap_Switch,The_Direction_Switch) : #print The_Radi/cm,The_Height/cm,The_HLA,The_Ang,The_Gap/cm,The_Foot/cm,The_Gap_Switch,The_Direction_Switch This_Gap = The_Direction_Switch * The_Gap * The_Gap_Switch if The_HLA == 0. : Base_x = This_Gap Base_y = sqrt(The_Radi**2 - This_Gap**2) else: Slope_a = tan(radians(The_HLA)) Slope_a2 = Slope_a**2 q = - This_Gap + The_Foot * Slope_a aa = 1 + Slope_a2 bb = 2 * q cc = q**2 - The_Radi**2 * Slope_a2 Base_x = (- bb + sqrt(bb**2 - 4 * aa * cc)) / (2 * aa) Base_y = (Base_x + q)/Slope_a centre_angle = atan2(Base_y, Base_x) - radians(The_Ang) centre_slope = tan(centre_angle) New_Base_x = The_Radi/sqrt(1 + centre_slope**2) New_Base_y = New_Base_x* centre_slope The_xxx = 0 The_yyy = 0 if New_Base_y - The_Foot == 0. : Transformed_x = This_Gap Transformed_y = The_Radi + The_Height else: Slope_b = (New_Base_x - This_Gap)/(New_Base_y - The_Foot) Switch = 1 if New_Base_x < This_Gap : Switch = 1 #print Switch , Slope_b, centre_slope, New_Base_x Slope_b2 = Slope_b**2 q = - This_Gap + The_Foot * Slope_b aa = 1 + Slope_b2 bb = 2 * q cc = q**2 - (The_Radi + The_Height)**2 * Slope_b2 Transformed_x = (- bb + Switch * sqrt(bb**2 - 4 * aa * cc)) / (2 * aa) Transformed_y = (Transformed_x + q)/Slope_b # This bit for illustrative purposes only centre_slope = New_Base_y/New_Base_x Original_x = (The_Radi + The_Height)/sqrt(1 + centre_slope**2) Original_y = Original_x * centre_slope return [The_Direction_Switch * Transformed_x, Transformed_y, The_Direction_Switch * Base_x, Base_y, The_Direction_Switch * New_Base_x, New_Base_y, The_Direction_Switch * Original_x, Original_y] 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, The_Number_Fill,The_Number_Stroke,The_Number_Stroke_Width ) : font(The_Font) fontsize(The_Font_Size) if The_Hour < 12 : Text_Switch = -1 elif The_Hour > 12 : Text_Switch = 1 else : Text_Switch = 0 Original_Text_Path = textpath(The_Text, -textwidth(The_Text)/2., 0) if Show_Text_1 and not Blocker == True : #============ ORIGINAL TEXT push() translate(0,-The_Radius) fill(1,0,0.,.2) stroke(0,0,1) strokewidth(.2) drawpath(Original_Text_Path) pop() #============ Stretched_Text_Path = [] for point in Original_Text_Path : point.x = point.x * The_Font_X_Stretch point.y = point.y * The_Font_Y_Stretch point.ctrl1.x = point.ctrl1.x * The_Font_X_Stretch point.ctrl1.y = point.ctrl1.y * The_Font_Y_Stretch point.ctrl2.x = point.ctrl2.x * The_Font_X_Stretch point.ctrl2.y = point.ctrl2.y * The_Font_Y_Stretch Stretched_Text_Path.append(point) if Show_Text_2 and not Blocker == True : #============ STRETCHED TEXT push() translate(0,-The_Radius) fill(1,1,0.) stroke(0,0,1) strokewidth(.2) drawpath(Stretched_Text_Path) pop() #============ Line_Text_Path = Lineate_Text(Stretched_Text_Path,0,-The_Radius, My_Fineness, Text_Switch, UpsideDown) if Show_Text_3 and not Blocker == True : #============ LINEATED TEXT fill(1,0,1) stroke(0,0,1) strokewidth(.2) drawpath(Line_Text_Path) #============ R4a = R4 - 1*mm R5a = R5 + 1.5*mm Circ_Char_Path = [] Saved_Angs = [] Saved_Hts = [] Switch_Tweak = 1. if The_Hour < 12 : Switch_Tweak = -1. for point in Line_Text_Path : Circ_xy = Long_Text_Circ(point.x,point.y, R5a, R4a) point.x = Circ_xy[0] point.y = -Circ_xy[1] Saved_Angs.append(degrees(atan(point.x/point.y)) + Switch_Tweak * The_Text_Angle_Tweak) Saved_Hts.append(sqrt(point.x**2 + point.y**2) -R5a) Circ_Char_Path.append(point) if Show_Text_4 and not Blocker == True : #============ CIRCULARIZED TEXT fill(0,1,0) stroke(0,0,1) strokewidth(.2) drawpath(Circ_Char_Path) #============ if The_Hour == 12 : if The_Number_Stroke_Width == 0. : nostroke() else : stroke(The_Number_Stroke) strokewidth(The_Number_Stroke_Width) fill(The_Number_Fill) drawpath(Circ_Char_Path) else: 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 False : 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 : 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() HLA_Turn_Char_Path =[] if Text_Switch == 0 : HLA_Turn_Char_Path = Circ_Char_Path else: if The_Hour < 6 or The_Hour > 18: mu_rad = atan2(-The_Noon_Gap/2.,Style_Foot) else : mu_rad = atan2(The_Noon_Gap/2.,Style_Foot) chi_rad = HLA_Rad + mu_rad phi_rad = asin(sqrt((The_Noon_Gap/2.)**2 + Style_Foot**2) * sin(chi_rad) / R5a) theta_rad = phi_rad + chi_rad - mu_rad for point in Circ_Char_Path : xx = point.x yy = point.y point.x = Text_Switch * (xx * cos(theta_rad) - yy * sin(theta_rad)) point.y = (xx * sin(theta_rad) + yy * cos(theta_rad) ) HLA_Turn_Char_Path.append(point) Mark(0,0,12,1) if Show_Text_5 and not Blocker == True : #============ TEXT TURNED TO HLA fill(1,0,1,.5) stroke(0,0,1) fill(0,1,1) strokewidth(.2) drawpath(HLA_Turn_Char_Path) #=============================== Gap_Switch = 1 if The_Hour > 18 or (The_Hour > 6 and The_Hour < 12) : Gap_Switch = -1 Direction_Switch = 1 if The_Hour < 12 : Direction_Switch = -1 count = 0 Slant_Char_Path =[] for point in HLA_Turn_Char_Path : Results = Slant_Text(R5a,Saved_Hts[count], HLA_Deg,-Saved_Angs[count], The_Noon_Gap/2,-Style_Foot, Gap_Switch, Direction_Switch) point.x = Results[0] point.y = -Results[1] Slant_Char_Path.append(point) count +=1 if The_Number_Stroke_Width == 0. : nostroke() else : stroke(The_Number_Stroke) strokewidth(The_Number_Stroke_Width) if Norm : fill(The_Number_Fill) drawpath(HLA_Turn_Char_Path) else: if Show_Text_6 or Blocker == True : if Blocker : fill(The_Number_Fill) else : fill(1,0,0) strokewidth(.2) stroke(0,0,1) drawpath(HLA_Turn_Char_Path) # ================================================================================================================================= # 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: y1 = sqrt(R1**2 - HNG**2) y2 = sqrt(R2**2 - HNG**2) line (HNG,-y1,HNG,-y2) line (-HNG,-y1,-HNG,-y2) # ================================================================================================================================= # Tick Mark Definition # ================================================================================================================================= def Hour_Lines(The_Hour,R1,The_Noon_Gap,Style_Foot,The_Latitue_Deg): 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) push() stroke (0,0,1) strokewidth(.4) if The_Hour <> 12. : #line(Switch * x1,-y1,Switch * HNG,Style_Foot) khkllkh=1 else: y1 = sqrt(R1**2 - HNG**2) y2 = sqrt(R2**2 - HNG**2) line (HNG,-y1,HNG,-y2) line (-HNG,-y1,-HNG,-y2) pop() # ================================================================================================================================= # 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, Radius) : Detail_Factor = 10. Rad = Radius * Detail_Factor 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) Balls = [] for point in compound : point.x = point.x / Detail_Factor point.y = point.y / Detail_Factor Balls.append(point) return Balls # ================================================================================================================================= # 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_Shape(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() # ================================================================================================================================= # Gnomon Definition # ================================================================================================================================= def Draw_Gnomon(My_x,My_y,Latitude,My_Strokewidth): Base_Latitude = 52. + 5/60. #Do not change. Thisis used to scale the whole gnomonfir other Lats 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() # ================================================================================================================================= # 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 # ================================================================================================================================= # EoT Blob-Mark Definition # ================================================================================================================================= def Blob (xx,yy,siz,Mon_Kol,The_Scale): push() if (siz == 0): strokewidth(.5 * The_Scale) 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 * The_Scale oval(xx-ss/2, yy-ss/2, ss, ss) pop() # ================================================================================================================================= # Calculate the EoT for a given day : This routine gives EoT accurate to +/- 1.5 second over the next 50 years # ================================================================================================================================= def EoT_Calc (YYYY,DDD,The_Time_Zone,The_Longitude) : # Input : YYYY is Year # : DDD Days from Start of Year (0 = 0:00 hrs on 31st Dec; 1.5 noon on 1st Jan) # : Note this is in Local Civil Time (not UTC) # : Time_Zone in Hours (+ve East of Greenwich) # : The_Longitude, local Longtitude (+ve East of Greenwich) # Output : EOT & Longtitude Correction in MINUTES # : This is the correction to Sundial Time to give Lacal Mean Time # Accuracy : This routine will give EOT correct to +/- 3 seconds over the next 50 years # Days_2000 is deciaml days from Epoch 2000 Days_2000 = int((YYYY - 2000) * 365.25) + DDD - The_Time_Zone/24 if YYYY % 4 <> 0 : Days_2000 = Days_2000 + 1 # Eccentricity Component Ang_Anom = Days_2000 / 58.1329 # Anomalistic Phase Ecc_1 = 7.653 * sin(1 * Ang_Anom + 6.214) Ecc_2 = 0.081 * sin(2 * Ang_Anom + 6.154) # Obliquity Component Ang_Trop = Days_2000 / 58.1301 # Tropical phase 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) Av = -0.006 Long_Adjust = The_Time_Zone * 60. - The_Longitude * 4. return Av + Ecc_1 + Ecc_2 + Obl_1 + Obl_2 + Obl_3 + Obl_4 + Long_Adjust # ================================================================================================================================= # 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,This_Tweak) : global EoT_Array, Flame_Array # these are the output from this subroutine The_Start_Day = 1.5 #(noon on 1st Jan) The_29_Feb_Index = ((4 - The_Start_Year % 4) % 4) * 365 + 59 # Fill a temporary array with 4 years of EoT values Temp = [] for i in range(0,1461) : Temp.append(EoT_Calc (The_Start_Year,i + The_Start_Day, The_Time_Zone, The_Longitude)) # Save & then delete the Leap Day value of EoT Leap_Value = Temp[The_29_Feb_Index] del Temp [The_29_Feb_Index] # Generate a 365 day array of average EoT values EoT_Array = [] EoT_Array = [(Temp[i] + Temp[i+365] + Temp[i+2*365] + Temp[i+3*365])/4. for i in range(0,365)] # Re-insert the 29th Feb EoT value EoT_Array.insert(59, Leap_Value) # Generate an array with the change in EoT from one day to the next Change_Array = [0] for i in range(1, 366) : Change_Array.append(EoT_Array[i] - EoT_Array[i-1]) # Max_Change is used in the final intrinsic curve calculation to ensure the curved base of the Flame 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 # The_Closing_Tweak marginally changes y-scale of Flame from Tweak_Start_Day to the end of the of the year # to force closure of the curve Tweak_Start_Day = 274 # 1st Oct # Direction_Changer folds the curve on the Fold Days Direction_Changer = 1 Intrinsic_Mod = 1 Flame_Array = [0] for i in range(1, 366) : if i == Fold_Day1 or i == Fold_Day2 or i == Fold_Day3 or i == Fold_Day4 : Direction_Changer = - Direction_Changer if i == Tweak_Start_Day : Intrinsic_Mod = This_Tweak # ==== This is the guts of an intrinsic curve calculation === Flame_Array.append(Flame_Array[i-1] + Intrinsic_Mod * Direction_Changer * sqrt(Max_Change**2 - Change_Array[i]**2) ) # ================================================================================================================================= # Routine for Drawing the EoT Flame # ================================================================================================================================= global EoT_Array, Flame_Array def DrawFlame(xx,yy, Chart_Width,Chart_Height,Coloured,Header,The_Font,The_Start_Year,The_Longitude,The_Time_Zone,The_Place,The_Tweak): global EoT_Array,Flame_Array # these calculated in the Get_Flame_Coords subroiutine Black = False Grey = False Colour = False if Coloured == 0 : Black = True if Coloured == -1 : Grey = True if Coloured == 1 : Colour = True # zz will lighten or darken the Greys if the Grey option is chosen zz = .4 My_Grey = color(zz,zz,zz) Blacks = [color(0,0,0),color(0,0,0),color(0,0,0),color(0,0,0)] Greys = [color(0,0,0),My_Grey,color(0,0,0), My_Grey] Colors = [color(1,0,0),color(0,0,1),color(.9,0,.8),color(0,.6,0)] push() # Scaler scales all chart components to that of the original design Scaler = Chart_Width/(6.4*cm) font(The_Font) fontsize(10* Scaler) strokewidth(.4 * Scaler) if Coloured == 0 : strokewidth(max(.7,.4 * Scaler)) # for Photo-etchind force linewidth to be at least .7 points # ============================================ # TRANSLATE TO ORIGIN AND DRAW SURROUNDING BOX # ============================================ translate (xx,yy) stroke(0) if Coloured == 1 : stroke(1,0,0) nofill() rect (0,0, Chart_Width, -Chart_Height) # ======================= # TRANSLATE TO GRAPH AREA # ======================= Numbers_Gap = -5.5*mm*Scaler translate (0, Numbers_Gap) Plot_Height = Chart_Height + 2* Numbers_Gap # ===================== # GET THE ARRAY OF EoTs # ===================== # This is a 366 day array with all days, except 29 Feb, being the average over 4 years EoT_Array = [] Get_Flame_Coords(The_Start_Year, The_Longitude, The_Time_Zone,The_Tweak) # =============== # 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 - Plot_Height * (Y_val- Min_Ys) /(Y_Range) # ============== # VERTICAL LINES # ============== for counter in range (down_scale + 1, up_scale) : aa = EoT_to_Chart(float(counter)) Tick = 1.2*mm*Scaler if Colour : if counter % 5 == 0 : stroke(1,0,0) line(aa, Tick,aa,- Plot_Height-Tick) else: stroke(.6,.6,1) line(aa, 0,aa,- Plot_Height) elif Grey : if counter % 5 == 0 : stroke(0) line(aa, Tick,aa,- Plot_Height-Tick) else : stroke(.8) line(aa, 0,aa,- Plot_Height) else : stroke(color(0)) if counter % 5 == 0 : line(aa, Tick,aa,- Plot_Height-Tick) else: Dash_Line(aa, 0,aa,- Plot_Height,200) # ====================== # TOP AND BOTTOM MARGINS # ====================== stroke(0) if Coloured == 1 : stroke(1,0,0) aa = EoT_to_Chart(float(down_scale)) bb = EoT_to_Chart(float(up_scale) ) line(aa, - Plot_Height,bb,- Plot_Height) line(aa, 0,bb,0) # ============================================================ # CREATE A WHITE FILL JUST OUTSIDE THE AREA TAKEN BY THE FLAME # ============================================================ x_prev = EoT_to_Chart(EoT_Array[365]) y_prev = Ys_to_Chart(Flame_Array[365]) x_this = EoT_to_Chart(EoT_Array[0]) y_this = Ys_to_Chart(Flame_Array[0]) for counter in range(0, 366): if counter <> 365 : x_next = EoT_to_Chart(EoT_Array[counter + 1]) y_next = Ys_to_Chart(Flame_Array[counter + 1]) else : x_next = EoT_to_Chart(EoT_Array[0]) y_next = Ys_to_Chart(Flame_Array[0]) # slope is normal to curve slope = atan2(-(y_next - y_prev),(x_next - x_prev)) xinc = x_this + .7 * mm * Scaler *sin(slope) yinc = y_this + .7 * mm * Scaler *cos(slope) if(counter == 0): beginpath(xinc, yinc) else: lineto(xinc, yinc) x_prev = x_this y_prev = y_this x_this = x_next y_this = y_next whiteout = endpath(draw=False) push() nostroke() fill(1) drawpath(whiteout) pop() # ============== # MINUTE NUMBERS # ============== font(My_Font) for counter in range (down_scale + 1, up_scale) : if counter % 5 == 0: textwid = 1.*textwidth (counter) textht = textheight(counter) xx = EoT_to_Chart(float(counter)) fill(0) if Coloured == 1: fill(0,0,1) push() translate(0, -Plot_Height) Do_Straight_String(counter,xx , -1.0*mm * Scaler) pop() Do_Straight_String(counter,xx , +2.3*mm * Scaler) # ============ # MONTH NAMES # ============ month_starts = [0,31,60,91,121,152,182,213,244,274,305,335,366] # Blob sizes for each day of the month 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] # Text alignment for each month name Aligner = [-1,-1,-1,-1,1,1,1,-1,1,1,1,1] # Offset on the month names from the arrow heads Text_XX_Offset = [ 4.5, -2.5, -6, -6, 2.0, +5.5, +5.0, -5.5, -6.5, -1.5, +4.0, +7] Text_YY_Offset = [-3.5, -4.0, -1.5, -.5, 10, +4.5, +4.0, -3.5, -0.9, +7.0, +6.2, +1.0] Text_X_Offset =[] Text_Y_Offset =[] for count in range(0,12) : Text_X_Offset.append(Text_XX_Offset[count] * Scaler) for count in range(0,12) : Text_Y_Offset.append(Text_YY_Offset[count] * Scaler) Month_Names = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"] for counter in range(0,12) : This_Month = Month_Names[counter] kol_index = counter % 4 if Black : Mon_Kol = Blacks[kol_index] if Grey : Mon_Kol = Greys [kol_index] if Colour : Mon_Kol = Colors[kol_index] 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]) fill(Mon_Kol) if counter == 4 : # Special for May push() translate(aa + Hor_Align,bb + Vert_Align) rotate (90) Do_Straight_String(This_Month, 0,0) rotate (-90) pop() else: nostroke() push() translate (aa+Hor_Align, bb + Vert_Align) Do_Straight_String(This_Month,0,0) pop() # ================== # LITTLE BENT ARROWS # ================== L1 = 3.0 * mm * Scaler # Length of first part of arrow shaft L2 = 1.8 * mm * Scaler # Length of first part of arrow shaft HW = 0.5 * mm * Scaler # Width of Arrow Head HS = 0.4 * mm * Scaler # Head Spur Length HL = 0.8 * mm * Scaler # Length of Arrow Head for counter in range(0, 12) : 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() kol_index = counter % 4 if Black : Mon_Kol = Blacks[kol_index] if Grey : Mon_Kol = Greys [kol_index] if Colour : Mon_Kol = Colors[kol_index] stroke(Mon_Kol) fill(Mon_Kol) translate(x1,y1) if counter <> 4: rotate(-turn) beginpath(0,0) lineto(0,-L1) lineto(L2,-L1) lineto(L2-HS,-L1-HW) lineto(L2+HL,-L1) lineto(L2-HS,-L1+HW) lineto(L2,-L1) lineto(0,-L1) lineto(0,0) endpath(draw=True) else : # Special for May rotate(-85) LL2 = 5*mm * Scaler HS2 = .4*mm * Scaler HW2 = .5*mm * Scaler HL2 = .45*mm * Scaler beginpath(0,0) lineto(LL2,0) lineto(LL2-HS,-HW) lineto(LL2+HS+HL2,0) lineto(LL2-HS,HW) lineto(LL2,0) lineto(0,0) endpath(draw=True) pop() # =========================== # MONTHLY LINES & DAILY BLOBS # =========================== counter = 0 month_count = 0 for month_count in range(0, 12) : the_index = month_starts[month_count] last_index = month_starts[month_count+1] day = 0 while the_index < last_index: aa1 = EoT_to_Chart (EoT_Array [counter]) bb1 = Ys_to_Chart (Flame_Array[counter]) kol_index = month_count % 4 if Black : Mon_Kol = Blacks[kol_index] if Grey : Mon_Kol = Greys [kol_index] if Colour : Mon_Kol = Colors[kol_index] Blob(aa1, bb1, siz[day],Mon_Kol,Scaler) day += 1 counter += 1 the_index += 1 # =============== # HEADER TEXT BOX # =============== if Header : stroke(0) if Coloured == 1 : stroke(1,0,0) fill(1) Line1 = "Equation of Time" Line2 = "& Longitude Correction" Line3 = "for " + The_Place Line4 = "- in Minutes -" fontsize(7.5 * Scaler) LL = .7*textheight(Line1) Box_x = Chart_Width - 1*mm*Scaler Box_y = -Plot_Height + 1*mm*Scaler Box_w = max(textwidth(Line1),textwidth(Line2),textwidth(Line3)) + 2*mm*Scaler Box_h = 4 * LL + 1.2*mm*Scaler rect(Box_x, Box_y, -Box_w, Box_h) Line_y1 = Box_y + LL Line_y2 = Box_y + 2*LL Line_y3 = Box_y + 3*LL Line_y4 = Box_y + 4*LL fill(0) if Coloured == 1 : fill(0,0,1) Do_Straight_String (Line1,Box_x - Box_w/2.- textwidth(Line1)/2., Line_y1) Do_Straight_String (Line2,Box_x - Box_w/2.- textwidth(Line2)/2., Line_y2) Do_Straight_String (Line3,Box_x - Box_w/2.- textwidth(Line3)/2., Line_y3) Do_Straight_String (Line4,Box_x - Box_w/2.- textwidth(Line4)/2., Line_y4) pop() # ================================================================================================================================= # Draws the Gnomon Supporters # ================================================================================================================================= def Draw_Gnomon_Supporters(xx,yy,rot,Supporter_Thickness, Supporter_Length): push() translate(xx,yy) rotate(rot) Supporter_Thickness = .5*cm Supporter_Length = 13.45*cm stroke(0) strokewidth(My_Line_Width) beginpath(0,0) lineto(Supporter_Length,0) lineto(Supporter_Length-Supporter_Thickness* cos(radians(My_Latitude)),-Supporter_Thickness) lineto(Supporter_Thickness*sin(radians(My_Latitude)),-Supporter_Thickness) lineto (0,0) qq = endpath(draw=False) if My_Cutting: fill(.9) else: nofill() drawpath(qq) 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) push() translate (0,-6*cm) if Want_Graph_Paper : Graph_Paper(My_Paper) 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 - 55*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 if Temporary_Number_Alignment_Rings : push() stroke(1,0,0,.5) strokewidth(.2) R4a = R4 - 1*mm R5a = R5 + 1.5*mm oval (-R4a,-R4a,2*R4a,2*R4a) oval (-R5a,-R5a,2*R5a,2*R5a) #R3a = R4 + 1.3*mm #oval (-R3a,-R3a,2* R3a,2* R3a) #rot = 139.2 #translate(-My_Noon_Gap/2, My_Style_Foot) #rotate(rot) #line(0,0,18*cm,0) #rotate(1.7) #line(0,0,18*cm,0) #rotate(1.81) #line(0,0,18*cm,0) #rotate(1.83) #line(0,0,18*cm,0) #rotate(4) #line(0,0,18*cm,0) pop() # ================================================================================================================================= # 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 Main Hour Number and Half Hour Symbols # ================================================================================================================================= Blocker = False 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] if Norm or The_Hour == Picked_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, My_Big_Number_Fill,My_Big_Number_Stroke,My_Big_Number_Stroke_Width) The_Hour = The_Hour + 1 Blocker = True # ================================================================================================================================= # 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. My_yy_Stretch = 1. Digit_Gap = .5 #degrees Big_Digit_Offset = 1.2*mm Little_Digit_Offset= 1.45*mm Noon_Little_Digit_Offset = -0*mm Little_Font_Size = 7 while The_10_Mins <= End_Hour * 6 : # The two noon digits 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 + Noon_Little_Digit_Offset , UpsideDown, "0", My_Font, Little_Font_Size, My_xx_Stretch, My_yy_Stretch, 0., My_Fineness, My_Small_Number_Fill,My_Small_Number_Stroke,My_Small_Number_Stroke_Width) translate(-My_Noon_Gap,0) Do_the_Hour(The_10_Mins/6., My_Latitude, My_Noon_Gap, My_Style_Foot, R4 + Big_Digit_Offset + Noon_Little_Digit_Offset , UpsideDown, "0", My_Font, Little_Font_Size, My_xx_Stretch, My_yy_Stretch, 0., My_Fineness, My_Small_Number_Fill,My_Small_Number_Stroke,My_Small_Number_Stroke_Width) translate(My_Noon_Gap/2.,0) pop() elif The_10_Mins % 6 == 0 : # Hour Digit 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_yy_Stretch, 0., My_Fineness, My_Small_Number_Fill,My_Small_Number_Stroke,My_Small_Number_Stroke_Width) else: # 10 min Digits 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_yy_Stretch, Digit_Gap, My_Fineness, My_Small_Number_Fill,My_Small_Number_Stroke,My_Small_Number_Stroke_Width) 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_yy_Stretch, -Digit_Gap, My_Fineness, My_Small_Number_Fill,My_Small_Number_Stroke,My_Small_Number_Stroke_Width) The_10_Mins = The_10_Mins + 1 # ================================================================================================================================= # Draw Inner Set of Time Markers (7.5 min, 15 min, 30 min & hour ticks) & Markers (Twinkles & Pawnbrokers) # ================================================================================================================================= if Inner_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 if not Norm : Hour_Lines(Picked_Hour,R1, My_Noon_Gap, My_Style_Foot, My_Latitude) # ================================================================================================================================= # 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 Local Solar Time to Civil Time,",R6-2.4*cm,R5+1*cm,1,1,-1,-1,0,My_Fineness) Do_Curved_String("apply the Date Correction from the Graph.",R6-1.9*cm,R5+1*cm,1,1,-1,-1,0,My_Fineness) Do_Curved_String("Add 1 hour during BST.",R6-1.4*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(u"Latitude 52° 05’ North : Longitude 2° 48’ 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) Motto_x = -4.7*cm Do_Straight_String(Line1, Motto_x,-1.3*cm) Do_Straight_String(Line2, Motto_x,-.5*cm) Do_Straight_String(Line3, Motto_x,.3*cm) pop() # ================================================================================================================================= # Draw Fecit & Date Text # ================================================================================================================================= if Fecit and not My_Cutting : Line9 = "KWK fec." Line10 = "2013" font(My_Font) fill(0) nostroke() fontsize(12) 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(14) translate(4.1*cm,-6.2*cm) Do_Straight_String(Line4,0,-0) Do_Straight_String(Line5,0,.25*cm) Do_Straight_String(Line6,0,.5*cm) Do_Straight_String(Line7,0,.75*cm) pop() # ================================================================================================================================= # Draws the EoT Flame # ================================================================================================================================= if EoT and not My_Cutting : EoT_x = My_Noon_Gap/2. + 8*mm EoT_Ht = 8.85*cm EoT_Wid = 6.4 *cm EoT_y = EoT_Ht/2 My_Tweak = 1.03 DrawFlame(EoT_x, EoT_y,EoT_Wid,EoT_Ht,0,False,"Times-Roman",2012,My_Longitude,My_Time_Zone,My_Place, My_Tweak) # ================================================================================================================================= # 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 : push() rotate(270) Draw_Gnomon(5*cm,12.9*cm, My_Latitude,1.) pop() # ================================================================================================================================= # Draws the Gnomon # ================================================================================================================================= if Gnomon_Supporters: Draw_Gnomon_Supporters(11*cm,6*cm,270,.5*cm, 13.45*cm) Draw_Gnomon_Supporters(13 *cm,6*cm,270,.5*cm, 13.45*cm)