📄 shapeutils.java
字号:
Point2D.Float result = null; Point2D.Float test = null; PointIterator iter = new PointIterator(s); // if you pass an empty shape it is your problem not mine doofus :) result = iter.nextPoint(); while(iter.hasNext()) { test = iter.nextPoint(); if (pt.distance(result) > pt.distance(test)) { result = test; } } return result; } /** * Find the line segment between two consecutive knot points of the given * <code>Shape</code> that is closest to a specified point. Note that this * method will return a line even if the segment it represents in the shape * is a cubic or quadratic bezier curve. * * @param aShape The shape from which to find the line segment * @param aPoint The point to which the distance is compared. * @return A unique line segment that is closer to the point than any other. * * @throws NoUniqueLineException If there are two or more lines equidistant * from the point. * @throws NotEnoughPointsException If the aShape contains less than 2 points * */ public static Line2D.Float nearestSegment(Shape aShape, Point2D.Float aPoint) throws NoUniqueLineException, NotEnoughPointsException { PointIterator iter = new PointIterator(aShape); Point2D.Float last = null; Point2D.Float curr = null; Line2D.Float closest = null; Line2D.Float nextBest = null; Line2D.Float other = null; double closestDist = -1; double nextBestDist = -1; if (iter.hasNext()) { last = iter.nextPoint(); } if (iter.hasNext()) { curr = iter.nextPoint(); } if (last == null || curr == null) { throw new NotEnoughPointsException("Not enough points for a line"); } if (last.equals(curr) && !iter.hasNext()) { throw new NotEnoughPointsException("Only two duplicate points"); } closest = new Line2D.Float(last,curr); closestDist = closest.ptSegDist(aPoint); while (iter.hasNext()) { last = curr; curr = iter.nextPoint(); if (last.equals(curr)) { continue; } other = new Line2D.Float(last,curr); double otherDist = other.ptSegDist(aPoint); if (nextBest == null) { nextBest = other; nextBestDist = otherDist; } if (closestDist == otherDist) { nextBest = other; nextBestDist = otherDist; } else { if (closestDist > otherDist) { nextBest = closest; nextBestDist = closestDist; closest = other; closestDist = otherDist; } } } // The following case would occr with a shape constructed with // moveTo(1,1) lineTo(1,1) closePath() or other "go nowhere" shapes. if (nextBest == null) { throw new NotEnoughPointsException("Only duplicate points found"); } if (closestDist == nextBestDist) { throw new NoUniqueLineException("More than one Line"); } return closest; } /** * Find the mean location of a list of <code>Point2D.Float</code>. * * @param pointList A list containing <em>only</em> Point2D.Float * @return The average point. * @throws ClassCastException If the objects in the supplied list are not * of type Point2D.Float */ public static Point2D.Float meanPoint(List pointList) { double sumX = 0; double sumY = 0; float meanX, meanY; for (int i=0; i<pointList.size();i++) { sumX += ((Point2D.Float) pointList.get(i)).x; sumY += ((Point2D.Float) pointList.get(i)).y; } meanX = new Double(sumX/pointList.size()).floatValue(); meanY = new Double(sumY/pointList.size()).floatValue(); return new Point2D.Float(meanX, meanY); } /** * Calcualte the average of all points contained within one shape and * belonging to another. * * @param container The shape which may contain points * @param containee The shape whose points may be contained * @return The average of the points contained. */ public static Point2D.Float meanContainedPoint(Shape container, Shape containee) throws NotEnoughPointsException { ArrayList contained = getContainedPoints(container, containee); if (contained.size() == 0) { throw new NotEnoughPointsException("no points contained by container"); } return meanPoint(contained); } /** * Get a list of the points belonging to one shape and contained within * another. * * @param container The shape which may contain points * @param containee The shape whose points may be contained * @return The points belonging to containee and within conainer */ public static ArrayList getContainedPoints(Shape container, Shape containee) { ArrayList points = new ArrayList(); PointIterator iter = new PointIterator(containee); Point2D.Float temp; while (iter.hasNext()) { temp = iter.nextPoint(); if (container.contains(temp.x,temp.y)) { points.add(temp.clone()); } } return points; } /** * Test to see if two <code>Shape</code> objects overlap. * The algorithim in this test will only detect the type of * overlap where a <a href="knotpts">knot point</a> from one shape is * contained by the other shape (as determined by each shape's * implementation of the <code>contains(double, double)</code> method. * * @param shapeA the first shape * @param shapeB the second shape * @return true if the shapes overlap false otherwise */ public static boolean isOverlapping(Shape shapeA, Shape shapeB) { PointIterator iter = new PointIterator(shapeA); PointIterator iter2 = new PointIterator(shapeB); Point2D.Float temp; // Begin CPU time optimization: // ---------------------------- // Most comparisons are between distant objects, so itterating // all points is unnecessary if the bounding boxes don't overlap. Rectangle rectA = shapeA.getBounds(); Rectangle rectB = shapeB.getBounds(); if(!rectA.intersects(rectB)) { return false; } // end CPU time optimization while(iter.hasNext()) { temp = iter.nextPoint(); if (shapeB.contains(temp.x,temp.y)) { return true; } } while(iter2.hasNext()) { temp = iter2.nextPoint(); if (shapeA.contains(temp.x,temp.y)) { return true; } } return false; } /** * Convert any AWT shape into a shape with a specified precision. * The specified precision indicates the maximum tolerable distance * between <a href="knotpts">knot points</a>. If the shape is already * precise enough then it is returned unmodified. * * @param aShape the shape to be converted if necessary. * @param precision the maximum tolerable distance between knot points. * @return A more precise version of the shape, or the same shape if * the precision is already satisfied. */ public static Shape getPreciseShape(Shape aShape, float precision) { GeneralPath path = new GeneralPath(aShape); GeneralPath newPath = getPrecisePath(path, precision); return (path == newPath) ? aShape : newPath; } /** * Increase the precision of a given <code>GeneralPath</code> object. * The specified precision indicates the maximum tolerable distance * between <a href="knotpts">knot points</a>. If the path is already * precise enough then it is returned unmodified. * * @param aPath The path to convert if necessary. * @param precision the maximum tolerable distance between knot points. * @return A more precise version of the path or the same path if the * precision was alredy satisfied. */ public static GeneralPath getPrecisePath(GeneralPath aPath, float precision) { GeneralPath[] paths = new GeneralPath[2]; paths[0] = aPath; while (paths[0] != paths[1]) { paths[1] = paths[0]; paths[0] = getImprovedPath(paths[0],precision); } return paths[0]; } /** * Used iteratively by getPrecisePath to acheive as specified precision. * The path is traversed and for every case in which the distance between * consecutive <a href="knotpts">knot points</a> is greater than the * precision value, a new knot point and associated control points are * inserted. The surroundng knot points have their control points modified * appropriately to maintain an Identical curve. The new knot point is * only guaranteed to lie on the curve and in extreme cases may even be * further from either of the orriginal knot points than the distance * between the original knot points, but this indicates a situation in * which a radical curve has been drawn and further itterations * will eventually reduce the distance.<p> * * Note that because GeneralPath does not overide equals we * return a reference to the SAME object passed in if there are no * improvements to be made. aPath.equals(newPath) is equivalent to * aPath == newPath. * * @param aPath The path that may need to be improved. * @param precision The minimum acceptable distance between knot points. */ public static GeneralPath getImprovedPath(GeneralPath aPath, float precision) { GeneralPath newPath = new GeneralPath(); PathIterator iter = aPath.getPathIterator(null); Point2D.Float currPt = new Point2D.Float(); Point2D.Float conPt1 = new Point2D.Float(); Point2D.Float conPt2 = new Point2D.Float();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -