/* * Copyright (c) 2008-2009, 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 edu.umd.cs.piccolox.util; import java.awt.Rectangle; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.geom.PathIterator; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; public class LineShape implements Shape, MutablePoints { private MutablePoints points; private final Rectangle2D bounds = new Rectangle2D.Double(); public LineShape(final MutablePoints points) { setPoints(points); } public void setPoints(MutablePoints points) { if (points == null) { points = new XYArray(); } this.points = points; } // from Points public int getPointCount() { return points.getPointCount(); } public double getX(final int i) { return points.getX(i); } public double getY(final int i) { return points.getY(i); } public Point2D getPoint(final int i, final Point2D dst) { return points.getPoint(i, dst); } public Rectangle2D getBounds(final Rectangle2D dst) { points.getBounds(dst); return dst; } // from MutablePoints public void updateBounds() { bounds.setRect(0.0d, 0.0d, 0.0d, 0.0d); points.getBounds(bounds); } public void setPoint(final int i, final double x, final double y) { points.setPoint(i, x, y); updateBounds(); } public void addPoint(final int pos, final double x, final double y) { points.addPoint(pos, x, y); updateBounds(); } public void removePoints(final int pos, final int num) { points.removePoints(pos, num); updateBounds(); } public void transformPoints(final AffineTransform trans) { final XYArray newPoints = new XYArray(points.getPointCount()); newPoints.appendPoints(points); newPoints.transformPoints(trans); points = newPoints; } // public Rectangle getBounds() { return new Rectangle((int) bounds.getX(), (int) bounds.getY(), (int) bounds.getWidth(), (int) bounds .getHeight()); } public Rectangle2D getBounds2D() { return bounds; } public static boolean contains(final double x, final double y, final double x1, final double y1, final double x2, final double y2, final boolean min, final boolean max, final double d) { double dx = x2 - x1, dy = y2 - y1; final double dx2 = dx * dx, dy2 = dy * dy; double p; if (dx != 0) { p = ((x - x1) / dx + dy * (y - y1) / dx2) / (1 + dy2 / dx2); } else if (dy != 0) { p = ((y - y1) / dy + dx * (x - x1) / dy2) / (1 + dx2 / dy2); } else { return false; } if (max && p > 1.0) { return false; } else if (min && p < 0.0) { return false; } dx = p * dx + x1 - x; dy = p * dy + y1 - y; final double len = dx * dx + dy * dy; return len < d; } public boolean contains(final double x, final double y, final double d) { double x1, y1, x2, y2; if (points.getPointCount() == 0) { return false; } x2 = points.getX(0); y2 = points.getX(0); for (int i = 0; i < points.getPointCount(); i++) { x1 = x2; y1 = y2; x2 = points.getX(i); y2 = points.getX(i); if (contains(x, y, x1, y1, x2, y2, false, false, d)) { return true; } } return false; } public boolean contains(final double x, final double y) { return contains(x, y, 2.0d); } public boolean contains(final Point2D p) { return contains(p.getX(), p.getY()); } public static boolean intersects(final double x1, final double y1, final double x2, final double y2, final double x3, final double y3, final double x4, final double y4, final boolean min1, final boolean max1, final boolean min2, final boolean max2) { final double dx1 = x2 - x1, dy1 = y2 - y1, dx2 = x4 - x3, dy2 = y4 - y3; double d, p2, p1; if (dy1 != 0.0) { d = dx1 / dy1; p2 = (x3 - x1 + d * (y1 - y3)) / (d * dy2 - dx2); p1 = (dy2 * p2 + y3 - y1) / dy1; } else if (dy2 != 0.0) { d = dx2 / dy2; p1 = (x1 - x3 + d * (y3 - y1)) / (d * dy1 - dx1); p2 = (dy1 * p1 + y1 - y3) / dy2; } else if (dx1 != 0.0) { d = dy1 / dx1; p2 = (y3 - y1 + d * (x1 - x3)) / (d * dx2 - dy2); p1 = (dx2 * p2 + x3 - x1) / dx1; } else if (dx2 != 0.0) { d = dy2 / dx2; p1 = (y1 - y3 + d * (x3 - x1)) / (d * dx1 - dy1); p2 = (dx1 * p1 + x1 - x3) / dx2; } else { return false; } return (!min1 || p1 >= 0.0) && (!max1 || p1 <= 1.0) && (!min2 || p2 >= 0.0) && (!max2 || p2 <= 1.0); } public boolean intersects(final double x, final double y, final double w, final double h) { double x1, y1, x2, y2; if (points.getPointCount() == 0) { return false; } x2 = points.getX(0); y2 = points.getY(0); for (int i = 0; i < points.getPointCount(); i++) { x1 = x2; y1 = y2; x2 = points.getX(i); y2 = points.getY(i); if (intersects(x, y, x + w, y, x1, y1, x2, y2, true, true, true, true) || intersects(x + w, y, x + w, y + h, x1, y1, x2, y2, true, true, true, true) || intersects(x + w, y + h, x, y + h, x1, y1, x2, y2, true, true, true, true) || intersects(x, y + h, x, y, x1, y1, x2, y2, true, true, true, true)) { return true; } } return false; } public boolean intersects(final Rectangle2D r) { return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); } public boolean contains(final double x, final double y, final double w, final double h) { return contains(x, y) && contains(x + w, y) && contains(x, y + h) && contains(x + w, y + h); } public boolean contains(final Rectangle2D r) { return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); } // // public PathIterator getPathIterator(final AffineTransform at) { return new LinePathIterator(points, at); } public PathIterator getPathIterator(final AffineTransform at, final double flatness) { return new LinePathIterator(points, at); } private static class LinePathIterator implements PathIterator { private final Points points; private final AffineTransform trans; private int i = 0; public LinePathIterator(final Points points, final AffineTransform trans) { this.points = points; this.trans = trans; } public int getWindingRule() { return GeneralPath.WIND_EVEN_ODD; } public boolean isDone() { return i >= points.getPointCount(); } public void next() { i++; } private final Point2D tempPoint = new Point2D.Double(); private void currentSegment() { tempPoint.setLocation(points.getX(i), points.getY(i)); if (trans != null) { trans.transform(tempPoint, tempPoint); } } public int currentSegment(final float[] coords) { currentSegment(); coords[0] = (float) tempPoint.getX(); coords[1] = (float) tempPoint.getY(); return i == 0 ? PathIterator.SEG_MOVETO : PathIterator.SEG_LINETO; } public int currentSegment(final double[] coords) { currentSegment(); coords[0] = tempPoint.getX(); coords[1] = tempPoint.getY(); return i == 0 ? PathIterator.SEG_MOVETO : PathIterator.SEG_LINETO; } } }