/* Class Grapher draws simple 2D-functions.
 * The class in drawj2d.yacas is derived from yacas.sourceforge.net (2014-2015)
 *
 * Copyright (C) 2007-2015 Ayal Pinkus

 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * The license is in COPYING.
 * If not,see http://www.gnu.org/licenses/old-licenses/lgpl-2.1.
 */


package net.sf.drawj2d.yacas;

import java.awt.*;

public class Grapher
{

    /**
     *
     * @param aCallList
     */
    public Grapher(String aCallList)
  {
    SetupCallList(aCallList);
  }

  public void SetupCallList(String aCallList)
  {
    xmin = 1e200;
    ymin = 1e200;
    xmax = -xmin;
    ymax = -ymin;
    iCallList = aCallList;
    RunCallList(null);
  }

  String execList;
  String token;
  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 DetermineBounds(double x, double y)
  {
    if (xmin > x) xmin = x;
    if (xmax < x) xmax = x;
    if (ymin > y) ymin = y;
    if (ymax < y) ymax = y;
  }
  int ProjectX(double x)
  {
    return (int)(graphx + graphWidth * (x - xmin) / (xmax - xmin));
  }
  int ProjectY(double y)
  {
    return (int)(graphy + graphHeight * (1.0 - (y - ymin) / (ymax - ymin)));
  }

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

      Color penColor = new Color(0,0,0);
      Color fillColor = new Color(0,0,0);
      if (g != null)
      {
        g.setColor(penColor);
      }
      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)
          {
            DetermineBounds(x2, y2);
          }
          double x1,y1;
          for (i=1;i 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 (r != null)
    {
      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);
  }

  public double xmin, ymin, xmax, ymax;
  String iCallList;



  /*
   * 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;
  }

}

 

Ads help maintain this website.