📄 generalpath.java
字号:
/* * @(#)GeneralPath.java 1.58 03/01/23 * * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */package java.awt.geom;import java.awt.Shape;import sun.awt.geom.Curve;import sun.awt.geom.Crossings;/** * The <code>GeneralPath</code> class represents a geometric path * constructed from straight lines, and quadratic and cubic * (Bézier) curves. It can contain multiple subpaths. * <p> * The winding rule specifies how the interior of a path is * determined. There are two types of winding rules: * EVEN_ODD and NON_ZERO. * <p> * An EVEN_ODD winding rule means that enclosed regions * of the path alternate between interior and exterior areas as * traversed from the outside of the path towards a point inside * the region. * <p> * A NON_ZERO winding rule means that if a ray is * drawn in any direction from a given point to infinity * and the places where the path intersects * the ray are examined, the point is inside of the path if and only if * the number of times that the path crosses the ray from * left to right does not equal the number of times that the path crosses * the ray from right to left. * @version 1.58, 01/23/03 * @author Jim Graham */public final class GeneralPath implements Shape, Cloneable { /** * An even-odd winding rule for determining the interior of * a path. */ public static final int WIND_EVEN_ODD = PathIterator.WIND_EVEN_ODD; /** * A non-zero winding rule for determining the interior of a * path. */ public static final int WIND_NON_ZERO = PathIterator.WIND_NON_ZERO; // For code simplicity, copy these constants to our namespace // and cast them to byte constants for easy storage. private static final byte SEG_MOVETO = (byte) PathIterator.SEG_MOVETO; private static final byte SEG_LINETO = (byte) PathIterator.SEG_LINETO; private static final byte SEG_QUADTO = (byte) PathIterator.SEG_QUADTO; private static final byte SEG_CUBICTO = (byte) PathIterator.SEG_CUBICTO; private static final byte SEG_CLOSE = (byte) PathIterator.SEG_CLOSE; byte[] pointTypes; float[] pointCoords; int numTypes; int numCoords; int windingRule; static final int INIT_SIZE = 20; static final int EXPAND_MAX = 500; /** * Constructs a new <code>GeneralPath</code> object. * If an operation performed on this path requires the * interior of the path to be defined then the default NON_ZERO * winding rule is used. * @see #WIND_NON_ZERO */ public GeneralPath() { this(WIND_NON_ZERO, INIT_SIZE, INIT_SIZE); } /** * Constructs a new <code>GeneralPath</code> object with the specified * winding rule to control operations that require the interior of the * path to be defined. * @param rule the winding rule * @see #WIND_EVEN_ODD * @see #WIND_NON_ZERO */ public GeneralPath(int rule) { this(rule, INIT_SIZE, INIT_SIZE); } /** * Constructs a new <code>GeneralPath</code> object with the specified * winding rule and the specified initial capacity to store path * coordinates. This number is an initial guess as to how many path * segments are in the path, but the storage is expanded * as needed to store whatever path segments are added to this path. * @param rule the winding rule * @param initialCapacity the estimate for the number of path segments * in the path * @see #WIND_EVEN_ODD * @see #WIND_NON_ZERO */ public GeneralPath(int rule, int initialCapacity) { this(rule, initialCapacity, initialCapacity); } /** * Constructs a new <code>GeneralPath</code> object with the specified * winding rule and the specified initial capacities to store point types * and coordinates. * These numbers are an initial guess as to how many path segments * and how many points are to be in the path, but the * storage is expanded as needed to store whatever path segments are * added to this path. * @param rule the winding rule * @param initialTypes the estimate for the number of path segments * in the path * @param initialCapacity the estimate for the number of points * @see #WIND_EVEN_ODD * @see #WIND_NON_ZERO */ GeneralPath(int rule, int initialTypes, int initialCoords) { setWindingRule(rule); pointTypes = new byte[initialTypes]; pointCoords = new float[initialCoords * 2]; } /** * Constructs a new <code>GeneralPath</code> object from an arbitrary * {@link Shape} object. * All of the initial geometry and the winding rule for this path are * taken from the specified <code>Shape</code> object. * @param s the specified <code>Shape</code> object */ public GeneralPath(Shape s) { this(WIND_NON_ZERO, INIT_SIZE, INIT_SIZE); PathIterator pi = s.getPathIterator(null); setWindingRule(pi.getWindingRule()); append(pi, false); } private void needRoom(int newTypes, int newCoords, boolean needMove) { if (needMove && numTypes == 0) { throw new IllegalPathStateException("missing initial moveto "+ "in path definition"); } int size = pointCoords.length; if (numCoords + newCoords > size) { int grow = size; if (grow > EXPAND_MAX * 2) { grow = EXPAND_MAX * 2; } if (grow < newCoords) { grow = newCoords; } float[] arr = new float[size + grow]; System.arraycopy(pointCoords, 0, arr, 0, numCoords); pointCoords = arr; } size = pointTypes.length; if (numTypes + newTypes > size) { int grow = size; if (grow > EXPAND_MAX) { grow = EXPAND_MAX; } if (grow < newTypes) { grow = newTypes; } byte[] arr = new byte[size + grow]; System.arraycopy(pointTypes, 0, arr, 0, numTypes); pointTypes = arr; } } /** * Adds a point to the path by moving to the specified * coordinates. * @param x, y the specified coordinates */ public synchronized void moveTo(float x, float y) { if (numTypes > 0 && pointTypes[numTypes - 1] == SEG_MOVETO) { pointCoords[numCoords - 2] = x; pointCoords[numCoords - 1] = y; } else { needRoom(1, 2, false); pointTypes[numTypes++] = SEG_MOVETO; pointCoords[numCoords++] = x; pointCoords[numCoords++] = y; } } /** * Adds a point to the path by drawing a straight line from the * current coordinates to the new specified coordinates. * @param x, y the specified coordinates */ public synchronized void lineTo(float x, float y) { needRoom(1, 2, true); pointTypes[numTypes++] = SEG_LINETO; pointCoords[numCoords++] = x; pointCoords[numCoords++] = y; } /** * Adds a curved segment, defined by two new points, to the path by * drawing a Quadratic curve that intersects both the current * coordinates and the coordinates (x2, y2), using the * specified point (x1, y1) as a quadratic parametric control * point. * @param x1, y1 the coordinates of the first quadratic control * point * @param x2, y2 the coordinates of the final endpoint */ public synchronized void quadTo(float x1, float y1, float x2, float y2) { needRoom(1, 4, true); pointTypes[numTypes++] = SEG_QUADTO; pointCoords[numCoords++] = x1; pointCoords[numCoords++] = y1; pointCoords[numCoords++] = x2; pointCoords[numCoords++] = y2; } /** * Adds a curved segment, defined by three new points, to the path by * drawing a Bézier curve that intersects both the current * coordinates and the coordinates (x3, y3), using the * specified points (x1, y1) and (x2, y2) as * Bézier control points. * @param x1, y1 the coordinates of the first Béezier * control point * @param x2, y2 the coordinates of the second Bézier * control point * @param x3, y3 the coordinates of the final endpoint */ public synchronized void curveTo(float x1, float y1, float x2, float y2, float x3, float y3) { needRoom(1, 6, true); pointTypes[numTypes++] = SEG_CUBICTO; pointCoords[numCoords++] = x1; pointCoords[numCoords++] = y1; pointCoords[numCoords++] = x2; pointCoords[numCoords++] = y2; pointCoords[numCoords++] = x3; pointCoords[numCoords++] = y3; } /** * Closes the current subpath by drawing a straight line back to * the coordinates of the last <code>moveTo</code>. If the path is already * closed then this method has no effect. */ public synchronized void closePath() { if (numTypes == 0 || pointTypes[numTypes - 1] != SEG_CLOSE) { needRoom(1, 0, true); pointTypes[numTypes++] = SEG_CLOSE; } } /** * Appends the geometry of the specified <code>Shape</code> object to the * path, possibly connecting the new geometry to the existing path * segments with a line segment. * If the <code>connect</code> parameter is <code>true</code> and the * path is not empty then any initial <code>moveTo</code> in the * geometry of the appended <code>Shape</code> * is turned into a <code>lineTo</code> segment. * If the destination coordinates of such a connecting <code>lineTo</code> * segment match the ending coordinates of a currently open * subpath then the segment is omitted as superfluous. * The winding rule of the specified <code>Shape</code> is ignored * and the appended geometry is governed by the winding * rule specified for this path. * @param s the <code>Shape</code> whose geometry is appended * to this path * @param connect a boolean to control whether or not to turn an * initial <code>moveTo</code> segment into a <code>lineTo</code> * segment to connect the new geometry to the existing path */ public void append(Shape s, boolean connect) { PathIterator pi = s.getPathIterator(null); append(pi,connect); } /** * Appends the geometry of the specified * {@link PathIterator} object * to the path, possibly connecting the new geometry to the existing * path segments with a line segment. * If the <code>connect</code> parameter is <code>true</code> and the * path is not empty then any initial <code>moveTo</code> in the * geometry of the appended <code>Shape</code> is turned into a * <code>lineTo</code> segment. * If the destination coordinates of such a connecting <code>lineTo</code> * segment match the ending coordinates of a currently open * subpath then the segment is omitted as superfluous. * The winding rule of the specified <code>Shape</code> is ignored * and the appended geometry is governed by the winding * rule specified for this path. * @param pi the <code>PathIterator</code> whose geometry is appended to * this path * @param connect a boolean to control whether or not to turn an * initial <code>moveTo</code> segment into a <code>lineTo</code> segment * to connect the new geometry to the existing path */ public void append(PathIterator pi, boolean connect) { float coords[] = new float[6]; while (!pi.isDone()) { switch (pi.currentSegment(coords)) { case SEG_MOVETO: if (!connect || numTypes < 1 || numCoords < 2) { moveTo(coords[0], coords[1]); break; } if (pointTypes[numTypes - 1] != SEG_CLOSE && pointCoords[numCoords - 2] == coords[0] && pointCoords[numCoords - 1] == coords[1]) { // Collapse out initial moveto/lineto
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -