Package plotter.xy

Source Code of plotter.xy.LinearXYAxis

/*******************************************************************************
* Mission Control Technologies, Copyright (c) 2009-2012, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* The MCT platform is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* MCT includes source code licensed under additional open source licenses. See
* the MCT Open Source Licenses file included with this distribution or the About
* MCT Licenses dialog available at runtime from the MCT Help menu for additional
* information.
*******************************************************************************/
package plotter.xy;

import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.text.NumberFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.Set;

import plotter.AxisLabel;
import plotter.DateNumberFormat;
import plotter.LinearTickMarkCalculator;
import plotter.MultiLineLabelUI;
import plotter.Rotation;
import plotter.TickMarkCalculator;

/**
* A linear XY axis is the normal case where points on the screen are linearly related to their corresponding data values.
* @author Adam Crume
*/
public class LinearXYAxis extends XYAxis {
  private static final long serialVersionUID = 1L;

  /** Start value of the axis at the time the labels were cached. */
  private double labelCacheStart = Double.NaN;

  /** End value of the axis at the time the labels were cached. */
  private double labelCacheEnd = Double.NaN;

  /** Values of the major tick marks. */
  private double[] majorVals;

  /** Values of the minor tick marks. */
  private double[] minorVals;

  /** Calculates tick marks and labels for the axis. */
  private TickMarkCalculator tickMarkCalculator = new LinearTickMarkCalculator();

  /** Format used to display values in labels. */
  private NumberFormat format = NumberFormat.getInstance();
 

  /** Time system axis label name. */
  private String timeSystemAxisLabelName;

 
  /**
   * Creates an axis.
   * @param d dimension the axis represents
   */
  public LinearXYAxis(XYDimension d) {
    super(d);
  }


  @Override
  public void doLayout() {
    super.doLayout();
    double start = getStart();
    double end = getEnd();
    double diff = end - start;
    XYDimension plotDimension = getPlotDimension();
    int startMargin = getStartMargin();
    int width = getWidth();
    int height = getHeight();
    int size = (plotDimension == XYDimension.X ? width : height) - startMargin - getEndMargin();

    // Labels only need to be recreated if the min or max changes.
    // Otherwise, they simply need to be repositioned.
    if(start != labelCacheStart || end != labelCacheEnd) {
      double[][] ticks = tickMarkCalculator.calculateTickMarks(this);
      majorVals = ticks[0];
      minorVals = ticks[1];
      labelCacheStart = start;
      labelCacheEnd = end;
    }

    // Calculate the physical locations of the tick marks from the logical locations.
    int[] major = new int[majorVals.length];
    int[] minor = new int[minorVals.length];
    for(int i = 0; i < major.length; i++) {
      major[i] = (int) ((majorVals[i] - start) / diff * size + .5) - 1;
    }
    for(int i = 0; i < minor.length; i++) {
      minor[i] = (int) ((minorVals[i] - start) / diff * size + .5) - 1;
    }
    setMajorTicks(major);
    setMinorTicks(minor);

    if(isShowLabels()) {
      updateLabels();
    } else {
      removeAll();
    }
  }


  /**
   * Updates labels to match the tick marks.
   * Labels may be added, removed, or repositioned.
   */
  private void updateLabels() {
    int[] major = getMajorTicks();
    int width = getWidth();
    int height = getHeight();
    int startMargin = getStartMargin();
    XYDimension plotDimension = getPlotDimension();
    double diff = getEnd() - getStart();
    Component[] components = getComponents();

    // oldLabels contains the original labels that have not been reused.
    Set<AxisLabel> oldLabels = new HashSet<AxisLabel>(components.length);
    for(Component c : components) {
      oldLabels.add((AxisLabel) c);
    }

    // maxLabelError defines the largest absolute difference between a label's value and the needed value.
    // If the error is greater than this, the label is not reused.
    double maxLabelError = .01 * Math.abs(diff);
    AxisLabel[] labels = new AxisLabel[majorVals.length];
    for(int i = 0; i < labels.length; i++) {
      labels[i] = createLabel(majorVals[i], oldLabels, maxLabelError);
    }

    // Remove labels that have not been reused.
    for(AxisLabel oldLabel : oldLabels) {
      remove(oldLabel);
    }

    // Position the labels to line up with the corresponding tick marks.
    int textMargin = getTextMargin();
    boolean inverted = getEnd() < getStart();
    if(plotDimension == XYDimension.X) {
      for(int i = 0; i < major.length; i++) {
        Component label = labels[i];
        double preferredSize = label.getPreferredSize().getWidth();
        double end = preferredSize / 2;
        double start = -end;
        if(inverted) {
          if(i < major.length - 1) {
            start = Math.max(start, (major[i + 1] - major[i]) / 2);
          }
          if(i > 0) {
            end = Math.min(end, (major[i - 1] - major[i]) / 2);
          }
        } else {
          if(i > 0) {
            start = Math.max(start, (major[i - 1] - major[i]) / 2);
          }
          if(i < major.length - 1) {
            end = Math.min(end, (major[i + 1] - major[i]) / 2);
          }
        }
        double labelWidth = end - start;
        label.setSize((int) labelWidth, label.getHeight());
        label.setLocation((int) (start + startMargin + major[i]), textMargin);
      }
    } else {
      int height2 = height - startMargin;
      int width2 = width - textMargin;
      for(int i = 0; i < major.length; i++) {
        Component label = labels[i];
        double preferredSize = label.getPreferredSize().getHeight();
        double end = preferredSize / 2;
        double start = -end;
        if(inverted) {
          if(i < major.length - 1) {
            start = Math.max(start, (major[i + 1] - major[i]) / 2);
          }
          if(i > 0) {
            end = Math.min(end, (major[i - 1] - major[i]) / 2);
          }
        } else {
          if(i > 0) {
            start = Math.max(start, (major[i - 1] - major[i]) / 2);
          }
          if(i < major.length - 1) {
            end = Math.min(end, (major[i + 1] - major[i]) / 2);
          }
        }
        double labelHeight = end - start;
        int labelWidth = label.getWidth();
        label.setSize(labelWidth, (int) labelHeight);
        label.setLocation(width2 - labelWidth, (int) (height2 - major[i] - end));
      }
    }
  }


  /**
   * Creates a label for the given value.
   * A label may instead be reused (and removed) from the <code>oldLabels</code> set.
   * @param value value the label displays
   * @param oldLabels labels that may be reused
   * @param maxLabelError largest absolute difference between a label's value and <code>value</code> that allows a label to be reused
   * @return the label, which may be new or reused
   */
  private AxisLabel createLabel(double value, Set<AxisLabel> oldLabels, double maxLabelError) {
    for(AxisLabel oldLabel : oldLabels) {
      // Value is the same, reuse the label.
      // It is currently assumed that if the value is close enough, the text doesn't change.
      // For well-behaved tick mark calculators and label formats, this should be true.  (Use rounding!)
      // The new text could be calculated, but that is expensive.
      if(Math.abs(value - oldLabel.getValue()) < maxLabelError) {
        oldLabels.remove(oldLabel);
        return oldLabel;
      }
    }

    AxisLabel label = new AxisLabel(value, format.format(value));
    if (format.getClass().equals(DateNumberFormat.class)) {
      GregorianCalendar gc = new GregorianCalendar();
      gc.setTimeInMillis((long) value);
      label.setToolTipText(format.format(value) +" " + gc.get(Calendar.YEAR) );
    }
    Rotation labelRotation = getLabelRotation();
    if(labelRotation != null) {
      label.putClientProperty(Rotation.class.getName(), labelRotation);
    }
    label.setUI(MultiLineLabelUI.labelUI);
    label.setForeground(getForeground());
    label.setFont(getFont());
    add(label);
    label.setSize(label.getPreferredSize());
    return label;
  }


  @Override
  public int toPhysical(double d) {
    double min = getStart();
    double max = getEnd();
    int endMargin = getEndMargin();
    if(getPlotDimension() == XYDimension.X) {
      int width = getWidth();
      int startMargin = getStartMargin();
      return (int) ((d - min) / (max - min) * (width - startMargin - endMargin) + .5) + getStartMargin() - 1;
    } else {
      int height = getHeight() - getStartMargin();
      return height - (int) ((d - min) / (max - min) * (height - endMargin) + .5);
    }
  }


  @Override
  public double toLogical(int n) {
    double min = getStart();
    double max = getEnd();
    int endMargin = getEndMargin();
    if(getPlotDimension() == XYDimension.X) {
      int width = getWidth();
      int startMargin = getStartMargin();
      return (n - startMargin + 1) * 1.0 / (width - startMargin - endMargin) * (max - min) + min;
    } else {
      int height = getHeight() - getStartMargin() - endMargin;
      return (height - n + endMargin) * 1.0 / height * (max - min) + min;
    }
  }


  /**
   * Sets the foreground color.
   * Overridden to update the color of the labels.
   * @param color the foreground color
   */
  @Override
  public void setForeground(Color color) {
    super.setForeground(color);
    for(Component c : getComponents()) {
      c.setForeground(color);
    }
  }


  /**
   * Sets the font.
   * Overridden to update the font of the labels.
   * @param font the font
   */
  @Override
  public void setFont(Font font) {
    super.setFont(font);
    for(Component c : getComponents()) {
      c.setFont(font);
    }
  }


  /**
   * Returns the tick mark calculator.
   * @return the tick mark calculator
   */
  public TickMarkCalculator getTickMarkCalculator() {
    return tickMarkCalculator;
  }


  /**
   * Sets the tick mark calculator.
   * @param tickMarkCalculator the tick mark calculator
   */
  public void setTickMarkCalculator(TickMarkCalculator tickMarkCalculator) {
    this.tickMarkCalculator = tickMarkCalculator;
  }


  /**
   * Returns the format for the labels.
   * @return the format for the labels
   */
  public NumberFormat getFormat() {
    return format;
  }


  /**
   * Sets the format for the labels.
   * @param format the format for the labels
   */
  public void setFormat(NumberFormat format) {
    this.format = format;
  }
 
  @Override
  public String getTimeSystemAxisLabelName() {
    return timeSystemAxisLabelName;
  }
  
  @Override
  public void setTimeSystemAxisLabelName(String labelName) {
    timeSystemAxisLabelName = labelName;
  }
}
TOP

Related Classes of plotter.xy.LinearXYAxis

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.