simplegraph5.frink

Download or view simplegraph5.frink in plain text format


// This is a simple but rather interesting program that graphs equations.
// You enter equations in terms of x and y, something like one of the
// following:
//
//  y = sin[x]
//
//  x^2 + y^2 = 81
//
//  y cos[x] = x sin[y]
//
// This version of the program can also graph INEQUALITIES, which have
// less-than or greater-than symbols instead of just equals.
//
// For example, try
//
// abs[y^2 + x^4 - 1] < cos[x]
// 
// This uses a recursive method to subdivide and test rectangles.
//
// This version of the program adds automatic generation of grid lines and
// axis labels using the Grid.frink sample library.

use Grid.frink

lasteq = ""

// If there are arguments to the program, graph them, otherwise prompt.
while func = (length[ARGS] > 0 ? ARGS@0 : input["Enter equation: ", lasteq])
{
   hasInequality = false
   certEq = undef
   lasteq = certFunc = func

   g = new graphics

   // If there's an inequality, let's make a test equation to see if we can
   // plot an entire rectangle using the "CERTAINLY" comparators.
   if func =~ %r/([<>]|!=)/
   {
      hasInequality = true
//      g.antialiased[false]
      certFunc =~ %s/<=/ CLE /g  // Replace <= with certainly less than or equals
      certFunc =~ %s/>=/ CGE /g  // Replace >= with certainly greater than or equals
      certFunc =~ %s/</ CLT /g   // Replace <  with certainly less than
      certFunc =~ %s/>/ CGT /g   // Replace >  with certainly greater than
      certFunc =~ %s/!=/ CNE /g   // Replace = with certainly not equals
      certFunc =~ %s/=/ CEQ /g   // Replace = with certainly equals
      certEq = parseToExpression[certFunc]
   }

   // These replacements turn normal comparator and equality tests into
   // "POSSIBLY EQUALS" tests.
   func =~ %s/<=/ PLE /g  // Replace <= with possibly less than or equals
   func =~ %s/>=/ PGE /g  // Replace >= with possibly greater than or equals
   func =~ %s/</ PLT /g   // Replace <  with possibly less than
   func =~ %s/>/ PGT /g   // Replace >  with possibly greater than
   func =~ %s/!=/ PNE /g   // Replace = with possibly not equals
   func =~ %s/=/ PEQ /g   // Replace = with possibly equals
   eq = parseToExpression[func]

   println[func]

   xmin = -10
   xmax = 10
   ymin = -10
   ymax = 10

   doublings = 12
   
   // Change the last number to vary the resolution.  This is the number
   // of doublings, so if the number is 10 we have 2^10=1024 doublings for
   // a resolution of 1024x1024.
   testRect[xmin, xmax, ymin, ymax, g, eq, certEq, doublings]

   grid = new Grid
   grid.auto[g]
   g.add[grid.getGrid[]]

   g.show[]
   g.write["graph5.png",2^doublings, 2^doublings]
   g.write["graph5.svg",2^doublings, 2^doublings]

   if length[ARGS] > 0
      exit[]
}

// Recursive function to test an interval containing the specified bounds.
// If no possible solution exists, the recursion halts.  If a possible solution
// exists, this breaks it down into 4 sub-rectangles and tests each of them
// recursively.  level is the maximum number of levels to split, so the total
// resolution of the final graph will be 2^level.
testRect[x1, x2, y1, y2, g, eq, certEq, level] :=
{
   nextLevel = level - 1
   x = new interval[x1, x2]
   y = new interval[y1, y2]
   
   // Test the rectangle.  If it possibly contains solutions, recursively
   // subdivide.
   res = eval[eq]
   
   if res or res==undef
   {
      if (nextLevel >= 0)
      {
         if (certEq != undef)  // Do we have inequalities and a CERTAINLY test?
            certRes = eval[certEq]
         if certRes == true
         {
            // If the entire rectangle is a solution, then fill the rectangle
            // and stop further recursion on this rectangle.
            g.fillRectSides[x1, -y1, x2, -y2]
            return
         }

         // Further subdivide the rectangle into 4 quadrants and recursively
         // test them all
         cx = (x1 + x2)/2
         cy = (y1 + y2)/2
         testRect[x1, cx, y1, cy, g, eq, certEq, nextLevel]
         testRect[cx, x2, y1, cy, g, eq, certEq, nextLevel]
         testRect[x1, cx, cy, y2, g, eq, certEq, nextLevel]
         testRect[cx, x2, cy, y2, g, eq, certEq, nextLevel]
      } else
           if (res)             // Valid point
              g.fillRectSides[x1, -y1, x2, -y2]
           else
           {
              // Error in evaluating point, plot in red.
              g.color[1,0,0]
              g.fillRectSides[x1, -y1, x2, -y2]
              g.color[0,0,0]
           }
   }
}


Download or view simplegraph5.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, 9 hours, 12 minutes ago.