//******************************************************** // Horizontal Sundial // Sundial Design by First Principles // Robert L. Kellogg, Ph.D. // 15 Feb 2016 - 9 Oct 2021 // // This licensed as part of the creative commons //******************************************************** // Note: base units are in mm and angles as degrees // This procedure draws a horizontal sundial for most // mid-latitude sites (~20 to 66 deg) either for // north or southern hemisphere (see latitude below) // Define constants and parameters echo("version=",1.0); //Digital Gnomon software version pi= 3.14159265358979323846; //value of pi ToDeg = 180/pi; //radians to degrees ToRad = pi/180; //degrees to radians octagon1 = 78/2; //dial base(~3") mm octagon2 = 75/2; //dial base (taper top) mm depth = 3; //dial base depth mm cdepth = .6; //hour line cut raise mm cwidth = 1; //hour line cut width mm crad = 20; //hour line inner radius mm chour = 6; //hour line length mm chalf = 4; //half hour line length mm gbase = 25; //gnomon base y-length mm gwidth = 1.5; //gnomon width mm goffset = -10; //gnomon offset mm tbase = 0.75*gbase; //gnomon brace length mm twide = 6.5; //gnomon brace height mm // ---------------------------------------------------- // These are the only parameters you need to change latitude = 40.0; //dial latitude deg name = "NASS-2021"; //name on dial place = "Philadelphia"; //place on dial echo("Lat",latitude); echo("Name",name); echo("Place",place); bottom = true; //First Pinciples on bottom // Font parameters dialNrs = "Angsana:style=Bold"; dialFont = "Calibri:style=Bold"; //"Aharoni:style=Bold" dialNameSize= 6; //use 6 for most // ---------------------------------------------------- $fa=45; //create hour & half hour lines for(H = [5:19]) { HA = 15*(H-12); w = gwidth/2; if(H>12) cut_hour_line(chour,HA, w); //hour line else cut_hour_line(chour,HA,-w); //hour line } for(H = [5.5:18.5]) { HA = 15*(H-12); w = gwidth/2; if(H>12) cut_hour_line(chalf,HA,w); //half hour line else cut_hour_line(chalf,HA,-w); //half hour line } for(H = [5:19]){ HA = 15*(H-12); w = gwidth/2; if(H>12) draw_hour_number(chalf,HA,H-12,w); //hour line number else draw_hour_number(chour,HA,H,-w); //hour line number } //create base and gnomon sbase = crad +chour - goffset; style = sbase*cos(latitude); p = sbase*abs(sin(latitude)); extra = p*tan(23.5); gtop = (style+1.6*extra)*cos(latitude); difference(){ union(){ //base rotate([0,0,45/2]) cylinder(h=depth,r1=octagon1,r2=octagon2,center=false); //gnomon if(abs(latitude)>48) create_gnomon(gtop+2); else create_gnomon(gtop); } if (bottom==true){ //cut out logo on bottom engrave_logo(); } } //create text embossed_text(name,place); //------------------------------------------------------------- //------------------------------------------------------------- //create hour or half hour line module cut_hour_line(clen,HA,w){ //classic angle theta = atan2(sin(latitude)*sin(HA),cos(HA)); //account for gnomon with width bo = -2*goffset*cos(theta); co = goffset*goffset - crad*crad; //now need distance r1 = abs((-bo -sqrt(bo*bo-4*co))/2); //width offset //create hour line translate([w,goffset,0]) rotate([0,0,90-theta]) translate([r1,-cwidth/2,depth]) cube(size=[clen,cwidth,cdepth], center = false); } module draw_hour_number(clen,HA,H,w){ //classic angle txt3 = str(H); theta = atan2(sin(latitude)*sin(HA),cos(HA))+1; //account for gnomon with width bo = -2*goffset*cos(theta); co = goffset*goffset - crad*crad; //now need distance r3 = 1.1*chour+1.15*abs((-bo -sqrt(bo*bo-4*co))/2); //create hour line x1 = r3*sin(theta-1)+0.5+w; y1 = r3*cos(theta-1)+goffset-3; translate([x1,y1,depth]) linear_extrude(height = cdepth) text(txt3, size = 4.5, halign = "center",font=dialNrs, $fn = 16); } module create_gnomon(gtop) { x1 = 0; y1 = goffset+gbase; x2 = 0; y2 = goffset; x3 = abs(gtop*tan(latitude)); y3 = goffset+gtop; //draw gnomon, perform minkowski rounding, trim bottom $fa=5; $fn=120; difference(){ difference(){ translate([gwidth/2,-(depth+cwidth)*abs(sin(latitude)),-depth/2]) rotate([0,-90,0]) minkowski(){ linear_extrude(height=gwidth,center = true,convexity = 10) polygon(points=[[x1,y1],[x2,y2],[x3,y3]]); cylinder(r=2, h=gwidth); } translate([-5,-gbase,-5]) cube(size=[10,2*gbase,5],center=false); } translate([0,1.3*gbase,2]) rotate([0,90,0]) cylinder(r=20, h=20,center=true); } //create gnomon brace p1 = 0; q1 = twide; p2 = -twide; q2 = 0; p3 = twide; q3 = 0; tshift = abs((twide)/tan(latitude))+1.4*goffset; translate([0,tshift,0]) rotate([90,0,180]) linear_extrude(height=tbase-.5,center=false) polygon(points=[[p1,q1],[p2,q2],[p3,q3]]); //create 12-noon mark translate([-gwidth/2,crad,depth/2]) cube(size=[1.5*gwidth,chour,2*cdepth], center = false); } module embossed_text(name,place){ //create embossed text lat = floor(latitude*10+.5)/10; txt1 = str(lat); translate([5,-.1*gbase,0]) linear_extrude(height = depth+cdepth) text(txt1, size = 4.5, font = str("Calibri:style=Bold"), $fn = 16); txt2 = "Lat"; translate([-17,-.1*gbase,depth]) linear_extrude(height = cdepth) text(txt2, size = 5, font = dialFont, $fn = 16); if (len(place)>0){ //then both name and place translate([0, -0.92*gbase,depth]) linear_extrude(height = cdepth) text(name, size = 5, halign="center",font = dialFont, $fn = 16); }else { //only name ... recenter translate([0, -1.10*gbase,depth]) linear_extrude(height = cdepth) text(name, size = dialNameSize, halign="center",font = dialFont, $fn = 16); } translate([0,-1.15*gbase,depth]) linear_extrude(height = cdepth) text(place, size = 5, halign="center",font = dialFont, $fn = 16); } module engrave_logo(){ txt1 = "First Principles"; txt2 = "rkellogg@comcast.net"; txt3 = "2021"; union(){ translate([0, octagon1/3,cdepth]) rotate([180,0,180]) linear_extrude(height = 2*cdepth,center=true) text(txt1, size = 4, halign="center",font = dialFont, $fn = 16); translate([0,-10,cdepth]) rotate([180,0,180]) linear_extrude(height = 2*cdepth, center=true) text(txt2, size = 3.5, halign="center",font = dialFont, $fn = 16); translate([0, -octagon1/3-4,0]) rotate([180,0,180]) linear_extrude(height = 2*cdepth, center=true) text(txt3, size = 3.5, halign="center",font = dialFont, $fn = 16); } }