############################################################################
#
#	File:     curves.icn
#
#	Subject:  Procedures to generate points on plain curves
#
#	Author:   Ralph E. Griswold
#
#	Date:     October 1, 1997
#
############################################################################
#
#   This file is in the public domain.
#
############################################################################
#
#  This file links procedure files that generate traces of points on various
#  plain curves.
#
#  The first two parameters determine the defining position of the
#  curve:
#
#	x	x coordinate
#	y	y coordinate
#
#  The meaning of "definition position" depends on the curve.  In some
#  cases it is the position at which plotting starts.  In others, it
#  is a "center" for the curve.
#
#  The next arguments vary and generally refer to parameters of the
#  curve.  There is no practical way to describe these here.  If they
#  are not obvious, the best reference is
#
#	A Catalog of Special Plane Curves, J. Dennis Lawrence,
#	Dover Publications, Inc., New York, 1972.
#
#  This book, which is in print at the time of this writing, is a
#  marvelous source of information about plane curves and is inexpensive
#  as well.
#
#  The trailing parameters give the number of steps and the end points
#  (generally in angles) of the curves:
#  
#	steps	number of points, default varies
#	lo	beginning of plotting range, default varies
#	hi	end of plotting range, default varies
#
#  Because of floating-point roundoff, the number of steps
#  may not be exactly the number specified.
#
#  Note:  Some of the curves may be "upside down" when plotted on
#  coordinate systems in which the y axis increases in a downward direction.
#
#  Caution:  Some of these procedures generate very large values
#  in portions of their ranges.  These may cause run-time errors when
#  used in versions of Icon prior to 8.10.  One work-around is to
#  turn on error conversion in such cases.
#
#  Warning:  The procedures that follow have not been tested thoroughly.
#  Corrections and additions are most welcome.
#
#  These  procedures are, in fact, probably most useful for the parametric
#  equations they contain.
#
############################################################################
#
#  Links:  gobject, math, step
#
############################################################################

link gobject
link math
link step

procedure bullet_nose(x, y, a, b, steps, lo, hi)
   local incr, theta

   /steps := 300
   lo := dtor(\lo) | -&pi
   hi := dtor(\hi) | &pi
   incr := (hi - lo) / steps

   every theta := step(lo, hi, incr) do
      suspend Point(
         x + a * cos(theta),
         y + b * tan(&pi / 2 - theta),
         0
         )

end

procedure cardioid(x, y, a, steps, lo, hi)
   local incr, theta, fact

   /steps := 300
   lo := dtor(\lo) | -&pi
   hi := dtor(\hi) | &pi
   incr := (hi - lo) / steps

   every theta := step(lo, hi, incr) do {
      fact := 2 * a * (1 + cos(theta))
      suspend Point(
         x + cos(theta) * fact,
         y + sin(theta) * fact,
         0
         )
      }

end

procedure cissoid_diocles(x, y, a, steps, lo, hi)
   local incr, theta, radius

   /steps := 300
   lo := dtor(\lo) | (-2 * &pi)
   hi := dtor(\hi) | (2 * &pi)
   incr := (hi - lo) / steps

   every theta := step(lo, hi, incr) do {
      radius := a * sin(theta) * cos(theta)
      suspend Point(
         x + radius * cos(theta),
         y + radius * sin(theta),
         0
         )
      }

end

procedure cross_curve(x, y, a, b, steps, lo, hi)
   local incr, theta

   /steps := 300
   lo := dtor(\lo) | -&pi
   hi := dtor(\hi) | &pi
   incr := (hi - lo) / steps

   every theta := step(lo, hi, incr) do
      suspend Point(
         x + a / cos(theta),
         y + b / sin(theta),
         0
         )

end

procedure cycloid(x, y, a, b, steps, lo, hi)
   local incr, theta

   /steps := 100
   lo := dtor(\lo) | 0
   hi := dtor(\hi) | (8 * &pi)
   incr := (hi - lo) / steps

   every theta := step(lo, hi, incr) do
      suspend Point(
         x + a * theta - b * sin(theta),
         y + a - b * cos(theta),
         0
         )

end

procedure deltoid(x, y, a, steps, lo, hi)
   local incr, theta

   /steps := 300
   lo := dtor(\lo) | -&pi
   hi := dtor(\hi) | &pi
   incr := (hi - lo) / steps

   every theta := step(lo, hi, incr) do
      suspend Point(
         x + a * (2 * cos(theta) + cos(2 * theta)),
         y + a * (2 * sin(theta) - sin(2 * theta)),
         0
         )

end

procedure ellipse(x, y, a, b, steps, lo, hi)
   local incr, theta

   /steps := 300
   lo := dtor(\lo) | -&pi
   hi := dtor(\hi) | &pi
   incr := (hi - lo) / steps

   every theta := step(lo, hi, incr) do
      suspend Point(
         x + a * cos(theta),
         y + b * sin(theta),
         0
         )

end

procedure ellipse_evolute(x, y, a, b, steps, lo, hi)
   local incr, theta

   /steps := 300
   lo := dtor(\lo) | -&pi
   hi := dtor(\hi) | &pi
   incr := (hi - lo) / steps

   every theta := step(lo, hi, incr) do
      suspend Point(
         x + a * cos(theta) ^ 3,
         y + b * sin(theta) ^ 3,
         0
         )

end

procedure epitrochoid(x, y, a, b, h, steps, lo, hi)
   local incr, theta, sum, fact

   /steps := 300
   lo := dtor(\lo) | -&pi
   hi := dtor(\hi) | &pi
   incr := (hi - lo) / steps

   sum := a + b
   fact := sum / b

   every theta := step(lo, hi, incr) do
      suspend Point(
         x + sum * cos(theta) - h * cos(fact * theta),
         y + sum * sin(theta) - h * sin(fact * theta),
         0
         )

end

procedure folium(x, y, a, b, steps, lo, hi)
   local incr, theta, radius

   /steps := 300
   lo := dtor(\lo) | -&pi
   hi := dtor(\hi) | &pi
   incr := (hi - lo) / steps

   every theta := step(lo, hi, incr) do {
      radius := (3 * a * sin(theta) * cos(theta)) /
         (sin(theta) ^ 2 + cos(theta) ^ 2)
      suspend Point(
         x + radius * cos(theta),
         y + radius * sin(theta),
         0
         )
      }

end

procedure hippopede(x, y, a, b, steps, lo, hi)
   local incr, theta, mul

   /steps := 300
   lo := dtor(\lo) | -&pi
   hi := dtor(\hi) | &pi
   incr := (hi - lo) / steps

   every theta := step(lo, hi, incr) do {
      mul := a * b - b ^ 2 * sin(theta) ^ 2
      if mul < 0 then next
      mul := 2 * sqrt(mul)
      suspend Point(
         x + mul *  cos(theta),
         y + mul *sin(theta),
         0
         )
      }

end

procedure kampyle_exodus(x, y, a, b, steps, lo, hi)
   local incr, theta, fact

   /steps := 300
   lo := dtor(\lo) | (-&pi / 2)
   hi := dtor(\hi) | (3 * &pi / 2)
   incr := (hi - lo) / steps

   every theta := step(lo, hi, incr) do {
      fact := a / cos(theta)
      suspend Point(
         x + fact,
         y + fact * tan(theta),
         0
         )
      }

end

procedure kappa(x, y, a, b, steps, lo, hi)
   local incr, theta, fact

   /steps := 300
   lo := dtor(\lo) | 0
   hi := dtor(\hi) | (2 * &pi)
   incr := (hi - lo) / steps

   every theta := step(lo, hi, incr) do {
      fact := a * cos(theta)
      suspend Point(
         x + fact / (0 ~= tan(theta)),
         y + fact,
         0
         )
      }

end

procedure lemniscate_bernoulli(x, y, a, steps, lo, hi)
   local incr, theta, fact

   /steps := 300
   lo := dtor(\lo) | -&pi
   hi := dtor(\hi) | &pi
   incr := (hi - lo) / steps

   every theta := step(lo, hi, incr) do {
      fact := a * cos(theta) / (1 + sin(theta) ^ 2)
      suspend Point(
         x + fact,
         y + fact * sin(theta),
         0
         )
      }

end

procedure lemniscate_gerono(x, y, a, b, steps, lo, hi)
   local incr, theta, fact

   /steps := 300
   lo := dtor(\lo) | -&pi
   hi := dtor(\hi) | &pi
   incr := (hi - lo) / steps

   every theta := step(lo, hi, incr) do {
      fact :=  a * cos(theta)
      suspend Point(
         x + fact,
         y + sin(theta) * fact,
         0
         )
      }

end

procedure limacon_pascal(x, y, a, b, steps, lo, hi)
   local incr, theta, fact

   /steps := 300
   lo := dtor(\lo) | -&pi
   hi := dtor(\hi) | &pi
   incr := (hi - lo) / steps

   every theta := step(lo, hi, incr) do {
      fact := b + 2 * a * cos(theta)
      suspend Point(
         x + fact * cos(theta),
         y + fact * sin(theta),
         0
         )
      }

end

procedure line(x, y, x1, y1, steps)
   local xincr, yincr

   /steps := 100

   xincr := (x1 - x)  / (steps - 1)
   yincr := (y1 - y) / (steps - 1)

   every 1 to steps do {
      suspend Point(x, y, 0)
      x +:= xincr
      y +:= yincr
      }

end

procedure lissajous(x, y, a, b, r, delta, steps, lo, hi)
   local incr, theta

   /steps := 300
   lo := dtor(\lo) | 0
   hi := dtor(\hi) | (16 * &pi)
   incr := (hi - lo) / steps

   r := dtor(r)

   every theta := step(lo, hi, incr) do
      suspend Point(
         x + a * sin(r * theta + delta),
         y + b * sin(theta),
         0
         )

end

procedure nephroid(x, y, a, steps, lo, hi)
   local incr, theta

   /steps := 300
   lo := dtor(\lo) | -&pi
   hi := dtor(\hi) | &pi
   incr := (hi - lo) / steps

   every theta := step(lo, hi, incr) do
      suspend Point(
         x + a * (3 * cos(theta) - cos(3 * theta)),
         y + a * (3 * sin(theta) - sin(3 * theta)),
         0
         )

end

#  Needs to be checked out

procedure parabola(x, y, a, steps, lo, hi)
   local incr, theta, denom, radius

   /steps := 300
   lo := dtor(\lo) | -&pi
   hi := dtor(\hi) | &pi
   incr := (hi - lo) / steps

   every theta := step(lo, hi, incr) do {
      denom := 1 - cos(theta)
      if denom = 0 then next
      radius := 2 * a / denom
      suspend Point(
         radius * cos(theta),
         radius * sin(theta),
         0
         )
      }

end

procedure piriform(x, y, a, b, steps, lo, hi)
   local incr, theta, fact

   /steps := 300
   lo := dtor(\lo) | (-&pi / 2)
   hi := dtor(\hi) | (3 * &pi / 2)
   incr := (hi - lo) / steps

   every theta := step(lo, hi, incr) do {
      fact := 1 + sin(theta)
      suspend Point(
         x + a * fact,
         y + b * cos(theta) * fact,
         0
         )
      }

end

procedure trisectrix_catalan(x, y, a, steps, lo, hi)
   local incr, theta, radius

   /steps := 300
   lo := dtor(\lo) | (-2 * &pi)
   hi := dtor(\hi) | (2 * &pi)
   incr := (hi - lo) / steps

   every theta := step(lo, hi, incr) do {
      radius := a / cos(theta / 3) ^ 3
      suspend Point(
         x + radius * cos(theta),
         y + radius * sin(theta),
         0
         )
      }

end

procedure trisectrix_maclaurin(x, y, a, b, steps, lo, hi)
   local incr, theta, fact

   /steps := 300
   lo := dtor(\lo) | (-&pi / 2)
   hi := dtor(\hi) | (&pi / 2)
   incr := (hi - lo) / steps

   every theta := step(lo, hi, incr) do {
      fact := a * (1 - 4 * cos(theta) ^ 2)
      suspend Point(
         x + fact,
         y + fact * tan(theta),
         0
         )
      }

end

procedure witch_agnesi(x, y, a, steps, lo, hi)
   local incr, theta, fact

   /steps := 300
   lo := dtor(\lo) | (-&pi /2)
   hi := dtor(\hi) | (&pi / 2)
   incr := (hi - lo) / steps

   fact := 2 * a

   every theta := step(lo, hi, incr) do
      suspend Point(
         x + fact * tan(theta),
         y - fact * cos(theta) ^ 2,
         0
         )

end
