content: // ===============================================================================
  // Authors: AFRL/RQQD
  // Organization: Air Force Research Laboratory, Aerospace Systems Directorate, Power and Control Division
  // 
  // Copyright (c) 2017 Government of the United State of America, as represented by
  // the Secretary of the Air Force.  No copyright is claimed in the United States under
  // Title 17, U.S. Code.  All Other Rights Reserved.
  // ===============================================================================
  
  /*
   * GRAL: GRAphing Library for Java(R)
   *
   * (C) Copyright 2009-2013 Erich Seifert <dev[at]erichseifert.de>,
   * Michael Seifert <mseifert[at]error-reports.org>
   *
   * This file is part of GRAL.
   *
   * GRAL 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 3 of the License, or
   * (at your option) any later version.
   *
   * GRAL 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 GRAL.  If not, see <http://www.gnu.org/licenses/>.
   */
  package de.erichseifert.gral.plots.lines;
  
  import java.awt.Paint;
  import java.awt.Shape;
  import java.awt.geom.Path2D;
  import java.awt.geom.Point2D;
  import java.util.List;
  
  import de.erichseifert.gral.graphics.AbstractDrawable;
  import de.erichseifert.gral.graphics.Drawable;
  import de.erichseifert.gral.graphics.DrawingContext;
  import de.erichseifert.gral.plots.DataPoint;
  import de.erichseifert.gral.util.GraphicsUtils;
  import de.erichseifert.gral.util.Orientation;
  
  
  /**
   * Class that connects {@code DataPoint}s with a stair-like line.
   */
  public class DiscreteLineRenderer2D extends AbstractLineRenderer2D {
  	/** Version id for serialization. */
  	private static final long serialVersionUID = 4648286099838467355L;
  
  	/** Primary direction of the "steps". */
  	private Orientation ascentDirection;
  	/** Relative distance between points, where the orientation changes. */
  	private Number ascendingPoint;
  
  	/**
  	 * Initializes a new {@code DiscreteLineRenderer2D} instance with default
  	 * settings.
  	 */
  	public DiscreteLineRenderer2D() {
  		ascentDirection = Orientation.HORIZONTAL;
  		ascendingPoint = 0.5;
  	}
  
  	/**
  	 * Returns a graphical representation for the line defined by
  	 * {@code points}.
  	 * @param points Points to be used for creating the line.
  	 * @param shape Geometric shape for this line.
  	 * @return Representation of the line.
  	 */
  	public Drawable getLine(final List<DataPoint> points, final Shape shape) {
  		Drawable d = new AbstractDrawable() {
  			/** Version id for serialization. */
  			private static final long serialVersionUID = -1686744943386843195L;
  
  			/**
  			 * Draws the {@code Drawable} with the specified drawing context.
  			 * @param context Environment used for drawing
  			 */
  			public void draw(DrawingContext context) {
  				// Draw path
  				Paint paint = DiscreteLineRenderer2D.this.getColor();
  				GraphicsUtils.fillPaintedShape(
  					context.getGraphics(), shape, paint, null);
  			}
  		};
  		return d;
  	}
  
  	/**
  	 * Returns the geometric shape for this line.
  	 * @param points Points used for creating the line.
  	 * @return Geometric shape for this line.
  	 */
  	public Shape getLineShape(List<DataPoint> points) {
  		Orientation dir = getAscentDirection();
  		double ascendingPoint = getAscendingPoint().doubleValue();
  
  		// Construct shape
  		Path2D shape = new Path2D.Double();
  		for (DataPoint point : points) {
  			Point2D pos = point.position.getPoint2D();
  			if (shape.getCurrentPoint() == null) {
  				shape.moveTo(pos.getX(), pos.getY());
  			} else {
  				Point2D posPrev = shape.getCurrentPoint();
  				if (dir == Orientation.HORIZONTAL) {
  					double ascendingX = posPrev.getX() +
  						(pos.getX() - posPrev.getX()) * ascendingPoint;
  					shape.lineTo(ascendingX,  posPrev.getY());
  					shape.lineTo(ascendingX,  pos.getY());
  				} else {
  					double ascendingY = posPrev.getY() +
  						(pos.getY() - posPrev.getY()) * ascendingPoint;
  					shape.lineTo(posPrev.getX(), ascendingY);
  					shape.lineTo(pos.getX(), ascendingY);
  				}
  				shape.lineTo(pos.getX(), pos.getY());
  			}
  		}
  
  		return punch(shape, points);
  	}
  
  	/**
  	 * Returns the primary direction of the "steps".
  	 * @return Orientation of the "steps".
  	 */
  	public Orientation getAscentDirection() {
  		return ascentDirection;
  	}
  
  	/**
  	 * Sets the primary direction of the "steps".
  	 * @param ascentDirection Orientation of the "steps".
  	 */
  	public void setAscentDirection(Orientation ascentDirection) {
  		this.ascentDirection = ascentDirection;
  	}
  
  	/**
  	 * Returns the relative distance between two points, {@literal i.e.} the "step" of a stair.
  	 * @return Relative point distance.
  	 */
  	public Number getAscendingPoint() {
  		return ascendingPoint;
  	}
  
  	/**
  	 * Sets the relative distance between two points, {@literal i.e.} the "step" of a stair.
  	 * @param ascendingPoint Relative point distance.
  	 */
  	public void setAscendingPoint(Number ascendingPoint) {
  		this.ascendingPoint = ascendingPoint;
  	}
  }
  