Example #1
0
 static {
   Stroke stroke = new BasicStroke(2);
   selectionShape = stroke.createStrokedShape(hitRect);
   format.setMinimumIntegerDigits(1);
   format.setMinimumFractionDigits(1);
   format.setMaximumFractionDigits(2);
 }
Example #2
0
/**
 * A Step is associated with a single frame of a TTrack. It contains an array of TPoints that define
 * its image data and a Footprint that determines its screen appearance. This is an abstract class
 * and cannot be instantiated directly.
 *
 * @author Douglas Brown
 */
public abstract class Step implements Cloneable {

  // static fields
  protected static Rectangle hitRect = new Rectangle(-4, -4, 8, 8);
  protected static Shape selectionShape;
  protected static AffineTransform transform = new AffineTransform();
  protected static NumberFormat format = NumberFormat.getNumberInstance(Locale.US);
  protected static Font textLayoutFont = new JTextField().getFont();
  protected static FontRenderContext frc =
      new FontRenderContext(
          null, // no AffineTransform
          false, // no antialiasing
          false); // no fractional metrics

  static {
    Stroke stroke = new BasicStroke(2);
    selectionShape = stroke.createStrokedShape(hitRect);
    format.setMinimumIntegerDigits(1);
    format.setMinimumFractionDigits(1);
    format.setMaximumFractionDigits(2);
  }

  // instance fields
  protected TTrack track; // track this belongs to
  protected int n; // frame number
  protected Footprint footprint; // determines appearance
  protected TPoint[] points; // defines image data
  protected Point[] screenPoints; // for transform conversions
  protected boolean valid; // invalid steps not drawn
  protected Map<TrackerPanel, Mark> marks // tracker panel to Mark
      = new HashMap<TrackerPanel, Mark>();
  protected int defaultIndex = 0; // array index of default TPoint
  protected boolean dataVisible = true; // true if visible in plots, tables

  /**
   * Constructs a Step with the specified frame number.
   *
   * @param track the track
   * @param n the frame number
   */
  protected Step(TTrack track, int n) {
    this.track = track;
    this.n = n;
  }

  /**
   * Gets the frame number.
   *
   * @return the frame number
   */
  public int getFrameNumber() {
    return n;
  }

  /**
   * Sets the footprint.
   *
   * @param footprint the footprint
   */
  public void setFootprint(Footprint footprint) {
    this.footprint = footprint;
  }

  /**
   * Gets the track.
   *
   * @return the track
   */
  public TTrack getTrack() {
    return track;
  }

  /**
   * Gets the array of TPoints contained in this step.
   *
   * @return the TPoints array
   */
  public TPoint[] getPoints() {
    return points;
  }

  /**
   * Gets the index of a point in the points[] array.
   *
   * @param p the point
   * @return the index, or -1 if not found
   */
  public int getPointIndex(TPoint p) {
    for (int i = 0; i < points.length; i++) {
      if (points[i] == p) return i;
    }
    return -1;
  }

  /**
   * Gets the default point. The default point is the point initially selected when the step is
   * created.
   *
   * @return the default TPoint
   */
  public TPoint getDefaultPoint() {
    return points[defaultIndex];
  }

  /**
   * Sets the default point index. This defines the index of the points array used to get the point
   * initially selected when the step is created.
   *
   * @param index the index
   */
  public void setDefaultPointIndex(int index) {
    index = Math.min(index, points.length - 1);
    defaultIndex = Math.max(0, index);
  }

  /**
   * Erases this on the specified tracker panel. Erasing adds the current bounds to the dirty region
   * and nulls the step's mark to trigger creation of a new one.
   *
   * @param trackerPanel the tracker panel
   */
  public void erase(TrackerPanel trackerPanel) {
    if (marks.get(trackerPanel) == null) return; // already dirty
    trackerPanel.addDirtyRegion(getBounds(trackerPanel)); // old bounds
    marks.put(trackerPanel, null); // triggers new mark
  }

  /**
   * Erases and remarks this on the specified tracker panel. Remarking creates a new mark for the
   * step and adds both the old and new bounds to the tracker panel's dirty region.
   *
   * @param trackerPanel the tracker panel
   */
  public void remark(TrackerPanel trackerPanel) {
    erase(trackerPanel);
    trackerPanel.addDirtyRegion(getBounds(trackerPanel)); // new bounds
  }

  /**
   * Repaints this on the specified tracker panel. Repainting a step first remarks it and then
   * requests a repaint of the panel's dirty region.
   *
   * @param trackerPanel the tracker panel
   */
  public void repaint(TrackerPanel trackerPanel) {
    remark(trackerPanel);
    trackerPanel.repaintDirtyRegion();
  }

  /** Erases this on all tracker panels. */
  public void erase() {
    Iterator<TrackerPanel> it = marks.keySet().iterator();
    while (it.hasNext()) erase(it.next());
  }

  /** Remarks this on all tracker panels. */
  public void remark() {
    Iterator<TrackerPanel> it = marks.keySet().iterator();
    while (it.hasNext()) remark(it.next());
  }

  /** Repaints this on all tracker panels. */
  public void repaint() {
    Iterator<TrackerPanel> it = marks.keySet().iterator();
    while (it.hasNext()) repaint(it.next());
  }

  /**
   * Draws this step.
   *
   * @param panel the drawing panel requesting the drawing
   * @param g the graphics context on which to draw
   */
  public void draw(DrawingPanel panel, Graphics g) {
    if (track.trackerPanel == panel) {
      AutoTracker autoTracker = track.trackerPanel.getAutoTracker();
      if (autoTracker.isInteracting(track)) return;
    }
    TrackerPanel trackerPanel = (TrackerPanel) panel;
    boolean highlighted = (trackerPanel.getFrameNumber() == n);
    if (trackerPanel.autoTracker != null
        && trackerPanel.autoTracker.getWizard().isVisible()
        && trackerPanel.autoTracker.getTrack() == track) {
      highlighted = false;
    }
    getMark(trackerPanel).draw((Graphics2D) g, highlighted);
  }

  /**
   * Finds the Interactive located at the specified pixel position.
   *
   * @param panel the drawing panel
   * @param xpix the x pixel position
   * @param ypix the y pixel position
   * @return the TPoint that is hit, or null
   */
  public Interactive findInteractive(DrawingPanel panel, int xpix, int ypix) {
    boolean highlighted = (track.trackerPanel.getFrameNumber() == getFrameNumber());
    AutoTracker autoTracker = track.trackerPanel.getAutoTracker();
    TrackerPanel trackerPanel = (TrackerPanel) panel;
    setHitRectCenter(xpix, ypix);
    for (int i = 0; i < points.length; i++) {
      if (points[i] == null || Double.isNaN(points[i].getX())) continue;
      if (hitRect.contains(points[i].getScreenPosition(trackerPanel))) {
        if (highlighted && autoTracker.isDrawingKeyFrameFor(track, i)) return null;
        return points[i];
      }
    }
    return null;
  }

  /**
   * Gets the screen bounds of this step on the specified tracker panel.
   *
   * @param trackerPanel the tracker panel drawing the step
   * @return the bounding rectangle
   */
  public Rectangle getBounds(TrackerPanel trackerPanel) {
    boolean highlighted = (trackerPanel.getFrameNumber() == n);
    return getMark(trackerPanel).getBounds(highlighted);
  }

  /**
   * Gets the mark for the specified panel.
   *
   * @param trackerPanel the tracker panel
   * @return the mark
   */
  protected Mark getMark(TrackerPanel trackerPanel) {
    Mark mark = marks.get(trackerPanel);
    TPoint selection = null;
    if (mark == null) {
      selection = trackerPanel.getSelectedPoint();
      Point p = null;
      valid = true; // assume true
      for (int n = 0; n < points.length; n++) {
        if (!valid) continue;
        // determine if point is valid (ie not NaN)
        valid = valid && !Double.isNaN(points[n].getX()) && !Double.isNaN(points[n].getY());
        screenPoints[n] = points[n].getScreenPosition(trackerPanel);
        if (valid && selection == points[n]) p = screenPoints[n];
      }
      mark = footprint.getMark(screenPoints);
      if (p != null) { // point is selected, so draw selection shape
        transform.setToTranslation(p.x, p.y);
        int scale = FontSizer.getIntegerFactor();
        if (scale > 1) {
          transform.scale(scale, scale);
        }
        final Color color = footprint.getColor();
        final Mark stepMark = mark;
        final Shape selectedShape = transform.createTransformedShape(selectionShape);
        mark =
            new Mark() {
              public void draw(Graphics2D g, boolean highlighted) {
                stepMark.draw(g, false);
                Paint gpaint = g.getPaint();
                g.setPaint(color);
                g.fill(selectedShape);
                g.setPaint(gpaint);
              }

              public Rectangle getBounds(boolean highlighted) {
                Rectangle bounds = selectedShape.getBounds();
                bounds.add(stepMark.getBounds(false));
                return bounds;
              }
            };
      }
      final Mark theMark = mark;
      mark =
          new Mark() {
            public void draw(Graphics2D g, boolean highlighted) {
              if (!valid) return;
              theMark.draw(g, false);
            }

            public Rectangle getBounds(boolean highlighted) {
              return theMark.getBounds(highlighted);
            }
          };
      marks.put(trackerPanel, mark);
    }
    return mark;
  }

  /**
   * Returns a String describing this step.
   *
   * @return a descriptive string
   */
  public String toString() {
    return "Step " + n; // $NON-NLS-1$
  }

  /**
   * Clones this Step.
   *
   * @return a clone of this step
   */
  public Object clone() {
    try {
      Step step = (Step) super.clone();
      step.points = new TPoint[points.length];
      step.screenPoints = new Point[points.length];
      step.marks = new HashMap<TrackerPanel, Mark>();
      return step;
    } catch (CloneNotSupportedException ex) {
      ex.printStackTrace();
    }
    return null;
  }

  /**
   * Centers the hit testing rectangle on the specified screen point.
   *
   * @param xpix the x pixel position
   * @param ypix the y pixel position
   */
  protected void setHitRectCenter(int xpix, int ypix) {
    hitRect.setLocation(xpix - hitRect.width / 2, ypix - hitRect.height / 2);
  }

  /**
   * Gets the step length. Default length is 1.
   *
   * @return the length of the points array
   */
  public static int getLength() {
    return 1;
  }

  /** An inner superclass of all handles. */
  class Handle extends TPoint {

    /**
     * Constructs a Handle with specified image coordinates.
     *
     * @param x the x coordinate
     * @param y the y coordinate
     */
    public Handle(double x, double y) {
      super(x, y);
    }

    /**
     * Sets the position of this handle on the line nearest the specified screen position.
     * Subclasses must override.
     *
     * @param xScreen the x screen position
     * @param yScreen the y screen position
     * @param trackerPanel the trackerPanel drawing this step
     */
    public void setPositionOnLine(int xScreen, int yScreen, TrackerPanel trackerPanel) {}
  }
}