from math import degrees, radians, atan, atan2, tan, asin, sin, acos, cos, sqrt, pi My_Paper = "A4" if My_Paper == "A3" : size (29.7*cm, 29.7*cm) else : size (21*cm, 21*cm) translate (WIDTH/2,HEIGHT/2) transform (mode=CORNER) if My_Paper == "A4" : My_Scale = 21./29.7 scale (My_Scale) Coloured = False Outer_Diameter = 14.5*cm Cutting_Octagon_Radius = Outer_Diameter/cos(radians(22.5)) Screw_Radius = Cutting_Octagon_Radius - 8*mm Outer_Octagon_Radius = Cutting_Octagon_Radius - 2*mm Inner_Octagon_Radius = Outer_Octagon_Radius - 1*mm Outer_Perimeter_Radius = Outer_Diameter - 4*mm Inner_Perimeter_Radius = Outer_Perimeter_Radius - 1*mm Big_Number_Radius = Inner_Perimeter_Radius - 16.5*mm Scale_Radius_1_Outer = Inner_Perimeter_Radius - 18*mm Scale_Radius_1_Mid = Scale_Radius_1_Outer- 6*mm Scale_Radius_1_Inner = Scale_Radius_1_Mid- 1*mm Small_Number_Radius_1 = Scale_Radius_1_Outer - 5*mm Outer_Hecto_Radius = Scale_Radius_1_Inner Inner_Hecto_Radius = Outer_Hecto_Radius - 5*cm Scale_Radius_2_Outer = Inner_Hecto_Radius Scale_Radius_2_Mid = Scale_Radius_2_Outer- 1*mm Scale_Radius_2_Inner = Scale_Radius_2_Mid - 5*mm Small_Number_Radius_2 = Scale_Radius_2_Mid - 3.9*mm Innermost_Circle_Radius = Scale_Radius_2_Inner - 1*mm Mess1 = u"ca. 1865 - Freedom Cottage, Llandogo >> KWK 1974" Mess2 = "KWK 1944 =1975 EAB 1949" Mess3 = "EHK 1978 =2012 ELB 1980" Mess4 = "EWK 1980 =2009 CWN 1972 >> AEK 2014" Mess5 = u"Latitude 51° 44’ North" Mess6 = u"Longtitude 2° 42’ West" Inst1 = u"Follow around today’s Month ring," Inst2 = "until the straight shadow line is" Inst3 = "reached. Then, follow the appropriate" Inst4 = "curve to read the Greenwich Mean Time." Inst5 = "Add 1 hour during British Summer Time." MottoL1 = "Let other" MottoL2 = "tell of Storms" MottoL3 = "and Showers," MottoR1 = u"I’ll only" MottoR2 = "count your" MottoR3 = "Sunny Hours" My_Start_Year = 2012 # Used for EoT calculation: This MUST be a LEAP YEAR Jan_1_EoT_Tweak = -0.868200549418 # = 0.25 x EoT at noon on Jan 1 My_Time_Zone = 0 My_Latitude_Deg = 51.735043 My_Longitude_Deg = -2.694806 My_Noon_Gap = 5*mm My_Style_Foot_Posn = 4*cm # Positive Downwards My_Gnomon_Foot_Lngth= 12*cm # Positive Downwards My_Tongue_Offset = 1*cm # Positive Downwards Start_Hour = 5 End_Hour = 19 Hecto_Fineness = 1 # Day Step for Hecto rountines : 1 for every day My_Fineness = 6 # Font detail, each bezier is split intoi "n" straight line pieces My_Italics = 0 # Degrees of Italicisation of font characters My_Line_Width = .8 My_UpsideDown = False My_Font = "Times-Roman" My_Font_Size = 60 My_Small_Size = 16 My_X_Stretch = 1 My_Y_Stretch = 1.0 My_X_Medium_Stretch = .7 My_Y_Medium_Stretch = 1.0 My_X_Small_Stretch = .5 My_Y_Small_Stretch = 1.0 First_Inner_Number = 7 # ================== Which_Text = 1 # 0=Roman, 1=Arabic, 2 = Symbol (see above) , 3=Alignment mark (|). 2 & 3 are used for debugging # ================== Red = color(1,0,0) Green = color(0,1,0) Blue = color(0,0,1) Black = color(0) Magenta = color(1,0,1) White = color(1) Blank = color(1,1,1,0) Gray = color(.5) My_Cutting = False # ================================================================================================================================= # Select Components to draw # ================================================================================================================================= def Draw_All() : if not My_Cutting : Draw_Big_Numbers() Draw_Time_Markers() Draw_Small_Numbers() Draw_Month_Circles() Draw_Month_Names () Draw_Hectormorous () Draw_Hour_Lines() Draw_Instructions () Draw_Location_Etc () Draw_Outer_Scenery () Draw_General_Geom() Draw_Balls() Draw_Triangles() Draw_Mottos() Draw_Fecit() else : Cutting_Pattern() # ================================================================================================================================= # Draw a single Hectormorous Curve # Calls EoT_Calc # needs My_Latitude_Deg, My_Longitude_Deg, My_Time_Zone, My_Noon_Gap, My_Style_Foot_Posn # My_Line_Width, My_Start_Year, Hecto_Fineness # ================================================================================================================================= def Hectormorous(The_GMT_Hour,Outer_Rad,Inner_Rad): This_Day = 0 Last_x = 0 Last_y = 0 The_Mean_Minute = int(60. * The_GMT_Hour + .00001) strokewidth(My_Line_Width) The_Kol = Black if Coloured : The_Kol = Blue Line_Type = 1 if The_Mean_Minute % 30 == 0 : Line_Type = 2 strokewidth(My_Line_Width*1.25) if Coloured : The_Kol = Green if The_Mean_Minute % 60 == 0 : Line_Type = 3 strokewidth(My_Line_Width*1.5) if Coloured : The_Kol = Red Blank_Switch = 1 while This_Day <= 366: EoT_Day = This_Day + 1 + The_GMT_Hour/24. if This_Day < 59 : EoT1 = EoT_Calc (My_Start_Year , EoT_Day ,My_Time_Zone, My_Longitude_Deg) EoT2 = EoT_Calc (My_Start_Year + 1, EoT_Day ,My_Time_Zone, My_Longitude_Deg) EoT3 = EoT_Calc (My_Start_Year + 2, EoT_Day ,My_Time_Zone, My_Longitude_Deg) EoT4 = EoT_Calc (My_Start_Year + 3, EoT_Day ,My_Time_Zone, My_Longitude_Deg) EoT = (EoT1 + EoT2 + EoT3 + EoT4) / 4. elif This_Day == 59 : EoT = EoT_Calc (My_Start_Year , EoT_Day ,My_Time_Zone, My_Longitude_Deg) else : EoT1 = EoT_Calc (My_Start_Year , EoT_Day ,My_Time_Zone, My_Longitude_Deg) EoT2 = EoT_Calc (My_Start_Year + 1, EoT_Day -1 ,My_Time_Zone, My_Longitude_Deg) EoT3 = EoT_Calc (My_Start_Year + 2, EoT_Day -1 ,My_Time_Zone, My_Longitude_Deg) EoT4 = EoT_Calc (My_Start_Year + 3, EoT_Day -1 ,My_Time_Zone, My_Longitude_Deg) EoT = (EoT1 + EoT2 + EoT3 + EoT4) / 4. The_Solar_Hour = The_GMT_Hour - EoT/60. HA_Deg = (The_Solar_Hour - 12.) * 15. HA_Rad = radians(abs(HA_Deg)) HLA_Rad = atan(tan(HA_Rad) * sin(radians(abs(My_Latitude_Deg)))) if (HA_Deg > 90 or HA_Deg < -90): HLA_Rad = HLA_Rad + pi HLA_Deg = degrees(HLA_Rad) if (The_Solar_Hour > 6 and The_Solar_Hour < 12) or The_Solar_Hour > 18 : HNG = -My_Noon_Gap/2. else : HNG = My_Noon_Gap/2. if The_Solar_Hour < 12 : Switch = -1 elif The_Solar_Hour > 12 : Switch = 1 else : Switch = 0 The_Radius = Outer_Rad - (Outer_Rad - Inner_Rad) * This_Day/366 Signer = 1 if HLA_Deg > 90 : Signer = -1 tanGamma = tan(radians(HLA_Deg)) dd = My_Style_Foot_Posn * tanGamma + Switch * HNG aaa = 1 + tanGamma**2 bbb = 2 * dd * tanGamma ccc = dd * dd - The_Radius**2 y1 = (-bbb + Signer * sqrt(bbb**2 - 4 * aaa * ccc)) / (2 * aaa) x1 = sqrt(The_Radius**2 - y1**2) if The_Solar_Hour <> 12. : xxx = Switch * x1 yyy = -y1 else: xxx = HNG yyy = -sqrt(The_Radius**2 - HNG**2) stroke(The_Kol) if Line_Type == 1 and Blank_Switch == -1 : stroke(Blank) else : stroke(The_Kol) if Last_x <> 0 and Last_y <> 0 : line(Last_x, Last_y,xxx,yyy) #print The_Mean_Minute, This_Day, Blank_Switch, The_Kol Last_x = xxx Last_y = yyy if This_Day % 4 == 0 : Blank_Switch = -Blank_Switch This_Day = This_Day + Hecto_Fineness # ================================================================================================================================= # Draw Hectormorous Curves every 10 minutes # Calls Hectormorous # ================================================================================================================================= def Draw_Hectormorous () : The_GMT_Hour = Start_Hour while The_GMT_Hour <= End_Hour : Hectormorous(The_GMT_Hour, Outer_Hecto_Radius, Inner_Hecto_Radius) The_GMT_Hour = The_GMT_Hour + 1/6. # ================================================================================================================================= # Tick Mark Definition # needs My_Latitude_Deg, My_Longitude_Deg, My_Time_Zone, My_Noon_Gap, My_Style_Foot_Posn, Jan_1_EoT_Tweak # needs Coloured & Colour Defns # ================================================================================================================================= def Tick(The_Minute,R1,R2): My_Hour = The_Minute/60. HA_Deg = (My_Hour - 12) * 15 + My_Longitude_Deg + Jan_1_EoT_Tweak HA_Rad = radians(abs(HA_Deg)) HLA_Rad = atan(tan(HA_Rad) * sin(radians(abs(My_Latitude_Deg)))) if (HA_Deg > 90 or HA_Deg < -90): HLA_Rad = HLA_Rad + pi if HA_Deg < 0 : HLA_Rad = -HLA_Rad HLA_Deg = degrees(HLA_Rad) if HLA_Deg == 0 : The_X_Slant_Point = 0.00001 The_Y_Slant_Point = My_Style_Foot_Posn elif (HLA_Deg > 0 and HLA_Deg <= 90) or HLA_Deg <= -90 : The_X_Slant_Point = My_Noon_Gap/2. The_Y_Slant_Point = My_Style_Foot_Posn else: The_X_Slant_Point = -My_Noon_Gap/2. The_Y_Slant_Point = My_Style_Foot_Posn Signer = 1 Sign = 1 if HLA_Deg > 90 or HLA_Deg < -90 : Signer = -1 if HLA_Deg < 0 : Sign = -1 tanGamma = tan(HLA_Rad) dd = The_Y_Slant_Point * tanGamma + The_X_Slant_Point 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) stroke(Black) if Coloured : stroke(Red) line(Sign * x1,-y1, Sign * x2,-y2) # ================================================================================================================================= # Draw Main Hour Digits # calls Do_Text # needs #Start_Hour = 10 #End_Hour = 15 #My_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"] #Big_Number_Radius = 10*cm #My_UpsideDown = False #My_Font ="Times-Roman" #My_Font_Size = 60 #My_X_Stretch = 1 #My_Y_Stretch = 1 #My_Italics = 0 #My_Fineness = 5 # ================================================================================================================================= def Draw_Big_Numbers() : My_Hour = Start_Hour while My_Hour <= End_Hour : My_String = My_Text[My_Hour] HA_Deg = (My_Hour - 12) * 15 + My_Longitude_Deg + Jan_1_EoT_Tweak HA_Rad = radians(abs(HA_Deg)) HLA_Rad = atan(tan(HA_Rad) * sin(radians(abs(My_Latitude_Deg)))) if (HA_Deg > 90 or HA_Deg < -90): HLA_Rad = HLA_Rad + pi if HA_Deg < 0 : HLA_Rad = -HLA_Rad HLA_Deg = degrees(HLA_Rad) if HLA_Deg == 0 : The_X_Slant_Point = 0.00001 The_Y_Slant_Point = My_Style_Foot_Posn elif (HLA_Deg > 0 and HLA_Deg <= 90) or HLA_Deg <= -90 : The_X_Slant_Point = My_Noon_Gap/2. The_Y_Slant_Point = My_Style_Foot_Posn else: The_X_Slant_Point = -My_Noon_Gap/2. The_Y_Slant_Point = My_Style_Foot_Posn mu_rad = atan2(The_X_Slant_Point, The_Y_Slant_Point) chi_rad = HLA_Rad + mu_rad phi_rad = asin(sqrt((The_X_Slant_Point)**2 + The_Y_Slant_Point**2) * sin(chi_rad) / Big_Number_Radius) theta_rad = phi_rad + chi_rad - mu_rad My_theta_deg = degrees(theta_rad) My_String_Turn = My_theta_deg # Positive Clockwise The_Fill = Black The_Stroke = Black if Coloured : The_Fill = Red The_Stroke = Blank The_Stroke_Width = .2 Do_Text(My_String, Big_Number_Radius, My_String_Turn, My_UpsideDown,The_X_Slant_Point,The_Y_Slant_Point, My_Font,My_Font_Size,My_X_Stretch,My_Y_Stretch, My_Italics, The_Fill, The_Stroke,The_Stroke_Width,My_Fineness) #xx = Big_Number_Radius*sin(theta_rad) #yy = -Big_Number_Radius*cos(theta_rad) #line (The_X_Slant_Point, The_Y_Slant_Point,xx,yy) My_Hour = My_Hour + 1 # ================================================================================================================================= # Draw Small Outer & Inner 10-min Digits # ================================================================================================================================= def Draw_Small_Numbers() : My_Chars = ["o","1","2","3","4","5"] My_Hour = Start_Hour count = 0 while My_Hour <= End_Hour : Which = count % 6 My_String = My_Chars[Which] HA_Deg = (My_Hour - 12) * 15 + My_Longitude_Deg + Jan_1_EoT_Tweak HA_Rad = radians(abs(HA_Deg)) HLA_Rad = atan(tan(HA_Rad) * sin(radians(abs(My_Latitude_Deg)))) if (HA_Deg > 90 or HA_Deg < -90): HLA_Rad = HLA_Rad + pi if HA_Deg < 0 : HLA_Rad = -HLA_Rad HLA_Deg = degrees(HLA_Rad) if HLA_Deg == 0 : The_X_Slant_Point = 0.00001 The_Y_Slant_Point = My_Style_Foot_Posn elif (HLA_Deg > 0 and HLA_Deg <= 90) or HLA_Deg <= -90 : The_X_Slant_Point = My_Noon_Gap/2. The_Y_Slant_Point = My_Style_Foot_Posn else: The_X_Slant_Point = -My_Noon_Gap/2. The_Y_Slant_Point = My_Style_Foot_Posn mu_rad = atan2(The_X_Slant_Point, The_Y_Slant_Point) chi_rad = HLA_Rad + mu_rad # Outer Scale Number phi_rad = asin(sqrt((The_X_Slant_Point)**2 + The_Y_Slant_Point**2) * sin(chi_rad) / Small_Number_Radius_1) theta_rad = phi_rad + chi_rad - mu_rad My_theta_deg = degrees(theta_rad) My_String_Turn = My_theta_deg # Positive Clockwise The_Kol = Black if Coloured : The_Kol = Blue if Which <> 0 : Digit_Tweak = 0.55 Zero_Tweak = 0.65 Do_Text(My_String, Small_Number_Radius_1, My_String_Turn-Digit_Tweak, My_UpsideDown,The_X_Slant_Point,The_Y_Slant_Point, My_Font,My_Small_Size, My_X_Medium_Stretch, My_Y_Medium_Stretch, My_Italics, The_Kol, Blank,.2,My_Fineness) Do_Text("o", Small_Number_Radius_1 +.7*mm, My_String_Turn+ Zero_Tweak, My_UpsideDown,The_X_Slant_Point,The_Y_Slant_Point, My_Font, My_Small_Size, My_X_Medium_Stretch, My_Y_Medium_Stretch, My_Italics, The_Kol, Blank,.2,My_Fineness) else : Zero_Tweak = .01 Do_Text("o", Small_Number_Radius_1 +.7*mm, My_String_Turn+ Zero_Tweak, My_UpsideDown,The_X_Slant_Point,The_Y_Slant_Point, My_Font, My_Small_Size, My_X_Medium_Stretch, My_Y_Medium_Stretch, My_Italics, The_Kol, Blank,.2,My_Fineness) # Inner Scale Number phi_rad = asin(sqrt((The_X_Slant_Point)**2 + The_Y_Slant_Point**2) * sin(chi_rad) / Small_Number_Radius_2) theta_rad = phi_rad + chi_rad - mu_rad My_theta_deg = degrees(theta_rad) My_String_Turn = My_theta_deg # Positive Clockwise if My_Hour >= First_Inner_Number and My_Hour <= (24 - First_Inner_Number) : Digit_Tweak = 0.7 Zero_Tweak = .85 if Which == 0 : Digit_Tweak = -.1 if Which <> 0 : Do_Text(My_String, Small_Number_Radius_2, My_String_Turn-Digit_Tweak, My_UpsideDown,The_X_Slant_Point,The_Y_Slant_Point, My_Font, My_Small_Size*.7, My_X_Small_Stretch, My_Y_Small_Stretch, My_Italics, The_Kol, Blank,.2,My_Fineness) Do_Text("o", Small_Number_Radius_2 +.2*mm, My_String_Turn+ Zero_Tweak, My_UpsideDown,The_X_Slant_Point,The_Y_Slant_Point, My_Font, My_Small_Size*.7,My_X_Small_Stretch,My_Y_Small_Stretch, My_Italics, The_Kol, Blank,.2,My_Fineness) else : Zero_Tweak = .01 Do_Text("o", Small_Number_Radius_2 +.2*mm, My_String_Turn+ Zero_Tweak, My_UpsideDown,The_X_Slant_Point,The_Y_Slant_Point, My_Font, My_Small_Size*.7,My_X_Small_Stretch,My_Y_Small_Stretch, My_Italics, The_Kol, Blank,.2,My_Fineness) else : if Which == 0 : Zero_Tweak = .01 Do_Text("o", Small_Number_Radius_2 +.2*mm, My_String_Turn+ Zero_Tweak, My_UpsideDown,The_X_Slant_Point,The_Y_Slant_Point, My_Font, My_Small_Size*.7,My_X_Small_Stretch,My_Y_Small_Stretch, My_Italics, The_Kol, Blank,.2,My_Fineness) count = count + 1 My_Hour = My_Hour + 1./6. # ================================================================================================================================= # Draw Outer & Inner Sets of Time Markers (10-min) # ================================================================================================================================= def Draw_Time_Markers () : Start_Minute = Start_Hour * 60 End_Minute = End_Hour * 60 The_Minute = Start_Minute stroke(1,0,0) strokewidth(My_Line_Width) while The_Minute <= End_Minute : if The_Minute % 60 == 0 : # Outer Scale R_out = Scale_Radius_1_Mid R_in = Scale_Radius_1_Inner Tick(The_Minute, R_in,R_out) Do_Shapes (3,1.1*mm,False,0., The_Minute/60., Scale_Radius_1_Outer-1*mm) Do_Shapes (3,1.1*mm,True,0., The_Minute/60., R_out+1*mm) # Inner Scale R_out = Scale_Radius_2_Outer R_in = Scale_Radius_2_Mid Tick(The_Minute, R_in,R_out) Do_Shapes (3,1.1*mm,False,0., The_Minute/60., R_in-1*mm) Do_Shapes (3,1.1*mm, True,0., The_Minute/60., Scale_Radius_2_Inner+1*mm) elif The_Minute % 30 == 0 : # Outer Scale R_out = Scale_Radius_1_Outer + 3*mm R_in = Scale_Radius_1_Inner Tick(The_Minute, R_in,R_out) R_out = Inner_Perimeter_Radius R_in = Inner_Perimeter_Radius - 4*mm Tick(The_Minute, R_in,R_out) Do_Shapes (3,1.1*mm,False,0., The_Minute/60., Scale_Radius_1_Outer-1*mm) Do_Shapes (3,1.1*mm,True,0., The_Minute/60., Scale_Radius_1_Mid +1*mm) # Inner Scale R_out = Scale_Radius_2_Outer R_in = Scale_Radius_2_Inner Tick(The_Minute, R_in,R_out) Do_Shapes (3,1.1*mm,True,0., The_Minute/60., Scale_Radius_2_Inner+1*mm) Do_Shapes (3,1.1*mm, False,0., The_Minute/60., Scale_Radius_2_Mid-1*mm) elif The_Minute % 10 == 0 : # Outer Scale R_out = Scale_Radius_1_Outer R_in = Scale_Radius_1_Inner Tick(The_Minute, R_in,R_out) # Inner Scale R_out = Scale_Radius_2_Outer R_in = Scale_Radius_2_Inner Tick(The_Minute, R_in,R_out) elif The_Minute % 2 == 0 : # Outer Scale R_out = Scale_Radius_1_Mid R_in = Scale_Radius_1_Inner Tick(The_Minute, R_in,R_out) # Inner Scale R_out = Scale_Radius_2_Outer R_in = Scale_Radius_2_Mid Tick(The_Minute, R_in,R_out) The_Minute = The_Minute + 1 # ================================================================================================================================= # Draw Month Circles # ================================================================================================================================= def Draw_Month_Circles() : nofill() strokewidth(My_Line_Width) stroke(0,1,0,.6) The_Months = ["January","February","March","April","May","June","July","August","September","October","November","December"] The_Day = 0 Month_Index = 0 while The_Day <= 366 : This_Day = The_Day if This_Day == 0 or This_Day == 31 or This_Day == 60 or This_Day == 91 or This_Day == 121 or This_Day == 152 or This_Day == 182 or This_Day == 213 or This_Day == 244 or This_Day == 274 or This_Day == 305 or This_Day == 335 : The_Radius = Outer_Hecto_Radius - (Outer_Hecto_Radius - Inner_Hecto_Radius) * The_Day/366 strokewidth(My_Line_Width) stroke(Black) if Coloured : stroke(Green) if This_Day <> 0 : Circle (The_Radius) The_Day = The_Day + 1 # ================================================================================================================================= # Draw Month Names # ================================================================================================================================= def Draw_Month_Names() : nofill() strokewidth(My_Line_Width) stroke(0,1,0,.6) The_Months = ["January","February","March","April","May","June","July","August","September","October","November","December"] The_Day = 0 Month_Index = 0 while The_Day <= 366 : This_Day = The_Day if This_Day == 0 or This_Day == 31 or This_Day == 60 or This_Day == 91 or This_Day == 121 or This_Day == 152 or This_Day == 182 or This_Day == 213 or This_Day == 244 or This_Day == 274 or This_Day == 305 or This_Day == 335 : The_Radius = Outer_Hecto_Radius - (Outer_Hecto_Radius - Inner_Hecto_Radius) * The_Day/366 strokewidth(My_Line_Width) stroke(Black) if Coloured : stroke(Green) My_Month = The_Months[Month_Index] Month_Offset_Angle1 = [45.8,44.4,44.7,43.9,43.4,42.2,41,37.8,34.1,33.7,29.8,27.2] Month_Offset_Angle2 = [40.2,38.7,38.8,39.0,37.7,36.7,35.5,33.2,28.9,28.7,24.4,22.1] The_Kol = Black if Coloured : The_Kol = Red Do_Text (My_Month, The_Radius - .5*mm, 180 - Month_Offset_Angle1[Month_Index], True, 0., 0.,"Times-Roman", 11,1,1, 0, The_Kol, color(1,1,1,0), .01, 6) Do_Text (My_Month, The_Radius - .5*mm, 180 + Month_Offset_Angle2[Month_Index], True, 0., 0.,"Times-Roman", 11,1,1, 0, The_Kol, color(1,1,1,0), .01, 6) nofill() Month_Index = Month_Index + 1 The_Day = The_Day + 1 # ================================================================================================================================= # Draw Twinkles, Polygons or Stars # ================================================================================================================================= def Do_Shapes (Which,Shape_Size,Shape_Param1,Shape_Param2, The_Hour,Radius) : 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) elif Which == 3 : The_Shape_Path = Triangles(0.,0., Shape_Size, Shape_Param1) else : The_Shape_Path = PawnBrokers_Balls(0.,0., Shape_Size) stroke(0) strokewidth(My_Line_Width) fill(0) HA_Deg = (The_Hour - 12) * 15 + My_Longitude_Deg + Jan_1_EoT_Tweak HA_Rad = radians(abs(HA_Deg)) HLA_Rad = atan(tan(HA_Rad) * sin(radians(abs(My_Latitude_Deg)))) if (HA_Deg > 90 or HA_Deg < -90): HLA_Rad = HLA_Rad + pi if HA_Deg < 0 : HLA_Rad = -HLA_Rad HLA_Deg = degrees(HLA_Rad) if HLA_Deg == 0 : The_X_Slant_Point = 0.00001 The_Y_Slant_Point = My_Style_Foot_Posn elif (HLA_Deg > 0 and HLA_Deg <= 90) or HLA_Deg <= -90 : The_X_Slant_Point = My_Noon_Gap/2. The_Y_Slant_Point = My_Style_Foot_Posn else: The_X_Slant_Point = -My_Noon_Gap/2. The_Y_Slant_Point = My_Style_Foot_Posn mu_rad = atan2(The_X_Slant_Point, The_Y_Slant_Point) chi_rad = HLA_Rad + mu_rad phi_rad = asin(sqrt((The_X_Slant_Point)**2 + The_Y_Slant_Point**2) * sin(chi_rad) / Radius) theta_rad = phi_rad + chi_rad - mu_rad My_theta_deg = degrees(theta_rad) String_Turn_deg = My_theta_deg # Positive Clockwise #drawpath(The_Shape_Path) # ================================================ # Stetch the Linearized Path & Translate to radius Shifted_Char_Path = [] for point in The_Shape_Path : point.y = point.y - Radius Shifted_Char_Path.append(point) #fill(1,0,0,.1) #drawpath(Shifted_Char_Path) # ================================================ # Circularize the Character to radius Circularize_Char_Path = [] Point_Angle_Store = [] Point_Height_Store = [] for point in Shifted_Char_Path : xx = point.x yy = point.y nu = xx/Radius sinnu = sin(nu) cosnu = cos(nu) point.x = xx - (yy + Radius)* sinnu point.y = -Radius + (yy + Radius)* cosnu Circularize_Char_Path.append(point) Point_Angle_Store.append(degrees(nu)) Point_Height_Store.append(point.y) #fill(0,1,0,.1) #drawpath(Circularize_Char_Path) # ================================================ # Rotate the Circularized Text (e.g. to theta = central Hour Line Angle) Rotated_Char_Path=[] String_Turn_rad = radians(String_Turn_deg) Overall_Char_Turn = String_Turn_rad cosTurn = cos(Overall_Char_Turn) sinTurn = sin(Overall_Char_Turn) for point in Circularize_Char_Path : xx = point.x yy = point.y point.x = xx * cosTurn - yy * sinTurn point.y = xx * sinTurn + yy * cosTurn Rotated_Char_Path.append(point) # ================================================ # Slant the Rotated Text (e.g. to Gnomon Foot) Slanted_Char_Path = [] Num_Pts = 0 for point in Rotated_Char_Path : Ht = Point_Height_Store[Num_Pts] kappa_deg = String_Turn_deg + Point_Angle_Store[Num_Pts] xx = Radius*sin(radians(kappa_deg)) yy = Radius*cos(radians(kappa_deg)) y_dif = -(The_Y_Slant_Point + yy) x_dif = (The_X_Slant_Point - xx) Slope = (y_dif/(x_dif + .00001)) ccc = yy - Slope*xx Switch = 1 if xx < The_X_Slant_Point : Switch = -1 Slope_2 = Slope**2 q = - The_X_Slant_Point + The_Y_Slant_Point * Slope aa = 1 + Slope_2 bb = 2 * Slope * ccc cc = ccc**2 - Ht**2 point.x = (- bb + Switch * sqrt(bb**2 - 4 * aa * cc)) / (2 * aa) point.y = -(Slope * point.x + ccc) Slanted_Char_Path.append(point) Num_Pts = Num_Pts + 1 stroke(Blank) strokewidth(My_Line_Width) fill(0) if Coloured : fill(Red) drawpath(Slanted_Char_Path) # ================================================================================================================================= # Select Appropriate Font # ================================================================================================================================= def Select_Text(The_Text) : 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] return All_Text[The_Text] # ================================================================================================================================= # Draw Hour Lines # ================================================================================================================================= def Draw_Hour_Lines() : The_Hour = Start_Hour while The_Hour <= End_Hour : HA_Deg = (The_Hour - 12) * 15 + My_Longitude_Deg + Jan_1_EoT_Tweak HA_Rad = radians(abs(HA_Deg)) HLA_Rad = atan(tan(HA_Rad) * sin(radians(abs(My_Latitude_Deg)))) if (HA_Deg > 90 or HA_Deg < -90): HLA_Rad = HLA_Rad + pi if HA_Deg < 0 : HLA_Rad = -HLA_Rad HLA_Deg = degrees(HLA_Rad) if HLA_Deg == 0 : The_X_Slant_Point = 0.00001 The_Y_Slant_Point = My_Style_Foot_Posn elif (HLA_Deg > 0 and HLA_Deg <= 90) or HLA_Deg <= -90 : The_X_Slant_Point = My_Noon_Gap/2. The_Y_Slant_Point = My_Style_Foot_Posn else: The_X_Slant_Point = -My_Noon_Gap/2. The_Y_Slant_Point = My_Style_Foot_Posn stroke(Black) if Coloured : stroke(Magenta) Tick(The_Hour * 60., Inner_Hecto_Radius, Outer_Hecto_Radius) The_Hour = The_Hour + 1 # ================================================================================================================================= # Print General Geometry # ================================================================================================================================= def Draw_General_Geom() : nofill() stroke(0) strokewidth(My_Line_Width) Mark(0,0,10,0,Black,.5) stroke(Black) if Coloured: stroke(Red) Circle(Outer_Perimeter_Radius) Circle(Inner_Perimeter_Radius) Circle(Scale_Radius_1_Outer) Circle(Scale_Radius_1_Mid) Circle(Scale_Radius_1_Inner) Circle(Scale_Radius_2_Outer) Circle(Scale_Radius_2_Mid) Circle(Scale_Radius_2_Inner) Circle(Innermost_Circle_Radius) fill(1) rect(-My_Noon_Gap/2, My_Style_Foot_Posn, My_Noon_Gap, -(My_Style_Foot_Posn+ Scale_Radius_1_Outer)) line(-My_Noon_Gap/2, My_Style_Foot_Posn - My_Tongue_Offset,My_Noon_Gap/2, My_Style_Foot_Posn - My_Tongue_Offset) line(-My_Noon_Gap/2, My_Style_Foot_Posn - My_Gnomon_Foot_Lngth,My_Noon_Gap/2, My_Style_Foot_Posn - My_Gnomon_Foot_Lngth) Mark(0,0,10,0,Black,.5) Mark(0,0,10,1,Black,.5) #Mark(-My_Noon_Gap/2, My_Style_Foot_Posn,10,0) #Mark( My_Noon_Gap/2, My_Style_Foot_Posn,10,0) #stroke(Red) #Circle(Big_Number_Radius) #Circle(Small_Number_Radius_1) #Circle(Small_Number_Radius_2) #Circle(Big_Number_Radius) #Circle(Small_Number_Radius_1) #stroke(Black) # ================================================================================================================================= # Print Balls # ================================================================================================================================= def Draw_Balls() : The_Hour = Start_Hour while The_Hour <= End_Hour - 1 : The_Time = The_Hour + 0.5 Do_Shapes (4,1*mm,0.,0., The_Time,13.1*cm) The_Hour = The_Hour + 1 # ================================================================================================================================= # Print Triangles (those not in Scales) # ================================================================================================================================= def Draw_Triangles() : The_Hour = Start_Hour while The_Hour <= End_Hour : The_Time = The_Hour Do_Shapes (3,1.1*mm,True,0., The_Time, Outer_Perimeter_Radius) Do_Shapes (3,1.1*mm,False,0., The_Time, Inner_Perimeter_Radius-1.*mm) Do_Shapes (3,1.1*mm,True,0., The_Time, Scale_Radius_1_Outer+1.*mm) Do_Shapes (3,1.1*mm,False,0., The_Time, Scale_Radius_2_Inner-1*mm) The_Hour = The_Hour + .5 # ================================================================================================================================= # Print Mottos # ================================================================================================================================= def Draw_Mottos() : fill(Black) if Coloured: fill(Blue) Line9 = "KWK delin:" Line10 = "2013" fill(0) nostroke() font(My_Font) fontsize(24) nostroke() fill(Black) LL = 3.1*cm UU =-7*mm Lead = 8*mm Do_Straight_String(MottoL1,-LL, UU) UU = UU + Lead Do_Straight_String(MottoL2,-LL,UU) UU = UU + Lead Do_Straight_String(MottoL3,-LL,UU) UU = UU - 2*Lead Do_Straight_String(MottoR1,LL, UU) UU = UU + Lead Do_Straight_String(MottoR2,LL,UU) UU = UU + Lead Do_Straight_String(MottoR3,LL,UU) # ================================================================================================================================= # Print Instructions # ================================================================================================================================= def Draw_Instructions () : R1 = Outer_Hecto_Radius - (Outer_Hecto_Radius - Inner_Hecto_Radius) * 60/366 R2 = Outer_Hecto_Radius - (Outer_Hecto_Radius - Inner_Hecto_Radius) * 274/366 Shield(R1, R2,112,68,Black,White,My_Line_Width) The_Kol = Black if Coloured : The_Kol = Blue Angl = 180 Text_Lead = 5*mm Rad = R1 - Text_Lead +1.8*mm Do_Text (Inst1, Rad - 4*Text_Lead, Angl, True, 0., 0.,"Times-Roman", 12,1,1, 0, The_Kol, Blank, .01, 10) Do_Text (Inst2, Rad - 3*Text_Lead, Angl, True, 0., 0.,"Times-Roman", 12,1,1, 0, The_Kol, Blank, .01, 10) Do_Text (Inst3, Rad - 2*Text_Lead, Angl, True, 0., 0.,"Times-Roman", 12,1,1, 0, The_Kol, Blank, .01, 10) Do_Text (Inst4, Rad - Text_Lead, Angl, True, 0., 0.,"Times-Roman", 12,1,1, 0, The_Kol, Blank, .01, 10) Do_Text (Inst5, Rad , Angl, True, 0., 0.,"Times-Roman", 12,1,1, 0, The_Kol , Blank, .01, 10) #Do_Text (Inst6, 8.0*cm, 177., True, 0., 0.,"Times-Roman", 9,1,1, 0, Red, Blank, .01, 10) # ================================================================================================================================= # Print Location & People # ================================================================================================================================= def Draw_Location_Etc () : The_Kol = Black if Coloured : The_Kol = Blue Text_Lead = 4*mm Rad = Scale_Radius_1_Outer + Text_Lead Span = 25. Do_Text (Mess1, Rad, 180., True, 0., 0.,"Times-Roman", 11,1,1, 0, The_Kol, Blank, .01, 10) Do_Text (Mess2, Rad + Text_Lead, 180., True, 0., 0.,"Times-Roman", 11,1,1, 0, The_Kol, Blank, .01, 10) Do_Text (Mess3, Rad + 2*Text_Lead, 180., True, 0., 0.,"Times-Roman", 11,1,1, 0, The_Kol, Blank, .01, 10) Do_Text (Mess4, Rad + 3*Text_Lead, 180., True, 0., 0.,"Times-Roman", 11,1,1, 0, The_Kol, Blank, .01, 10) Do_Text (Mess5, Rad + 2*Text_Lead, 180.+Span, True, 0., 0.,"Times-Roman", 11,1,1, 0, The_Kol, Blank, .01, 10) Do_Text (Mess6, Rad + 2*Text_Lead, 180.-Span, True, 0., 0.,"Times-Roman", 11,1,1, 0, The_Kol, Blank, .01, 10) # ================================================================================================================================= # Print Fecit & Date Text # ================================================================================================================================= def Draw_Fecit() : The_Kol = Black if Coloured : The_Kol = Blue Line9 = "KWK delin:" Line10 = "2013" font(My_Font) fill(0) nostroke() font(My_Font) fontsize(10) nostroke() fill(The_Kol) Do_Straight_String(Line9,-4.3*cm, 7*cm) Do_Straight_String(Line10,4.3*cm,7*cm) # ================================================================================================================================= # Draws the Screw Holes # ================================================================================================================================= def Draw_Screws(Screw_Radius): counter = 0 Outer_Screw = 3*mm Inner_Screw = 1*mm push() rotate(22.5) while counter < 8 : stroke(Black) if Coloured : stroke(Red) strokewidth(My_Line_Width) push() translate (Screw_Radius,0) nofill() oval(-Outer_Screw,-Outer_Screw, 2*Outer_Screw, 2*Outer_Screw) fill(Blank) if Coloured : fill(0,0,0,.3) oval(-Inner_Screw,-Inner_Screw, 2* Inner_Screw, 2* Inner_Screw) Mark(0.,0.,16,1,Black,.5) pop() rotate (45) counter = counter + 1 pop() # ================================================================================================================================= # Print Outer Octagons & Screw Holes # ================================================================================================================================= def Draw_Outer_Scenery() : Draw_Octagon(Cutting_Octagon_Radius) Draw_Octagon(Outer_Octagon_Radius) Draw_Octagon(Inner_Octagon_Radius) Draw_Screws(Screw_Radius) # ================================================================================================================================= # Draws Water-jet Cutting Perimeter # ================================================================================================================================= def Cutting_Pattern() : Draw_Octagon(Cutting_Octagon_Radius) fill(1) rect(-My_Noon_Gap/2, My_Style_Foot_Posn - My_Tongue_Offset, My_Noon_Gap, -My_Gnomon_Foot_Lngth) Mark(0,0,10,0,Black,.5) Mark(0,0,10,1,Black,.5) # ================================================================================================================================= # ================================================================================================================================= # ================================================================================================================================= # ================================================================================================================================= # ================================================================================================================================= # ================================================================================================================================= # ================================================================================================================================= # General Routine to 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 # ================================================================================================================================= # General Routine to Transform Text Strings # ================================================================================================================================= #def Do_Text (The_Text, Radius, String_Turn_deg, Upside_Down, The_X_Slant_Point, The_Y_Slant_Point, # The_Font, The_Font_Size,The_X_Stretch,The_Y_Stretch, The_Italics, Kol_Fill, Kol_Stroke, Wid_Stroke, The_Fineness) : # font(The_Font) # fontsize(The_Font_Size) # Char_List = list(The_Text) # if Upside_Down : Char_List.reverse() # letter_x = 0. # for This_Char in Char_List : # letter_x = letter_x - The_X_Stretch * textwidth(This_Char)/2 # for This_Char in Char_List : # char_Len = The_X_Stretch * textwidth(This_Char) # letter_offset = letter_x + char_Len/2 # Char_Turn_rad = letter_offset/Radius # Orig_Char_Path = textpath(This_Char,-textwidth(This_Char)/2,0) # # ================================================ # # Linearize the Curved Character # Line_Char_Path = [] # autoclosepath(close=False) # for point in Orig_Char_Path : # if point.cmd == CURVETO or point.cmd == LINETO : # 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) # else : # curveto(Last_x,Last_y, point.x,point.y, point.x,point.y) # This_Segment = endpath(draw=False) # count = 1 # while count <= The_Fineness : # This_Sub_Segment = This_Segment.point(count/float(The_Fineness)) # This_Sub_Segment.cmd = LINETO # Line_Char_Path.append(This_Sub_Segment) # count = count + 1 # else : # Line_Char_Path.append(point) # Last_x = point.x # Last_y = point.y # # ================================================ # # Stetch the Linearized Path & Translate to radius # Stretch_Char_Path = [] # Signer = 1 # if Upside_Down : Signer = -1 # for point in Line_Char_Path : # point.x = Signer * point.x * The_X_Stretch # point.y = Signer * point.y * The_Y_Stretch - Radius # Stretch_Char_Path.append(point) # # ================================================ # # Italicize the Stretched Path # Italicised_Char_Path = [] # for point in Stretch_Char_Path : # point.x = point.x + (point.y + Radius) * sin(radians(The_Italics)) # Italicised_Char_Path.append(point) # # ================================================ # # Circularize the Character to radius # Circularize_Char_Path = [] # Point_Angle_Store = [] # Point_Height_Store = [] # for point in Italicised_Char_Path : # xx = point.x # yy = point.y # nu = xx/Radius # sinnu = sin(nu) # cosnu = cos(nu) # point.x = xx - (yy + Radius)* sinnu # point.y = -Radius + (yy + Radius)* cosnu # Circularize_Char_Path.append(point) # Point_Angle_Store.append(degrees(nu) + degrees(Char_Turn_rad)) # Point_Height_Store.append(point.y) # # ================================================ # # Rotate the Circularized Text (e.g. to theta = central Hour Line Angle) # Rotated_Char_Path=[] # String_Turn_rad = radians(String_Turn_deg) # Overall_Char_Turn = Char_Turn_rad + String_Turn_rad # cosTurn = cos(Overall_Char_Turn) # sinTurn = sin(Overall_Char_Turn) # for point in Circularize_Char_Path : # xx = point.x # yy = point.y # point.x = xx * cosTurn - yy * sinTurn # point.y = xx * sinTurn + yy * cosTurn # Rotated_Char_Path.append(point) # # ================================================ # # Slant the Rotated Text (e.g. to Gnomon Foot) # if(The_X_Slant_Point <> 0 or The_Y_Slant_Point <> 0) : # Slanted_Char_Path = [] # Num_Pts = 0 # for point in Rotated_Char_Path : # Ht = Point_Height_Store[Num_Pts] # kappa_deg = String_Turn_deg + Point_Angle_Store[Num_Pts] # xx = Radius*sin(radians(kappa_deg)) # yy = Radius*cos(radians(kappa_deg)) # y_dif = -(The_Y_Slant_Point + yy) # x_dif = (The_X_Slant_Point - xx) # Slope = (y_dif/(x_dif + .00001)) # ccc = yy - Slope*xx # Switch = 1 # if xx < The_X_Slant_Point : Switch = -1 # Slope_2 = Slope**2 # q = - The_X_Slant_Point + The_Y_Slant_Point * Slope # aa = 1 + Slope_2 # bb = 2 * Slope * ccc # cc = ccc**2 - Ht**2 # point.x = (- bb + Switch * sqrt(bb**2 - 4 * aa * cc)) / (2 * aa) # point.y = -(Slope * point.x + ccc) # Slanted_Char_Path.append(point) # Num_Pts = Num_Pts + 1 # else: # Slanted_Char_Path = Rotated_Char_Path # strokewidth(Wid_Stroke) # stroke(0) # if Coloured : # stroke (Kol_Stroke) # fill (Kol_Fill) # drawpath (Slanted_Char_Path) # letter_x = letter_x + char_Len def Do_Text(The_Text, Radius, String_Turn_deg, Upside_Down, The_X_Slant_Point, The_Y_Slant_Point, The_Font, The_Font_Size,The_X_Stretch,The_Y_Stretch, The_Italics, Kol_Fill, Kol_Stroke, Wid_Stroke, The_Fineness) : #Draw_Text takes the following parameters… # the Text String # the Turn angle θ in degrees (this is a funtion of style foot position & Hour Line Angle) # inversion of string : True = chars are upside-down # the x position of the Style Foot # the y position of the Style Foot # the font face e.g. 'Times-Roman' # the font size in points # the x stretch factor for the font # the y stretch factor for the font # the degrees of italicization for tht font # the fill colour # ahe stroke colour # the stroke width # the fineness of the Bezier linearization, from 1 upwards (8 is usually very good) font(The_Font) fontsize(The_Font_Size) Char_List = list(The_Text) if Upside_Down : Char_List.reverse() letter_x = 0. for This_Char in Char_List : letter_x = letter_x - The_X_Stretch * textwidth(This_Char)/2 for This_Char in Char_List : char_Len = The_X_Stretch * textwidth(This_Char) letter_offset = letter_x + char_Len/2 Char_Turn_rad = letter_offset/Radius Orig_Char_Path = textpath(This_Char,-textwidth(This_Char)/2,0) # ================================================ # Linearize the Curved Character Line_Char_Path = [] autoclosepath(close=False) for point in Orig_Char_Path : if point.cmd == CURVETO or point.cmd == LINETO : 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) else : curveto(Last_x,Last_y, point.x,point.y, point.x,point.y) This_Segment = endpath(draw=False) count = 1 while count <= The_Fineness : This_Sub_Segment = This_Segment.point(count/float(The_Fineness)) This_Sub_Segment.cmd = LINETO Line_Char_Path.append(This_Sub_Segment) count = count + 1 else : Line_Char_Path.append(point) Last_x = point.x Last_y = point.y # ================================================ # Stetch the Linearized Path & Translate to radius count = 0 Py = 8 Stretch_Char_Path = [] Signer = 1 if Upside_Down : Signer = -1 for point in Line_Char_Path : x0 = point.x y0 = point.y point.x = Signer * x0 * The_X_Stretch point.y = Signer * y0 * The_Y_Stretch - Radius Stretch_Char_Path.append(point) count = count + 1 # ================================================ # Italicize the Stretched Path Italicised_Char_Path = [] for point in Stretch_Char_Path : point.x = point.x + (point.y + Radius) * sin(radians(The_Italics)) Italicised_Char_Path.append(point) count = count + 1 # ================================================ # Circularize the Character to radius Circularize_Char_Path = [] Point_Angle_Store = [] Point_Height_Store = [] count = 0 for point in Italicised_Char_Path : x1 = point.x y1 = point.y x2 = x1 y2 = -sqrt(y1**2-x1**2) alpha = -x2 / Radius beta = atan2(-x2,-y2) gamma = -alpha + beta cosg = cos(gamma) sing = sin(gamma) x3 = x2 * cosg - y2 * sing y3 = x2 * sing + y2 * cosg point.x = x3 point.y = y3 gamma2 = -atan2(x3,Radius) Ht = -sqrt(x3**2 + y3** 2) Circularize_Char_Path.append(point) Point_Angle_Store.append(degrees(-alpha) + degrees(Char_Turn_rad)) Point_Height_Store.append(Ht) count = count + 1 # ================================================ # Rotate the Circularized Text (e.g. to theta = central Hour Line Angle) Rotated_Char_Path=[] count = 0 String_Turn_rad = radians(String_Turn_deg) Overall_Char_Turn = Char_Turn_rad + String_Turn_rad cosTurn = cos(Overall_Char_Turn) sinTurn = sin(Overall_Char_Turn) for point in Circularize_Char_Path : x4 = point.x * cosTurn - point.y * sinTurn y4 = point.x * sinTurn + point.y * cosTurn point.x = x4 point.y = y4 Rotated_Char_Path.append(point) count = count + 1 # ================================================ # Slant the Rotated Text (e.g. to Gnomon Foot) #if False : if(The_X_Slant_Point <> 0 or The_Y_Slant_Point <> 0) : Slanted_Char_Path = [] Num_Pts = 0 count = 0 for point in Rotated_Char_Path : Ht = Point_Height_Store[Num_Pts] kappa_deg = String_Turn_deg + Point_Angle_Store[Num_Pts] xr = Radius*sin(radians(kappa_deg)) yr = Radius*cos(radians(kappa_deg)) y_dif = -(The_Y_Slant_Point + yr) x_dif = (The_X_Slant_Point - xr) Slope = (y_dif/(x_dif + .00001)) ccc = yr - Slope*xr Switch = 1 if xr < The_X_Slant_Point : Switch = -1 Slope_2 = Slope**2 q = - The_X_Slant_Point + The_Y_Slant_Point * Slope aa = 1 + Slope_2 bb = 2 * Slope * ccc cc = ccc**2 - Ht**2 x5 = (- bb + Switch * sqrt(bb**2 - 4 * aa * cc)) / (2 * aa) y5 = -(Slope * x5 + ccc) point.x = x5 point.y = y5 Slanted_Char_Path.append(point) Num_Pts = Num_Pts + 1 count = count + 1 else: Slanted_Char_Path = Rotated_Char_Path letter_x = letter_x + char_Len strokewidth(Wid_Stroke) stroke (Kol_Stroke) fill (Kol_Fill) drawpath (Slanted_Char_Path) # ================================================================================================================================= # 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 # ================================================================================================================================= # General Routine to draw Straight String of Lineated Text # Calls Lineate_Text # ================================================================================================================================= 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() # ================================================================================================================================= # General Routine to draw an Octagon # ================================================================================================================================= def Draw_Octagon(Rad) : push() rotate (22.5) stroke(Black) if Coloured : stroke(Red) strokewidth(My_Line_Width) if not My_Cutting : nofill() else : strokewidth(.3) fill (.95) drawpath(Polygon(0.,0., Rad,8,1)) pop() # ================================================================================================================================= # General Routine to draw Pornbrokers Balls # ================================================================================================================================= def PawnBrokers_Balls(The_x,The_y, Radius) : push() translate(The_x,The_y) Detail_Factor = 10. Rad = Radius * Detail_Factor x1 = 0 y1 = -Rad x2 = .8*Rad *sin(radians(60.)) y2 = Rad *cos(radians(60.)) y2 = 0 x3 = -x2 y3 = y2 x4 = x1 y4 = -y1 path1 = oval(-x1-Rad/2, -y1-Rad/2, Rad, Rad, draw= False) path2 = oval(-x2-Rad/2, -y2-Rad/2, Rad, Rad, draw=False) path3 = oval(-x3-Rad/2, -y3-Rad/2, Rad, Rad, draw=False) path4 = oval(-x4-Rad/2, -y4-Rad/2, Rad, Rad, draw= False) compound = path1.union(path2) compound = compound.union(path3) compound = compound.union(path4) Balls = [] for point in compound : point.x = point.x / Detail_Factor point.y = point.y / Detail_Factor Balls.append(point) pop() return Balls # ================================================================================================================================= # General Routine to draw Triangles # ================================================================================================================================= def Triangles(The_x,The_y, Size,Up_or_Down) : Detail_Factor = 10. Size = Size * Detail_Factor x1 = 0 y1 = 0 x2 = Size * cos(radians(60)) y2 = Size * sin(radians(60)) x3 = -x2 y3 = y2 autoclosepath(close=True) beginpath(x1,y1) lineto (x2,y2) lineto (x3,y3) p = endpath(draw=False) Triangle = [] for point in p : if Up_or_Down : point.x = point.x / Detail_Factor point.y = point.y / Detail_Factor else : point.x = point.x / Detail_Factor point.y = -point.y / Detail_Factor Triangle.append(point) return Triangle # ================================================================================================================================= # General Routine to draw an Instruction Shield # ================================================================================================================================= def Shield(R1,R2,Ang1,Ang2,Kol_Stroke,Kol_Fill,LineTh): A1 = radians(Ang1) A2 = radians(Ang2) beginpath(R1*cos(A1),R1*sin(A1)) z = SmallArc(R1,Ang1,Ang2) curveto(z[2],z[3],z[4],z[5],z[6],z[7]) lineto(R2*cos(A2),R2*sin(A2)) z = SmallArc(R2,Ang2,Ang1) curveto(z[2],z[3],z[4],z[5],z[6],z[7]) autoclosepath(True) p = endpath(draw=False) strokewidth(LineTh) stroke(Kol_Stroke) fill(Kol_Fill) drawpath(p) # ================================================================================================================================= # General Routine to draw a Circle # ================================================================================================================================= def Circle(The_Rad) : Rad2 = 2*The_Rad oval(-The_Rad,-The_Rad,Rad2,Rad2) # ================================================================================================================================= # General Routine to draw a Mark # ================================================================================================================================= def Mark(The_x_Centre,The_y_Centre,Mark_Size,Mark_Orient,Kol,Thick): push() ms = Mark_Size/2 translate(The_x_Centre,The_y_Centre) if (Mark_Orient == 0): line(-ms, -ms, ms, ms, stroke= Kol, strokewidth=Thick) line(-ms, ms, ms, -ms, stroke= Kol, strokewidth=Thick) else: line(-ms,0,ms,0, stroke= Kol, strokewidth=Thick) line(0,-ms,0,ms, stroke= Kol, strokewidth=Thick) pop() # ================================================================================================================================= # General Routine to draw a Circular Arc of < 90° # ================================================================================================================================= def SmallArc(r, a1, a2) : a = (a2 - a1) / 2.0 x4 = r * cos(radians(a)) y4 = r * sin(radians(a)) x1 = x4 y1 = -y4 q1 = x1*x1 + y1*y1 q2 = q1 + x1*x4 + y1*y4 k2 = 4./3. * (sqrt(2 * q1 * q2) - q2) / (x1 * y4 - y1 * x4) x2 = x1 - k2 * y1 y2 = y1 + k2 * x1 x3 = x2 y3 = -y2 ar = a + a1 ar = radians(ar) cos_ar = cos(ar) sin_ar = sin(ar) x1 = r * cos(a1) y1 = r * sin(a1) xx2 = x2 * cos_ar - y2 * sin_ar yy2 = x2 * sin_ar + y2 * cos_ar xx3 = x3 * cos_ar - y3 * sin_ar yy3 = x3 * sin_ar + y3 * cos_ar x4 = r * cos(radians(a2)) y4 = r * sin(radians(a2)) return[x1,y1,xx2,yy2,xx3,yy3,x4,y4] # ================================================================================================================================= # General Routine to draw a Polygon or Star # ================================================================================================================================= 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 # ================================================================================================================================= # Finally, do the Work………… # ================================================================================================================================= My_Text = Select_Text(Which_Text) Draw_All() #push() #translate (My_Noon_Gap/2, My_Style_Foot_Posn) #rotate(208) #stroke(0) #strokewidth(.3) #line(0,0,10*cm,0) #pop() #push() #translate (-My_Noon_Gap/2, My_Style_Foot_Posn) #rotate(338.5) #stroke(0) #strokewidth(.3) #line(0,0,10*cm,0) #pop()