planarSundial.frink

Download or view planarSundial.frink in plain text format


// This allows the construction of a planar sundial of any given orientation
// and inclination.
//
// It also draws a scaled horizontal line indicating the size of the gnomon.
//
// See Jean Meeus, Astronomical Algorithms, Chapter 58 for description.

calculatePoint[lat, D, a, z, H, delta] :=
{
   P = calcP[lat, D, a, z]
   Q = sin[D] sin[z] sin[H] + (cos[lat] cos[z] + sin[lat] sin[z] cos[D]) cos[H] + P tan[delta]
   Nx = cos[D] sin[H] - sin[D] (sin[lat] cos[H] - cos[lat] tan[delta])
   Ny = cos[z] sin[D] sin[H] - (cos[lat] sin[z] - sin[lat] cos[z] cos[D]) cos[H] - (sin[lat] sin[z] + cos[lat] cos[z] cos[D]) tan[delta]

   x = a Nx / Q
   y = a Ny / Q

   return [x,y,Q]
}

drawHourAngles[g is graphics, lat, D, a, z] :=
{
   deltas  = [-23.44 deg, -20.15 deg, -11.47 deg, 0 deg, 11.47 deg, 20.15 deg , 23.44 deg]
   Hs = new range[-45 deg, 46 deg, 15 deg]

   for H = Hs
   {
      p = new polyline
      pointFound = false
      for delta = deltas
      {
         sunset = arccos[-tan[lat] tan[delta]]
         // println["sunset is " + format[sunset, "deg", 3]]
         if (H < sunset) and (H > -sunset)
         {
            [x,y,Q] = calculatePoint[lat, D, a, z, H, delta]
            if Q > 0    // Plane illuminated?
            {
               pointFound = true
               p.addPoint[x,-y]
            }
         }
      }

      if pointFound
      {
         g.add[p]
         [x,y] = calculatePoint[lat, D, a, z, H, 23.55 deg]
         time = round[(H/(15 degrees) * hour + 12 hours)/hour, 1]
         // println["H is " + format[H, "deg", 2] + " time is $time "]
         g.font["SansSerif", a/15]
         g.text["$time:00", x, -y, "right", "top"]
      }
   }
}


/*
  Calculate the "center" point of the sundial.  This is not where the gnomon
  is placed, but where the lines for each hour angle converge.
*/

findCenter[lat, D, a, z] :=
{
   P = calcP[lat, D, a, z]
   x0 =  a / P cos[lat] sin[D]
   y0 = -a / P (sin[lat] sin[z] + cos[lat] cos[z] cos[D])

   return [x0, y0]
}

calcP[lat, D, a, z] := sin[lat] cos[z] - cos[lat] sin[z] cos[D]

// Latitude on the Earth where the sundial will be placed.
lat = 40 deg

// Alignment of the face of the sundial with respect to the compass
align = (180-22) deg   // 180 deg = due south, 90 deg = due east

stylusLength = 3

// Alignment of the plane of the sundial
z = 0.1 deg  //  0 deg = horizontal sundial (on floor)
            // 90 deg = vertical sundial (on wall)

// Convert compass alignment to Meeus coordinates.  To convert to/from
// compass coordinates, use (align + 180 deg) mod circle
alignMeeus = (align + 180 deg) mod circle

g = new graphics
drawHourAngles[g, lat, alignMeeus, stylusLength, z]
g.drawEllipseCenter[0,0,stylusLength/100, stylusLength/100]

// Draw the gnomon
g.line[-stylusLength/2, -stylusLength/10, stylusLength/2, -stylusLength/10]

g.show[]


Download or view planarSundial.frink in plain text format


This is a program written in the programming language Frink.
For more information, view the Frink Documentation or see More Sample Frink Programs.

Alan Eliasen was born 19966 days, 4 hours, 24 minutes ago.