planarSundial.frink

View or download 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[-60 deg, 61 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, "center", "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 = (270-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[]


View or download 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 19093 days, 18 hours, 43 minutes ago.