[Arakhnę-Dev] [414] * Fixing the functions intersects() and contains() of the Path2f in the case it is open or close. |
[ Thread Index |
Date Index
| More arakhne.org/dev Archives
]
- To: dev@xxxxxxxxxxx
- Subject: [Arakhnę-Dev] [414] * Fixing the functions intersects() and contains() of the Path2f in the case it is open or close.
- From: subversion@xxxxxxxxxxxxx
- Date: Fri, 05 Apr 2013 23:45:08 +0200
Revision: 414
Author: galland
Date: 2013-04-05 23:45:07 +0200 (Fri, 05 Apr 2013)
Log Message:
-----------
* Fixing the functions intersects() and contains() of the Path2f in the case it is open or close.
Modified Paths:
--------------
trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Ellipse2f.java
trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Path2f.java
trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Segment2f.java
trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/Ellipse2fTest.java
trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/Segment2fTest.java
Added Paths:
-----------
trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/AbstractPath2fTestCase.java
trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/ClosePath2fTest.java
trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/OpenPath2fTest.java
Modified: trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Ellipse2f.java
===================================================================
--- trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Ellipse2f.java 2013-04-05 20:39:57 UTC (rev 413)
+++ trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Ellipse2f.java 2013-04-05 21:45:07 UTC (rev 414)
@@ -164,7 +164,7 @@
*/
public static boolean intersectsEllipseLine(float ex, float ey, float ew, float eh, float x1, float y1, float x2, float y2) {
// If the ellipse or line segment are empty, return no intersections.
- if (eh<=0f || ew<=0f || x1==x2 || y1==y2) {
+ if (eh<=0f || ew<=0f) {
return false;
}
@@ -215,7 +215,7 @@
*/
public static boolean intersectsEllipseSegment(float ex, float ey, float ew, float eh, float x1, float y1, float x2, float y2) {
// If the ellipse or line segment are empty, return no intersections.
- if (eh<=0f || ew<=0f || x1==x2 || y1==y2) {
+ if (eh<=0f || ew<=0f) {
return false;
}
Modified: trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Path2f.java
===================================================================
--- trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Path2f.java 2013-04-05 20:39:57 UTC (rev 413)
+++ trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Path2f.java 2013-04-05 21:45:07 UTC (rev 414)
@@ -67,7 +67,7 @@
public static boolean contains(PathIterator2f pi, float x, float y) {
// Copied from the AWT API
int mask = (pi.getWindingRule() == PathWindingRule.NON_ZERO ? -1 : 1);
- int cross = computeCrossingsFromPoint(pi, x, y);
+ int cross = computeCrossingsFromPoint(pi, x, y, false, true);
return ((cross & mask) != 0);
}
@@ -93,7 +93,11 @@
return false;
}
int mask = (pi.getWindingRule() == PathWindingRule.NON_ZERO ? -1 : 2);
- int crossings = computeCrossingsFromRect(pi, rx, ry, rx+rwidth, ry+rheight);
+ int crossings = computeCrossingsFromRect(
+ pi,
+ rx, ry, rx+rwidth, ry+rheight,
+ false,
+ true);
return (crossings != MathConstants.SHAPE_INTERSECTS &&
(crossings & mask) != 0);
}
@@ -134,7 +138,7 @@
return false;
}
int mask = (pi.getWindingRule() == PathWindingRule.NON_ZERO ? -1 : 2);
- int crossings = computeCrossingsFromRect(pi, x, y, x+w, y+h);
+ int crossings = computeCrossingsFromRect(pi, x, y, x+w, y+h, false, true);
return (crossings == MathConstants.SHAPE_INTERSECTS ||
(crossings & mask) != 0);
}
@@ -157,6 +161,34 @@
* @return the crossing
*/
public static int computeCrossingsFromPoint(PathIterator2f pi, float px, float py) {
+ return computeCrossingsFromPoint(pi, px, py, true, true);
+ }
+
+ /**
+ * Calculates the number of times the given path
+ * crosses the ray extending to the right from (px,py).
+ * If the point lies on a part of the path,
+ * then no crossings are counted for that intersection.
+ * +1 is added for each crossing where the Y coordinate is increasing
+ * -1 is added for each crossing where the Y coordinate is decreasing
+ * The return value is the sum of all crossings for every segment in
+ * the path.
+ * The path must start with a MOVE_TO, otherwise an exception is
+ * thrown.
+ *
+ * @param pi is the description of the path.
+ * @param px is the reference point to test.
+ * @param py is the reference point to test.
+ * @param closeable indicates if the shape is automatically closed or not.
+ * @param onlyIntersectWhenOpen indicates if the crossings is set to 0 when
+ * the path is open and there is not SHAPE_INTERSECT.
+ * @return the crossing
+ */
+ static int computeCrossingsFromPoint(
+ PathIterator2f pi,
+ float px, float py,
+ boolean closeable,
+ boolean onlyIntersectWhenOpen) {
// Copied from the AWT API
if (!pi.hasNext()) return 0;
PathElement2f element;
@@ -166,12 +198,13 @@
throw new IllegalArgumentException("missing initial moveto in path definition"); //$NON-NLS-1$
}
+ Path2f subPath;
float movx = element.toX;
float movy = element.toY;
float curx = movx;
float cury = movy;
float endx, endy;
- int crossings = 0;
+ int r, crossings = 0;
while (pi.hasNext()) {
element = pi.next();
switch (element.type) {
@@ -182,6 +215,8 @@
case LINE_TO:
endx = element.toX;
endy = element.toY;
+ if (endx==px && endy==py)
+ return MathConstants.SHAPE_INTERSECTS;
crossings += Segment2f.computeCrossingsFromPoint(
px, py,
curx, cury,
@@ -192,28 +227,51 @@
case QUAD_TO:
endx = element.toX;
endy = element.toY;
- crossings += computeQuadCurveCrossingsFromPoint(
- px, py,
- curx, cury,
+ if (endx==px && endy==py)
+ return MathConstants.SHAPE_INTERSECTS;
+ subPath = new Path2f();
+ subPath.moveTo(curx, cury);
+ subPath.quadTo(
element.ctrlX1, element.ctrlY1,
- endx, endy, 0);
+ endx, endy);
+ r = computeCrossingsFromPoint(
+ subPath.getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO),
+ px, py,
+ false,
+ false);
+ if (r==MathConstants.SHAPE_INTERSECTS)
+ return r;
+ crossings += r;
curx = endx;
cury = endy;
break;
case CURVE_TO:
endx = element.toX;
endy = element.toY;
- crossings += computeCubicCurveCrossingsFromPoint(
- px, py,
- curx, cury,
+ if (endx==px || endy==py)
+ return MathConstants.SHAPE_INTERSECTS;
+ subPath = new Path2f();
+ subPath.moveTo(curx, cury);
+ subPath.curveTo(
element.ctrlX1, element.ctrlY1,
element.ctrlX2, element.ctrlY2,
- endx, endy, 0);
+ endx, endy);
+ r = computeCrossingsFromPoint(
+ subPath.getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO),
+ px, py,
+ false,
+ false);
+ if (r==MathConstants.SHAPE_INTERSECTS) {
+ return r;
+ }
+ crossings += r;
curx = endx;
cury = endy;
break;
case CLOSE:
if (cury != movy || curx != movx) {
+ if (movx==px && movy==py)
+ return MathConstants.SHAPE_INTERSECTS;
crossings += Segment2f.computeCrossingsFromPoint(
px, py,
curx, cury,
@@ -225,13 +283,28 @@
default:
}
}
+
+ assert(crossings!=MathConstants.SHAPE_INTERSECTS);
- if (cury != movy) {
- crossings += Segment2f.computeCrossingsFromPoint(
- px, py,
- curx, cury,
- movx, movy);
+ boolean isOpen = (curx != movx) || (cury != movy);
+
+ if (isOpen) {
+ if (closeable) {
+ // Not closed
+ if (movx==px && movy==py)
+ return MathConstants.SHAPE_INTERSECTS;
+ crossings += Segment2f.computeCrossingsFromPoint(
+ px, py,
+ curx, cury,
+ movx, movy);
+ }
+ else if (onlyIntersectWhenOpen) {
+ // Assume that when is the path is open, only
+ // SHAPE_INTERSECTS may be return
+ crossings = 0;
+ }
}
+
return crossings;
}
@@ -247,7 +320,7 @@
* @return the crossing or {@link MathConstants#SHAPE_INTERSECTS}
*/
public static int computeCrossingsFromEllipse(PathIterator2f pi, float ex, float ey, float ew, float eh) {
- return computeCrossingsFromEllipse(0, pi, ex, ey, ew, eh, true);
+ return computeCrossingsFromEllipse(0, pi, ex, ey, ew, eh, true, true);
}
/**
@@ -261,9 +334,16 @@
* @param ew is the width of the ellipse.
* @param eh is the height of the ellipse.
* @param closeable indicates if the shape is automatically closed or not.
+ * @param onlyIntersectWhenOpen indicates if the crossings is set to 0 when
+ * the path is open and there is not SHAPE_INTERSECT.
* @return the crossing or {@link MathConstants#SHAPE_INTERSECTS}
*/
- static int computeCrossingsFromEllipse(int crossings, PathIterator2f pi, float ex, float ey, float ew, float eh, boolean closeable) {
+ static int computeCrossingsFromEllipse(
+ int crossings,
+ PathIterator2f pi,
+ float ex, float ey, float ew, float eh,
+ boolean closeable,
+ boolean onlyIntersectWhenOpen) {
// Copied from the AWT API
if (!pi.hasNext()) return 0;
PathElement2f element;
@@ -294,6 +374,9 @@
ex, ey, ew, eh,
curx, cury,
endx, endy);
+ if (numCrosses==MathConstants.SHAPE_INTERSECTS) {
+ return numCrosses;
+ }
curx = endx;
cury = endy;
break;
@@ -302,7 +385,7 @@
endx = element.toX;
endy = element.toY;
Path2f localPath = new Path2f();
- localPath.moveTo(element.fromX, element.fromY);
+ localPath.moveTo(curx, cury);
localPath.quadTo(
element.ctrlX1, element.ctrlY1,
endx, endy);
@@ -310,7 +393,11 @@
numCrosses,
localPath.getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO),
ex, ey, ew, eh,
+ false,
false);
+ if (numCrosses==MathConstants.SHAPE_INTERSECTS) {
+ return numCrosses;
+ }
curx = endx;
cury = endy;
break;
@@ -319,7 +406,7 @@
endx = element.toX;
endy = element.toY;
Path2f localPath = new Path2f();
- localPath.moveTo(element.fromX, element.fromY);
+ localPath.moveTo(curx, cury);
localPath.curveTo(
element.ctrlX1, element.ctrlY1,
element.ctrlX2, element.ctrlY2,
@@ -328,7 +415,11 @@
numCrosses,
localPath.getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO),
ex, ey, ew, eh,
+ false,
false);
+ if (numCrosses==MathConstants.SHAPE_INTERSECTS) {
+ return numCrosses;
+ }
curx = endx;
cury = endy;
break;
@@ -339,6 +430,9 @@
ex, ey, ew, eh,
curx, cury,
movx, movy);
+ if (numCrosses==MathConstants.SHAPE_INTERSECTS) {
+ return numCrosses;
+ }
}
curx = movx;
cury = movy;
@@ -347,12 +441,24 @@
}
}
- if (numCrosses!=MathConstants.SHAPE_INTERSECTS && closeable && cury != movy) {
- numCrosses = Segment2f.computeCrossingsFromEllipse(
- numCrosses,
- ex, ey, ew, eh,
- curx, cury,
- movx, movy);
+ assert(numCrosses!=MathConstants.SHAPE_INTERSECTS);
+
+ boolean isOpen = (curx != movx) || (cury != movy);
+
+ if (isOpen) {
+ if (closeable) {
+ // Not closed
+ numCrosses = Segment2f.computeCrossingsFromEllipse(
+ numCrosses,
+ ex, ey, ew, eh,
+ curx, cury,
+ movx, movy);
+ }
+ else if (onlyIntersectWhenOpen) {
+ // Assume that when is the path is open, only
+ // SHAPE_INTERSECTS may be return
+ numCrosses = 0;
+ }
}
return numCrosses;
@@ -369,7 +475,7 @@
* @return the crossing or {@link MathConstants#SHAPE_INTERSECTS}.
*/
public static int computeCrossingsFromCircle(PathIterator2f pi, float cx, float cy, float radius) {
- return computeCrossingsFromCircle(0, pi, cx, cy, radius, true);
+ return computeCrossingsFromCircle(0, pi, cx, cy, radius, true, true);
}
/**
@@ -382,9 +488,16 @@
* @param cy is the center of the circle.
* @param radius is the radius of the circle.
* @param closeable indicates if the shape is automatically closed or not.
+ * @param onlyIntersectWhenOpen indicates if the crossings is set to 0 when
+ * the path is open and there is not SHAPE_INTERSECT.
* @return the crossing
*/
- static int computeCrossingsFromCircle(int crossings, PathIterator2f pi, float cx, float cy, float radius, boolean closeable) {
+ static int computeCrossingsFromCircle(
+ int crossings,
+ PathIterator2f pi,
+ float cx, float cy, float radius,
+ boolean closeable,
+ boolean onlyIntersectWhenOpen) {
// Copied from the AWT API
if (!pi.hasNext()) return 0;
PathElement2f element;
@@ -415,6 +528,9 @@
cx, cy, radius,
curx, cury,
endx, endy);
+ if (numCrosses==MathConstants.SHAPE_INTERSECTS) {
+ return numCrosses;
+ }
curx = endx;
cury = endy;
break;
@@ -431,7 +547,11 @@
numCrosses,
localPath.getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO),
cx, cy, radius,
+ false,
false);
+ if (numCrosses==MathConstants.SHAPE_INTERSECTS) {
+ return numCrosses;
+ }
curx = endx;
cury = endy;
break;
@@ -449,7 +569,11 @@
numCrosses,
localPath.getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO),
cx, cy, radius,
+ false,
false);
+ if (numCrosses==MathConstants.SHAPE_INTERSECTS) {
+ return numCrosses;
+ }
curx = endx;
cury = endy;
break;
@@ -460,6 +584,9 @@
cx, cy, radius,
curx, cury,
movx, movy);
+ if (numCrosses==MathConstants.SHAPE_INTERSECTS) {
+ return numCrosses;
+ }
}
curx = movx;
cury = movy;
@@ -467,13 +594,25 @@
default:
}
}
+
+ assert(numCrosses!=MathConstants.SHAPE_INTERSECTS);
- if (numCrosses!=MathConstants.SHAPE_INTERSECTS && closeable && cury != movy) {
- numCrosses = Segment2f.computeCrossingsFromCircle(
- numCrosses,
- cx, cy, radius,
- curx, cury,
- movx, movy);
+ boolean isOpen = (curx != movx) || (cury != movy);
+
+ if (isOpen) {
+ if (closeable) {
+ // Not closed
+ numCrosses = Segment2f.computeCrossingsFromCircle(
+ numCrosses,
+ cx, cy, radius,
+ curx, cury,
+ movx, movy);
+ }
+ else if (onlyIntersectWhenOpen) {
+ // Assume that when is the path is open, only
+ // SHAPE_INTERSECTS may be return
+ numCrosses = 0;
+ }
}
return numCrosses;
@@ -509,7 +648,7 @@
*/
static int computeCrossingsFromSegment(int crossings, PathIterator2f pi, float x1, float y1, float x2, float y2, boolean closeable) {
// Copied from the AWT API
- if (!pi.hasNext()) return 0;
+ if (!pi.hasNext() || crossings==MathConstants.SHAPE_INTERSECTS) return crossings;
PathElement2f element;
element = pi.next();
@@ -537,7 +676,10 @@
numCrosses,
x1, y1, x2, y2,
curx, cury,
- endx, endy);
+ endx, endy,
+ true);
+ if (numCrosses==MathConstants.SHAPE_INTERSECTS)
+ return numCrosses;
curx = endx;
cury = endy;
break;
@@ -546,7 +688,7 @@
endx = element.toX;
endy = element.toY;
Path2f localPath = new Path2f();
- localPath.moveTo(element.fromX, element.fromY);
+ localPath.moveTo(curx, cury);
localPath.quadTo(
element.ctrlX1, element.ctrlY1,
endx, endy);
@@ -555,6 +697,8 @@
localPath.getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO),
x1, y1, x2, y2,
false);
+ if (numCrosses==MathConstants.SHAPE_INTERSECTS)
+ return numCrosses;
curx = endx;
cury = endy;
break;
@@ -563,7 +707,7 @@
endx = element.toX;
endy = element.toY;
Path2f localPath = new Path2f();
- localPath.moveTo(element.fromX, element.fromY);
+ localPath.moveTo(curx, cury);
localPath.curveTo(
element.ctrlX1, element.ctrlY1,
element.ctrlX2, element.ctrlY2,
@@ -573,6 +717,8 @@
localPath.getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO),
x1, y1, x2, y2,
false);
+ if (numCrosses==MathConstants.SHAPE_INTERSECTS)
+ return numCrosses;
curx = endx;
cury = endy;
break;
@@ -582,8 +728,10 @@
numCrosses,
x1, y1, x2, y2,
curx, cury,
- movx, movy);
+ movx, movy,
+ true);
}
+ if (numCrosses!=0) return numCrosses;
curx = movx;
cury = movy;
break;
@@ -591,154 +739,55 @@
}
}
- if (numCrosses!=MathConstants.SHAPE_INTERSECTS && closeable && cury != movy) {
- numCrosses = Segment2f.computeCrossingsFromSegment(
- numCrosses,
- x1, y1, x2, y2,
- curx, cury,
- movx, movy);
+ assert(numCrosses!=MathConstants.SHAPE_INTERSECTS);
+
+ boolean isOpen = (curx != movx) || (cury != movy);
+
+ if (isOpen) {
+ if (closeable) {
+ numCrosses = Segment2f.computeCrossingsFromSegment(
+ numCrosses,
+ x1, y1, x2, y2,
+ curx, cury,
+ movx, movy,
+ true);
+ }
+ else {
+ // Assume that when is the path is open, only
+ // SHAPE_INTERSECTS may be return
+ numCrosses = 0;
+ }
}
return numCrosses;
}
/**
- * Calculates the number of times the quad from (x0,y0) to (x1,y1)
- * crosses the ray extending to the right from (px,py).
- * If the point lies on a part of the curve,
- * then no crossings are counted for that intersection.
- * the level parameter should be 0 at the top-level call and will count
- * up for each recursion level to prevent infinite recursion
- * +1 is added for each crossing where the Y coordinate is increasing
- * -1 is added for each crossing where the Y coordinate is decreasing
+ * Accumulate the number of times the path crosses the shadow
+ * extending to the right of the rectangle. See the comment
+ * for the RECT_INTERSECTS constant for more complete details.
+ * The return value is the sum of all crossings for both the
+ * top and bottom of the shadow for every segment in the path,
+ * or the special value RECT_INTERSECTS if the path ever enters
+ * the interior of the rectangle.
+ * The path must start with a SEG_MOVETO, otherwise an exception is
+ * thrown.
+ * The caller must check r[xy]{min,max} for NaN values.
*
- * @param px is the reference point to test.
- * @param py is the reference point to test.
- * @param x0 is the first point of the quad curve.
- * @param y0 is the first point of the quad curve.
- * @param xc is the control point of the quad curve.
- * @param yc is the control point of the quad curve.
- * @param x1 is the last point of the quad curve.
- * @param y1 is the last point of the quad curve.
- * @param level may be zero.
- * @return the crossing.
+ * @param pi is the iterator on the path elements.
+ * @param rxmin is the first corner of the rectangle.
+ * @param rymin is the first corner of the rectangle.
+ * @param rxmax is the second corner of the rectangle.
+ * @param rymax is the second corner of the rectangle.
+ * @return the crossings.
*/
- static int computeQuadCurveCrossingsFromPoint(float px, float py,
- float x0, float y0,
- float xc, float yc,
- float x1, float y1,
- int level) {
- // Copied from AWT API
- if (py < y0 && py < yc && py < y1) return 0;
- if (py >= y0 && py >= yc && py >= y1) return 0;
- // Note y0 could equal y1...
- if (px >= x0 && px >= xc && px >= x1) return 0;
- if (px < x0 && px < xc && px < x1) {
- if (py >= y0) {
- if (py < y1) return 1;
- } else {
- // py < y0
- if (py >= y1) return -1;
- }
- // py outside of y01 range, and/or y0==y1
- return 0;
- }
- // float precision only has 52 bits of mantissa
- if (level > 52) return Segment2f.computeCrossingsFromPoint(px, py, x0, y0, x1, y1);
- float x0c = (x0 + xc) / 2;
- float y0c = (y0 + yc) / 2;
- float xc1 = (xc + x1) / 2;
- float yc1 = (yc + y1) / 2;
- float nxc = (x0c + xc1) / 2;
- float nyc = (y0c + yc1) / 2;
- if (Double.isNaN(nxc) || Double.isNaN(nyc)) {
- // [xy]c are NaN if any of [xy]0c or [xy]c1 are NaN
- // [xy]0c or [xy]c1 are NaN if any of [xy][0c1] are NaN
- // These values are also NaN if opposing infinities are added
- return 0;
- }
- return (computeQuadCurveCrossingsFromPoint(px, py,
- x0, y0, x0c, y0c, nxc, nyc,
- level+1) +
- computeQuadCurveCrossingsFromPoint(px, py,
- nxc, nyc, xc1, yc1, x1, y1,
- level+1));
+ public static int computeCrossingsFromRect(PathIterator2f pi,
+ float rxmin, float rymin,
+ float rxmax, float rymax) {
+ return computeCrossingsFromRect(pi, rxmin, rymin, rxmax, rymax, true, true);
}
/**
- * Calculates the number of times the cubic from (x0,y0) to (x1,y1)
- * crosses the ray extending to the right from (px,py).
- * If the point lies on a part of the curve,
- * then no crossings are counted for that intersection.
- * the level parameter should be 0 at the top-level call and will count
- * up for each recursion level to prevent infinite recursion
- * +1 is added for each crossing where the Y coordinate is increasing
- *
- * @param px is the reference point to test.
- * @param py is the reference point to test.
- * @param x0 is the first point of the quad curve.
- * @param y0 is the first point of the quad curve.
- * @param xc0 is the first control point of the cubic curve.
- * @param yc0 is the first control point of the cubic curve.
- * @param xc1 is the second control point of the cubic curve.
- * @param yc1 is the second control point of the cubic curve.
- * @param x1 is the last point of the quad curve.
- * @param y1 is the last point of the quad curve.
- * @param level may be zero.
- * @return the crossing.
- * -1 is added for each crossing where the Y coordinate is decreasing
- */
- static int computeCubicCurveCrossingsFromPoint(
- float px, float py,
- float x0, float y0,
- float xc0, float yc0,
- float xc1, float yc1,
- float x1, float y1,
- int level) {
- // Copied from AWT API
- if (py < y0 && py < yc0 && py < yc1 && py < y1) return 0;
- if (py >= y0 && py >= yc0 && py >= yc1 && py >= y1) return 0;
- // Note y0 could equal yc0...
- if (px >= x0 && px >= xc0 && px >= xc1 && px >= x1) return 0;
- if (px < x0 && px < xc0 && px < xc1 && px < x1) {
- if (py >= y0) {
- if (py < y1) return 1;
- } else {
- // py < y0
- if (py >= y1) return -1;
- }
- // py outside of y01 range, and/or y0==yc0
- return 0;
- }
- // float precision only has 52 bits of mantissa
- if (level > 52) return Segment2f.computeCrossingsFromPoint(px, py, x0, y0, x1, y1);
- float xmid = (xc0 + xc1) / 2;
- float ymid = (yc0 + yc1) / 2;
- float nxc0 = (x0 + xc0) / 2;
- float nyc0 = (y0 + yc0) / 2;
- float nxc1 = (xc1 + x1) / 2;
- float nyc1 = (yc1 + y1) / 2;
- float xc0m = (nxc0 + xmid) / 2;
- float yc0m = (nyc0 + ymid) / 2;
- float xmc1 = (xmid + nxc1) / 2;
- float ymc1 = (ymid + nyc1) / 2;
- xmid = (xc0m + xmc1) / 2;
- ymid = (yc0m + ymc1) / 2;
- if (Double.isNaN(xmid) || Double.isNaN(ymid)) {
- // [xy]mid are NaN if any of [xy]c0m or [xy]mc1 are NaN
- // [xy]c0m or [xy]mc1 are NaN if any of [xy][c][01] are NaN
- // These values are also NaN if opposing infinities are added
- return 0;
- }
- return (computeCubicCurveCrossingsFromPoint(px, py,
- x0, y0, nxc0, nyc0,
- xc0m, yc0m, xmid, ymid, level+1) +
- computeCubicCurveCrossingsFromPoint(px, py,
- xmid, ymid, xmc1, ymc1,
- nxc1, nyc1, x1, y1, level+1));
- }
-
- /**
* Accumulate the number of times the path crosses the shadow
* extending to the right of the rectangle. See the comment
* for the RECT_INTERSECTS constant for more complete details.
@@ -755,11 +804,16 @@
* @param rymin is the first corner of the rectangle.
* @param rxmax is the second corner of the rectangle.
* @param rymax is the second corner of the rectangle.
+ * @param closeable indicates if the shape is automatically closed or not.
+ * @param onlyIntersectWhenOpen indicates if the crossings is set to 0 when
+ * the path is open and there is not SHAPE_INTERSECT.
* @return the crossings.
*/
- public static int computeCrossingsFromRect(PathIterator2f pi,
+ static int computeCrossingsFromRect(PathIterator2f pi,
float rxmin, float rymin,
- float rxmax, float rymax) {
+ float rxmax, float rymax,
+ boolean closeable,
+ boolean onlyIntersectWhenOpen) {
// Copied from AWT API
if (rxmax <= rxmin || rymax <= rymin) return 0;
if (!pi.hasNext()) return 0;
@@ -770,10 +824,12 @@
throw new IllegalArgumentException("missing initial moveto in path definition"); //$NON-NLS-1$
}
+ Path2f subPath;
float curx, cury, movx, movy, endx, endy;
curx = movx = pathElement.toX;
cury = movy = pathElement.toY;
int crossings = 0;
+ int n;
while (crossings != MathConstants.SHAPE_INTERSECTS
&& pi.hasNext()) {
@@ -793,31 +849,49 @@
rxmax, rymax,
curx, cury,
endx, endy);
+ if (crossings==MathConstants.SHAPE_INTERSECTS)
+ return crossings;
curx = endx;
cury = endy;
break;
case QUAD_TO:
endx = pathElement.toX;
endy = pathElement.toY;
- crossings = computeQuadCurveCrossingsFromRect(crossings,
+ subPath = new Path2f();
+ subPath.moveTo(curx, cury);
+ subPath.quadTo(
+ pathElement.ctrlX1, pathElement.ctrlY1,
+ endx, endy);
+ n = computeCrossingsFromRect(
+ subPath.getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO),
rxmin, rymin,
rxmax, rymax,
- curx, cury,
- pathElement.ctrlX1, pathElement.ctrlY1,
- endx, endy, 0);
+ false,
+ false);
+ if (n==MathConstants.SHAPE_INTERSECTS)
+ return n;
+ crossings += n;
curx = endx;
cury = endy;
break;
case CURVE_TO:
endx = pathElement.toX;
endy = pathElement.toY;
- crossings = computeCubicCurveCrossingsFromRect(crossings,
- rxmin, rymin,
- rxmax, rymax,
- curx, cury,
+ subPath = new Path2f();
+ subPath.moveTo(curx, cury);
+ subPath.curveTo(
pathElement.ctrlX1, pathElement.ctrlY1,
pathElement.ctrlX2, pathElement.ctrlY2,
- endx, endy, 0);
+ endx, endy);
+ n = computeCrossingsFromRect(
+ subPath.getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO),
+ rxmin, rymin,
+ rxmax, rymax,
+ false,
+ false);
+ if (n==MathConstants.SHAPE_INTERSECTS)
+ return n;
+ crossings += n;
curx = endx;
cury = endy;
break;
@@ -829,233 +903,35 @@
curx, cury,
movx, movy);
}
+ // Stop as soon as possible
+ if (crossings!=0) return crossings;
curx = movx;
cury = movy;
- // Count should always be a multiple of 2 here.
- // assert((crossings & 1) != 0);
break;
default:
}
}
+
+ assert(crossings != MathConstants.SHAPE_INTERSECTS);
- if (crossings != MathConstants.SHAPE_INTERSECTS && (curx != movx || cury != movy)) {
- crossings = Segment2f.computeCrossingsFromRect(crossings,
- rxmin, rymin,
- rxmax, rymax,
- curx, cury,
- movx, movy);
- }
-
- // Count should always be a multiple of 2 here.
- // assert((crossings & 1) != 0);
- return crossings;
- }
-
- /**
- * Accumulate the number of times the quad crosses the shadow
- * extending to the right of the rectangle. See the comment
- * for the RECT_INTERSECTS constant for more complete details.
- *
- * @param crossings is the initial value for the crossings.
- * @param rxmin is the first corner of the rectangle.
- * @param rymin is the first corner of the rectangle.
- * @param rxmax is the second corner of the rectangle.
- * @param rymax is the second corner of the rectangle.
- * @param x0 is the first point of the curve.
- * @param y0 is the first point of the curve.
- * @param xc is the control point of the curve.
- * @param yc is the control point of the curve.
- * @param x1 is the last point of the curve.
- * @param y1 is the last point of the curve.
- * @param level is the recursion level. It may be equal to {@code 0} for the intiial call.
- * @return the crossings.
- */
- static int computeQuadCurveCrossingsFromRect(
- int crossings,
- float rxmin, float rymin,
- float rxmax, float rymax,
- float x0, float y0,
- float xc, float yc,
- float x1, float y1,
- int level) {
- // Copied from AWT API
- float ctrlx = xc;
- float ctrly = yc;
- int numCrosses = crossings;
-
- if (y0 >= rymax && ctrly >= rymax && y1 >= rymax) return numCrosses;
- if (y0 <= rymin && ctrly <= rymin && y1 <= rymin) return numCrosses;
- if (x0 <= rxmin && ctrlx <= rxmin && x1 <= rxmin) return numCrosses;
- if (x0 >= rxmax && ctrlx >= rxmax && x1 >= rxmax) {
- // Quad is entirely to the right of the rect
- // and the vertical range of the 3 Y coordinates of the quad
- // overlaps the vertical range of the rect by a non-empty amount
- // We now judge the crossings solely based on the line segment
- // connecting the endpoints of the quad.
- // Note that we may have 0, 1, or 2 crossings as the control
- // point may be causing the Y range intersection while the
- // two endpoints are entirely above or below.
- if (y0 < y1) {
- // y-increasing line segment...
- if (y0 <= rymin && y1 > rymin) ++numCrosses;
- if (y0 < rymax && y1 >= rymax) ++numCrosses;
+ boolean isOpen = (curx != movx) || (cury != movy);
+
+ if (isOpen) {
+ if (closeable) {
+ // Not closed
+ crossings = Segment2f.computeCrossingsFromRect(crossings,
+ rxmin, rymin,
+ rxmax, rymax,
+ curx, cury,
+ movx, movy);
}
- else if (y1 < y0) {
- // y-decreasing line segment...
- if (y1 <= rymin && y0 > rymin) --numCrosses;
- if (y1 < rymax && y0 >= rymax) --numCrosses;
+ else if (onlyIntersectWhenOpen) {
+ // Assume that when is the path is open, only
+ // SHAPE_INTERSECTS may be return
+ crossings = 0;
}
- return numCrosses;
}
-
- // The intersection of ranges is more complicated
- // First do trivial INTERSECTS rejection of the cases
- // where one of the endpoints is inside the rectangle.
- if ((x0 < rxmax && x0 > rxmin && y0 < rymax && y0 > rymin) ||
- (x1 < rxmax && x1 > rxmin && y1 < rymax && y1 > rymin)) {
- return MathConstants.SHAPE_INTERSECTS;
- }
- // Otherwise, subdivide and look for one of the cases above.
- // float precision only has 52 bits of mantissa
- if (level > 52) {
- return Segment2f.computeCrossingsFromRect(numCrosses,
- rxmin, rymin, rxmax, rymax,
- x0, y0, x1, y1);
- }
- float x0c = (x0 + ctrlx) / 2;
- float y0c = (y0 + ctrly) / 2;
- float xc1 = (ctrlx + x1) / 2;
- float yc1 = (ctrly + y1) / 2;
- ctrlx = (x0c + xc1) / 2;
- ctrly = (y0c + yc1) / 2;
- if (Double.isNaN(ctrlx) || Double.isNaN(ctrly)) {
- // [xy]c are NaN if any of [xy]0c or [xy]c1 are NaN
- // [xy]0c or [xy]c1 are NaN if any of [xy][0c1] are NaN
- // These values are also NaN if opposing infinities are added
- return 0;
- }
- numCrosses = computeQuadCurveCrossingsFromRect(numCrosses,
- rxmin, rymin, rxmax, rymax,
- x0, y0, x0c, y0c, ctrlx, ctrly,
- level+1);
- if (numCrosses != MathConstants.SHAPE_INTERSECTS) {
- numCrosses = computeQuadCurveCrossingsFromRect(numCrosses,
- rxmin, rymin, rxmax, rymax,
- ctrlx, ctrly, xc1, yc1, x1, y1,
- level+1);
- }
- return numCrosses;
- }
-
- /**
- * Accumulate the number of times the cubic crosses the shadow
- * extending to the right of the rectangle. See the comment
- * for the RECT_INTERSECTS constant for more complete details.
- *
- * @param crossings is the initial value for the crossings.
- * @param rxmin is the first corner of the rectangle.
- * @param rymin is the first corner of the rectangle.
- * @param rxmax is the second corner of the rectangle.
- * @param rymax is the second corner of the rectangle.
- * @param x0 is the first point of the curve.
- * @param y0 is the first point of the curve.
- * @param xc0 is the first control point of the curve.
- * @param yc0 is the first control point of the curve.
- * @param xc1 is the second control point of the curve.
- * @param yc1 is the second control point of the curve.
- * @param x1 is the last point of the curve.
- * @param y1 is the last point of the curve.
- * @param level is the recursion level. It may be equal to {@code 0} for the intiial call.
- * @return the crossings.
- */
- static int computeCubicCurveCrossingsFromRect(
- int crossings,
- float rxmin, float rymin,
- float rxmax, float rymax,
- float x0, float y0,
- float xc0, float yc0,
- float xc1, float yc1,
- float x1, float y1,
- int level) {
- // Copied from AWT API
- float ctrlx0 = xc0;
- float ctrly0 = yc0;
- float ctrlx1 = xc1;
- float ctrly1 = yc1;
- int numCrosses = crossings;
-
- if (y0 >= rymax && ctrly0 >= rymax && ctrly1 >= rymax && y1 >= rymax) {
- return numCrosses;
- }
- if (y0 <= rymin && ctrly0 <= rymin && ctrly1 <= rymin && y1 <= rymin) {
- return numCrosses;
- }
- if (x0 <= rxmin && ctrlx0 <= rxmin && ctrlx1 <= rxmin && x1 <= rxmin) {
- return numCrosses;
- }
- if (x0 >= rxmax && ctrlx0 >= rxmax && ctrlx1 >= rxmax && x1 >= rxmax) {
- // Cubic is entirely to the right of the rect
- // and the vertical range of the 4 Y coordinates of the cubic
- // overlaps the vertical range of the rect by a non-empty amount
- // We now judge the crossings solely based on the line segment
- // connecting the endpoints of the cubic.
- // Note that we may have 0, 1, or 2 crossings as the control
- // points may be causing the Y range intersection while the
- // two endpoints are entirely above or below.
- if (y0 < y1) {
- // y-increasing line segment...
- if (y0 <= rymin && y1 > rymin) ++numCrosses;
- if (y0 < rymax && y1 >= rymax) ++numCrosses;
- }
- else if (y1 < y0) {
- // y-decreasing line segment...
- if (y1 <= rymin && y0 > rymin) --numCrosses;
- if (y1 < rymax && y0 >= rymax) --numCrosses;
- }
- return numCrosses;
- }
- // The intersection of ranges is more complicated
- // First do trivial INTERSECTS rejection of the cases
- // where one of the endpoints is inside the rectangle.
- if ((x0 > rxmin && x0 < rxmax && y0 > rymin && y0 < rymax) ||
- (x1 > rxmin && x1 < rxmax && y1 > rymin && y1 < rymax)) {
- return MathConstants.SHAPE_INTERSECTS;
- }
- // Otherwise, subdivide and look for one of the cases above.
- // float precision only has 52 bits of mantissa
- if (level > 52) {
- return Segment2f.computeCrossingsFromRect(numCrosses,
- rxmin, rymin, rxmax, rymax,
- x0, y0, x1, y1);
- }
- float xmid = (ctrlx0 + ctrlx1) / 2;
- float ymid = (ctrly0 + ctrly1) / 2;
- ctrlx0 = (x0 + ctrlx0) / 2;
- ctrly0 = (y0 + ctrly0) / 2;
- ctrlx1 = (ctrlx1 + x1) / 2;
- ctrly1 = (ctrly1 + y1) / 2;
- float xc0m = (ctrlx0 + xmid) / 2;
- float yc0m = (ctrly0 + ymid) / 2;
- float xmc1 = (xmid + ctrlx1) / 2;
- float ymc1 = (ymid + ctrly1) / 2;
- xmid = (xc0m + xmc1) / 2;
- ymid = (yc0m + ymc1) / 2;
- if (Double.isNaN(xmid) || Double.isNaN(ymid)) {
- // [xy]mid are NaN if any of [xy]c0m or [xy]mc1 are NaN
- // [xy]c0m or [xy]mc1 are NaN if any of [xy][c][01] are NaN
- // These values are also NaN if opposing infinities are added
- return 0;
- }
- numCrosses = computeCubicCurveCrossingsFromRect(numCrosses,
- rxmin, rymin, rxmax, rymax,
- x0, y0, ctrlx0, ctrly0,
- xc0m, yc0m, xmid, ymid, level+1);
- if (numCrosses != MathConstants.SHAPE_INTERSECTS) {
- numCrosses = computeCubicCurveCrossingsFromRect(numCrosses,
- rxmin, rymin, rxmax, rymax,
- xmid, ymid, xmc1, ymc1,
- ctrlx1, ctrly1, x1, y1, level+1);
- }
+
return crossings;
}
@@ -1485,12 +1361,12 @@
@Override
public boolean contains(float x, float y) {
- return contains(getPathIterator(), x, y);
+ return contains(getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO), x, y);
}
@Override
public boolean contains(Rectangle2f r) {
- return contains(getPathIterator(),
+ return contains(getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO),
r.getMinX(), r.getMinY(), r.getWidth(), r.getHeight());
}
@@ -1500,8 +1376,9 @@
if (s.isEmpty()) return false;
int mask = (this.windingRule == PathWindingRule.NON_ZERO ? -1 : 2);
int crossings = computeCrossingsFromRect(
- getPathIterator(),
- s.getMinX(), s.getMinY(), s.getMaxX(), s.getMaxY());
+ getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO),
+ s.getMinX(), s.getMinY(), s.getMaxX(), s.getMaxY(),
+ false, true);
return (crossings == MathConstants.SHAPE_INTERSECTS ||
(crossings & mask) != 0);
}
@@ -1510,8 +1387,10 @@
public boolean intersects(Ellipse2f s) {
int mask = (this.windingRule == PathWindingRule.NON_ZERO ? -1 : 2);
int crossings = computeCrossingsFromEllipse(
- getPathIterator(),
- s.getMinX(), s.getMinY(), s.getWidth(), s.getHeight());
+ 0,
+ getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO),
+ s.getMinX(), s.getMinY(), s.getWidth(), s.getHeight(),
+ false, true);
return (crossings == MathConstants.SHAPE_INTERSECTS ||
(crossings & mask) != 0);
}
@@ -1520,8 +1399,11 @@
public boolean intersects(Circle2f s) {
int mask = (this.windingRule == PathWindingRule.NON_ZERO ? -1 : 2);
int crossings = computeCrossingsFromCircle(
- getPathIterator(),
- s.getX(), s.getY(), s.getRadius());
+ 0,
+ getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO),
+ s.getX(), s.getY(), s.getRadius(),
+ false,
+ true);
return (crossings == MathConstants.SHAPE_INTERSECTS ||
(crossings & mask) != 0);
}
@@ -1530,11 +1412,77 @@
public boolean intersects(Segment2f s) {
int mask = (this.windingRule == PathWindingRule.NON_ZERO ? -1 : 2);
int crossings = computeCrossingsFromSegment(
- getPathIterator(),
- s.getX1(), s.getY1(), s.getX2(), s.getY2());
+ 0,
+ getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO),
+ s.getX1(), s.getY1(), s.getX2(), s.getY2(),
+ false);
return (crossings == MathConstants.SHAPE_INTERSECTS ||
(crossings & mask) != 0);
}
+
+ @Override
+ public boolean intersects(Path2f s) {
+ if (s.size()>size())
+ return intersects(s.getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO), getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO));
+ return intersects(getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO), s.getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO));
+ }
+
+ private static boolean intersects(PathIterator2f iterator1, PathIterator2f iterator2) {
+ int mask = (iterator1.getWindingRule() == PathWindingRule.NON_ZERO ? -1 : 2);
+ Path2f subPath;
+ PathElement2f element;
+ while (iterator1.hasNext()) {
+ element = iterator1.next();
+ switch(element.type) {
+ case CLOSE:
+ case LINE_TO:
+ int crossings = computeCrossingsFromSegment(
+ iterator2,
+ element.fromX, element.fromY,
+ element.toX, element.toY);
+ if (crossings == MathConstants.SHAPE_INTERSECTS ||
+ (crossings & mask) != 0) {
+ return true;
+ }
+ break;
+ case MOVE_TO:
+ break;
+ case CURVE_TO:
+ subPath = new Path2f();
+ subPath.moveTo(element.fromX, element.fromY);
+ subPath.curveTo(
+ element.ctrlX1, element.ctrlY1,
+ element.ctrlX2, element.ctrlY2,
+ element.toX, element.toY);
+ if (intersects(
+ subPath.getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO),
+ iterator2)) {
+ return true;
+ }
+ break;
+ case QUAD_TO:
+ subPath = new Path2f();
+ subPath.moveTo(element.fromX, element.fromY);
+ subPath.quadTo(
+ element.ctrlX1, element.ctrlY1,
+ element.toX, element.toY);
+ if (intersects(
+ subPath.getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO),
+ iterator2)) {
+ return true;
+ }
+ break;
+ default:
+ throw new IllegalStateException();
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean intersects(PathIterator2f s) {
+ return intersects(getPathIterator(), s);
+ }
@Override
public Rectangle2f toBoundingBox() {
@@ -1588,28 +1536,18 @@
int mask = (pi.getWindingRule() == PathWindingRule.NON_ZERO ? -1 : 1);
int crossings = 0;
- boolean isClosed = false;
- float moveX, moveY, currentX, currentY;
- moveX = moveY = currentX = currentY = Float.NaN;
while (pi.hasNext()) {
pe = pi.next();
candidate = null;
- currentX = pe.toX;
- currentY = pe.toY;
-
switch(pe.type) {
case MOVE_TO:
- moveX = pe.toX;
- moveY = pe.toY;
- isClosed = false;
candidate = new Point2f(pe.toX, pe.toY);
break;
case LINE_TO:
{
- isClosed = false;
float factor = MathUtil.projectsPointOnLine(
p.getX(), p.getY(),
pe.fromX, pe.fromY, pe.toX, pe.toY);
@@ -1626,7 +1564,11 @@
break;
}
case CLOSE:
- isClosed = true;
+ crossings += Segment2f.computeCrossingsFromPoint(
+ p.getX(), p.getY(),
+ pe.fromX, pe.fromY, pe.toX, pe.toY);
+ if ((crossings & mask) != 0) return p;
+
if (!pe.isEmpty()) {
float factor = MathUtil.projectsPointOnLine(
p.getX(), p.getY(),
@@ -1638,10 +1580,8 @@
candidate = new Point2f(
pe.fromX + v.getX(),
pe.fromY + v.getY());
- crossings += Segment2f.computeCrossingsFromPoint(
- p.getX(), p.getY(),
- pe.fromX, pe.fromY, pe.toX, pe.toY);
}
+ crossings = 0;
break;
case QUAD_TO:
case CURVE_TO:
@@ -1658,14 +1598,6 @@
}
}
- if (!isClosed) {
- crossings += Segment2f.computeCrossingsFromPoint(
- p.getX(), p.getY(),
- currentX, currentY,
- moveX, moveY);
- }
-
- if ((crossings & mask) != 0) return p;
return closest;
}
Modified: trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Segment2f.java
===================================================================
--- trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Segment2f.java 2013-04-05 20:39:57 UTC (rev 413)
+++ trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Segment2f.java 2013-04-05 21:45:07 UTC (rev 414)
@@ -73,6 +73,34 @@
/**
* Calculates the number of times the line from (x0,y0) to (x1,y1)
+ * crosses the ray extending to the right from (px,py).
+ * If the point lies on the line, then no crossings are recorded.
+ * +1 is returned for a crossing where the Y coordinate is increasing
+ * -1 is returned for a crossing where the Y coordinate is decreasing
+ *
+ * @param px is the reference point to test.
+ * @param py is the reference point to test.
+ * @param x0 is the first point of the line.
+ * @param y0 is the first point of the line.
+ * @param x1 is the second point of the line.
+ * @param y1 is the secondpoint of the line.
+ * @return the crossing.
+ */
+ static int computeCrossingsFromPoint1(
+ float px, float py,
+ float x0, float y0,
+ float x1, float y1) {
+ if (py < y0 && py < y1) return 0;
+ if (py > y0 && py > y1) return 0;
+ if (px > x0 && px > x1) return 0;
+ if (px < x0 && px < x1) return (y0 < y1) ? 1 : -1;
+ float xintercept = x0 + (py - y0) * (x1 - x0) / (y1 - y0);
+ if (px > xintercept) return 0;
+ return (y0 < y1) ? 1 : -1;
+ }
+
+ /**
+ * Calculates the number of times the line from (x0,y0) to (x1,y1)
* crosses the segment (sx0,sy0) to (sx1,sy1) extending to the right.
*
* @param crossings is the initial value for the number of crossings.
@@ -92,6 +120,32 @@
float sx2, float sy2,
float x0, float y0,
float x1, float y1) {
+ return computeCrossingsFromSegment(crossings, sx1, sy1, sx2, sy2, x0, y0, x1, y1, false);
+ }
+
+ /**
+ * Calculates the number of times the line from (x0,y0) to (x1,y1)
+ * crosses the segment (sx0,sy0) to (sx1,sy1) extending to the right.
+ *
+ * @param crossings is the initial value for the number of crossings.
+ * @param sx1 is the first point of the segment to extend.
+ * @param sy1 is the first point of the segment to extend.
+ * @param sx2 is the second point of the segment to extend.
+ * @param sy2 is the second point of the segment to extend.
+ * @param x0 is the first point of the line.
+ * @param y0 is the first point of the line.
+ * @param x1 is the second point of the line.
+ * @param y1 is the secondpoint of the line.
+ * @param linesAreCrossing indicates if the shadow lines are crossing.
+ * @return the crossing, or {@link MathConstants#SHAPE_INTERSECTS}
+ */
+ static int computeCrossingsFromSegment(
+ int crossings,
+ float sx1, float sy1,
+ float sx2, float sy2,
+ float x0, float y0,
+ float x1, float y1,
+ boolean linesAreCrossing) {
int numCrosses = crossings;
float xmin = Math.min(sx1, sx2);
@@ -128,8 +182,14 @@
}
if (side1>0 || side2>0) {
int n1, n2;
- n1 = computeCrossingsFromPoint(sx1, sy1, x0, y0, x1, y1);
- n2 = computeCrossingsFromPoint(sx2, sy2, x0, y0, x1, y1);
+ if (linesAreCrossing) {
+ n1 = computeCrossingsFromPoint1(sx1, sy1, x0, y0, x1, y1);
+ n2 = computeCrossingsFromPoint1(sx2, sy2, x0, y0, x1, y1);
+ }
+ else {
+ n1 = computeCrossingsFromPoint(sx1, sy1, x0, y0, x1, y1);
+ n2 = computeCrossingsFromPoint(sx2, sy2, x0, y0, x1, y1);
+ }
numCrosses += n1 + n2;
}
}
@@ -162,8 +222,8 @@
float xmin = ex;
float ymin = ey;
- float xmax = ex + Math.max(0, ew);
- float ymax = ey + Math.max(0, eh);
+ float xmax = ex + ew;
+ float ymax = ey + eh;
if (y0<=ymin && y1<=ymin) return numCrosses;
if (y0>=ymax && y1>=ymax) return numCrosses;
@@ -181,7 +241,7 @@
}
}
else if (Ellipse2f.intersectsEllipseSegment(
- xmin, ymin, xmax, ymax,
+ xmin, ymin, xmax-xmin, ymax-ymin,
x0, y0, x1, y1)) {
return MathConstants.SHAPE_INTERSECTS;
}
@@ -860,7 +920,7 @@
public boolean intersects(Ellipse2f s) {
return Ellipse2f.intersectsEllipseSegment(
s.getMinX(), s.getMinY(),
- s.getMaxX(), s.getMaxY(),
+ s.getWidth(), s.getHeight(),
getX1(), getY1(),
getX2(), getY2());
}
Added: trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/AbstractPath2fTestCase.java
===================================================================
--- trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/AbstractPath2fTestCase.java (rev 0)
+++ trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/AbstractPath2fTestCase.java 2013-04-05 21:45:07 UTC (rev 414)
@@ -0,0 +1,216 @@
+/*
+ * $Id$
+ *
+ * Copyright (c) 2006-10, Multiagent Team, Laboratoire Systemes et Transports, Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2012 Stephane GALLAND.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.math.continous.object2d;
+
+import org.arakhne.afc.math.generic.PathWindingRule;
+
+/** Abstract tests for the paths.
+ *
+ * @author $Author: galland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public abstract class AbstractPath2fTestCase extends AbstractShape2fTestCase<Path2f> {
+
+ @Override
+ public void testIsEmpty() {
+ assertFalse(this.r.isEmpty());
+
+ this.r.clear();
+ assertTrue(this.r.isEmpty());
+
+ this.r.moveTo(1f, 2f);
+ assertTrue(this.r.isEmpty());
+ this.r.moveTo(3f, 4f);
+ assertTrue(this.r.isEmpty());
+ this.r.lineTo(5f, 6f);
+ assertFalse(this.r.isEmpty());
+ this.r.closePath();
+ assertFalse(this.r.isEmpty());
+
+ this.r.clear();
+ assertTrue(this.r.isEmpty());
+
+ this.r.moveTo(1f, 2f);
+ assertTrue(this.r.isEmpty());
+ this.r.moveTo(3f, 4f);
+ assertTrue(this.r.isEmpty());
+ this.r.lineTo(3f, 4f);
+ assertTrue(this.r.isEmpty());
+ this.r.closePath();
+ assertTrue(this.r.isEmpty());
+
+ this.r.clear();
+ assertTrue(this.r.isEmpty());
+
+ this.r.moveTo(1f, 2f);
+ assertTrue(this.r.isEmpty());
+ this.r.moveTo(3f, 4f);
+ assertTrue(this.r.isEmpty());
+ this.r.lineTo(3f, 4f);
+ assertTrue(this.r.isEmpty());
+ this.r.lineTo(5f, 6f);
+ assertFalse(this.r.isEmpty());
+ }
+
+ @Override
+ public void testClear() {
+ this.r.clear();
+ assertEquals(0, this.r.size());
+ }
+
+ @Override
+ public void testClone() {
+ Path2f b = this.r.clone();
+
+ assertNotSame(b, this.r);
+ PathElement2f pe1, pe2;
+ PathIterator2f i1 = this.r.getPathIterator();
+ PathIterator2f i2 = b.getPathIterator();
+ assertNotSame(i1, i2);
+ while (i1.hasNext()) {
+ assertTrue(i2.hasNext());
+ pe1 = i1.next();
+ pe2 = i2.next();
+ assertNotSame(pe1, pe2);
+ assertEquals(pe1.type, pe2.type);
+ assertEpsilonEquals(pe1.fromX, pe2.fromX);
+ assertEpsilonEquals(pe1.fromY, pe2.fromY);
+ assertEpsilonEquals(pe1.ctrlX1, pe2.ctrlX1);
+ assertEpsilonEquals(pe1.ctrlY1, pe2.ctrlY1);
+ assertEpsilonEquals(pe1.ctrlX2, pe2.ctrlX2);
+ assertEpsilonEquals(pe1.ctrlY2, pe2.ctrlY2);
+ assertEpsilonEquals(pe1.toX, pe2.toX);
+ assertEpsilonEquals(pe1.toY, pe2.toY);
+
+ }
+ assertFalse(i2.hasNext());
+
+ b.translate(1f, 1f);
+
+ i1 = this.r.getPathIterator();
+ i2 = b.getPathIterator();
+ while (i1.hasNext()) {
+ assertTrue(i2.hasNext());
+ pe1 = i1.next();
+ pe2 = i2.next();
+ assertEquals(pe1.type, pe2.type);
+ assertNotEpsilonEquals(pe1.fromX, pe2.fromX);
+ assertNotEpsilonEquals(pe1.fromY, pe2.fromY);
+ assertNotEpsilonEquals(pe1.ctrlX1, pe2.ctrlX1);
+ assertNotEpsilonEquals(pe1.ctrlY1, pe2.ctrlY1);
+ assertNotEpsilonEquals(pe1.ctrlX2, pe2.ctrlX2);
+ assertNotEpsilonEquals(pe1.ctrlY2, pe2.ctrlY2);
+ assertNotEpsilonEquals(pe1.toX, pe2.toX);
+ assertNotEpsilonEquals(pe1.toY, pe2.toY);
+
+ }
+ assertFalse(i2.hasNext());
+ }
+
+ /**
+ */
+ public abstract void testContainsPathIterator2fFloatFloat();
+
+ /**
+ */
+ public abstract void testIntersectsPathIterator2fFloatFloatFloatFloat();
+
+ /**
+ */
+ public abstract void testGetClosestPointTo();
+
+ /**
+ */
+ public void testSetWindingRule() {
+ assertEquals(PathWindingRule.NON_ZERO, this.r.getWindingRule());
+ for(PathWindingRule rule : PathWindingRule.values()) {
+ this.r.setWindingRule(rule);
+ assertEquals(rule, this.r.getWindingRule());
+ }
+ }
+
+ /**
+ */
+ public abstract void testAddIterator();
+
+ /**
+ */
+ public abstract void testGetPathIteratorVoid();
+
+ /**
+ */
+ public abstract void testGetPathIteratorTransform2D();
+
+ /**
+ */
+ public abstract void testTransformTransform2D();
+
+ /**
+ */
+ public abstract void testCreateTransformedShape2D();
+
+ /**
+ */
+ public abstract void testContainsFloatfloat();
+
+ /**
+ */
+ public abstract void testContainsRectangle2f();
+
+ /**
+ */
+ public abstract void testIntersectsRectangle2f();
+
+ /**
+ */
+ public abstract void testIntersectsEllipse2f();
+
+ /**
+ */
+ public abstract void testIntersectsCircle2f();
+
+ /**
+ */
+ public abstract void testIntersectsSegment2f();
+
+ @Override
+ public abstract void testToBoundingBox();
+
+ /**
+ */
+ public abstract void testRemoveLast();
+
+ /**
+ */
+ public abstract void testSetLastPointFloatFloat();
+
+ /**
+ */
+ public abstract void testRemoveFloatFloat();
+
+ /**
+ */
+ public abstract void testContainsPointPoint2D();
+
+}
\ No newline at end of file
Added: trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/ClosePath2fTest.java
===================================================================
--- trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/ClosePath2fTest.java (rev 0)
+++ trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/ClosePath2fTest.java 2013-04-05 21:45:07 UTC (rev 414)
@@ -0,0 +1,538 @@
+/*
+ * $Id$
+ *
+ * Copyright (c) 2006-10, Multiagent Team, Laboratoire Systemes et Transports, Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2012 Stephane GALLAND.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.math.continous.object2d;
+
+import org.arakhne.afc.math.generic.PathElementType;
+import org.arakhne.afc.math.generic.Point2D;
+import org.arakhne.afc.math.matrix.Transform2D;
+
+/**
+ * @author $Author: galland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class ClosePath2fTest extends AbstractPath2fTestCase {
+
+ @Override
+ protected Path2f createShape() {
+ Path2f p = new Path2f();
+ p.moveTo(1f, 1f);
+ p.lineTo(2f, 2f);
+ p.quadTo(3f, 0f, 4f, 3f);
+ p.curveTo(5f, -1f, 6f, 5f, 7f, -5f);
+ p.closePath();
+ return p;
+ }
+
+ /**
+ */
+ @Override
+ public void testGetClosestPointTo() {
+ Point2D p;
+
+ p = this.r.getClosestPointTo(new Point2f(0f, 0f));
+ assertEpsilonEquals(1f, p.getX());
+ assertEpsilonEquals(1f, p.getY());
+
+ p = this.r.getClosestPointTo(new Point2f(4f, 0f));
+ assertEpsilonEquals(4f, p.getX());
+ assertEpsilonEquals(0f, p.getY());
+
+ p = this.r.getClosestPointTo(new Point2f(4f, 2f));
+ assertEpsilonEquals(4f, p.getX());
+ assertEpsilonEquals(2f, p.getY());
+
+ p = this.r.getClosestPointTo(new Point2f(1f, 0f));
+ assertEpsilonEquals(1.5f, p.getX());
+ assertEpsilonEquals(.5f, p.getY());
+ }
+
+
+ @Override
+ public void testDistancePoint2D() {
+ assertEpsilonEquals(1.414213562f, this.r.distance(new Point2f(0f, 0f)));
+ assertEpsilonEquals(0f, this.r.distance(new Point2f(4f, 0f)));
+ assertEpsilonEquals(0f, this.r.distance(new Point2f(4f, 2f)));
+ assertEpsilonEquals(0.707106781f, this.r.distance(new Point2f(1f, 0f)));
+ }
+
+ @Override
+ public void testDistanceSquaredPoint2D() {
+ assertEpsilonEquals(2f, this.r.distanceSquared(new Point2f(0f, 0f)));
+ assertEpsilonEquals(0f, this.r.distanceSquared(new Point2f(4f, 0f)));
+ assertEpsilonEquals(0f, this.r.distanceSquared(new Point2f(4f, 2f)));
+ assertEpsilonEquals(.5f, this.r.distanceSquared(new Point2f(1f, 0f)));
+ }
+
+ @Override
+ public void testDistanceL1Point2D() {
+ // (1,1)
+ assertEpsilonEquals(2f, this.r.distanceL1(new Point2f(0f, 0f)));
+ // (4,0)
+ assertEpsilonEquals(0f, this.r.distanceL1(new Point2f(4f, 0f)));
+ // (4,2)
+ assertEpsilonEquals(0f, this.r.distanceL1(new Point2f(4f, 2f)));
+ // (1.5,.5)
+ assertEpsilonEquals(1f, this.r.distanceL1(new Point2f(1f, 0f)));
+ }
+
+ @Override
+ public void testDistanceLinfPoint2D() {
+ // (1,1)
+ assertEpsilonEquals(1f, this.r.distanceLinf(new Point2f(0f, 0f)));
+ // (4,0)
+ assertEpsilonEquals(0f, this.r.distanceLinf(new Point2f(4f, 0f)));
+ // (4,2)
+ assertEpsilonEquals(0f, this.r.distanceLinf(new Point2f(4f, 2f)));
+ // (1.5,.5)
+ assertEpsilonEquals(.5f, this.r.distanceLinf(new Point2f(1f, 0f)));
+ }
+
+ @Override
+ public void testTranslateFloatFloat() {
+ this.r.translate(3.4f, 4.5f);
+ PathIterator2f pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 4.4f, 5.5f);
+ assertElement(pi, PathElementType.LINE_TO, 5.4f, 6.5f);
+ assertElement(pi, PathElementType.QUAD_TO, 6.4f, 4.5f, 7.4f, 7.5f);
+ assertElement(pi, PathElementType.CURVE_TO, 8.4f, 3.5f, 9.4f, 9.5f, 10.4f, -.5f);
+ assertElement(pi, PathElementType.CLOSE);
+ assertNoElement(pi);
+ }
+
+ /**
+ */
+ @Override
+ public void testAddIterator() {
+ Path2f p2 = new Path2f();
+ p2.moveTo(3.4f, 4.5f);
+ p2.lineTo(5.6f, 6.7f);
+
+ this.r.add(p2.getPathIterator());
+
+ PathIterator2f pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertElement(pi, PathElementType.LINE_TO, 2f, 2f);
+ assertElement(pi, PathElementType.QUAD_TO, 3f, 0f, 4f, 3f);
+ assertElement(pi, PathElementType.CURVE_TO, 5f, -1f, 6f, 5f, 7f, -5f);
+ assertElement(pi, PathElementType.CLOSE);
+ assertElement(pi, PathElementType.MOVE_TO, 3.4f, 4.5f);
+ assertElement(pi, PathElementType.LINE_TO, 5.6f, 6.7f);
+ assertNoElement(pi);
+ }
+
+ /**
+ */
+ @Override
+ public void testGetPathIteratorVoid() {
+ PathIterator2f pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertElement(pi, PathElementType.LINE_TO, 2f, 2f);
+ assertElement(pi, PathElementType.QUAD_TO, 3f, 0f, 4f, 3f);
+ assertElement(pi, PathElementType.CURVE_TO, 5f, -1f, 6f, 5f, 7f, -5f);
+ assertElement(pi, PathElementType.CLOSE);
+ assertNoElement(pi);
+ }
+
+ /**
+ */
+ @Override
+ public void testGetPathIteratorTransform2D() {
+ Transform2D tr;
+ PathIterator2f pi;
+
+ tr = new Transform2D();
+ pi = this.r.getPathIterator(tr);
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertElement(pi, PathElementType.LINE_TO, 2f, 2f);
+ assertElement(pi, PathElementType.QUAD_TO, 3f, 0f, 4f, 3f);
+ assertElement(pi, PathElementType.CURVE_TO, 5f, -1f, 6f, 5f, 7f, -5f);
+ assertElement(pi, PathElementType.CLOSE);
+ assertNoElement(pi);
+
+ tr = new Transform2D();
+ tr.makeTranslationMatrix(3.4f, 4.5f);
+ pi = this.r.getPathIterator(tr);
+ assertElement(pi, PathElementType.MOVE_TO, 4.4f, 5.5f);
+ assertElement(pi, PathElementType.LINE_TO, 5.4f, 6.5f);
+ assertElement(pi, PathElementType.QUAD_TO, 6.4f, 4.5f, 7.4f, 7.5f);
+ assertElement(pi, PathElementType.CURVE_TO, 8.4f, 3.5f, 9.4f, 9.5f, 10.4f, -.5f);
+ assertElement(pi, PathElementType.CLOSE);
+ assertNoElement(pi);
+ }
+
+ /**
+ */
+ @Override
+ public void testTransformTransform2D() {
+ Transform2D tr = new Transform2D();
+ tr.makeTranslationMatrix(3.4f, 4.5f);
+ Transform2D tr2 = new Transform2D();
+ tr2.makeRotationMatrix(5.6f);
+
+ Path2f clone = this.r.clone();
+ clone.transform(tr);
+
+ PathIterator2f pi = clone.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 4.4f, 5.5f);
+ assertElement(pi, PathElementType.LINE_TO, 5.4f, 6.5f);
+ assertElement(pi, PathElementType.QUAD_TO, 6.4f, 4.5f, 7.4f, 7.5f);
+ assertElement(pi, PathElementType.CURVE_TO, 8.4f, 3.5f, 9.4f, 9.5f, 10.4f, -.5f);
+ assertElement(pi, PathElementType.CLOSE);
+ assertNoElement(pi);
+
+ clone = this.r.clone();
+ clone.transform(tr2);
+
+ pi = clone.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1.406832516382571f, 0.144299240637928f);
+ assertElement(pi, PathElementType.LINE_TO, 2.813665032765142f, 0.288598481275856f);
+ assertElement(pi, PathElementType.QUAD_TO, 2.32669763553075f, -1.89379991361696f,
+ 4.996063427657964f, -0.198368915958538f);
+ assertElement(pi, PathElementType.CURVE_TO, 3.24656275467893f, -3.93189906787186f,
+ 7.8097284604231056f, 0.0902295653173185f,
+ 2.27262796021014f, -8.29669585765750f);
+ assertElement(pi, PathElementType.CLOSE);
+ assertNoElement(pi);
+
+ Transform2D tr3 = new Transform2D();
+ tr3.mul(tr, tr2);
+ clone = this.r.clone();
+ clone.transform(tr3);
+
+ pi = clone.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 4.80683251638257f, 4.64429924063793f);
+ assertElement(pi, PathElementType.LINE_TO, 6.21366503276514f, 4.78859848127586f);
+ assertElement(pi, PathElementType.QUAD_TO, 5.72669763553075f, 2.60620008638304f,
+ 8.39606342765796f, 4.30163108404146f);
+ assertElement(pi, PathElementType.CURVE_TO, 6.646562754678927f, 0.568100932128142f,
+ 11.20972846042311f, 4.59022956531732f, 5.67262796021014f, -3.79669585765750f);
+ assertElement(pi, PathElementType.CLOSE);
+ assertNoElement(pi);
+ }
+
+ /**
+ */
+ @Override
+ public void testCreateTransformedShape2D() {
+ Transform2D tr = new Transform2D();
+ tr.makeTranslationMatrix(3.4f, 4.5f);
+ Path2f p2 = (Path2f)this.r.createTransformedShape(tr);
+
+ PathIterator2f pi = p2.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 4.4f, 5.5f);
+ assertElement(pi, PathElementType.LINE_TO, 5.4f, 6.5f);
+ assertElement(pi, PathElementType.QUAD_TO, 6.4f, 4.5f, 7.4f, 7.5f);
+ assertElement(pi, PathElementType.CURVE_TO, 8.4f, 3.5f, 9.4f, 9.5f, 10.4f, -.5f);
+ assertElement(pi, PathElementType.CLOSE);
+ assertNoElement(pi);
+ }
+
+ /**
+ */
+ @Override
+ public void testContainsPathIterator2fFloatFloat() {
+ assertFalse(Path2f.contains(this.r.getPathIterator(), 0f, 0f));
+ assertTrue(Path2f.contains(this.r.getPathIterator(), 4f, 3f));
+ assertTrue(Path2f.contains(this.r.getPathIterator(), 2f, 2f));
+ assertTrue(Path2f.contains(this.r.getPathIterator(), 2f, 1f));
+ assertTrue(Path2f.contains(this.r.getPathIterator(), 5f, 0f));
+ assertFalse(Path2f.contains(this.r.getPathIterator(), -1f, -1f));
+ }
+
+ /**
+ */
+ @Override
+ public void testContainsFloatfloat() {
+ assertFalse(this.r.contains(0f, 0f));
+ assertTrue(this.r.contains(4f, 3f));
+ assertTrue(this.r.contains(2f, 2f));
+ assertTrue(this.r.contains(2f, 1f));
+ assertTrue(this.r.contains(5f, 0f));
+ assertFalse(this.r.contains(-1f, -1f));
+ assertFalse(this.r.contains(5f, 2f));
+ assertFalse(this.r.contains(3.5f, -2.5f));
+ assertFalse(this.r.contains(7f, -4f));
+ assertFalse(this.r.contains(2.5f, 1.5f));
+ }
+
+ /**
+ */
+ @Override
+ public void testContainsRectangle2f() {
+ assertFalse(this.r.contains(new Rectangle2f(0f, 0f, 1f, 1f)));
+ assertFalse(this.r.contains(new Rectangle2f(4f, 3f, 1f, 1f)));
+ assertFalse(this.r.contains(new Rectangle2f(2f, 2f, 1f, 1f)));
+ assertFalse(this.r.contains(new Rectangle2f(2f, 1f, 1f, 1f)));
+ assertTrue(this.r.contains(new Rectangle2f(3f, 0f, 1f, 1f)));
+ assertFalse(this.r.contains(new Rectangle2f(-1f, -1f, 1f, 1f)));
+ assertFalse(this.r.contains(new Rectangle2f(4f, -3f, 1f, 1f)));
+ assertFalse(this.r.contains(new Rectangle2f(-3f, 4f, 1f, 1f)));
+ assertFalse(this.r.contains(new Rectangle2f(6f, -5f, 1f, 1f)));
+ assertTrue(this.r.contains(new Rectangle2f(4f, 0f, 1f, 1f)));
+ assertFalse(this.r.contains(new Rectangle2f(5f, 0f, 1f, 1f)));
+ assertFalse(this.r.contains(new Rectangle2f(.01f, .01f, 1f, 1f)));
+ }
+
+ /**
+ */
+ @Override
+ public void testIntersectsRectangle2f() {
+ assertFalse(this.r.intersects(new Rectangle2f(0f, 0f, 1f, 1f)));
+ assertFalse(this.r.intersects(new Rectangle2f(4f, 3f, 1f, 1f)));
+ assertFalse(this.r.intersects(new Rectangle2f(2f, 2f, 1f, 1f)));
+ assertTrue(this.r.intersects(new Rectangle2f(2f, 1f, 1f, 1f)));
+ assertTrue(this.r.intersects(new Rectangle2f(3f, 0f, 1f, 1f)));
+ assertFalse(this.r.intersects(new Rectangle2f(-1f, -1f, 1f, 1f)));
+ assertTrue(this.r.intersects(new Rectangle2f(4f, -3f, 1f, 1f)));
+ assertFalse(this.r.intersects(new Rectangle2f(-3f, 4f, 1f, 1f)));
+ assertTrue(this.r.intersects(new Rectangle2f(6f, -5f, 1f, 1f)));
+ assertTrue(this.r.intersects(new Rectangle2f(4f, 0f, 1f, 1f)));
+ assertTrue(this.r.intersects(new Rectangle2f(5f, 0f, 1f, 1f)));
+ assertTrue(this.r.intersects(new Rectangle2f(.01f, .01f, 1f, 1f)));
+ }
+
+ @Override
+ public void testIntersectsPathIterator2fFloatFloatFloatFloat() {
+ assertFalse(Path2f.intersects(this.r.getPathIterator(), 0f, 0f, 1f, 1f));
+ assertFalse(Path2f.intersects(this.r.getPathIterator(), 4f, 3f, 1f, 1f));
+ assertFalse(Path2f.intersects(this.r.getPathIterator(),2f, 2f, 1f, 1f));
+ assertTrue(Path2f.intersects(this.r.getPathIterator(), 2f, 1f, 1f, 1f));
+ assertTrue(Path2f.intersects(this.r.getPathIterator(), 3f, 0f, 1f, 1f));
+ assertFalse(Path2f.intersects(this.r.getPathIterator(), -1f, -1f, 1f, 1f));
+ assertTrue(Path2f.intersects(this.r.getPathIterator(), 4f, -3f, 1f, 1f));
+ assertFalse(Path2f.intersects(this.r.getPathIterator(), -3f, 4f, 1f, 1f));
+ assertTrue(Path2f.intersects(this.r.getPathIterator(), 6f, -5f, 1f, 1f));
+ assertTrue(Path2f.intersects(this.r.getPathIterator(), 4f, 0f, 1f, 1f));
+ assertTrue(Path2f.intersects(this.r.getPathIterator(), 5f, 0f, 1f, 1f));
+ assertTrue(Path2f.intersects(this.r.getPathIterator(), .01f, .01f, 1f, 1f));
+ }
+
+ /**
+ */
+ @Override
+ public void testIntersectsEllipse2f() {
+ assertFalse(this.r.intersects(new Ellipse2f(0f, 0f, 1f, 2f)));
+ assertFalse(this.r.intersects(new Ellipse2f(4f, 3f, 1f, 2f)));
+ assertFalse(this.r.intersects(new Ellipse2f(2f, 2f, 1f, 2f)));
+ assertTrue(this.r.intersects(new Ellipse2f(2f, 1f, 1f, 2f)));
+ assertTrue(this.r.intersects(new Ellipse2f(3f, 0f, 1f, 2f)));
+ assertFalse(this.r.intersects(new Ellipse2f(-1f, -1f, 1f, 2f)));
+ assertTrue(this.r.intersects(new Ellipse2f(4f, -3f, 1f, 2f)));
+ assertFalse(this.r.intersects(new Ellipse2f(-3f, 4f, 1f, 2f)));
+ assertTrue(this.r.intersects(new Ellipse2f(6f, -5f, 1f, 2f)));
+ assertTrue(this.r.intersects(new Ellipse2f(6f, -5f, .8f, 2f)));
+ assertTrue(this.r.intersects(new Ellipse2f(4f, 0f, 1f, 2f)));
+ assertFalse(this.r.intersects(new Ellipse2f(6f, 0f, 1f, 2f)));
+ }
+
+ /**
+ */
+ @Override
+ public void testIntersectsCircle2f() {
+ assertFalse(this.r.intersects(new Circle2f(0f, 0f, 1f)));
+ assertTrue(this.r.intersects(new Circle2f(4f, 3f, 1f)));
+ assertTrue(this.r.intersects(new Circle2f(2f, 2f, 1f)));
+ assertTrue(this.r.intersects(new Circle2f(2f, 1f, 1f)));
+ assertTrue(this.r.intersects(new Circle2f(3f, 0f, 1f)));
+ assertFalse(this.r.intersects(new Circle2f(-1f, -1f, 1f)));
+ assertTrue(this.r.intersects(new Circle2f(4f, -3f, 1f)));
+ assertFalse(this.r.intersects(new Circle2f(-3f, 4f, 1f)));
+ assertTrue(this.r.intersects(new Circle2f(6f, -5f, 1f)));
+ assertTrue(this.r.intersects(new Circle2f(6f, -5f, .95f)));
+ assertTrue(this.r.intersects(new Circle2f(4f, 0f, 1f)));
+ assertTrue(this.r.intersects(new Circle2f(5f, 0f, 1f)));
+ assertFalse(this.r.intersects(new Circle2f(.01f, .01f, 1f)));
+ assertFalse(this.r.intersects(new Circle2f(6f, 2f, .8f)));
+ }
+
+ /**
+ */
+ @Override
+ public void testIntersectsSegment2f() {
+ assertFalse(this.r.intersects(new Segment2f(0f, 0f, 1f, 1f)));
+ assertTrue(this.r.intersects(new Segment2f(4f, 3f, 1f, 1f)));
+ assertTrue(this.r.intersects(new Segment2f(2f, 2f, 1f, 1f)));
+ assertTrue(this.r.intersects(new Segment2f(2f, 1f, 1f, 1f)));
+ assertTrue(this.r.intersects(new Segment2f(3f, 0f, 1f, 1f)));
+ assertTrue(this.r.intersects(new Segment2f(3f, 0f, 1.5f, 1f)));
+ assertFalse(this.r.intersects(new Segment2f(-1f, -1f, 1f, 1f)));
+ assertFalse(this.r.intersects(new Segment2f(4f, -3f, 1f, 1f)));
+ assertFalse(this.r.intersects(new Segment2f(4f, -3f, 1f, 0f)));
+ assertFalse(this.r.intersects(new Segment2f(-3f, 4f, 1f, 1f)));
+ assertFalse(this.r.intersects(new Segment2f(6f, -5f, 1f, 1f)));
+ assertFalse(this.r.intersects(new Segment2f(6f, -5f, 1f, 0f)));
+ assertTrue(this.r.intersects(new Segment2f(4f, 0f, 1f, 1f)));
+ assertTrue(this.r.intersects(new Segment2f(5f, 0f, 1f, 1f)));
+ assertFalse(this.r.intersects(new Segment2f(.01f, .01f, 1f, 1f)));
+ }
+
+ @Override
+ public void testToBoundingBox() {
+ Rectangle2f bb = this.r.toBoundingBox();
+ assertEpsilonEquals(1f, bb.getMinX());
+ assertEpsilonEquals(-5f, bb.getMinY());
+ assertEpsilonEquals(7f, bb.getMaxX());
+ assertEpsilonEquals(5f, bb.getMaxY());
+ }
+
+ /**
+ */
+ @Override
+ public void testRemoveLast() {
+ PathIterator2f pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertElement(pi, PathElementType.LINE_TO, 2f, 2f);
+ assertElement(pi, PathElementType.QUAD_TO, 3f, 0f, 4f, 3f);
+ assertElement(pi, PathElementType.CURVE_TO, 5f, -1f, 6f, 5f, 7f, -5f);
+ assertElement(pi, PathElementType.CLOSE);
+ assertNoElement(pi);
+
+ this.r.removeLast();
+
+ pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertElement(pi, PathElementType.LINE_TO, 2f, 2f);
+ assertElement(pi, PathElementType.QUAD_TO, 3f, 0f, 4f, 3f);
+ assertElement(pi, PathElementType.CURVE_TO, 5f, -1f, 6f, 5f, 7f, -5f);
+ assertNoElement(pi);
+
+ this.r.removeLast();
+
+ pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertElement(pi, PathElementType.LINE_TO, 2f, 2f);
+ assertElement(pi, PathElementType.QUAD_TO, 3f, 0f, 4f, 3f);
+ assertNoElement(pi);
+
+ this.r.removeLast();
+
+ pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertElement(pi, PathElementType.LINE_TO, 2f, 2f);
+ assertNoElement(pi);
+
+ this.r.removeLast();
+
+ pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertNoElement(pi);
+
+ this.r.removeLast();
+
+ pi = this.r.getPathIterator();
+ assertNoElement(pi);
+
+ this.r.removeLast();
+
+ pi = this.r.getPathIterator();
+ assertNoElement(pi);
+ }
+
+ /**
+ */
+ @Override
+ public void testSetLastPointFloatFloat() {
+ PathIterator2f pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertElement(pi, PathElementType.LINE_TO, 2f, 2f);
+ assertElement(pi, PathElementType.QUAD_TO, 3f, 0f, 4f, 3f);
+ assertElement(pi, PathElementType.CURVE_TO, 5f, -1f, 6f, 5f, 7f, -5f);
+ assertElement(pi, PathElementType.CLOSE);
+ assertNoElement(pi);
+
+ this.r.setLastPoint(123.456f, 789.1011f);
+
+ pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertElement(pi, PathElementType.LINE_TO, 2f, 2f);
+ assertElement(pi, PathElementType.QUAD_TO, 3f, 0f, 4f, 3f);
+ assertElement(pi, PathElementType.CURVE_TO, 5f, -1f, 6f, 5f, 123.456f, 789.1011f);
+ assertElement(pi, PathElementType.CLOSE);
+ assertNoElement(pi);
+ }
+
+ /**
+ */
+ @Override
+ public void testRemoveFloatFloat() {
+ PathIterator2f pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertElement(pi, PathElementType.LINE_TO, 2f, 2f);
+ assertElement(pi, PathElementType.QUAD_TO, 3f, 0f, 4f, 3f);
+ assertElement(pi, PathElementType.CURVE_TO, 5f, -1f, 6f, 5f, 7f, -5f);
+ assertElement(pi, PathElementType.CLOSE);
+ assertNoElement(pi);
+
+ this.r.remove(2f, 2f);
+
+ pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertElement(pi, PathElementType.QUAD_TO, 3f, 0f, 4f, 3f);
+ assertElement(pi, PathElementType.CURVE_TO, 5f, -1f, 6f, 5f, 7f, -5f);
+ assertElement(pi, PathElementType.CLOSE);
+ assertNoElement(pi);
+
+ this.r.remove(4f, 3f);
+
+ pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertElement(pi, PathElementType.CURVE_TO, 5f, -1f, 6f, 5f, 7f, -5f);
+ assertElement(pi, PathElementType.CLOSE);
+ assertNoElement(pi);
+
+ this.r.remove(6f, 5f);
+
+ pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertElement(pi, PathElementType.CLOSE);
+ assertNoElement(pi);
+
+ this.r.remove(6f, 5f);
+
+ pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertElement(pi, PathElementType.CLOSE);
+ assertNoElement(pi);
+ }
+
+ /**
+ */
+ @Override
+ public void testContainsPointPoint2D() {
+ PathIterator2f pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertElement(pi, PathElementType.LINE_TO, 2f, 2f);
+ assertElement(pi, PathElementType.QUAD_TO, 3f, 0f, 4f, 3f);
+ assertElement(pi, PathElementType.CURVE_TO, 5f, -1f, 6f, 5f, 7f, -5f);
+ assertElement(pi, PathElementType.CLOSE);
+ assertNoElement(pi);
+
+ assertTrue(this.r.containsPoint(new Point2f(2f, 2f)));
+ assertFalse(this.r.containsPoint(new Point2f(4f, 4f)));
+ assertTrue(this.r.containsPoint(new Point2f(6f, 5f)));
+ assertFalse(this.r.containsPoint(new Point2f(-1f, 6f)));
+ assertFalse(this.r.containsPoint(new Point2f(1234f, 5678f)));
+ }
+
+}
\ No newline at end of file
Modified: trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/Ellipse2fTest.java
===================================================================
--- trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/Ellipse2fTest.java 2013-04-05 20:39:57 UTC (rev 413)
+++ trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/Ellipse2fTest.java 2013-04-05 21:45:07 UTC (rev 414)
@@ -451,6 +451,11 @@
6f, -5f, 1f, 2f, 6.9765625f, -4.7685423f, 6.9882812f, -4.8835435f));
assertTrue(Ellipse2f.intersectsEllipseLine(
6f, -5f, 1f, 2f, 6.9882812f, -4.8835435f, 7f, -5f));
+
+ assertTrue(Ellipse2f.intersectsEllipseLine(
+ 0f, 0f, 1f, 2f, .5f, -1f, .5f, 2f));
+ assertTrue(Ellipse2f.intersectsEllipseLine(
+ 0f, 0f, 1f, 2f, .5f, -1f, .5f, -.5f));
}
/**
@@ -517,6 +522,11 @@
6f, -5f, 1f, 2f, 6.9765625f, -4.7685423f, 6.9882812f, -4.8835435f));
assertFalse(Ellipse2f.intersectsEllipseSegment(
6f, -5f, 1f, 2f, 6.9882812f, -4.8835435f, 7f, -5f));
+
+ assertTrue(Ellipse2f.intersectsEllipseSegment(
+ 0f, 0f, 1f, 2f, .5f, -1f, .5f, 2f));
+ assertFalse(Ellipse2f.intersectsEllipseSegment(
+ 0f, 0f, 1f, 2f, .5f, -1f, .5f, -.5f));
}
}
\ No newline at end of file
Added: trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/OpenPath2fTest.java
===================================================================
--- trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/OpenPath2fTest.java (rev 0)
+++ trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/OpenPath2fTest.java 2013-04-05 21:45:07 UTC (rev 414)
@@ -0,0 +1,746 @@
+/*
+ * $Id$
+ *
+ * Copyright (c) 2006-10, Multiagent Team, Laboratoire Systemes et Transports, Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2012 Stephane GALLAND.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.math.continous.object2d;
+
+import org.arakhne.afc.math.generic.PathElementType;
+import org.arakhne.afc.math.generic.Point2D;
+import org.arakhne.afc.math.matrix.Transform2D;
+
+/**
+ * @author $Author: galland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class OpenPath2fTest extends AbstractPath2fTestCase {
+
+ @Override
+ protected Path2f createShape() {
+ Path2f p = new Path2f();
+ p.moveTo(1f, 1f);
+ p.lineTo(2f, 2f);
+ p.quadTo(3f, 0f, 4f, 3f);
+ p.curveTo(5f, -1f, 6f, 5f, 7f, -5f);
+ return p;
+ }
+
+ /**
+ */
+ @Override
+ public void testGetClosestPointTo() {
+ Point2D p;
+
+ p = this.r.getClosestPointTo(new Point2f(0f, 0f));
+ assertEpsilonEquals(1f, p.getX());
+ assertEpsilonEquals(1f, p.getY());
+
+ p = this.r.getClosestPointTo(new Point2f(4f, 0f));
+ assertEpsilonEquals(3f, p.getX());
+ assertEpsilonEquals(1.25f, p.getY());
+
+ p = this.r.getClosestPointTo(new Point2f(4f, 2f));
+ assertEpsilonEquals(4.28125f, p.getX());
+ assertEpsilonEquals(2.11724f, p.getY());
+
+ p = this.r.getClosestPointTo(new Point2f(1f, 0f));
+ assertEpsilonEquals(1f, p.getX());
+ assertEpsilonEquals(1f, p.getY());
+ }
+
+
+ @Override
+ public void testDistancePoint2D() {
+ assertEpsilonEquals(1.414213562f, this.r.distance(new Point2f(0f, 0f)));
+ assertEpsilonEquals(1.600781059f, this.r.distance(new Point2f(4f, 0f)));
+ assertEpsilonEquals(0.304707696f, this.r.distance(new Point2f(4f, 2f)));
+ assertEpsilonEquals(1f, this.r.distance(new Point2f(1f, 0f)));
+ }
+
+ @Override
+ public void testDistanceSquaredPoint2D() {
+ assertEpsilonEquals(2f, this.r.distanceSquared(new Point2f(0f, 0f)));
+ assertEpsilonEquals(2.5625f, this.r.distanceSquared(new Point2f(4f, 0f)));
+ assertEpsilonEquals(.09284678f, this.r.distanceSquared(new Point2f(4f, 2f)));
+ assertEpsilonEquals(1f, this.r.distanceSquared(new Point2f(1f, 0f)));
+ }
+
+ @Override
+ public void testDistanceL1Point2D() {
+ // (1,1)
+ assertEpsilonEquals(2f, this.r.distanceL1(new Point2f(0f, 0f)));
+ // (3,1.25)
+ assertEpsilonEquals(2.25f, this.r.distanceL1(new Point2f(4f, 0f)));
+ // (4.28125,2.11724)
+ assertEpsilonEquals(.39849f, this.r.distanceL1(new Point2f(4f, 2f)));
+ // (1,1)
+ assertEpsilonEquals(1f, this.r.distanceL1(new Point2f(1f, 0f)));
+ }
+
+ @Override
+ public void testDistanceLinfPoint2D() {
+ // (1,1)
+ assertEpsilonEquals(1f, this.r.distanceLinf(new Point2f(0f, 0f)));
+ // (3,1.25)
+ assertEpsilonEquals(1.25f, this.r.distanceLinf(new Point2f(4f, 0f)));
+ // (4.28125,2.11724)
+ assertEpsilonEquals(.28125f, this.r.distanceLinf(new Point2f(4f, 2f)));
+ // (1,1)
+ assertEpsilonEquals(1f, this.r.distanceLinf(new Point2f(1f, 0f)));
+ }
+
+ @Override
+ public void testTranslateFloatFloat() {
+ this.r.translate(3.4f, 4.5f);
+ PathIterator2f pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 4.4f, 5.5f);
+ assertElement(pi, PathElementType.LINE_TO, 5.4f, 6.5f);
+ assertElement(pi, PathElementType.QUAD_TO, 6.4f, 4.5f, 7.4f, 7.5f);
+ assertElement(pi, PathElementType.CURVE_TO, 8.4f, 3.5f, 9.4f, 9.5f, 10.4f, -.5f);
+ assertNoElement(pi);
+ }
+
+ /**
+ */
+ @Override
+ public void testAddIterator() {
+ Path2f p2 = new Path2f();
+ p2.moveTo(3.4f, 4.5f);
+ p2.lineTo(5.6f, 6.7f);
+
+ this.r.add(p2.getPathIterator());
+
+ PathIterator2f pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertElement(pi, PathElementType.LINE_TO, 2f, 2f);
+ assertElement(pi, PathElementType.QUAD_TO, 3f, 0f, 4f, 3f);
+ assertElement(pi, PathElementType.CURVE_TO, 5f, -1f, 6f, 5f, 7f, -5f);
+ assertElement(pi, PathElementType.MOVE_TO, 3.4f, 4.5f);
+ assertElement(pi, PathElementType.LINE_TO, 5.6f, 6.7f);
+ assertNoElement(pi);
+ }
+
+ /**
+ */
+ @Override
+ public void testGetPathIteratorVoid() {
+ PathIterator2f pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertElement(pi, PathElementType.LINE_TO, 2f, 2f);
+ assertElement(pi, PathElementType.QUAD_TO, 3f, 0f, 4f, 3f);
+ assertElement(pi, PathElementType.CURVE_TO, 5f, -1f, 6f, 5f, 7f, -5f);
+ assertNoElement(pi);
+ }
+
+ /**
+ */
+ @Override
+ public void testGetPathIteratorTransform2D() {
+ Transform2D tr;
+ PathIterator2f pi;
+
+ tr = new Transform2D();
+ pi = this.r.getPathIterator(tr);
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertElement(pi, PathElementType.LINE_TO, 2f, 2f);
+ assertElement(pi, PathElementType.QUAD_TO, 3f, 0f, 4f, 3f);
+ assertElement(pi, PathElementType.CURVE_TO, 5f, -1f, 6f, 5f, 7f, -5f);
+ assertNoElement(pi);
+
+ tr = new Transform2D();
+ tr.makeTranslationMatrix(3.4f, 4.5f);
+ pi = this.r.getPathIterator(tr);
+ assertElement(pi, PathElementType.MOVE_TO, 4.4f, 5.5f);
+ assertElement(pi, PathElementType.LINE_TO, 5.4f, 6.5f);
+ assertElement(pi, PathElementType.QUAD_TO, 6.4f, 4.5f, 7.4f, 7.5f);
+ assertElement(pi, PathElementType.CURVE_TO, 8.4f, 3.5f, 9.4f, 9.5f, 10.4f, -.5f);
+ assertNoElement(pi);
+ }
+
+ /**
+ */
+ @Override
+ public void testTransformTransform2D() {
+ Transform2D tr = new Transform2D();
+ tr.makeTranslationMatrix(3.4f, 4.5f);
+ Transform2D tr2 = new Transform2D();
+ tr2.makeRotationMatrix(5.6f);
+
+ Path2f clone = this.r.clone();
+ clone.transform(tr);
+
+ PathIterator2f pi = clone.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 4.4f, 5.5f);
+ assertElement(pi, PathElementType.LINE_TO, 5.4f, 6.5f);
+ assertElement(pi, PathElementType.QUAD_TO, 6.4f, 4.5f, 7.4f, 7.5f);
+ assertElement(pi, PathElementType.CURVE_TO, 8.4f, 3.5f, 9.4f, 9.5f, 10.4f, -.5f);
+ assertNoElement(pi);
+
+ clone = this.r.clone();
+ clone.transform(tr2);
+
+ pi = clone.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1.406832516382571f, 0.144299240637928f);
+ assertElement(pi, PathElementType.LINE_TO, 2.813665032765142f, 0.288598481275856f);
+ assertElement(pi, PathElementType.QUAD_TO, 2.32669763553075f, -1.89379991361696f,
+ 4.996063427657964f, -0.198368915958538f);
+ assertElement(pi, PathElementType.CURVE_TO, 3.24656275467893f, -3.93189906787186f,
+ 7.8097284604231056f, 0.0902295653173185f,
+ 2.27262796021014f, -8.29669585765750f);
+ assertNoElement(pi);
+
+ Transform2D tr3 = new Transform2D();
+ tr3.mul(tr, tr2);
+ clone = this.r.clone();
+ clone.transform(tr3);
+
+ pi = clone.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 4.80683251638257f, 4.64429924063793f);
+ assertElement(pi, PathElementType.LINE_TO, 6.21366503276514f, 4.78859848127586f);
+ assertElement(pi, PathElementType.QUAD_TO, 5.72669763553075f, 2.60620008638304f,
+ 8.39606342765796f, 4.30163108404146f);
+ assertElement(pi, PathElementType.CURVE_TO, 6.646562754678927f, 0.568100932128142f,
+ 11.20972846042311f, 4.59022956531732f, 5.67262796021014f, -3.79669585765750f);
+ assertNoElement(pi);
+ }
+
+ /**
+ */
+ @Override
+ public void testCreateTransformedShape2D() {
+ Transform2D tr = new Transform2D();
+ tr.makeTranslationMatrix(3.4f, 4.5f);
+ Path2f p2 = (Path2f)this.r.createTransformedShape(tr);
+
+ PathIterator2f pi = p2.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 4.4f, 5.5f);
+ assertElement(pi, PathElementType.LINE_TO, 5.4f, 6.5f);
+ assertElement(pi, PathElementType.QUAD_TO, 6.4f, 4.5f, 7.4f, 7.5f);
+ assertElement(pi, PathElementType.CURVE_TO, 8.4f, 3.5f, 9.4f, 9.5f, 10.4f, -.5f);
+ assertNoElement(pi);
+ }
+
+/* private static int toX(float x) {
+ return (int)(x * 100) + 20;
+ }
+
+ private static int toY(float y) {
+ return (int)(1000 - ((y * 100) + 600));
+ }
+
+ private static int toS(float s) {
+ return (int)(s * 100);
+ }
+
+ public void testImageGeneration() throws IOException {
+ PathIterator2f pi;
+ BufferedImage img = new BufferedImage(800, 1000, BufferedImage.TYPE_INT_ARGB);
+ Graphics2D g = (Graphics2D)img.getGraphics();
+ //Background
+ g.setColor(Color.WHITE);
+ g.fillRect(0, 0, 800, 1000);
+
+ //
+ // POINTS
+ Point2f[] points = new Point2f[] {
+ // new Point2f(0f, 0f),
+ // new Point2f(4f, 3f),
+ // new Point2f(2f, 2f),
+ // new Point2f(2f, 1f),
+ // new Point2f(5f, 0f),
+ // new Point2f(-1f, -1f),
+ // new Point2f(5f, 2f),
+ // new Point2f(3.5f, -2.5f),
+ // new Point2f(7f, -4f),
+ // new Point2f(2.5f, 1.5f),
+ };
+
+ //
+ // LINES
+ Segment2f[] lines = new Segment2f[] {
+ //new Segment2f(6.7773438f, -3.0272121f, 6.7890625f, -3.1188917f),
+ //new Segment2f(6.7890625f, -3.1188917f, 6.8007812f, -3.2118688f),
+ //new Segment2f(6.8007812f, -3.2118688f, 6.8125f, -3.3061523f),
+ //new Segment2f(6.9414062f, -4.4321795f, 6.953125f, -4.5428696f),
+ //new Segment2f(.5f, -1f, .5f, 2f),
+ };
+
+ //
+ // SEGMENTS
+ Segment2f[] segments = new Segment2f[] {
+ // new Segment2f(0f, 0f, 1f, 1f),
+ // new Segment2f(4f, 3f, 1f, 1f),
+ // new Segment2f(2f, 2f, 1f, 1f),
+ // new Segment2f(2f, 1f, 1f, 1f),
+ // new Segment2f(3f, 0f, 1f, 1f),
+ // new Segment2f(3f, 0f, 1.5f, 1f),
+ // new Segment2f(-1f, -1f, 1f, 1f),
+ // new Segment2f(4f, -3f, 1f, 1f),
+ // new Segment2f(4f, -3f, 1f, 0f),
+ // new Segment2f(-3f, 4f, 1f, 1f),
+ // new Segment2f(6f, -5f, 1f, 1f),
+ // new Segment2f(6f, -5f, 1f, 0f),
+ // new Segment2f(4f, 0f, 1f, 1f),
+ // new Segment2f(5f, 0f, 1f, 1f),
+ // new Segment2f(.01f, .01f, 1f, 1f),
+ };
+
+ //
+ // CIRCLES
+ Circle2f[] circles = new Circle2f[] {
+ // new Circle2f(0f, 0f, 1f),
+ // new Circle2f(4f, 3f, 1f),
+ // new Circle2f(2f, 2f, 1f),
+ // new Circle2f(2f, 1f, 1f),
+ // new Circle2f(3f, 0f, 1f),
+ // new Circle2f(-1f, -1f, 1f),
+ // new Circle2f(4f, -3f, 1f),
+ // new Circle2f(-3f, 4f, 1f),
+ // new Circle2f(6f, -5f, 1f),
+ // new Circle2f(6f, -5f, .95f),
+ // new Circle2f(4f, 0f, 1f),
+ // new Circle2f(5f, 0f, 1f),
+ // new Circle2f(.01f, .01f, 1f),
+ // new Circle2f(6f, 2f, .8f),
+ };
+
+ //
+ // RECTANGLES
+ Rectangle2f[] rectangles = new Rectangle2f[] {
+ new Rectangle2f(0f, 0f, 1f, 1f),
+ new Rectangle2f(4f, 3f, 1f, 1f),
+ new Rectangle2f(2f, 2f, 1f, 1f),
+ new Rectangle2f(2f, 1f, 1f, 1f),
+ new Rectangle2f(3f, 0f, 1f, 1f),
+ new Rectangle2f(-1f, -1f, 1f, 1f),
+ new Rectangle2f(4f, -3f, 1f, 1f),
+ new Rectangle2f(-3f, 4f, 1f, 1f),
+ new Rectangle2f(6f, -5f, 1f, 1f),
+ new Rectangle2f(4f, 0f, 1f, 1f),
+ new Rectangle2f(5f, 0f, 1f, 1f),
+ new Rectangle2f(.01f, .01f, 1f, 1f),
+ };
+
+ //
+ // ELLIPSES
+ Ellipse2f[] ellipses = new Ellipse2f[] {
+ // new Ellipse2f(0f, 0f, 1f, 2f),
+ // new Ellipse2f(4f, 3f, 1f, 2f),
+ // new Ellipse2f(2f, 2f, 1f, 2f),
+ // new Ellipse2f(2f, 1f, 1f, 2f),
+ // new Ellipse2f(3f, 0f, 1f, 2f),
+ // new Ellipse2f(-1f, -1f, 1f, 2f),
+ // new Ellipse2f(4f, -3f, 1f, 2f),
+ // new Ellipse2f(-3f, 4f, 1f, 2f),
+ // new Ellipse2f(6f, -5f, 1f, 2f),
+ // new Ellipse2f(6f, -5f, .8f, 2f),
+ // new Ellipse2f(4f, 0f, 1f, 2f),
+ // new Ellipse2f(6f, 0f, 1f, 2f),
+ };
+
+ // Elements
+ g.setColor(Color.ORANGE);
+ for(Point2f obj : points) {
+ g.fillRect(
+ toX(obj.getX()) - 4, toY(obj.getY()) - 4,
+ 9, 9);
+ }
+ Stroke oldStroke = g.getStroke();
+ for(Segment2f obj : lines) {
+ int xx1 = toX(obj.getX1());
+ int yy1 = toY(obj.getY1());
+ int xx2 = toX(obj.getX2());
+ int yy2 = toY(obj.getY2());
+
+ g.setStroke(new BasicStroke(2));
+ Vector2f v = new Vector2f(xx2 - xx1, yy2 - yy1);
+ v.normalize();
+ v.scale(1000);
+ int px1 = (int)(xx1 + v.x);
+ int py1 = (int)(yy1 + v.y);
+ int px2 = (int)(xx1 - v.x);
+ int py2 = (int)(yy1 - v.y);
+ g.drawLine(px1, py1, px2, py2);
+
+ g.setStroke(new BasicStroke(4));
+ g.drawLine(xx1, yy1, xx2, yy2);
+ }
+ g.setStroke(new BasicStroke(3));
+ for(Segment2f obj : segments) {
+ g.drawLine(
+ toX(obj.getX1()), toY(obj.getY1()),
+ toX(obj.getX2()), toY(obj.getY2()));
+ }
+ g.setStroke(oldStroke);
+ for(Circle2f obj : circles) {
+ int r = toS(obj.getRadius());
+ g.drawOval(
+ toX(obj.getX())-r, toY(obj.getY())-r,
+ r*2, r*2);
+ }
+ for(Ellipse2f obj : ellipses) {
+ int x1 = toX(obj.getMinX());
+ int y1 = toY(obj.getMinY());
+ int x2 = toX(obj.getMaxX());
+ int y2 = toY(obj.getMaxY());
+ g.drawOval(
+ Math.min(x1, x2), Math.min(y1, y2),
+ toS(obj.getWidth()), toS(obj.getHeight()));
+ }
+ for(Rectangle2f obj : rectangles) {
+ int x1 = toX(obj.getMinX());
+ int y1 = toY(obj.getMinY());
+ int x2 = toX(obj.getMaxX());
+ int y2 = toY(obj.getMaxY());
+ g.fillRect(
+ Math.min(x1, x2), Math.min(y1, y2),
+ toS(obj.getWidth()), toS(obj.getHeight()));
+ }
+
+ // Cells
+ g.setColor(Color.LIGHT_GRAY);
+ for(float y=-6; y<=4; y+=1) {
+ if (y!=0f) g.drawLine(toX(-10), toY(y), toX(10), toY(y));
+ }
+ for(float x=-1; x<=8; x+=1) {
+ if (x!=0f) g.drawLine(toX(x), toY(-10), toX(x), toY(10));
+ }
+ g.setColor(Color.BLACK);
+ g.drawLine(toX(-10), toY(0), toX(10), toY(0));
+ g.drawLine(toX(0), toY(-10), toX(0), toY(10));
+
+ // Path
+ g.setColor(Color.RED);
+ pi = this.r.getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO);
+ boolean closed = false;
+ int mx, my, cx, cy;
+ mx = my = cx = cy = 0;
+ while (pi.hasNext()) {
+ PathElement2f pe = pi.next();
+ switch(pe.type) {
+ case MOVE_TO:
+ cx = mx = toX(pe.toX);
+ cy = my = toY(pe.toY);
+ break;
+ case LINE_TO:
+ cx = toX(pe.toX);
+ cy = toY(pe.toY);
+ g.drawLine(
+ toX(pe.fromX), toY(pe.fromY),
+ cx, cy);
+ break;
+ case CLOSE:
+ cx = toX(pe.toX);
+ cy = toY(pe.toY);
+ g.drawLine(
+ toX(pe.fromX), toY(pe.fromY),
+ cx, cy);
+ closed = true;
+ break;
+ default:
+ }
+ }
+ if (!closed) {
+ g.setStroke(new BasicStroke(
+ 1,
+ BasicStroke.CAP_ROUND,
+ BasicStroke.JOIN_ROUND,
+ 2,
+ new float[]{5,5},
+ 0f));
+ g.drawLine(
+ mx, my,
+ cx, cy);
+ }
+ g.dispose();
+ ImageIO.write(img, "png", new File(FileSystem.getUserHomeDirectory(), "mytest.png"));
+ }*/
+
+ /**
+ */
+ @Override
+ public void testContainsPathIterator2fFloatFloat() {
+ assertFalse(Path2f.contains(this.r.getPathIterator(), 0f, 0f));
+ assertTrue(Path2f.contains(this.r.getPathIterator(), 4f, 3f));
+ assertTrue(Path2f.contains(this.r.getPathIterator(), 2f, 2f));
+ assertFalse(Path2f.contains(this.r.getPathIterator(), 2f, 1f));
+ assertFalse(Path2f.contains(this.r.getPathIterator(), 5f, 0f));
+ assertFalse(Path2f.contains(this.r.getPathIterator(), -1f, -1f));
+ }
+
+ /**
+ */
+ @Override
+ public void testContainsFloatfloat() {
+ assertFalse(this.r.contains(0f, 0f));
+ assertTrue(this.r.contains(4f, 3f));
+ assertTrue(this.r.contains(2f, 2f));
+ assertFalse(this.r.contains(2f, 1f));
+ assertFalse(this.r.contains(5f, 0f));
+ assertFalse(this.r.contains(-1f, -1f));
+ assertFalse(this.r.contains(5f, 2f));
+ assertFalse(this.r.contains(3.5f, -2.5f));
+ assertFalse(this.r.contains(7f, -4f));
+ assertFalse(this.r.contains(2.5f, 1.5f));
+ }
+
+ /**
+ */
+ @Override
+ public void testContainsRectangle2f() {
+ assertFalse(this.r.contains(new Rectangle2f(0f, 0f, 1f, 1f)));
+ assertFalse(this.r.contains(new Rectangle2f(4f, 3f, 1f, 1f)));
+ assertFalse(this.r.contains(new Rectangle2f(2f, 2f, 1f, 1f)));
+ assertFalse(this.r.contains(new Rectangle2f(2f, 1f, 1f, 1f)));
+ assertFalse(this.r.contains(new Rectangle2f(3f, 0f, 1f, 1f)));
+ assertFalse(this.r.contains(new Rectangle2f(-1f, -1f, 1f, 1f)));
+ assertFalse(this.r.contains(new Rectangle2f(4f, -3f, 1f, 1f)));
+ assertFalse(this.r.contains(new Rectangle2f(-3f, 4f, 1f, 1f)));
+ assertFalse(this.r.contains(new Rectangle2f(6f, -5f, 1f, 1f)));
+ assertFalse(this.r.contains(new Rectangle2f(4f, 0f, 1f, 1f)));
+ assertFalse(this.r.contains(new Rectangle2f(5f, 0f, 1f, 1f)));
+ assertFalse(this.r.contains(new Rectangle2f(.01f, .01f, 1f, 1f)));
+ }
+
+ /**
+ */
+ @Override
+ public void testIntersectsRectangle2f() {
+ assertFalse(this.r.intersects(new Rectangle2f(0f, 0f, 1f, 1f)));
+ assertFalse(this.r.intersects(new Rectangle2f(4f, 3f, 1f, 1f)));
+ assertFalse(this.r.intersects(new Rectangle2f(2f, 2f, 1f, 1f)));
+ assertTrue(this.r.intersects(new Rectangle2f(2f, 1f, 1f, 1f)));
+ assertFalse(this.r.intersects(new Rectangle2f(3f, 0f, 1f, 1f)));
+ assertFalse(this.r.intersects(new Rectangle2f(-1f, -1f, 1f, 1f)));
+ assertFalse(this.r.intersects(new Rectangle2f(4f, -3f, 1f, 1f)));
+ assertFalse(this.r.intersects(new Rectangle2f(-3f, 4f, 1f, 1f)));
+ assertTrue(this.r.intersects(new Rectangle2f(6f, -5f, 1f, 1f)));
+ assertFalse(this.r.intersects(new Rectangle2f(4f, 0f, 1f, 1f)));
+ assertTrue(this.r.intersects(new Rectangle2f(5f, 0f, 1f, 1f)));
+ assertTrue(this.r.intersects(new Rectangle2f(.01f, .01f, 1f, 1f)));
+ }
+
+ @Override
+ public void testIntersectsPathIterator2fFloatFloatFloatFloat() {
+ assertFalse(Path2f.intersects(this.r.getPathIterator(), 0f, 0f, 1f, 1f));
+ assertFalse(Path2f.intersects(this.r.getPathIterator(), 4f, 3f, 1f, 1f));
+ assertFalse(Path2f.intersects(this.r.getPathIterator(), 2f, 2f, 1f, 1f));
+ assertTrue(Path2f.intersects(this.r.getPathIterator(), 2f, 1f, 1f, 1f));
+ assertFalse(Path2f.intersects(this.r.getPathIterator(), 3f, 0f, 1f, 1f));
+ assertFalse(Path2f.intersects(this.r.getPathIterator(), -1f, -1f, 1f, 1f));
+ assertFalse(Path2f.intersects(this.r.getPathIterator(), 4f, -3f, 1f, 1f));
+ assertFalse(Path2f.intersects(this.r.getPathIterator(), -3f, 4f, 1f, 1f));
+ assertTrue(Path2f.intersects(this.r.getPathIterator(), 6f, -5f, 1f, 1f));
+ assertFalse(Path2f.intersects(this.r.getPathIterator(), 4f, 0f, 1f, 1f));
+ assertTrue(Path2f.intersects(this.r.getPathIterator(), 5f, 0f, 1f, 1f));
+ assertTrue(Path2f.intersects(this.r.getPathIterator(), .01f, .01f, 1f, 1f));
+ }
+
+ /**
+ */
+ @Override
+ public void testIntersectsEllipse2f() {
+ assertFalse(this.r.intersects(new Ellipse2f(0f, 0f, 1f, 2f)));
+ assertFalse(this.r.intersects(new Ellipse2f(4f, 3f, 1f, 2f)));
+ assertFalse(this.r.intersects(new Ellipse2f(2f, 2f, 1f, 2f)));
+ assertTrue(this.r.intersects(new Ellipse2f(2f, 1f, 1f, 2f)));
+ assertTrue(this.r.intersects(new Ellipse2f(3f, 0f, 1f, 2f)));
+ assertFalse(this.r.intersects(new Ellipse2f(-1f, -1f, 1f, 2f)));
+ assertFalse(this.r.intersects(new Ellipse2f(4f, -3f, 1f, 2f)));
+ assertFalse(this.r.intersects(new Ellipse2f(-3f, 4f, 1f, 2f)));
+ assertTrue(this.r.intersects(new Ellipse2f(6f, -5f, 1f, 2f)));
+ assertFalse(this.r.intersects(new Ellipse2f(6f, -5f, .8f, 2f)));
+ assertTrue(this.r.intersects(new Ellipse2f(4f, 0f, 1f, 2f)));
+ assertFalse(this.r.intersects(new Ellipse2f(6f, 0f, 1f, 2f)));
+ }
+
+ /**
+ */
+ @Override
+ public void testIntersectsCircle2f() {
+ assertFalse(this.r.intersects(new Circle2f(0f, 0f, 1f)));
+ assertTrue(this.r.intersects(new Circle2f(4f, 3f, 1f)));
+ assertTrue(this.r.intersects(new Circle2f(2f, 2f, 1f)));
+ assertTrue(this.r.intersects(new Circle2f(2f, 1f, 1f)));
+ assertFalse(this.r.intersects(new Circle2f(3f, 0f, 1f)));
+ assertFalse(this.r.intersects(new Circle2f(-1f, -1f, 1f)));
+ assertFalse(this.r.intersects(new Circle2f(4f, -3f, 1f)));
+ assertFalse(this.r.intersects(new Circle2f(-3f, 4f, 1f)));
+ assertTrue(this.r.intersects(new Circle2f(6f, -5f, 1f)));
+ assertFalse(this.r.intersects(new Circle2f(6f, -5f, .95f)));
+ assertFalse(this.r.intersects(new Circle2f(4f, 0f, 1f)));
+ assertFalse(this.r.intersects(new Circle2f(5f, 0f, 1f)));
+ assertFalse(this.r.intersects(new Circle2f(.01f, .01f, 1f)));
+ assertFalse(this.r.intersects(new Circle2f(6f, 2f, .8f)));
+ }
+
+ /**
+ */
+ @Override
+ public void testIntersectsSegment2f() {
+ assertFalse(this.r.intersects(new Segment2f(0f, 0f, 1f, 1f)));
+ assertTrue(this.r.intersects(new Segment2f(4f, 3f, 1f, 1f)));
+ assertTrue(this.r.intersects(new Segment2f(2f, 2f, 1f, 1f)));
+ assertFalse(this.r.intersects(new Segment2f(2f, 1f, 1f, 1f)));
+ assertFalse(this.r.intersects(new Segment2f(3f, 0f, 1f, 1f)));
+ assertFalse(this.r.intersects(new Segment2f(3f, 0f, 1.5f, 1f)));
+ assertFalse(this.r.intersects(new Segment2f(-1f, -1f, 1f, 1f)));
+ assertFalse(this.r.intersects(new Segment2f(4f, -3f, 1f, 1f)));
+ assertFalse(this.r.intersects(new Segment2f(4f, -3f, 1f, 0f)));
+ assertFalse(this.r.intersects(new Segment2f(-3f, 4f, 1f, 1f)));
+ assertFalse(this.r.intersects(new Segment2f(6f, -5f, 1f, 1f)));
+ assertFalse(this.r.intersects(new Segment2f(6f, -5f, 1f, 0f)));
+ assertFalse(this.r.intersects(new Segment2f(4f, 0f, 1f, 1f)));
+ assertFalse(this.r.intersects(new Segment2f(5f, 0f, 1f, 1f)));
+ assertFalse(this.r.intersects(new Segment2f(.01f, .01f, 1f, 1f)));
+ }
+
+ @Override
+ public void testToBoundingBox() {
+ Rectangle2f bb = this.r.toBoundingBox();
+ assertEpsilonEquals(1f, bb.getMinX());
+ assertEpsilonEquals(-5f, bb.getMinY());
+ assertEpsilonEquals(7f, bb.getMaxX());
+ assertEpsilonEquals(5f, bb.getMaxY());
+ }
+
+ /**
+ */
+ @Override
+ public void testRemoveLast() {
+ PathIterator2f pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertElement(pi, PathElementType.LINE_TO, 2f, 2f);
+ assertElement(pi, PathElementType.QUAD_TO, 3f, 0f, 4f, 3f);
+ assertElement(pi, PathElementType.CURVE_TO, 5f, -1f, 6f, 5f, 7f, -5f);
+ assertNoElement(pi);
+
+ this.r.removeLast();
+
+ pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertElement(pi, PathElementType.LINE_TO, 2f, 2f);
+ assertElement(pi, PathElementType.QUAD_TO, 3f, 0f, 4f, 3f);
+ assertNoElement(pi);
+
+ this.r.removeLast();
+
+ pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertElement(pi, PathElementType.LINE_TO, 2f, 2f);
+ assertNoElement(pi);
+
+ this.r.removeLast();
+
+ pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertNoElement(pi);
+
+ this.r.removeLast();
+
+ pi = this.r.getPathIterator();
+ assertNoElement(pi);
+
+ this.r.removeLast();
+
+ pi = this.r.getPathIterator();
+ assertNoElement(pi);
+ }
+
+ /**
+ */
+ @Override
+ public void testSetLastPointFloatFloat() {
+ PathIterator2f pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertElement(pi, PathElementType.LINE_TO, 2f, 2f);
+ assertElement(pi, PathElementType.QUAD_TO, 3f, 0f, 4f, 3f);
+ assertElement(pi, PathElementType.CURVE_TO, 5f, -1f, 6f, 5f, 7f, -5f);
+ assertNoElement(pi);
+
+ this.r.setLastPoint(123.456f, 789.1011f);
+
+ pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertElement(pi, PathElementType.LINE_TO, 2f, 2f);
+ assertElement(pi, PathElementType.QUAD_TO, 3f, 0f, 4f, 3f);
+ assertElement(pi, PathElementType.CURVE_TO, 5f, -1f, 6f, 5f, 123.456f, 789.1011f);
+ assertNoElement(pi);
+ }
+
+ /**
+ */
+ @Override
+ public void testRemoveFloatFloat() {
+ PathIterator2f pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertElement(pi, PathElementType.LINE_TO, 2f, 2f);
+ assertElement(pi, PathElementType.QUAD_TO, 3f, 0f, 4f, 3f);
+ assertElement(pi, PathElementType.CURVE_TO, 5f, -1f, 6f, 5f, 7f, -5f);
+ assertNoElement(pi);
+
+ this.r.remove(2f, 2f);
+
+ pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertElement(pi, PathElementType.QUAD_TO, 3f, 0f, 4f, 3f);
+ assertElement(pi, PathElementType.CURVE_TO, 5f, -1f, 6f, 5f, 7f, -5f);
+ assertNoElement(pi);
+
+ this.r.remove(4f, 3f);
+
+ pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertElement(pi, PathElementType.CURVE_TO, 5f, -1f, 6f, 5f, 7f, -5f);
+ assertNoElement(pi);
+
+ this.r.remove(6f, 5f);
+
+ pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertNoElement(pi);
+
+ this.r.remove(6f, 5f);
+
+ pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertNoElement(pi);
+ }
+
+ /**
+ */
+ @Override
+ public void testContainsPointPoint2D() {
+ PathIterator2f pi = this.r.getPathIterator();
+ assertElement(pi, PathElementType.MOVE_TO, 1f, 1f);
+ assertElement(pi, PathElementType.LINE_TO, 2f, 2f);
+ assertElement(pi, PathElementType.QUAD_TO, 3f, 0f, 4f, 3f);
+ assertElement(pi, PathElementType.CURVE_TO, 5f, -1f, 6f, 5f, 7f, -5f);
+ assertNoElement(pi);
+
+ assertTrue(this.r.containsPoint(new Point2f(2f, 2f)));
+ assertFalse(this.r.containsPoint(new Point2f(4f, 4f)));
+ assertTrue(this.r.containsPoint(new Point2f(6f, 5f)));
+ assertFalse(this.r.containsPoint(new Point2f(-1f, 6f)));
+ assertFalse(this.r.containsPoint(new Point2f(1234f, 5678f)));
+ }
+
+}
\ No newline at end of file
Modified: trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/Segment2fTest.java
===================================================================
--- trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/Segment2fTest.java 2013-04-05 20:39:57 UTC (rev 413)
+++ trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/Segment2fTest.java 2013-04-05 21:45:07 UTC (rev 414)
@@ -336,6 +336,30 @@
0,
7f, -5f, 1f, 1f,
4f, -3f, 1f, 1f));
+ assertEquals(
+ 1,
+ Segment2f.computeCrossingsFromSegment(
+ 0,
+ 4f, -3f, 1f, 1f,
+ 7f, -5f, 1f, 1f));
+ assertEquals(
+ 1,
+ Segment2f.computeCrossingsFromSegment(
+ 0,
+ 1f, 1f, 4f, -3f,
+ 7f, -5f, 1f, 1f));
+ assertEquals(
+ -1,
+ Segment2f.computeCrossingsFromSegment(
+ 0,
+ 4f, -3f, 1f, 1f,
+ 1f, 1f, 7f, -5f));
+ assertEquals(
+ -1,
+ Segment2f.computeCrossingsFromSegment(
+ 0,
+ 1f, 1f, 4f, -3f,
+ 1f, 1f, 7f, -5f));
}
/**