Logo Search packages:      
Sourcecode: mathpiper version File versions  Download package

Grapher.java

/* {{{ License.
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */ //}}}

// :indentSize=4:lineSeparator=\n:noTabs=false:tabSize=4:folding=explicit:collapseFolds=0:

package org.mathpiper.ui.gui.worksheets;

import java.awt.*;

public class Grapher
{
      public double xmin, ymin, xmax, ymax;
      String iCallList;
      String execList;
      String token;
      int graphx = 0;
      int graphy = 0;
      int graphWidth = 10;
      int graphHeight = 10;
      int axesFontHeight = 12;
      FontMetrics fontMetrics = null;
      int exampleWidth = 48;

      Grapher(String aCallList)
      {
            xmin = 1e200;
            ymin = 1e200;
            xmax = -xmin;
            ymax = -ymin;
            iCallList = aCallList;
            runCallList(null);
      }


      void nextToken()
      {
            int startPos = 0;
            while (startPos < execList.length() && execList.charAt(startPos) == ' ')
                  startPos++;
            int endPos = startPos;
            while (endPos < execList.length() && execList.charAt(endPos) != ' ')
                  endPos++;
            token = execList.substring(startPos, endPos);
            execList = execList.substring(endPos);
      }


      void runCallList(Graphics g)
      {
            try
            {
                  Graphics2D g2d = null;
                  if (g != null)
                  {
                        if (g instanceof Graphics2D)
                        {
                              g2d = (Graphics2D)g;
                        }
                  }

                  execList = iCallList;
                  nextToken();
                  while (token.length() > 0)
                  {
                        if (token.equals("lines2d"))
                        {
                              int i;
                              nextToken();
                              int nr = Integer.parseInt(token);
                              nextToken();
                              double x2,y2=0;
                              x2 = Float.parseFloat(token);
                              nextToken();
                              y2 = Float.parseFloat(token);
                              if (g == null)
                              {
                                    if (xmin > x2) xmin = x2;
                                    if (xmax < x2) xmax = x2;
                                    if (ymin > y2) ymin = y2;
                                    if (ymax < y2) ymax = y2;
                              }
                              double x1,y1;
                              for (i=1;i<nr;i++)
                              {
                                    x1 = x2;
                                    y1 = y2;
                                    nextToken();
                                    x2 = Float.parseFloat(token);
                                    nextToken();
                                    y2 = Float.parseFloat(token);
                                    if (g == null)
                                    {
                                          if (xmin > x2) xmin = x2;
                                          if (xmax < x2) xmax = x2;
                                          if (ymin > y2) ymin = y2;
                                          if (ymax < y2) ymax = y2;
                                    }
                                    if (g != null)
                                    {
                                          int xPix1 = (int)(graphx + graphWidth * (x1 - xmin) / (xmax - xmin));
                                          int yPix1 = (int)(graphy + graphHeight * (1.0 - (y1 - ymin) / (ymax - ymin)));
                                          int xPix2 = (int)(graphx + graphWidth * (x2 - xmin) / (xmax - xmin));
                                          int yPix2 = (int)(graphy + graphHeight * (1.0 - (y2 - ymin) / (ymax - ymin)));
                                          g.drawLine(xPix1, yPix1, xPix2, yPix2);
                                    }
                              }
                        }
                        else if (token.equals("pencolor"))
                        {
                              nextToken();
                              int red = Integer.parseInt(token);
                              nextToken();
                              int green = Integer.parseInt(token);
                              nextToken();
                              int blue = Integer.parseInt(token);
                              if (g != null)
                              {
                                    g.setColor(new Color(red, green, blue));
                              }
                        }
                        else if (token.equals("pensize"))
                        {
                              nextToken();
                              float width = Float.parseFloat(token);
                              if (g != null)
                              {
                                    if (g2d != null)
                                    {
                                          g2d.setStroke(new BasicStroke(width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
                                    }
                              }
                        }
                        else
                        {
                              //TODO raise an exception here
                              return;
                        }
                        nextToken();
                  }
            }
            catch (Exception e)
            {
                  //TODO handle exception here
            }
      }


      void determineGraphBounds(int xleft, int ytop, Dimension d)
      {
            if (fontMetrics != null)
            {
                  exampleWidth = fontMetrics.stringWidth("100000");
            }
            graphx = xleft + exampleWidth;
            graphy = ytop + axesFontHeight;
            graphWidth = d.width - (3 * exampleWidth) / 2;
            graphHeight = d.height - 3 * axesFontHeight;
      }
      public void paint(Graphics g, int xleft, int ytop, Dimension d)
      {
            Shape clip = g.getClip();
            Rectangle r = clip.getBounds();
            Graphics2D g2d = null;
            if (g instanceof Graphics2D)
            {
                  g2d = (Graphics2D)g;
            }
            if (g2d != null)
            {
                  g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON));
            }
            int clipHeight = d.height;
            if (ytop+clipHeight > r.y+r.height)
            {
                  clipHeight = r.y+r.height-ytop;
            }
            g.setClip(xleft, ytop, d.width, clipHeight);

            // Erase the previous image
            g.setColor(Color.white);
            g.fillRect(xleft, ytop, d.width, d.height);

            Font font;
            font = new Font("Verdana", Font.PLAIN, axesFontHeight);
            g.setFont(font);
            fontMetrics = g.getFontMetrics(font);
            determineGraphBounds(xleft, ytop, d);

            Color grey = new Color(164, 164, 164);

            double x, y;

            PlotRange xRange = new PlotRange(xmin, xmax, d.width / ((3 * exampleWidth) / 2));
            int xtick = ((int)(xmin / xRange.TickSize() - 1));
            if (xRange.TickSize() * xtick < xmin)
                  xtick = xtick + 1;
            double xstart = xRange.TickSize() * xtick;
            {
                  g.setColor(Color.black);
                  for (x = xstart; x <= xmax; x += xRange.TickSize())
                  {
                        int xPix = (int)(graphx + graphWidth * (x - xmin) / (xmax - xmin));
                        g.setColor(grey);
                        g.drawLine(xPix, graphy, xPix, graphy + graphHeight);
                        g.setColor(Color.black);
                        String num = xRange.Format(xtick);
                        int numWidth = fontMetrics.stringWidth(num);
                        g.drawString(num, xPix - numWidth / 2, graphy + graphHeight + fontMetrics.getAscent());
                        xtick++;
                  }

                  PlotRange yRange = new PlotRange(ymin, ymax, d.height / (axesFontHeight * 2));
                  int ytick = ((int)(ymin / yRange.TickSize() - 1));
                  if (yRange.TickSize() * ytick < ymin)
                        ytick = ytick + 1;
                  double ystart = yRange.TickSize() * ytick;
                  for (y = ystart; y <= ymax; y += yRange.TickSize())
                  {
                        int yPix = (int)(graphy + graphHeight * (ymax - y) / (ymax - ymin));
                        g.setColor(grey);
                        g.drawLine(graphx, yPix, graphx + graphWidth, yPix);
                        g.setColor(Color.black);
                        String num = yRange.Format(ytick);
                        int numWidth = fontMetrics.stringWidth(num);
                        g.drawString(num, graphx - numWidth - 8, yPix + fontMetrics.getAscent() - (axesFontHeight) / 2);
                        ytick++;
                  }
            }

            int graphClipHeight = graphHeight;
            if (graphy+graphClipHeight > r.y+r.height)
            {
                  graphClipHeight = r.y+r.height-graphy;
            }

            g.setClip(graphx,graphy,graphWidth,graphClipHeight);
            runCallList(g);
            g.setClip(xleft, ytop, d.width, clipHeight);
            g.setColor(Color.black);
            if (g2d != null)
            {
                  g2d.setStroke(new BasicStroke(3.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
            }
            g.drawRect(graphx, graphy, graphWidth, graphHeight);
            g.setClip(clip);
      }



      /*
       * Determine the ticks of the graph. The calling routine should first determine the minimum and maximum values, and
       * the number of steps (based on size of the axis to draw relative to font size).
       * 
       * Steps will always be m*10^n, for some suitable n, with m either 1, 2 or 5.
       */
      class PlotRange
      {
            public PlotRange(double aMinValue, double aMaxValue, int aMaxSteps)
            {
                  iMinValue = aMinValue;
                  iMaxValue = aMaxValue;
                  iMaxSteps = aMaxSteps;

                  //TODO handle zero length range
                  double range = aMaxValue - aMinValue;
                  iN = (int)(Math.log(range) / Math.log(10) - 1);
                  iN = iN - 1;
                  iStep = 1;
                  for (; ; )
                  {
                        double tickSize = TickSize();
                        int nrSteps = (int)(range / tickSize);
                        if (nrSteps <= aMaxSteps)
                              break;
                        switch (iStep)
                        {
                        case 1:
                              iStep = 2;
                              break;
                        case 2:
                              iStep = 5;
                              break;
                        case 5:
                              iN++;
                              iStep = 1;
                              break;
                        }
                  }
            }
            public double TickSize()
            {
                  return iStep * Math.pow(10, iN);
            }

            public String Format(int tick)
            {
                  String result = "";
                  int fct = tick * iStep;
                  if (iN >= 0 && iN < 3)
                  {
                        if (iN > 0)
                              fct = fct * 10;
                        if (iN > 1)
                              fct = fct * 10;
                        result = "" + fct;
                  }
                  else
                  {
                        int n = iN;
                        if (fct == 10 * (fct / 10))
                        {
                              fct /= 10;
                              n += 1;
                        }
                        String ex = "";
                        if (n != 0 && tick != 0)
                              ex = "e" + n;
                        result = "" + fct + ex;
                  }
                  return result;
            }

            double iMinValue;
            double iMaxValue;
            int iMaxSteps;

            public int iN;
            public int iStep;
      }

}

Generated by  Doxygen 1.6.0   Back to index