All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.javagl.viewer.painters.CoordinateSystemPainter Maven / Gradle / Ivy

There is a newer version: 0.1.3
Show newest version
/*
 * www.javagl.de - Viewer
 *
 * Copyright (c) 2013-2015 Marco Hutter - http://www.javagl.de
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */
package de.javagl.viewer.painters;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.function.IntSupplier;

import de.javagl.geom.AffineTransforms;
import de.javagl.geom.Lines;
import de.javagl.geom.Points;
import de.javagl.geom.Rectangles;
import de.javagl.viewer.Painter;

/**
 * Implementation of the {@link Painter} interface that paints a coordinate
 * system, consisting of a grid and labeled coordinate axes.
 */
public final class CoordinateSystemPainter implements Painter
{
    /**
     * A line object, used internally in various methods
     */
    private static final Line2D.Double TEMP_LINE = new Line2D.Double();

    /**
     * A point object, used internally in various methods
     */
    private static final Point2D.Double TEMP_POINT = new Point2D.Double();
    
    /**
     * The font that will be used for the labels
     */
    private final Font font = new Font("Dialog", Font.PLAIN, 9);
    
    /**
     * The stroke for the axes
     */
    private final Stroke stroke = new BasicStroke(1.0f);

    /**
     * The color of the x-axis. If this is null, then the
     * x-axis will not be painted.
     */
    private Color axisColorX = Color.GRAY;
    
    /**
     * The color of the labels on the x-axis. If this is null, 
     * then the labels on the x-axis will not be painted.
     */
    private Color labelColorX = Color.GRAY;
    
    /**
     * The color of the y-axis. If this is null, then the
     * y-axis will not be painted.
     */
    private Color axisColorY = Color.GRAY;
    
    /**
     * The color of the labels on the y-axis. If this is null, 
     * then the labels on the y-axis will not be painted.
     */
    private Color labelColorY = Color.GRAY;
    
    /**
     * The size of the tick marks on the screen
     */
    private final double tickSizeScreen = 5;
    
    /**
     * The minimum distance that two ticks should have on the screen
     */
    private final double minScreenTickDistanceX = 20;

    /**
     * The minimum distance that two ticks should have on the screen
     */
    private final double minScreenTickDistanceY = 20;
    
    /**
     * Whether the "minScreenTickDistanceX" should be adjusted
     * based on the strings that are printed for the labels
     */
    private final boolean adjustForStringLengths = true;
    
    /**
     * The color for the x-axis tick grid lines. If this is null, 
     * then no grid lines will be painted 
     */
    private Color gridColorX = new Color(240,240,240);
    
    /**
     * The color for the y-axis tick grid lines. If this is null, 
     * then no grid lines will be painted 
     */
    private Color gridColorY = new Color(240,240,240);
    
    /**
     * The fixed distance between ticks on the x-axis, in world coordinates
     */
    private double fixedWorldTickDistanceX = Double.NaN;
    
    /**
     * The fixed distance between ticks on the y-axis, in world coordinates
     */
    private double fixedWorldTickDistanceY = Double.NaN;
    
    /**
     * The tick positions of the x-axis, in world coordinates
     */
    private double worldTicksX[];

    /**
     * The label format for the x-axis. May be null
     * if no labels should be painted
     */
    private String labelFormatX;
    
    /**
     * The tick positions of the y-axis, in world coordinates
     */
    private double worldTicksY[];

    /**
     * The label format for the y-axis. May be null
     * if no labels should be painted
     */
    private String labelFormatY;
        
    /**
     * The bounds of the currently visible area, in world coordinates
     */
    private final Rectangle2D worldBounds = new Rectangle2D.Double();
    
    /**
     * The supplier that provides the x-coordinate on the screen
     * where the x-axis should start
     */
    private IntSupplier supplierScreenMinX = null;

    /**
     * The supplier that provides the x-coordinate on the screen
     * where the x-axis should end
     */
    private IntSupplier supplierScreenMaxX = null;

    /**
     * The supplier that provides the y-coordinate on the screen
     * where the x-axis should be located
     */
    private IntSupplier supplierScreenY = null;
    
    /**
     * The supplier that provides the y-coordinate on the screen
     * where the y-axis should start
     */
    private IntSupplier supplierScreenMinY = null;

    /**
     * The supplier that provides the y-coordinate on the screen
     * where the y-axis should end
     */
    private IntSupplier supplierScreenMaxY = null;

    /**
     * The supplier that provides the x-coordinate on the screen
     * where the y-axis should be located
     */
    private IntSupplier supplierScreenX = null;
    
    /**
     * The minimum value for the x-axis, in world coordinates
     * 
     * @see #setAxisRangeX(double, double)
     */
    private double worldMinAxisX = Double.NaN;
    
    /**
     * The maximum value for the x-axis, in world coordinates
     * 
     * @see #setAxisRangeX(double, double)
     */
    private double worldMaxAxisX = Double.NaN;

    /**
     * The minimum value for the Y-axis, in world coordinates
     * 
     * @see #setAxisRangeY(double, double)
     */
    private double worldMinAxisY = Double.NaN;
    
    /**
     * The maximum value for the y-axis, in world coordinates
     * 
     * @see #setAxisRangeY(double, double)
     */
    private double worldMaxAxisY = Double.NaN;
    
    /**
     * The x-coordinate where the y-axis should be, in world coordinates
     */
    private double worldXofY = 0.0;

    /**
     * The y-coordinate where the x-axis should be, in world coordinates
     */
    private double worldYofX = 0.0;
    
    /**
     * Whether ticks on the x-axis should be oriented along the positive y-axis
     */
    private boolean tickOrientationPositiveX = false;
    
    /**
     * Whether ticks on the y-axis should be oriented along the positive x-axis
     */
    private boolean tickOrientationPositiveY = false;
    
    /**
     * The {@link LabelPainter} for the labels on the x-axis
     */
    private final LabelPainter labelPainterX;
    
    /**
     * The {@link LabelPainter} for the labels on the y-axis
     */
    private final LabelPainter labelPainterY;
    
    /**
     * Creates a new default coordinate system painter
     */
    public CoordinateSystemPainter()
    {
        labelPainterX = new LabelPainter();
        labelPainterX.setPaint(axisColorX);
        labelPainterX.setTransformingLabels(false);
        labelPainterX.setFont(font);
        
        labelPainterY = new LabelPainter();
        labelPainterY.setPaint(axisColorY);
        labelPainterY.setTransformingLabels(false);
        labelPainterY.setFont(font);
    }
    
    /**
     * Set the fixed distance between ticks on the x-axis, in world coordinates.
     * If the given value is NaN, then the distance will be computed 
     * automatically.
     * 
     * @param fixedWorldTickDistanceX The tick distance
     * @throws IllegalArgumentException If the given distance is not positive
     */
    public void setFixedWorldTickDistanceX(double fixedWorldTickDistanceX)
    {
        if (fixedWorldTickDistanceX <= 0)
        {
            throw new IllegalArgumentException(
                "Tick distance must be positive, "
                + "but is "+fixedWorldTickDistanceX);
        }
        this.fixedWorldTickDistanceX = fixedWorldTickDistanceX;
    }

    /**
     * Set the fixed distance between ticks on the y-axis, in world coordinates.
     * If the given value is NaN, then the distance will be computed 
     * automatically.
     * 
     * @param fixedWorldTickDistanceY The tick distance
     * @throws IllegalArgumentException If the given distance is not positive
     */
    public void setFixedWorldTickDistanceY(double fixedWorldTickDistanceY)
    {
        if (fixedWorldTickDistanceY <= 0)
        {
            throw new IllegalArgumentException(
                "Tick distance must be positive, "
                + "but is "+fixedWorldTickDistanceY);
        }
        this.fixedWorldTickDistanceY = fixedWorldTickDistanceY;
    }
    
    /**
     * Set the color for the grid lines that should be painted at the x-axis
     * ticks in the background. If the given color is null, then 
     * the grid lines will not be painted.
     * 
     * @param gridColorX The grid color
     */
    public void setGridColorX(Color gridColorX)
    {
        this.gridColorX = gridColorX;
    }

    /**
     * Set the color for the grid lines that should be painted at the y-axis
     * ticks in the background. If the given color is null, then 
     * the grid lines will not be painted.
     * 
     * @param gridColorY The grid color
     */
    public void setGridColorY(Color gridColorY)
    {
        this.gridColorY = gridColorY;
    }
    
    /**
     * Set the color for the x-axis. If this is null, then
     * the x-axis will not be painted.
     * 
     * @param axisColorX The color for the x-axis
     */
    public void setAxisColorX(Color axisColorX)
    {
        this.axisColorX = axisColorX;
    }
    
    /**
     * Set the color of the labels on the x-axis. If this is null, 
     * then the labels on the x-axis will not be painted. 
     * 
     * @param labelColorX The label color
     */
    public void setLabelColorX(Color labelColorX)
    {
        this.labelColorX = labelColorX;
        labelPainterX.setPaint(labelColorX);
    }
    
    /**
     * Set whether ticks on the x-axis should be oriented along the positive 
     * y-axis
     * 
     * @param tickOrientationPositiveX Whether the ticks should be oriented
     * along the positive axis
     */
    void setTickOrientationPositiveX(boolean tickOrientationPositiveX)
    {
        this.tickOrientationPositiveX = tickOrientationPositiveX;
    }

    /**
     * Set the range of the x-axis that should be displayed. If either
     * of the given values is Double.NaN, then the minimum
     * or maximum value of the currently visible world area will be
     * used, respectively
     * 
     * @param worldMinAxisX The minimum value, in world coordinates
     * @param worldMaxAxisX The maximum value, in world coordinates
     */
    public void setAxisRangeX(double worldMinAxisX, double worldMaxAxisX)
    {
        this.worldMinAxisX = worldMinAxisX;
        this.worldMaxAxisX = worldMaxAxisX;
    }
    
    /**
     * Set the location where the x-axis should be painted
     *  
     * @param worldYofX The y-coordinate where the x-axis should be painted
     */
    public void setAxisLocationX(double worldYofX)
    {
        this.worldYofX = worldYofX;
    }
    
    
    /**
     * Set the layout for the x-axis. The given suppliers will provide
     * the screen coordinates that determine how the x-axis should be 
     * displayed. If any of the given suppliers is null, 
     * then the axis will be painted in world coordinates.
*
* Note that this screen-relative layout is not sensibly applicable * when the view is rotated. * * @param supplierScreenMinX The supplier for the x-coordinate on the * screen where the x-axis should start * @param supplierScreenMaxX The supplier for the x-coordinate on the * screen where the x-axis should end * @param supplierScreenY The supplier for the y-coordinate on the * screen where the x-axis should be located */ public void setScreenAxisLayoutX( IntSupplier supplierScreenMinX, IntSupplier supplierScreenMaxX, IntSupplier supplierScreenY) { this.supplierScreenMinX = supplierScreenMinX; this.supplierScreenMaxX = supplierScreenMaxX; this.supplierScreenY = supplierScreenY; } /** * Set the color for the y-axis. If this is null, then * the y-axis will not be painted. * * @param axisColorY The color for the y-axis */ public void setAxisColorY(Color axisColorY) { this.axisColorY = axisColorY; } /** * Set the color of the labels on the y-axis. If this is null, * then the labels on the y-axis will not be painted. * * @param labelColorY The label color */ public void setLabelColorY(Color labelColorY) { this.labelColorY = labelColorY; labelPainterY.setPaint(labelColorY); } /** * Set the range of the y-axis that should be displayed. If either * of the given values is Double.NaN, then the minimum * or maximum value of the currently visible world area will be * used, respectively * * @param worldMinAxisY The minimum value, in world coordinates * @param worldMaxAxisY The maximum value, in world coordinates */ public void setAxisRangeY(double worldMinAxisY, double worldMaxAxisY) { this.worldMinAxisY = worldMinAxisY; this.worldMaxAxisY = worldMaxAxisY; } /** * Set the location where the y-axis should be painted * * @param worldXofY The x-coordinate where the y-axis should be painted */ public void setAxisLocationY(double worldXofY) { this.worldXofY = worldXofY; } /** * Set whether ticks on the y-axis should be oriented along the positive * x-axis * * @param tickOrientationPositiveY Whether the ticks should be oriented * along the positive axis */ void setTickOrientationPositiveY(boolean tickOrientationPositiveY) { this.tickOrientationPositiveY = tickOrientationPositiveY; } /** * Set the layout for the y-axis. The given suppliers will provide * the screen coordinates that determine how the y-axis should be * displayed. If any of the given suppliers is null, * then the axis will be painted in world coordinates.
*
* Note that this screen-relative layout is not sensibly applicable * when the view is rotated. * * @param supplierScreenMinY The supplier for the y-coordinate on the * screen where the y-axis should start * @param supplierScreenMaxY The supplier for the y-coordinate on the * screen where the y-axis should end * @param supplierScreenX The supplier for the x-coordinate on the * screen where the y-axis should be located */ public void setScreenAxisLayoutY( IntSupplier supplierScreenMinY, IntSupplier supplierScreenMaxY, IntSupplier supplierScreenX) { this.supplierScreenMinY = supplierScreenMinY; this.supplierScreenMaxY = supplierScreenMaxY; this.supplierScreenX = supplierScreenX; } /** * Update the data that is used internally for painting the x-axis, * namely the {@link #worldTicksX} and the {@link #labelFormatX} * * @param worldToScreen The world-to-screen transform * @param worldMinX The minimum x-coordinate * @param worldMaxX The maximum x-coordinate */ private void updateX(AffineTransform worldToScreen, double worldMinX, double worldMaxX) { double worldTickDistanceX = fixedWorldTickDistanceX; if (!Double.isFinite(worldTickDistanceX)) { worldTickDistanceX = Axes.computeWorldTickDistanceX( worldToScreen, minScreenTickDistanceX); if (labelColorX != null && adjustForStringLengths) { worldTickDistanceX = Axes.computeAdjustedWorldTickDistanceX( font, worldToScreen, worldMinX, worldMaxX, worldTickDistanceX, minScreenTickDistanceX); } } worldTicksX = Axes.computeWorldTicks( worldMinX, worldMaxX, worldTickDistanceX); if (labelColorX != null) { labelFormatX = Axes.formatStringFor(worldTickDistanceX); } if (tickOrientationPositiveX) { if (worldToScreen.getScaleY() > 0) { labelPainterX.setLabelAnchor(0.5, 0.0); } else { labelPainterX.setLabelAnchor(0.5, 1.0); } } else { if (worldToScreen.getScaleY() > 0) { labelPainterX.setLabelAnchor(0.5, 1.0); } else { labelPainterX.setLabelAnchor(0.5, 0.0); } } } /** * Update the data that is used internally for painting the y-axis, * namely the {@link #worldTicksY} and the {@link #labelFormatY} * * @param worldToScreen The world-to-screen transform * @param worldMinY The minimum y-coordinate * @param worldMaxY The maximum y-coordinate */ private void updateY(AffineTransform worldToScreen, double worldMinY, double worldMaxY) { double worldTickDistanceY = fixedWorldTickDistanceY; if (!Double.isFinite(worldTickDistanceY)) { worldTickDistanceY = Axes.computeWorldTickDistanceY( worldToScreen, minScreenTickDistanceY); } worldTicksY = Axes.computeWorldTicks( worldMinY, worldMaxY, worldTickDistanceY); if (labelColorY != null) { labelFormatY = Axes.formatStringFor(worldTickDistanceY); } if (tickOrientationPositiveY) { if (worldToScreen.getScaleX() > 0) { labelPainterY.setLabelAnchor(0.0, 0.5); } else { labelPainterY.setLabelAnchor(1.0, 0.5); } } else { if (worldToScreen.getScaleX() > 0) { labelPainterY.setLabelAnchor(1.0, 0.5); } else { labelPainterY.setLabelAnchor(0.0, 0.5); } } } @Override public final void paint(Graphics2D g, AffineTransform worldToScreen, double w, double h) { Rectangle2D screenBounds = new Rectangle2D.Double(0, 0, w, h); AffineTransform screenToWorld = AffineTransforms.invert(worldToScreen, null); Rectangles.computeBounds( screenToWorld, screenBounds, worldBounds); updateX(worldToScreen, worldBounds.getMinX(), worldBounds.getMaxX()); updateY(worldToScreen, worldBounds.getMinY(), worldBounds.getMaxY()); g.setStroke(stroke); if (gridColorX != null) { g.setColor(gridColorX); paintInternalGridX(g, worldToScreen); } if (gridColorY != null) { g.setColor(gridColorY); paintInternalGridY(g, worldToScreen); } if (axisColorX != null) { g.setColor(axisColorX); paintAxisX(g, worldToScreen); } if (axisColorY != null) { g.setColor(axisColorY); paintAxisY(g, worldToScreen); } } /** * Paint the x-axis. * * @param g The graphics to paint to * @param worldToScreen The world-to-screen transform */ private void paintAxisX( Graphics2D g, AffineTransform worldToScreen) { if (supplierScreenMinX == null || supplierScreenMaxX == null || supplierScreenY == null) { paintAxisX(g, worldToScreen, getValue(worldMinAxisX, worldBounds.getMinX()), getValue(worldMaxAxisX, worldBounds.getMaxX()), worldYofX); } else { int screenMinX = supplierScreenMinX.getAsInt(); int screenMaxX = supplierScreenMaxX.getAsInt(); int screenY = supplierScreenY.getAsInt(); Point2D pxMin = new Point2D.Double(screenMinX, screenY); Point2D pxMax = new Point2D.Double(screenMaxX, screenY); Points.inverseTransform(worldToScreen, pxMin, pxMin); Points.inverseTransform(worldToScreen, pxMax, pxMax); updateX(worldToScreen, pxMin.getX(), pxMax.getX()); paintAxisX(g, worldToScreen, pxMin.getX(), pxMax.getX(), pxMin.getY()); } } /** * Paint the y-axis. * * @param g The graphics to paint to * @param worldToScreen The world-to-screen transform */ protected void paintAxisY( Graphics2D g, AffineTransform worldToScreen) { if (supplierScreenMinY == null || supplierScreenMaxY == null || supplierScreenX == null) { paintAxisY(g, worldToScreen, getValue(worldMinAxisY, worldBounds.getMinY()), getValue(worldMaxAxisY, worldBounds.getMaxY()), worldXofY); } else { int screenMinY = supplierScreenMinY.getAsInt(); int screenMaxY = supplierScreenMaxY.getAsInt(); int screenX = supplierScreenX.getAsInt(); Point2D pyMin = new Point2D.Double(screenX, screenMinY); Point2D pyMax = new Point2D.Double(screenX, screenMaxY); Points.inverseTransform(worldToScreen, pyMin, pyMin); Points.inverseTransform(worldToScreen, pyMax, pyMax); paintAxisY(g, worldToScreen, pyMin.getY(), pyMax.getY(), pyMin.getX()); } } /** * Paint the x-axis after it has been made sure that the * {@link #worldTicksX} and {@link #labelFormatX} are up to date * * @param g The graphics to paint to * @param worldToScreen The world-to-screen transform * @param worldMinX The minimum world coordinate of the axis * @param worldMaxX The maximum world coordinate of the axis * @param worldY The world coordinate at which the axis should be painted */ private void paintAxisX( Graphics2D g, AffineTransform worldToScreen, double worldMinX, double worldMaxX, double worldY) { TEMP_LINE.setLine(worldMinX,worldY,worldMaxX,worldY); Lines.transform(worldToScreen, TEMP_LINE, TEMP_LINE); g.draw(TEMP_LINE); for (int i=0; i= worldMinX && worldTickX <= worldMaxX) { paintTickX(g, worldToScreen, worldTickX, worldY); } } } /** * Paint the y-axis after it has been made sure that the * {@link #worldTicksY} and {@link #labelFormatY} are up to date * * @param g The graphics to paint to * @param worldToScreen The world-to-screen transform * @param worldMinY The minimum world coordinate of the axis * @param worldMaxY The maximum world coordinate of the axis * @param worldX The world coordinate at which the axis should be painted */ private void paintAxisY( Graphics2D g, AffineTransform worldToScreen, double worldMinY, double worldMaxY, double worldX) { TEMP_LINE.setLine(worldX,worldMinY,worldX,worldMaxY); Lines.transform(worldToScreen, TEMP_LINE, TEMP_LINE); g.draw(TEMP_LINE); for (int i=0; i= worldMinY && worldTickY <= worldMaxY) { paintTickY(g, worldToScreen, worldX, worldTickY); } } } /** * Paint the coordinate grid in the background, after it has been * made sure that the data for painting the grid and axes is up * to date * * @param g The graphics to paint to * @param worldToScreen The world-to-screen transform */ private void paintInternalGridX(Graphics2D g, AffineTransform worldToScreen) { double worldMinX = getValue(worldMinAxisX, worldBounds.getMinX()); double worldMaxX = getValue(worldMaxAxisX, worldBounds.getMaxX()); double worldMinY = getValue(worldMinAxisY, worldBounds.getMinY()); double worldMaxY = getValue(worldMaxAxisY, worldBounds.getMaxY()); for (int i=0; i= worldMinX && worldTickX <= worldMaxX) { paintGridLineX(g, worldToScreen, worldTickX, worldMinY, worldMaxY); } } } /** * Paint the coordinate grid in the background, after it has been * made sure that the data for painting the grid and axes is up * to date * * @param g The graphics to paint to * @param worldToScreen The world-to-screen transform */ private void paintInternalGridY(Graphics2D g, AffineTransform worldToScreen) { double worldMinX = getValue(worldMinAxisX, worldBounds.getMinX()); double worldMaxX = getValue(worldMaxAxisX, worldBounds.getMaxX()); double worldMinY = getValue(worldMinAxisY, worldBounds.getMinY()); double worldMaxY = getValue(worldMaxAxisY, worldBounds.getMaxY()); for (int i=0; i= worldMinY && worldTickY <= worldMaxY) { paintGridLineY(g, worldToScreen, worldTickY, worldMinX, worldMaxX); } } } /** * Paints a single grid line at the given x-coordinate * * @param g The graphics context * @param worldToScreen The world-to-screen transform * @param worldX The world coordinate of the grid line * @param worldMinY The minimum y-coordinate * @param worldMaxY The maximum y-coordinate */ private void paintGridLineX(Graphics2D g, AffineTransform worldToScreen, double worldX, double worldMinY, double worldMaxY) { TEMP_LINE.setLine(worldX, worldMinY, worldX, worldMaxY); Lines.transform(worldToScreen, TEMP_LINE, TEMP_LINE); g.draw(TEMP_LINE); } /** * Paints a single grid line at the given y-coordinate * * @param g The graphics context * @param worldToScreen The world-to-screen transform * @param worldY The world coordinate of the tick * @param worldMinX The minimum x-coordinate * @param worldMaxX The maximum x-coordinate */ private void paintGridLineY(Graphics2D g, AffineTransform worldToScreen, double worldY, double worldMinX, double worldMaxX) { TEMP_LINE.setLine(worldMinX, worldY, worldMaxX, worldY); Lines.transform(worldToScreen, TEMP_LINE, TEMP_LINE); g.draw(TEMP_LINE); } /** * Paints a single tick of the x-axis * * @param g The graphics context * @param worldToScreen The world-to-screen transform * @param worldX The x-world coordinate of the tick * @param worldY The y-world coordinate of the tick */ private void paintTickX(Graphics2D g, AffineTransform worldToScreen, double worldX, double worldY) { TEMP_LINE.setLine(worldX, worldY, worldX, worldY+1); Lines.transform(worldToScreen, TEMP_LINE, TEMP_LINE); double length = -tickSizeScreen; if (tickOrientationPositiveX) { length = -length; } Lines.scaleToLength(length, TEMP_LINE, TEMP_LINE); g.draw(TEMP_LINE); if (labelColorX != null ) { TEMP_POINT.setLocation(TEMP_LINE.getX2(), TEMP_LINE.getY2()); Points.inverseTransform(worldToScreen, TEMP_POINT, TEMP_POINT); paintLabelX(g, worldToScreen, TEMP_POINT.getX(), TEMP_POINT.getY()); } } /** * Paints a single label of the x-axis * * @param g The graphics context * @param worldToScreen The world-to-screen transform * @param worldX The x-world coordinate of the label * @param worldY The y-world coordinate of the label */ private void paintLabelX(Graphics2D g, AffineTransform worldToScreen, double worldX, double worldY) { String string = String.format(labelFormatX, worldX); labelPainterX.setLabelLocation(worldX, worldY); labelPainterX.paint(g, worldToScreen, 0, 0, string); } /** * Paints a single tick of the y-axis * * @param g The graphics context * @param worldToScreen The world-to-screen transform * @param worldX The x-world coordinate of the tick * @param worldY The y-world coordinate of the tick */ private void paintTickY(Graphics2D g, AffineTransform worldToScreen, double worldX, double worldY) { TEMP_LINE.setLine(worldX, worldY, worldX+1.0, worldY); Lines.transform(worldToScreen, TEMP_LINE, TEMP_LINE); double length = -tickSizeScreen; if (tickOrientationPositiveY) { length = -length; } Lines.scaleToLength(length, TEMP_LINE, TEMP_LINE); g.draw(TEMP_LINE); if (labelColorY != null ) { TEMP_POINT.setLocation(TEMP_LINE.getX2(), TEMP_LINE.getY2()); Points.inverseTransform(worldToScreen, TEMP_POINT, TEMP_POINT); paintLabelY(g, worldToScreen, TEMP_POINT.getX(), TEMP_POINT.getY()); } } /** * Paints a single label of the y-axis * * @param g The graphics context * @param worldToScreen The world-to-screen transform * @param worldX The x-world coordinate of the label * @param worldY The y-world coordinate of the label */ private void paintLabelY(Graphics2D g, AffineTransform worldToScreen, double worldX, double worldY) { String string = String.format(labelFormatY, worldY); labelPainterY.setLabelLocation(worldX, worldY); labelPainterY.paint(g, worldToScreen, 0, 0, string); } /** * Returns the given optional value if it is not Double.NaN, * and the given value otherwise * * @param optionalValue The optional value * @param value The value * @return The respective value */ private static double getValue(double optionalValue, double value) { if (!Double.isNaN(optionalValue)) { return optionalValue; } return value; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy