⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 quadcurve2d.java

📁 JAVA基本类源代码,大家可以学习学习!
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
	boolean include1 = ((y1 - y2) * (ctrly - y2) >= 0);	double eqn[] = new double[3];	double res[] = new double[3];	fillEqn(eqn, y, y1, ctrly, y2);	int roots = solveQuadratic(eqn, res);	roots = evalQuadratic(res, roots,			      include0, include1, eqn,			      x1, ctrlx, x2);	while (--roots >= 0) {	    if (x < res[roots]) {		crossings++;	    }	}	return ((crossings & 1) == 1);    }    /**     * Tests if a specified <code>Point2D</code> is inside the boundary of     * the shape of this <code>QuadCurve2D</code>.     * @param p the specified <code>Point2D</code>     * @return <code>true</code> if the specified <code>Point2D</code> is     *		inside the boundary of the shape of this     *		<code>QuadCurve2D</code>.     */    public boolean contains(Point2D p) {	return contains(p.getX(), p.getY());    }    /*     * Fill an array with the coefficients of the parametric equation     * in t, ready for solving against val with solveQuadratic.     * We currently have:     *     val = Py(t) = C1*(1-t)^2 + 2*CP*t*(1-t) + C2*t^2     *                 = C1 - 2*C1*t + C1*t^2 + 2*CP*t - 2*CP*t^2 + C2*t^2     *                 = C1 + (2*CP - 2*C1)*t + (C1 - 2*CP + C2)*t^2     *               0 = (C1 - val) + (2*CP - 2*C1)*t + (C1 - 2*CP + C2)*t^2     *               0 = C + Bt + At^2     *     C = C1 - val     *     B = 2*CP - 2*C1     *     A = C1 - 2*CP + C2     */    private static void fillEqn(double eqn[], double val,				double c1, double cp, double c2) {	eqn[0] = c1 - val;	eqn[1] = cp + cp - c1 - c1;	eqn[2] = c1 - cp - cp + c2;	return;    }    /*     * Evaluate the t values in the first num slots of the vals[] array     * and place the evaluated values back into the same array.  Only     * evaluate t values that are within the range <0, 1>, including     * the 0 and 1 ends of the range iff the include0 or include1     * booleans are true.  If an "inflection" equation is handed in,     * then any points which represent a point of inflection for that     * quadratic equation are also ignored.     */    private static int evalQuadratic(double vals[], int num,				     boolean include0,				     boolean include1,				     double inflect[],				     double c1, double ctrl, double c2) {	int j = 0;	for (int i = 0; i < num; i++) {	    double t = vals[i];	    if ((include0 ? t >= 0 : t > 0) &&		(include1 ? t <= 1 : t < 1) &&		(inflect == null ||		 inflect[1] + 2*inflect[2]*t != 0))	    {		double u = 1 - t;		vals[j++] = c1*u*u + 2*ctrl*t*u + c2*t*t;	    }	}	return j;    }    private static final int BELOW = -2;    private static final int LOWEDGE = -1;    private static final int INSIDE = 0;    private static final int HIGHEDGE = 1;    private static final int ABOVE = 2;    /*     * Determine where coord lies with respect to the range from     * low to high.  It is assumed that low <= high.  The return     * value is one of the 5 values BELOW, LOWEDGE, INSIDE, HIGHEDGE,     * or ABOVE.     */    private static int getTag(double coord, double low, double high) {	if (coord <= low) {	    return (coord < low ? BELOW : LOWEDGE);	}	if (coord >= high) {	    return (coord > high ? ABOVE : HIGHEDGE);	}	return INSIDE;    }    /*     * Determine if the pttag represents a coordinate that is already     * in its test range, or is on the border with either of the two     * opttags representing another coordinate that is "towards the     * inside" of that test range.  In other words, are either of the     * two "opt" points "drawing the pt inward"?     */    private static boolean inwards(int pttag, int opt1tag, int opt2tag) {	switch (pttag) {	case BELOW:	case ABOVE:	default:	    return false;	case LOWEDGE:	    return (opt1tag >= INSIDE || opt2tag >= INSIDE);	case INSIDE:	    return true;	case HIGHEDGE:	    return (opt1tag <= INSIDE || opt2tag <= INSIDE);	}    }    /**     * Tests if the shape of this <code>QuadCurve2D</code> intersects the     * interior of a specified set of rectangular coordinates.     * @param x,&nbsp;y the coordinates of the upper-left corner of the     *		specified rectangular area     * @param w the width of the specified rectangular area     * @param h the height of the specified rectangular area     * @return <code>true</code> if the shape of this     * 		<code>QuadCurve2D</code> intersects the interior of the     *		specified set of rectangular coordinates;     *		<code>false</code> otherwise.     */    public boolean intersects(double x, double y, double w, double h) {	// Trivially reject non-existant rectangles	if (w < 0 || h < 0) {	    return false;	}	// Trivially accept if either endpoint is inside the rectangle	// (not on its border since it may end there and not go inside)	// Record where they lie with respect to the rectangle.	//     -1 => left, 0 => inside, 1 => right	double x1 = getX1();	double y1 = getY1();	int x1tag = getTag(x1, x, x+w);	int y1tag = getTag(y1, y, y+h);	if (x1tag == INSIDE && y1tag == INSIDE) {	    return true;	}	double x2 = getX2();	double y2 = getY2();	int x2tag = getTag(x2, x, x+w);	int y2tag = getTag(y2, y, y+h);	if (x2tag == INSIDE && y2tag == INSIDE) {	    return true;	}	double ctrlx = getCtrlX();	double ctrly = getCtrlY();	int ctrlxtag = getTag(ctrlx, x, x+w);	int ctrlytag = getTag(ctrly, y, y+h);	// Trivially reject if all points are entirely to one side of	// the rectangle.	if (x1tag < INSIDE && x2tag < INSIDE && ctrlxtag < INSIDE) {	    return false;	// All points left	}	if (y1tag < INSIDE && y2tag < INSIDE && ctrlytag < INSIDE) {	    return false;	// All points above	}	if (x1tag > INSIDE && x2tag > INSIDE && ctrlxtag > INSIDE) {	    return false;	// All points right	}	if (y1tag > INSIDE && y2tag > INSIDE && ctrlytag > INSIDE) {	    return false;	// All points below	}	// Test for endpoints on the edge where either the segment	// or the curve is headed "inwards" from them	// Note: These tests are a superset of the fast endpoint tests	//       above and thus repeat those tests, but take more time	//       and cover more cases	if (inwards(x1tag, x2tag, ctrlxtag) &&	    inwards(y1tag, y2tag, ctrlytag))	{	    // First endpoint on border with either edge moving inside	    return true;	}	if (inwards(x2tag, x1tag, ctrlxtag) &&	    inwards(y2tag, y1tag, ctrlytag))	{	    // Second endpoint on border with either edge moving inside	    return true;	}	// Trivially accept if endpoints span directly across the rectangle	boolean xoverlap = (x1tag * x2tag <= 0);	boolean yoverlap = (y1tag * y2tag <= 0);	if (x1tag == INSIDE && x2tag == INSIDE && yoverlap) {	    return true;	}	if (y1tag == INSIDE && y2tag == INSIDE && xoverlap) {	    return true;	}	// We now know that both endpoints are outside the rectangle	// but the 3 points are not all on one side of the rectangle.	// Therefore the curve cannot be contained inside the rectangle,	// but the rectangle might be contained inside the curve, or	// the curve might intersect the boundary of the rectangle.	double[] eqn = new double[3];	double[] res = new double[3];	if (!yoverlap) {	    // Both y coordinates for the closing segment are above or	    // below the rectangle which means that we can only intersect	    // if the curve crosses the top (or bottom) of the rectangle	    // in more than one place and if those crossing locations	    // span the horizontal range of the rectangle.	    fillEqn(eqn, (y1tag < INSIDE ? y : y+h), y1, ctrly, y2);	    return (solveQuadratic(eqn, res) == 2 &&		    evalQuadratic(res, 2, true, true, null,				  x1, ctrlx, x2) == 2 &&		    getTag(res[0], x, x+w) * getTag(res[1], x, x+w) <= 0);	}	// Y ranges overlap.  Now we examine the X ranges	if (!xoverlap) {	    // Both x coordinates for the closing segment are left of	    // or right of the rectangle which means that we can only	    // intersect if the curve crosses the left (or right) edge	    // of the rectangle in more than one place and if those	    // crossing locations span the vertical range of the rectangle.	    fillEqn(eqn, (x1tag < INSIDE ? x : x+w), x1, ctrlx, x2);	    return (solveQuadratic(eqn, res) == 2 &&		    evalQuadratic(res, 2, true, true, null,				  y1, ctrly, y2) == 2 &&		    getTag(res[0], y, y+h) * getTag(res[1], y, y+h) <= 0);	}	// The X and Y ranges of the endpoints overlap the X and Y	// ranges of the rectangle, now find out how the endpoint	// line segment intersects the Y range of the rectangle	double dx = x2 - x1;	double dy = y2 - y1;	double k = y2 * x1 - x2 * y1;	int c1tag, c2tag;	if (y1tag == INSIDE) {	    c1tag = x1tag;	} else {	    c1tag = getTag((k + dx * (y1tag < INSIDE ? y : y+h)) / dy, x, x+w);	}	if (y2tag == INSIDE) {	    c2tag = x2tag;	} else {	    c2tag = getTag((k + dx * (y2tag < INSIDE ? y : y+h)) / dy, x, x+w);	}	// If the part of the line segment that intersects the Y range	// of the rectangle crosses it horizontally - trivially accept	if (c1tag * c2tag <= 0) {	    return true;	}	// Now we know that both the X and Y ranges intersect and that	// the endpoint line segment does not directly cross the rectangle.	//	// We can almost treat this case like one of the cases above	// where both endpoints are to one side, except that we will	// only get one intersection of the curve with the vertical	// side of the rectangle.  This is because the endpoint segment	// accounts for the other intersection.	//	// (Remember there is overlap in both the X and Y ranges which	//  means that the segment must cross at least one vertical edge	//  of the rectangle - in particular, the "near vertical side" -	//  leaving only one intersection for the curve.)	//	// Now we calculate the y tags of the two intersections on the	// "near vertical side" of the rectangle.  We will have one with	// the endpoint segment, and one with the curve.  If those two	// vertical intersections overlap the Y range of the rectangle,	// we have an intersection.  Otherwise, we don't.	// c1tag = vertical intersection class of the endpoint segment	//	// Choose the y tag of the endpoint that was not on the same	// side of the rectangle as the subsegment calculated above.	// Note that we can "steal" the existing Y tag of that endpoint	// since it will be provably the same as the vertical intersection.	c1tag = ((c1tag * x1tag <= 0) ? y1tag : y2tag);	// c2tag = vertical intersection class of the curve	//	// We have to calculate this one the straightforward way.	// Note that the c2tag can still tell us which vertical edge	// to test against.	fillEqn(eqn, (c2tag < INSIDE ? x : x+w), x1, ctrlx, x2);	int num = solveQuadratic(eqn, res);	// Note: We should be able to assert(num == 2); since the	// X range "crosses" (not touches) the vertical boundary,	// but we pass num to evalQuadratic for completeness.	evalQuadratic(res, num, true, true, null, y1, ctrly, y2);	// Note: We can assert(num evals == 1); since one of the	// 2 crossings will be out of the [0,1] range.	c2tag = getTag(res[0], y, y+h);	// Finally, we have an intersection if the two crossings	// overlap the Y range of the rectangle.	return (c1tag * c2tag <= 0);    }    /**     * Tests if the shape of this <code>QuadCurve2D</code> intersects the     * interior of a specified <code>Rectangle2D</code>.     * @param r the specified <code>Rectangle2D</code>     * @return <code>true</code> if the shape of this     * 		<code>QuadCurve2D</code> intersects the interior of      *		the specified <code>Rectangle2D</code>;     *		<code>false</code> otherwise.     */    public boolean intersects(Rectangle2D r) {	return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());    }    /**     * Tests if the interior of the shape of this     * <code>QuadCurve2D</code> entirely contains the specified     * set of rectangular coordinates.     * @param x,&nbsp;y the coordinates of the upper-left corner of the     *		specified rectangular area     * @param w the width of the specified rectangular area     * @param h the height of the specified rectangular area     * @return <code>true</code> if the interior of the shape of this     *		<code>QuadCurve2D</code> entirely contains the specified     *		rectangluar area; <code>false</code> otherwise.     */    public boolean contains(double x, double y, double w, double h) {	// Assertion: Quadratic curves closed by connecting their	// endpoints are always convex.	return (contains(x, y) &&		contains(x + w, y) &&		contains(x + w, y + h) &&		contains(x, y + h));    }    /**     * Tests if the interior of the shape of this     * <code>QuadCurve2D</code> entirely contains the specified     * <code>Rectangle2D</code>.     * @param r the specified <code>Rectangle2D</code>     * @return <code>true</code> if the interior of the shape of this     *		<code>QuadCurve2D</code> entirely contains the specified     *		<code>Rectangle2D</code>; <code>false</code> otherwise.     */    public boolean contains(Rectangle2D r) {	return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());    }    /**     * Returns the bounding box of this <code>QuadCurve2D</code>.     * @return a {@link Rectangle} that is the bounding box of the shape     * 		of this <code>QuadCurve2D</code>.     */    public Rectangle getBounds() {	return getBounds2D().getBounds();    }    /**     * Returns an iteration object that defines the boundary of the     * shape of this <code>QuadCurve2D</code>.     * The iterator for this class is not multi-threaded safe,     * which means that this <code>QuadCurve2D</code> class does not     * guarantee that modifications to the geometry of this     * <code>QuadCurve2D</code> object do not affect any iterations of     * that geometry that are already in process.     * @param at an optional {@link AffineTransform} to apply to the     *		shape boundary     * @return a {@link PathIterator} object that defines the boundary     *		of the shape.     */    public PathIterator getPathIterator(AffineTransform at) {	return new QuadIterator(this, at);    }    /**     * Returns an iteration object that defines the boundary of the     * flattened shape of this <code>QuadCurve2D</code>.     * The iterator for this class is not multi-threaded safe,     * which means that this <code>QuadCurve2D</code> class does not     * guarantee that modifications to the geometry of this     * <code>QuadCurve2D</code> object do not affect any iterations of     * that geometry that are already in process.      * @param at an optional <code>AffineTransform</code> to apply     *		to the boundary of the shape     * @param flatness the maximum distance that the control points for a      *		subdivided curve can be with respect to a line connecting     * 		the endpoints of this curve before this curve is     *		replaced by a straight line connecting the endpoints.     * @return a <code>PathIterator</code> object that defines the      *		flattened boundary of the shape.     */    public PathIterator getPathIterator(AffineTransform at, double flatness) {	return new FlatteningPathIterator(getPathIterator(at), flatness);    }    /**     * Creates a new object of the same class and with the same contents      * as this object.     *     * @return     a clone of this instance.     * @exception  OutOfMemoryError            if there is not enough memory.     * @see        java.lang.Cloneable     * @since      1.2     */    public Object clone() {	try {	    return super.clone();	} catch (CloneNotSupportedException e) {	    // this shouldn't happen, since we are Cloneable	    throw new InternalError();	}    }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -