org.piccolo2d.extras.nodes.PLine Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2011, Piccolo2D project, http://piccolo2d.org
* Copyright (c) 1998-2008, University of Maryland
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of conditions
* and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions
* and the following disclaimer in the documentation and/or other materials provided with the
* distribution.
*
* None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
* contributors may be used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.piccolo2d.extras.nodes;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Stroke;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import org.piccolo2d.PNode;
import org.piccolo2d.extras.util.LineShape;
import org.piccolo2d.nodes.PPath;
import org.piccolo2d.util.PAffineTransform;
import org.piccolo2d.util.PPaintContext;
import org.piccolo2d.util.PUtil;
/**
* PLine a class for drawing multisegment lines.
*
* @author Hallvard Traetteberg.
*/
public class PLine extends PNode {
private static final long serialVersionUID = 1L;
private static final PAffineTransform TEMP_TRANSFORM = new PAffineTransform();
private static final BasicStroke DEFAULT_STROKE = new BasicStroke(1.0f);
private static final Color DEFAULT_STROKE_PAINT = Color.black;
private static final String PROPERTY_STROKE_PAINT = "strokePaint";
private static final int PROPERTY_CODE_STROKE_PAINT = 1 << 16;
private static final String PROPERTY_STROKE = "stroke";
private static final int PROPERTY_CODE_STROKE = 1 << 17;
private static final String PROPERTY_PATH = "path";
private static final int PROPERTY_CODE_PATH = 1 << 18;
private final transient LineShape lineShape;
private transient Stroke stroke;
private Paint strokePaint;
/**
* Constructs a new PLine with an empty LineShape.
*/
public PLine() {
this(null);
}
/**
* Constructs a PLine object for displaying the provided line.
*
* @param lineShape will be displayed by this PLine
*/
public PLine(final LineShape lineShape) {
strokePaint = DEFAULT_STROKE_PAINT;
stroke = DEFAULT_STROKE;
if (lineShape == null) {
this.lineShape = new LineShape(null);
}
else {
this.lineShape = lineShape;
}
}
/**
* Constructs a PLine for the given lineShape and the given stroke.
*
* @param line line to be wrapped by this PLine
* @param aStroke stroke to use when drawling the line
*/
public PLine(final LineShape line, final Stroke aStroke) {
this(line);
stroke = aStroke;
}
/**
* Returns the paint to be used while drawing the line.
*
* @return paint used when drawing the line
*/
public Paint getStrokePaint() {
return strokePaint;
}
/**
* Changes the paint to be used while drawing the line.
*
* @param newStrokePaint paint to use when drawing the line
*/
public void setStrokePaint(final Paint newStrokePaint) {
final Paint oldPaint = strokePaint;
strokePaint = newStrokePaint;
invalidatePaint();
firePropertyChange(PROPERTY_CODE_STROKE_PAINT, PROPERTY_STROKE_PAINT, oldPaint, strokePaint);
}
/**
* Returns the stroke that will be used when drawing the line.
*
* @return stroke used to draw the line
*/
public Stroke getStroke() {
return stroke;
}
/**
* Sets stroke to use when drawing the line.
*
* @param newStroke stroke to use when drawing the line
*/
public void setStroke(final Stroke newStroke) {
final Stroke oldStroke = stroke;
stroke = newStroke;
updateBoundsFromLine();
invalidatePaint();
firePropertyChange(PROPERTY_CODE_STROKE, PROPERTY_STROKE, oldStroke, stroke);
}
/** {@inheritDoc} */
public boolean setBounds(final double x, final double y, final double width, final double height) {
if (lineShape == null || !super.setBounds(x, y, width, height)) {
return false;
}
final Rectangle2D lineBounds = lineShape.getBounds2D();
final Rectangle2D lineStrokeBounds = getLineBoundsWithStroke();
final double strokeOutset = Math.max(lineStrokeBounds.getWidth() - lineBounds.getWidth(), lineStrokeBounds
.getHeight()
- lineBounds.getHeight());
double adjustedX = x + strokeOutset / 2;
double adjustedY = y + strokeOutset / 2;
double adjustedWidth = width - strokeOutset;
double adjustedHeight = height - strokeOutset;
TEMP_TRANSFORM.setToIdentity();
TEMP_TRANSFORM.translate(adjustedX, adjustedY);
TEMP_TRANSFORM.scale(adjustedWidth / lineBounds.getWidth(), adjustedHeight / lineBounds.getHeight());
TEMP_TRANSFORM.translate(-lineBounds.getX(), -lineBounds.getY());
lineShape.transformPoints(TEMP_TRANSFORM);
return true;
}
/** {@inheritDoc} */
public boolean intersects(final Rectangle2D aBounds) {
if (super.intersects(aBounds)) {
if (lineShape.intersects(aBounds)) {
return true;
}
else if (stroke != null && strokePaint != null) {
return stroke.createStrokedShape(lineShape).intersects(aBounds);
}
}
return false;
}
/**
* Calculates the bounds of the line taking stroke width into account.
*
* @return rectangle representing the bounds of the line taking stroke width
* into account
*/
public Rectangle2D getLineBoundsWithStroke() {
if (stroke != null) {
return stroke.createStrokedShape(lineShape).getBounds2D();
}
else {
return lineShape.getBounds2D();
}
}
/**
* Recalculates the bounds when a change to the underlying line occurs.
*/
public void updateBoundsFromLine() {
if (lineShape.getPointCount() == 0) {
resetBounds();
}
else {
final Rectangle2D b = getLineBoundsWithStroke();
super.setBounds(b.getX(), b.getY(), b.getWidth(), b.getHeight());
}
}
/**
* Paints the PLine in the provided context if it has both a stroke and a
* stroke paint assigned.
*
* @param paintContext the context into which the line should be drawn
*/
protected void paint(final PPaintContext paintContext) {
final Graphics2D g2 = paintContext.getGraphics();
if (stroke != null && strokePaint != null) {
g2.setPaint(strokePaint);
g2.setStroke(stroke);
g2.draw(lineShape);
}
}
/**
* Returns a reference to the underlying line shape. Be careful!
*
* @return direct reference to the underlying line shape
*/
public LineShape getLineReference() {
return lineShape;
}
/**
* Returns the number of points in the line.
*
* @return number of points in the line
*/
public int getPointCount() {
return lineShape.getPointCount();
}
/**
* Returns the point at the provided index. If dst is not null, it will
* populate it with the point's coordinates rather than create a new point.
*
* @param pointIndex index of desired point in line
* @param dst point to populate, may be null
* @return the desired point, or dst populate with its coordinates
*/
public Point2D getPoint(final int pointIndex, final Point2D dst) {
final Point2D result;
if (dst == null) {
result = new Point2D.Double();
}
else {
result = dst;
}
return lineShape.getPoint(pointIndex, result);
}
/**
* Fires appropriate change events, updates line bounds and flags the PLine
* as requiring a repaint.
*/
protected void lineChanged() {
firePropertyChange(PROPERTY_CODE_PATH, PROPERTY_PATH, null, lineShape);
updateBoundsFromLine();
invalidatePaint();
}
/**
* Changes the point at the provided index.
*
* @param pointIndex index of point to change
* @param x x component to assign to the point
* @param y y component to assign to the point
*/
public void setPoint(final int pointIndex, final double x, final double y) {
lineShape.setPoint(pointIndex, x, y);
lineChanged();
}
/**
* Inserts a point at the provided index.
*
* @param pointIndex index at which to add the point
* @param x x component of new point
* @param y y component of new point
*/
public void addPoint(final int pointIndex, final double x, final double y) {
lineShape.addPoint(pointIndex, x, y);
lineChanged();
}
/**
* Removes points from the line.
*
* @param startIndex index from which to remove the points
* @param numberOfPoints number of points to remove
*/
public void removePoints(final int startIndex, final int numberOfPoints) {
lineShape.removePoints(startIndex, numberOfPoints);
lineChanged();
}
/**
* Removes all points from the underlying line.
*/
public void removeAllPoints() {
lineShape.removePoints(0, lineShape.getPointCount());
lineChanged();
}
private void writeObject(final ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
PUtil.writeStroke(stroke, out);
}
private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
stroke = PUtil.readStroke(in);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy