public void draw(Graphics g) {
    animate();

    g.setColor(Color.black);
    g.fillRect(0, 0, dim.width, dim.height);
    g.setColor(Color.white);

    numpaint++;
    DebugPrinter dbg = new DebugPrinter(g, 50, 60);
    dbg.print(
        "Spring-mass demo by yigal irani, drag balls or create new ones by clicking inside box");
    dbg.print("frame", numpaint);
    dbg.print("fps", 1 / timer.time_diff);

    Point top_left = point_by_vec(new Vec(-1, 1));
    g.draw3DRect(top_left.x, top_left.y, screen_dist(2), screen_dist(2), true);
    for (int i = 0; i < springs.size(); i++) {
      Spring spring = springs.get2(i);
      Point p1 = point_by_vec(balls.get2(spring.start).pos);
      Point p2 = point_by_vec(balls.get2(spring.end).pos);
      g.drawLine(p1.x, p1.y, p2.x, p2.y);
    }
    for (int i = 0; i < balls.size(); i++) {
      Ball ball = balls.get2(i);
      Point p = point_by_vec(ball.pos);
      int screen_radius = screen_dist(RADIUS);
      g.setColor(Color.blue);
      g.fillOval(p.x - screen_radius, p.y - screen_radius, screen_radius * 2, screen_radius * 2);

      g.setColor(Color.white);
      g.drawOval(p.x - screen_radius, p.y - screen_radius, screen_radius * 2, screen_radius * 2);

      g.drawString("" + i, p.x, p.y);
    }
  }
Example #2
0
  public void label(Graphics g, String var, double m, String units, int adj) {
    g.setColor(Color.black);
    g.setFont(font);
    String s = format.format(m);

    g.drawString(var + ": " + s, x + 5, y + h / 2 - 5);
    g.drawString(units, x + w - adj, y + h / 2 - 5);
  }
Example #3
0
 protected void paintComponent(Graphics g) {
   super.paintComponent(g);
   if (model != null) {
     newImgBuf(); // refresh the image buffer if necessary
     // compute the real-to-screen ratio, this variable differs
     // from model.real2Screen by zoomScale
     Dimension sz = getSize();
     double real2Screen0 = model.getScaleFromSpan(realSpan, sz.width, sz.height);
     model.setMatrix(viewMatrix, real2Screen0 * zoomScale, sz.width / 2, sz.height / 2);
     imgG.setColor(Color.BLACK);
     imgG.fillRect(0, 0, sz.width, sz.height);
     model.paint(imgG);
     g.drawImage(img, 0, 0, this);
   }
 }
Example #4
0
 void drawLine(Graphics g, DrawObject L) {
   if (L == null) {
     return;
   }
   if ((sequencingOn) && (L.sequenceNum != currentSequenceNumDisplay)) {
     return;
   }
   Graphics2D g2 = (Graphics2D) g;
   g2.setStroke(L.drawStroke);
   int x1 = (int) ((L.x - minX) / (maxX - minX) * (D.width - 2 * inset));
   int y1 = (int) ((L.y - minY) / (maxY - minY) * (D.height - 2.0 * inset));
   int x2 = (int) ((L.x2 - minX) / (maxX - minX) * (D.width - 2 * inset));
   int y2 = (int) ((L.y2 - minY) / (maxY - minY) * (D.height - 2.0 * inset));
   if (L.isArrow) {
     drawArrow(
         (Graphics2D) g,
         inset + x1,
         D.height - y1 - inset,
         inset + x2,
         D.height - y2 - inset,
         1.0f,
         L.drawStroke);
   } else {
     g.drawLine(inset + x1, D.height - y1 - inset, inset + x2, D.height - y2 - inset);
   }
 }
 public static void drawLine(Graphics g, int x1, int y1, int x2, int y2, int lineWidth) {
   if (lineWidth == 1) g.drawLine(x1, y1, x2, y2);
   else {
     double angle;
     double halfWidth = ((double) lineWidth) / 2.0;
     double deltaX = (double) (x2 - x1);
     double deltaY = (double) (y2 - y1);
     if (x1 == x2) angle = Math.PI;
     else angle = Math.atan(deltaY / deltaX) + Math.PI / 2;
     int xOffset = (int) (halfWidth * Math.cos(angle));
     int yOffset = (int) (halfWidth * Math.sin(angle));
     int[] xCorners = {x1 - xOffset, x2 - xOffset + 1, x2 + xOffset + 1, x1 + xOffset};
     int[] yCorners = {y1 - yOffset, y2 - yOffset, y2 + yOffset + 1, y1 + yOffset + 1};
     g.fillPolygon(xCorners, yCorners, 4);
   }
 }
 public static void drawArrow(Graphics g, int x1, int y1, int x2, int y2, int lineWidth) {
   // Draw line using user defined drawline() which can specify line width
   drawLine(g, x1, y1, x2, y2, lineWidth);
   // Calculate x-y values for arrow head
   calcValues(x1, y1, x2, y2);
   g.fillPolygon(xValues, yValues, 3);
 }
Example #7
0
 void drawPoint(Graphics g, DrawObject p) {
   if (p == null) {
     return;
   }
   if ((sequencingOn) && (p.sequenceNum != currentSequenceNumDisplay)) {
     return;
   }
   int x = (int) ((p.x - minX) / (maxX - minX) * (D.width - 2 * inset));
   int y = (int) ((p.y - minY) / (maxY - minY) * (D.height - 2.0 * inset));
   if (p.diameter > 1) {
     int r = p.diameter / 2;
     g.fillOval(inset + x - r, D.height - y - inset - r, 2 * r, 2 * r);
   } else {
     g.fillRect(inset + x, D.height - y - inset, 1, 1);
   }
 }
Example #8
0
 /** This internal method begins a new line */
 protected void newline() {
   charnum = 0; // Reset character number to 0
   linenum++; // Increment line number
   if (linenum >= lines_per_page) { // If we've reached the end of the page
     page.dispose(); //    send page to printer
     page = null; //    but don't start a new page yet.
   }
 }
Example #9
0
 void drawLabel(Graphics g, DrawObject L) {
   if ((sequencingOn) && (L.sequenceNum != currentSequenceNumDisplay)) {
     return;
   }
   int x = (int) ((L.x - minX) / (maxX - minX) * (D.width - 2 * inset));
   int y = (int) ((L.y - minY) / (maxY - minY) * (D.height - 2.0 * inset));
   g.drawString(L.str, inset + x, D.height - y - inset);
 }
Example #10
0
  /**
   * Draw a ball at screen coordinate (x, y) with a ball index `id' (0, 0) represents the top-left
   * corner `x', `y', `radius' are given in pixels the ball index (gray code) `id' can be 0 to 15
   */
  void paint(Graphics gc, int x, int y, int id, double radius) {
    if (balls == null) makeBalls();
    Image img = balls[id]; // id = [0..15]

    int size = (int) (radius * 2 + .5);
    gc.drawImage(img, x - size / 2, y - size / 2, size, size, null);
    // System.out.println("" + x + " " + y + " " + id + " " + radius);
  }
Example #11
0
 void drawImage(Graphics g, DrawObject I) {
   if ((sequencingOn) && (I.sequenceNum != currentSequenceNumDisplay)) {
     return;
   }
   for (int i = 0; i < I.pixels.length; i++) {
     for (int j = 0; j < I.pixels[i].length; j++) {
       Color c = new Color(I.pixels[i][j][1], I.pixels[i][j][2], I.pixels[i][j][3]);
       g.setColor(c);
       // Note: i starts at the top row of the image.
       int x = j; // x along the x-axis is the column coord of pixels
       int y = I.pixels[i].length - i;
       int x1 = (int) ((x - minX) / (maxX - minX) * (D.width - 2 * inset));
       int y1 = (int) ((y - minY) / (maxY - minY) * (D.height - 2.0 * inset));
       int x2 = (int) ((x + 1 - minX) / (maxX - minX) * (D.width - 2 * inset));
       int y2 = (int) ((y - 1 - minY) / (maxY - minY) * (D.height - 2.0 * inset));
       g.fillRect(inset + x1, D.height - y1 - inset, x2 - x1, y1 - y2);
     }
   }
 }
    @Override
    protected void paintComponent(Graphics g) {

      super.paintComponent(g);

      if (resourceImage != null) {

        g.drawImage(resourceImage, 1, 1, this);
      }
    }
Example #13
0
 /**
  * Prepare a buffer for the image, return if the canvas is ready Only need to call this when the
  * size of the canvas is changed, Since we automatically detect the size change in paint() only
  * call this on start
  */
 public boolean newImgBuf() {
   Dimension sz = getSize();
   if (sz.width == 0 || sz.height == 0) return false;
   // quit if the current image already has the right size
   if (img != null && imgG != null && sz.equals(imgSize)) return true;
   img = createImage(sz.width, sz.height);
   if (imgG != null) imgG.dispose();
   imgG = img.getGraphics();
   imgSize = sz;
   return true;
 }
Example #14
0
 void drawOvalOrRectangle(Graphics g, DrawObject R, boolean isRect) {
   if (R == null) {
     return;
   }
   if ((sequencingOn) && (R.sequenceNum != currentSequenceNumDisplay)) {
     return;
   }
   Graphics2D g2 = (Graphics2D) g;
   g2.setStroke(R.drawStroke);
   int x1 = (int) ((R.x - minX) / (maxX - minX) * (D.width - 2 * inset));
   int y1 = (int) ((R.y - minY) / (maxY - minY) * (D.height - 2.0 * inset));
   double x = R.x + R.width;
   double y = R.y - R.height;
   int x2 = (int) ((x - minX) / (maxX - minX) * (D.width - 2 * inset));
   int y2 = (int) ((y - minY) / (maxY - minY) * (D.height - 2.0 * inset));
   if (isRect) {
     g.drawRect(inset + x1, D.height - y1 - inset, x2 - x1, y1 - y2);
   } else {
     g.drawOval(inset + x1, D.height - y1 - inset, x2 - x1, y1 - y2);
   }
 }
Example #15
0
 /**
  * Set the font style. The argument should be one of the font style constants defined by the
  * java.awt.Font class. All subsequent output will be in that style. This method relies on all
  * styles of the Monospaced font having the same metrics.
  */
 public void setFontStyle(int style) {
   synchronized (this.lock) {
     // Try to set a new font, but restore current one if it fails
     Font current = font;
     try {
       font = new Font("Monospaced", style, fontsize);
     } catch (Exception e) {
       font = current;
     }
     // If a page is pending, set the new font.  Otherwise newpage() will.
     if (page != null) page.setFont(font);
   }
 }
 /**
  * Paint the glyphs for the given view. This is implemented to only render if the Graphics is of
  * type Graphics2D which is required by TextLayout (and this should be the case if running on the
  * JDK).
  */
 public void paint(GlyphView v, Graphics g, Shape a, int p0, int p1) {
   if (g instanceof Graphics2D) {
     Rectangle2D alloc = a.getBounds2D();
     Graphics2D g2d = (Graphics2D) g;
     float y = (float) alloc.getY() + layout.getAscent() + layout.getLeading();
     float x = (float) alloc.getX();
     if (p0 > v.getStartOffset() || p1 < v.getEndOffset()) {
       try {
         // TextLayout can't render only part of it's range, so if a
         // partial range is required, add a clip region.
         Shape s = v.modelToView(p0, Position.Bias.Forward, p1, Position.Bias.Backward, a);
         Shape savedClip = g.getClip();
         g2d.clip(s);
         layout.draw(g2d, x, y);
         g.setClip(savedClip);
       } catch (BadLocationException e) {
       }
     } else {
       layout.draw(g2d, x, y);
     }
   }
 }
Example #17
0
 /* paint() - get current time and draw (centered) in Component. */
 public void paint(Graphics g) {
   Calendar myCal = Calendar.getInstance();
   StringBuffer sb = new StringBuffer();
   sb.append(tf.format(myCal.get(Calendar.HOUR)));
   sb.append(':');
   sb.append(tflz.format(myCal.get(Calendar.MINUTE)));
   sb.append(':');
   sb.append(tflz.format(myCal.get(Calendar.SECOND)));
   String s = sb.toString();
   FontMetrics fm = getFontMetrics(getFont());
   int x = (getSize().width - fm.stringWidth(s)) / 2;
   // System.out.println("Size is " + getSize());
   g.drawString(s, x, 10);
 }
Example #18
0
 void drawScribbles(Graphics g) {
   if ((scribbles == null) || (scribbles.size() == 0)) {
     return;
   }
   DrawObject L = (DrawObject) scribbles.get(0);
   int scribbleCounter = L.scribbleNum;
   g.setColor(scribbleColor);
   ((Graphics2D) g).setStroke(new BasicStroke(2f));
   int prevX = L.scribbleX;
   int prevY = L.scribbleY;
   for (int i = 1; i < scribbles.size(); i++) {
     L = (DrawObject) scribbles.get(i);
     if (L.scribbleNum == scribbleCounter) {
       // Keep drawing.
       g.drawLine(prevX, prevY, L.scribbleX, L.scribbleY);
       prevX = L.scribbleX;
       prevY = L.scribbleY;
     } else {
       scribbleCounter = L.scribbleNum;
       prevX = L.scribbleX;
       prevY = L.scribbleY;
     }
   }
 }
Example #19
0
  /**
   * This is the write() method of the stream. All Writer subclasses implement this. All other
   * versions of write() are variants of this one
   */
  public void write(char[] buffer, int index, int len) {
    synchronized (this.lock) {
      // Loop through all the characters passed to us
      for (int i = index; i < index + len; i++) {
        // If we haven't begun a page (or a new page), do that now.
        if (page == null) newpage();

        // If the character is a line terminator, then begin new line,
        // unless it is a \n immediately after a \r.
        if (buffer[i] == '\n') {
          if (!last_char_was_return) newline();
          continue;
        }
        if (buffer[i] == '\r') {
          newline();
          last_char_was_return = true;
          continue;
        } else last_char_was_return = false;

        // If it some other non-printing character, ignore it.
        if (Character.isWhitespace(buffer[i])
            && !Character.isSpaceChar(buffer[i])
            && (buffer[i] != '\t')) continue;

        // If no more characters will fit on the line, start a new line.
        if (charnum >= chars_per_line) {
          newline();
          if (page == null) newpage(); // and start a new page, if necessary
        }

        // Now print the character:
        // If it is a space, skip one space, without output.
        // If it is a tab, skip the necessary number of spaces.
        // Otherwise, print the character.
        // It is inefficient to draw only one character at a time, but
        // because our FontMetrics don't match up exactly to what the
        // printer uses we need to position each character individually.
        if (Character.isSpaceChar(buffer[i])) charnum++;
        else if (buffer[i] == '\t') charnum += 8 - (charnum % 8);
        else {
          page.drawChars(
              buffer, i, 1, x0 + charnum * charwidth, y0 + (linenum * lineheight) + lineascent);
          charnum++;
        }
      }
    }
  }
Example #20
0
  /**
   * Called by the paint method to draw the graph and its graph items.
   *
   * @param g the graphics context.
   */
  public void paintComponent(Graphics g) {

    Dimension dim = getSize();
    Insets insets = getInsets();
    dataArea =
        new Rectangle(
            insets.left,
            insets.top,
            dim.width - insets.left - insets.right - 1,
            dim.height - insets.top - insets.bottom - 1);
    // background
    if (isOpaque()) {
      g.setColor(getBackground());
      g.fillRect(0, 0, dim.width, dim.height);
    }
    g.setColor(getForeground());
    // get axis tickmarks
    double xticks[] = xAxis.getTicks();
    double yticks[] = yAxis.getTicks();
    int yb = dataArea.y + dataArea.height;
    // draw grid
    if (showGrid) {
      g.setColor(gridColor != null ? gridColor : getBackground().darker());
      // vertical x grid lines
      for (int i = 0; i < xticks.length; i += 2) {
        int x = dataArea.x + (int) Math.round(xticks[i]);
        g.drawLine(x, dataArea.y, x, dataArea.y + dataArea.height);
      }
      // horizontal y grid lines
      for (int i = 0; i < yticks.length; i += 2) {
        int y = yb - (int) Math.round(yticks[i]);
        g.drawLine(dataArea.x, y, dataArea.x + dataArea.width, y);
      }
    }
    for (int i = 0; i < graphItems.size(); i++) {
      ((GraphItem) graphItems.elementAt(i)).draw(this, g, dataArea, xAxis, yAxis);
    }
    if (sPt != null && ePt != null) {
      g.setColor(getForeground());
      g.drawRect(
          Math.min(sPt.x, ePt.x), Math.min(sPt.y, ePt.y),
          Math.abs(ePt.x - sPt.x), Math.abs(ePt.y - sPt.y));
    }
  }
  public static void drawValueBar(
      int x, int y, String labelhead, double value, double percentage, int colorindex, Graphics g) {
    g.setColor(GetColor(colorindex));
    g.drawRect(x, y, VALUE_BAR_WIDTH, VALUE_BAR_HEIGHT);

    int barwidth;
    if (percentage < 0.0) {
      // Unknown value
      barwidth = VALUE_BAR_WIDTH - 1;
    } else {
      barwidth = (int) ((VALUE_BAR_WIDTH - 1) * Math.min(1.0, percentage));
    }
    // g.setColor(gradientColor(percentage));
    g.fillRect(x + 1, y + 1, barwidth, VALUE_BAR_HEIGHT - 1);

    if (labelhead != null) {
      g.setFont(MainFrame.defaultFont);
      // g.setColor(MainFrame.labelColor);
      int off = 2;
      g.drawString(labelhead, x + VALUE_BAR_WIDTH + 2, y + VALUE_BAR_HEIGHT);
      // off += (labelhead.length()+1) * 4; // Just a guess
      String maxStr = new String("DateRate [/sec]:");
      off += (int) ((maxStr.length() + 1) * 5.5);

      if (value < 0.0) {
        g.drawString("?", x + VALUE_BAR_WIDTH + off, y + VALUE_BAR_HEIGHT);
      } else {
        if (percentage < 0.0) {
          g.drawString(format(value), x + VALUE_BAR_WIDTH + off, y + VALUE_BAR_HEIGHT);
        } else {
          g.drawString(
              format(value) + " (" + format(percentage * 100) + "%)",
              x + VALUE_BAR_WIDTH + off,
              y + VALUE_BAR_HEIGHT);
        }
      }
    }
  }
Example #22
0
  /** This internal method begins a new page and prints the header. */
  protected void newpage() {
    page = job.getGraphics(); // Begin the new page
    linenum = 0;
    charnum = 0; // Reset line and char number
    pagenum++; // Increment page number
    page.setFont(headerfont); // Set the header font.
    page.drawString(jobname, x0, headery); // Print job name left justified

    String s = "- " + pagenum + " -"; // Print the page number centered.
    int w = headermetrics.stringWidth(s);
    page.drawString(s, x0 + (this.width - w) / 2, headery);
    w = headermetrics.stringWidth(time); // Print date right justified
    page.drawString(time, x0 + width - w, headery);

    // Draw a line beneath the header
    int y = headery + headermetrics.getDescent() + 1;
    page.drawLine(x0, y, x0 + width, y);

    // Set the basic monospaced font for the rest of the page.
    page.setFont(font);
  }
Example #23
0
  void drawObjects(
      Graphics g,
      java.util.List<DrawObject> points,
      java.util.List<DrawObject> lines,
      java.util.List<DrawObject> ovals,
      java.util.List<DrawObject> rectangles,
      java.util.List<DrawObject> images,
      java.util.List<DrawObject> labels,
      java.util.List<DrawObject> eqnLines) {
    try {
      // Images
      synchronized (images) {
        for (DrawObject I : images) {
          drawImage(g, I);
        }
      }

      // Labels
      synchronized (labels) {
        for (DrawObject L : labels) {
          drawLabel(g, L);
        }
      }

      // Eqn Lines
      synchronized (eqnLines) {
        for (DrawObject L : eqnLines) {
          g.setColor(L.color);
          drawEqnLine(g, L);
        }
      }

      // Lines
      synchronized (lines) {
        for (DrawObject L : lines) {
          g.setColor(L.color);
          drawLine(g, L);
        }
      }

      // Rectangles
      synchronized (rectangles) {
        for (DrawObject R : rectangles) {
          g.setColor(R.color);
          drawOvalOrRectangle(g, R, true);
        }
      }

      // Ovals
      synchronized (ovals) {
        for (DrawObject R : ovals) {
          g.setColor(R.color);
          drawOvalOrRectangle(g, R, false);
        }
      }

      // Points.
      synchronized (points) {
        for (DrawObject p : points) {
          g.setColor(p.color);
          drawPoint(g, p);
        }
      }
    } catch (ConcurrentModificationException e) {
      e.printStackTrace();
      System.exit(0);
    }
  }
Example #24
0
 public void paint(Graphics g) {
   draw(getBufferGraphics());
   g.drawImage(bufferImage, 0, 0, null);
 }
Example #25
0
 void print(String str) {
   g.drawString(str, x, y += 20);
 }
Example #26
0
 void print(String name, Vec value) {
   g.drawString(name + ":" + df.format(value.x) + " , " + df.format(value.y), x, y += 20);
 }
Example #27
0
 void print(String name, double value) {
   g.drawString(name + ":" + df.format(value), x, y += 20);
 }
Example #28
0
 void print(String name, int value) {
   g.drawString(name + ":" + value, x, y += 20);
 }
Example #29
0
  void drawEqnLine(Graphics g, DrawObject L) {
    if (L == null) {
      return;
    }
    if ((sequencingOn) && (L.sequenceNum != currentSequenceNumDisplay)) {
      return;
    }
    // First, special cases:
    if ((L.a == 0) && (L.b == 0)) {
      return;
    }
    double px = 0, py = 0, qx = 0, qy = 0;
    double leftX = px, rightX = qx, leftY = py, rightY = qy;
    if (L.a == 0) {
      // Case 2: a=0 => horizontal line.
      leftX = minX;
      rightX = maxX;
      py = -L.c / L.b;
      qy = -L.c / L.b;
      if ((py < minY) || (py > maxY)) {
        // Cannot display.
        return;
      }
      leftY = rightY = py;
    } else if (L.b == 0) {
      // Case 3: b=0 => vertical line.
      leftX = -L.c / L.a;
      rightX = -L.c / L.a;
      leftY = minY;
      rightY = maxY;
      if ((leftX < minX) || (leftX > maxX)) {
        return;
      }
    } else {
      // Case 4: regular.
      // Note: the line could intersect the drawable region in weird ways.
      px = (-L.c - L.b * minY) / L.a;
      qx = (-L.c - L.b * maxY) / L.a;
      py = (-L.c - L.a * minX) / L.b;
      qy = (-L.c - L.a * maxX) / L.b;
      // System.out.println ("px=" + px + " qx=" + qx + " py=" + py + " qy=" + qy);
      // Find leftmost point to draw.
      if ((py >= minY) && (py <= maxY)) {
        // Leftmost point is on the x=minX line.
        leftX = minX;
        leftY = py;
        // System.out.println ("case(a): leftmost on minX-line");
      } else {
        // Leftmost point is not on the x=minX line.
        // Find leftmost point intersecting with low or high
        if (px < qx) {
          leftX = px;
          leftY = minY;
          // System.out.println ("case(a.1): on minY-line");
        } else {
          leftX = qx;
          leftY = maxY;
          // System.out.println ("case(a.2): on maxY-line");
        }
      }

      // Now find rightmost point.
      if ((qy >= minY) && (qy <= maxY)) {
        // Rightmost point is on the x=maxX line.
        rightX = maxX;
        rightY = qy;
        // System.out.println ("case(b): rightmost on maxX-line");
      } else {
        if (px > qx) {
          rightX = px;
          rightY = minY;
          // System.out.println ("case(b.1): rightmost on minY-line");
        } else {
          rightX = qx;
          rightY = maxY;
          // System.out.println ("case(b.1): rightmost on maxY-line");
        }
      }
    }

    // System.out.println ("left:(" + leftX + "," + leftY + ")  right:(" + rightX + "," + rightY +
    // ")");

    int x1 = (int) ((leftX - minX) / (maxX - minX) * (D.width - 2 * inset));
    int y1 = (int) ((leftY - minY) / (maxY - minY) * (D.height - 2.0 * inset));
    int x2 = (int) ((rightX - minX) / (maxX - minX) * (D.width - 2 * inset));
    int y2 = (int) ((rightY - minY) / (maxY - minY) * (D.height - 2.0 * inset));
    Graphics2D g2 = (Graphics2D) g;
    g2.setStroke(L.drawStroke);
    g.drawLine(inset + x1, D.height - y1 - inset, inset + x2, D.height - y2 - inset);
  }
Example #30
0
  public void paintComponent(Graphics g) {
    super.paintComponent(g);

    Graphics2D g2d = (Graphics2D) g;
    RenderingHints rh = g2d.getRenderingHints();
    rh.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    rh.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
    g2d.setRenderingHints(rh);

    // Background.
    D = this.getSize();
    g.setColor(backgroundColor);
    g.fillRect(0, 0, D.width, D.height);
    Graphics2D g2 = (Graphics2D) g;
    g2.setStroke(lineStroke);

    // Axes, bounding box.
    g.setColor(Color.gray);
    g.drawLine(inset, D.height - inset, D.width - inset, D.height - inset);
    g.drawLine(D.width - inset, inset, D.width - inset, D.height - inset);
    g.drawLine(inset, inset, inset, D.height - inset);
    g.drawLine(inset, inset, D.width - inset, inset);

    double xDelta = (maxX - minX) / numIntervals;

    // X-ticks and labels.
    for (int i = 1; i <= numIntervals; i++) {
      double xTickd = i * xDelta;
      int xTick = (int) (xTickd / (maxX - minX) * (D.width - 2 * inset));
      g.drawLine(inset + xTick, D.height - inset - 5, inset + xTick, D.height - inset + 5);
      double x = minX + i * xDelta;
      g.drawString(df.format(x), xTick + inset - 5, D.height - inset + 20);
    }

    // Y-ticks
    double yDelta = (maxY - minY) / numIntervals;
    for (int i = 0; i < numIntervals; i++) {
      int yTick = (i + 1) * (int) ((D.height - 2 * inset) / (double) numIntervals);
      g.drawLine(inset - 5, D.height - yTick - inset, inset + 5, D.height - yTick - inset);
      double y = minY + (i + 1) * yDelta;
      g.drawString(df.format(y), 1, D.height - yTick - inset);
    }

    // Zoom+move
    Font savedFont = g.getFont();
    g.setFont(plusFont);
    g.drawString("+", D.width - 25, 20);
    g.setFont(minusFont);
    g.drawString("-", D.width - 25, 50);
    drawArrow(g2d, D.width - 70, 20, D.width - 70, 0, 1.0f, lineStroke); // Up
    drawArrow(g2d, D.width - 70, 30, D.width - 70, 50, 1.0f, lineStroke); // Down
    drawArrow(g2d, D.width - 65, 25, D.width - 45, 25, 1.0f, lineStroke); // Right
    drawArrow(g2d, D.width - 75, 25, D.width - 95, 25, 1.0f, lineStroke); // Left
    g.setFont(savedFont);

    // See if standard axes are in the middle.
    g.setColor(Color.gray);
    if ((minX < 0) && (maxX > 0) && (drawMiddleAxes)) {
      // Draw y-axis
      int x = (int) ((0 - minX) / (maxX - minX) * (D.width - 2 * inset));
      g.drawLine(inset + x, D.height - inset, inset + x, inset);
    }
    if ((minY < 0) && (maxY > 0) && (drawMiddleAxes)) {
      // Draw x-axis
      int y = (int) ((0 - minY) / (maxY - minY) * (D.height - 2.0 * inset));
      g.drawLine(inset, D.height - y - inset, D.width - inset, D.height - y - inset);
    }

    // Draw the objects.
    drawObjects(g, points, lines, ovals, rectangles, images, labels, eqnLines);
    if (animationMode) {
      drawObjects(g, animPoints, animLines, animOvals, animRectangles, null, labels, eqnLines);
      // No images in animation mode.
    }

    drawScribbles(g);
  }