/*
* Copyright (C) 2011-2016, Peter Abeles. All Rights Reserved.
*
* This file is part of Geometric Regression Library (GeoRegression).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package georegression.metric;
import georegression.geometry.UtilEllipse_F32;
import georegression.geometry.UtilLine2D_F32;
import georegression.misc.GrlConstants;
import georegression.struct.line.LineGeneral2D_F32;
import georegression.struct.line.LineParametric2D_F32;
import georegression.struct.line.LineSegment2D_F32;
import georegression.struct.point.Point2D_F32;
import georegression.struct.point.Point3D_F32;
import georegression.struct.se.Se2_F32;
import georegression.struct.shapes.*;
import georegression.transform.se.SePointOps_F32;
import org.junit.Test;
import java.util.Random;
import static org.junit.Assert.*;
/**
* @author Peter Abeles
*/
public class TestIntersection2D_F32 {
Random rand = new Random( 234 );
@Test
public void containConvex() {
Polygon2D_F32 poly = new Polygon2D_F32(4);
poly.vertexes.data[0].set(-1,-1);
poly.vertexes.data[1].set(1, -1);
poly.vertexes.data[2].set(1, 1);
poly.vertexes.data[3].set(-1, 1);
Point2D_F32 online = new Point2D_F32(1,-1);
Point2D_F32 inside = new Point2D_F32(0.5f,0.5f);
Point2D_F32 outside = new Point2D_F32(1.5f,0.5f);
assertFalse(Intersection2D_F32.containConvex(poly,online));
assertTrue(Intersection2D_F32.containConvex(poly,inside));
assertFalse(Intersection2D_F32.containConvex(poly,outside));
// change the order of the vertexes
poly.flip();
assertFalse(Intersection2D_F32.containConvex(poly,online));
assertTrue(Intersection2D_F32.containConvex(poly,inside));
assertFalse(Intersection2D_F32.containConvex(poly,outside));
}
@Test
public void containConcave_rectangle() {
Polygon2D_F32 poly = new Polygon2D_F32(4);
poly.vertexes.data[0].set(-1,-1);
poly.vertexes.data[1].set(1, -1);
poly.vertexes.data[2].set(1, 1);
poly.vertexes.data[3].set(-1, 1);
assertTrue(Intersection2D_F32.containConcave(poly, new Point2D_F32(0, 0)));
// perimeter cases intentionally not handled here
assertFalse(Intersection2D_F32.containConcave(poly, new Point2D_F32(2, 0)));
assertFalse(Intersection2D_F32.containConcave(poly, new Point2D_F32(-2, 0)));
assertFalse(Intersection2D_F32.containConcave(poly, new Point2D_F32(0, 2)));
assertFalse(Intersection2D_F32.containConcave(poly, new Point2D_F32(0, -2)));
}
@Test
public void contains_quadrilateral() {
Quadrilateral_F32 quad = new Quadrilateral_F32();
quad.a.set(-1, -1);
quad.b.set(1, -1);
quad.c.set(1, 1);
quad.d.set(-1, 1);
assertTrue(Intersection2D_F32.contains(quad, new Point2D_F32(0, 0)));
// perimeter cases intentionally not handled here
assertFalse(Intersection2D_F32.contains(quad, new Point2D_F32(2, 0)));
assertFalse(Intersection2D_F32.contains(quad, new Point2D_F32(-2, 0)));
assertFalse(Intersection2D_F32.contains(quad, new Point2D_F32(0, 2)));
assertFalse(Intersection2D_F32.contains(quad, new Point2D_F32(0, -2)));
}
@Test
public void containTriangle() {
Point2D_F32 a = new Point2D_F32(1,2);
Point2D_F32 b = new Point2D_F32(4,2);
Point2D_F32 c = new Point2D_F32(4,5);
Point2D_F32 inside = new Point2D_F32(3,3);
Point2D_F32 outside = new Point2D_F32(-10,2);
assertTrue(Intersection2D_F32.containTriangle(a, b, c, inside));
assertFalse(Intersection2D_F32.containTriangle(a, b, c, outside));
}
@Test
public void containEllipseRotated() {
EllipseRotated_F32 ellipse = new EllipseRotated_F32(5,6,4,3, GrlConstants.F_PId2);
assertFalse(Intersection2D_F32.contains(ellipse,0,0));
assertTrue(Intersection2D_F32.contains(ellipse,5,6));
assertTrue(Intersection2D_F32.contains(ellipse,5,6+4 - GrlConstants.FLOAT_TEST_TOL));
assertTrue(Intersection2D_F32.contains(ellipse,5+3.0f - GrlConstants.FLOAT_TEST_TOL,6));
assertFalse(Intersection2D_F32.contains(ellipse,5,6+4.0f + GrlConstants.FLOAT_TEST_TOL));
assertFalse(Intersection2D_F32.contains(ellipse,5+3 + GrlConstants.FLOAT_TEST_TOL,6));
}
@Test
public void containConcave_concave() {
Polygon2D_F32 poly = new Polygon2D_F32(5);
poly.vertexes.data[0].set(-1,-1);
poly.vertexes.data[1].set( 0, 0);
poly.vertexes.data[2].set(1, -1);
poly.vertexes.data[3].set(1, 1);
poly.vertexes.data[4].set(-1, 1);
assertTrue(Intersection2D_F32.containConcave(poly, new Point2D_F32(0,0.5f)));
assertTrue(Intersection2D_F32.containConcave(poly, new Point2D_F32(-0.75f,-0.25f)));
assertTrue(Intersection2D_F32.containConcave(poly, new Point2D_F32(0.75f,-0.25f)));
assertFalse(Intersection2D_F32.containConcave(poly, new Point2D_F32(0,-0.5f)));
assertFalse(Intersection2D_F32.containConcave(poly, new Point2D_F32(2,0)));
assertFalse(Intersection2D_F32.containConcave(poly, new Point2D_F32(-2,0)));
assertFalse(Intersection2D_F32.containConcave(poly, new Point2D_F32(0, 2)));
assertFalse(Intersection2D_F32.containConcave(poly, new Point2D_F32(0, -2)));
}
@Test
public void intersection_ls_to_ls() {
// check positive, none pathological cases
checkIntersection(new LineSegment2D_F32(0, 2, 2, 2), new LineSegment2D_F32(2, 0, 2, 3), new Point2D_F32(2, 2));
checkIntersection(new LineSegment2D_F32(0, 2, 2, 0), new LineSegment2D_F32(0, 0, 2, 2), new Point2D_F32(1, 1));
// check boundary conditions
checkIntersection(new LineSegment2D_F32(0, 2, 2, 2), new LineSegment2D_F32(0, 0, 0, 2), new Point2D_F32(0, 2));
checkIntersection(new LineSegment2D_F32(0, 2, 2, 2), new LineSegment2D_F32(2, 0, 2, 2), new Point2D_F32(2, 2));
checkIntersection(new LineSegment2D_F32(1, 0, 1, 2), new LineSegment2D_F32(0, 0, 2, 0), new Point2D_F32(1, 0));
// check negative
checkIntersection(new LineSegment2D_F32(0, 2, 2, 2), new LineSegment2D_F32(0, 0, 0, 1.9f), null);
checkIntersection(new LineSegment2D_F32(0, 2, 2, 2), new LineSegment2D_F32(2, 0, 2, 1.9f), null);
checkIntersection(new LineSegment2D_F32(1, 0.1f, 1, 2), new LineSegment2D_F32(0, 0, 2, 0), null);
// check parallel closestPoint
checkIntersection(new LineSegment2D_F32(0, 2, 0, 5), new LineSegment2D_F32(0, 1, 0, 3), null);
}
public void checkIntersection( LineSegment2D_F32 a, LineSegment2D_F32 b, Point2D_F32 expected ) {
Point2D_F32 found = Intersection2D_F32.intersection( a, b, null );
if( found == null )
assertTrue( expected == null );
else {
assertEquals( found.getX(), expected.getX(), GrlConstants.FLOAT_TEST_TOL );
assertEquals( found.getY(), expected.getY(), GrlConstants.FLOAT_TEST_TOL );
}
}
/**
* Checks to see if the expected distance is returned and that the end points of the
* line segment are respected. The test cases are rotated around in a circle to test
* more geometric configurations
*/
@Test
public void intersection_p_to_ls() {
LineParametric2D_F32 paraLine = new LineParametric2D_F32();
LineSegment2D_F32 target = new LineSegment2D_F32( -1, 1, 1, 1 );
Se2_F32 tran = new Se2_F32();
// rotate it in a circle to check more geometric configurations
for( int i = 0; i < 20; i++ ) {
tran.setTranslation( (float)rand.nextGaussian(), (float)rand.nextGaussian() );
tran.setYaw( (float) ( 2 * (float)Math.PI * i / 20 ) );
checkIntersection_p_to_ls( paraLine, target, tran );
}
// check parallel overlapping lines
paraLine.setPoint(-1,1);
paraLine.setSlope(2,0);
assertTrue( Float.isNaN( Intersection2D_F32.intersection(paraLine,target) ) );
}
private void checkIntersection_p_to_ls( LineParametric2D_F32 paraLine,
LineSegment2D_F32 target,
Se2_F32 tran ) {
// create a copy so the original isn't modified
paraLine = paraLine.copy();
target = target.copy();
// apply the transform to the two lines
paraLine.setPoint( SePointOps_F32.transform( tran, paraLine.getPoint(), null ) );
target.setA( SePointOps_F32.transform( tran, target.getA(), null ) );
target.setB( SePointOps_F32.transform( tran, target.getB(), null ) );
// should hit it dead center
paraLine.setSlope( 0, 1 );
paraLine.setAngle( paraLine.getAngle() + tran.getYaw() );
float dist = Intersection2D_F32.intersection( paraLine, target );
assertEquals( 1, dist, GrlConstants.FLOAT_TEST_TOL );
// should hit dead center, but negative
paraLine.setSlope( 0, -1 );
paraLine.setAngle( paraLine.getAngle() + tran.getYaw() );
dist = Intersection2D_F32.intersection( paraLine, target );
assertEquals( -1, dist, GrlConstants.FLOAT_TEST_TOL );
// should miss it to the left
paraLine.setSlope( -1.1f, 1 );
paraLine.setAngle( paraLine.getAngle() + tran.getYaw() );
dist = Intersection2D_F32.intersection( paraLine, target );
assertTrue( Float.isNaN( dist ) );
// should miss it to the right
paraLine.setSlope( 1.1f, 1 );
paraLine.setAngle( paraLine.getAngle() + tran.getYaw() );
dist = Intersection2D_F32.intersection( paraLine, target );
assertTrue( Float.isNaN( dist ) );
}
@Test
public void intersection_l_to_l_parametric_pt() {
LineParametric2D_F32 a = new LineParametric2D_F32(2,3,1,0);
LineParametric2D_F32 b = new LineParametric2D_F32(-2,-4,0,1);
Point2D_F32 found = Intersection2D_F32.intersection(a,b,null);
assertEquals( -2, found.x, GrlConstants.FLOAT_TEST_TOL);
assertEquals(3, found.y, GrlConstants.FLOAT_TEST_TOL);
LineParametric2D_F32 c = new LineParametric2D_F32(-8,2,0,1);
assertTrue(null == Intersection2D_F32.intersection(b,c,null));
}
@Test
public void intersection_l_to_l_parametric_t() {
LineParametric2D_F32 a = new LineParametric2D_F32(2,3,1,0);
LineParametric2D_F32 b = new LineParametric2D_F32(-2,-4,0,1);
float t = Intersection2D_F32.intersection(a,b);
Point2D_F32 found = new Point2D_F32(2+t,3);
assertEquals( -2, found.x, GrlConstants.FLOAT_TEST_TOL);
assertEquals(3, found.y, GrlConstants.FLOAT_TEST_TOL);
LineParametric2D_F32 c = new LineParametric2D_F32(-8,2,0,1);
assertTrue(Float.isNaN(Intersection2D_F32.intersection(b, c)));
}
@Test
public void intersection_l_to_l_general_3D() {
// check two arbitrary lines
LineGeneral2D_F32 a = new LineGeneral2D_F32(1,2,3);
LineGeneral2D_F32 b = new LineGeneral2D_F32(2,-1,0.5f);
Point3D_F32 found = Intersection2D_F32.intersection(a,b,(Point3D_F32)null);
assertEquals(0,a.A*found.x/found.z+a.B*found.y/found.z+a.C, GrlConstants.FLOAT_TEST_TOL);
assertEquals(0,a.A*found.x+a.B*found.y+a.C*found.z, GrlConstants.FLOAT_TEST_TOL);
// give it two parallel lines
a = new LineGeneral2D_F32(1,2,3);
b = new LineGeneral2D_F32(1,2,0.5f);
Intersection2D_F32.intersection(a, b, found);
assertEquals(0,found.z,GrlConstants.FLOAT_TEST_TOL);
assertEquals(0, a.A * found.x + a.B * found.y + a.C * found.z, GrlConstants.FLOAT_TEST_TOL);
}
@Test
public void intersection_l_to_l_general_2D() {
// check two arbitrary lines
LineGeneral2D_F32 a = new LineGeneral2D_F32(1,2,3);
LineGeneral2D_F32 b = new LineGeneral2D_F32(2,-1,0.5f);
Point2D_F32 found = Intersection2D_F32.intersection(a,b,(Point2D_F32)null);
assertEquals(0,a.A*found.x+a.B*found.y+a.C, GrlConstants.FLOAT_TEST_TOL);
// give it two parallel lines
a = new LineGeneral2D_F32(1,2,3);
b = new LineGeneral2D_F32(1,2,0.5f);
assertTrue(null == Intersection2D_F32.intersection(a, b, found));
}
@Test
public void intersects_rect_corners() {
// check several positive cases
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(0,0,100,120),true);
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(10,12,99,119),true);
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(50,50,200,200),true);
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(-10,-10,10,10),true);
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(90,-10,105,1),true);
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(90,5,105,105),true);
// negative cases
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(200,200,300,305),false);
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(-200,-200,-10,-10),false);
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(0,-20,100,-5),false);
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(0,125,100,130),false);
// edge cases
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(0,0,0,0),false);
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(100,120,100,120),false);
check(new Rectangle2D_F32(0, 0, 100, 120), new Rectangle2D_F32(-10, 0, 0, 120), false);
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(100,0,105,120),false);
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(0,-10,100,0),false);
check(new Rectangle2D_F32(0, 0, 100, 120), new Rectangle2D_F32(0, 120, 100, 125), false);
}
private void check( Rectangle2D_F32 a , Rectangle2D_F32 b , boolean expected ) {
assertTrue(expected==Intersection2D_F32.intersects(a,b));
}
@Test
public void intersection_rect_corners() {
// check several positive cases
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(0,0,100,120),
new Rectangle2D_F32(0,0,100,120));
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(10,12,99,119),
new Rectangle2D_F32(10,12,99,119));
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(50,50,200,200),
new Rectangle2D_F32(50,50,100,120));
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(-10,-10,10,10),
new Rectangle2D_F32(0,0,10,10));
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(90,-10,105,1),
new Rectangle2D_F32(90,0,100,1));
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(90,5,105,105),
new Rectangle2D_F32(90,5,100,105));
// negative cases
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(200,200,300,305),null);
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(-200,-200,-10,-10),null);
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(0,-20,100,-5),null);
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(0,125,100,130),null);
// edge cases
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(0,0,0,0),null);
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(100,120,100,120),null);
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(-10,0,0,120),null);
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(100,0,105,120),null);
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(0,-10,100,0),null);
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(0,120,100,125),null);
}
private void check( Rectangle2D_F32 a , Rectangle2D_F32 b , Rectangle2D_F32 expected ) {
if( expected == null ) {
assertFalse(Intersection2D_F32.intersection(a, b, null));
return;
}
Rectangle2D_F32 found = new Rectangle2D_F32();
assertTrue(Intersection2D_F32.intersection(a, b, found));
assertEquals(expected.p0.x,found.p0.x,GrlConstants.FLOAT_TEST_TOL);
assertEquals(expected.p1.x,found.p1.x,GrlConstants.FLOAT_TEST_TOL);
assertEquals(expected.p0.y,found.p0.y,GrlConstants.FLOAT_TEST_TOL);
assertEquals(expected.p1.y,found.p1.y,GrlConstants.FLOAT_TEST_TOL);
}
@Test
public void contains_rectLength_pt() {
RectangleLength2D_F32 rect = new RectangleLength2D_F32(-10,-5,5,10);
assertTrue(Intersection2D_F32.contains(rect,-10,-5));
assertTrue(Intersection2D_F32.contains(rect,-6,4));
assertTrue(Intersection2D_F32.contains(rect,-9.9f,-4.99f));
assertTrue(Intersection2D_F32.contains(rect,-6.001f,4.99f));
assertTrue(Intersection2D_F32.contains(rect,-5.99f,4));
assertTrue(Intersection2D_F32.contains(rect, -10, 4.001f));
assertFalse(Intersection2D_F32.contains(rect, -11, -5));
assertFalse(Intersection2D_F32.contains(rect, -10, -6));
assertFalse(Intersection2D_F32.contains(rect, -5, 4));
assertFalse(Intersection2D_F32.contains(rect, -6, 5));
}
@Test
public void contains2_rectLength_pt() {
RectangleLength2D_F32 rect = new RectangleLength2D_F32(-10,-5,5,10);
assertTrue(Intersection2D_F32.contains2(rect, -10, -5));
assertTrue(Intersection2D_F32.contains2(rect, -6, 4));
assertTrue(Intersection2D_F32.contains2(rect, -9.9f, -4.99f));
assertTrue(Intersection2D_F32.contains2(rect, -6.001f, 4.99f));
assertTrue(Intersection2D_F32.contains2(rect, -5.99f, 4));
assertTrue(Intersection2D_F32.contains2(rect, -10, 4.001f));
assertFalse(Intersection2D_F32.contains2(rect, -11, -5));
assertFalse(Intersection2D_F32.contains2(rect, -10, -6));
assertTrue(Intersection2D_F32.contains2(rect, -5, 4));
assertTrue(Intersection2D_F32.contains2(rect, -6, 5));
}
@Test
public void contains_rect_pt() {
Rectangle2D_F32 rect = new Rectangle2D_F32(-10,-5,-5,5);
assertTrue(Intersection2D_F32.contains(rect, -10, -5));
assertTrue(Intersection2D_F32.contains(rect, -6, 4));
assertTrue(Intersection2D_F32.contains(rect, -9.9f, -4.99f));
assertTrue(Intersection2D_F32.contains(rect, -6.001f, 4.99f));
assertTrue(Intersection2D_F32.contains(rect, -5.99f, 4));
assertTrue(Intersection2D_F32.contains(rect, -10, 4.001f));
assertFalse(Intersection2D_F32.contains(rect, -11, -5));
assertFalse(Intersection2D_F32.contains(rect, -10, -6));
assertFalse(Intersection2D_F32.contains(rect, -5, 4));
assertFalse(Intersection2D_F32.contains(rect, -6, 5));
}
@Test
public void contains2_rect_pt() {
Rectangle2D_F32 rect = new Rectangle2D_F32(-10,-5,-5,5);
assertTrue(Intersection2D_F32.contains2(rect, -10, -5));
assertTrue(Intersection2D_F32.contains2(rect, -6, 4));
assertTrue(Intersection2D_F32.contains2(rect, -9.9f, -4.99f));
assertTrue(Intersection2D_F32.contains2(rect, -6.001f, 4.99f));
assertTrue(Intersection2D_F32.contains2(rect, -5.99f, 4));
assertTrue(Intersection2D_F32.contains2(rect, -10, 4.001f));
assertFalse(Intersection2D_F32.contains2(rect, -11, -5));
assertFalse(Intersection2D_F32.contains2(rect, -10, -6));
assertTrue(Intersection2D_F32.contains2(rect, -5, 4));
assertTrue(Intersection2D_F32.contains2(rect, -6, 5));
}
@Test
public void intersectionArea_rect_rect() {
// check several positive cases
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(0,0,100,120), 100*120);
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(10,12,99,119), 89*107);
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(50,50,200,200), 50*70 );
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(-10,-10,10,10), 10*10 );
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(90,-10,105,1), 10*1 );
check( new Rectangle2D_F32(0,0,100,120),new Rectangle2D_F32(90,5,105,105), 10*100 );
// negative cases
check(new Rectangle2D_F32(0, 0, 100, 120), new Rectangle2D_F32(200, 200, 300, 305), 0);
check(new Rectangle2D_F32(0, 0, 100, 120), new Rectangle2D_F32(-200, -200, -10, -10), 0);
check(new Rectangle2D_F32(0, 0, 100, 120), new Rectangle2D_F32(0, -20, 100, -5), 0);
check(new Rectangle2D_F32(0, 0, 100, 120), new Rectangle2D_F32(0, 125, 100, 130), 0);
// edge cases
check(new Rectangle2D_F32(0, 0, 100, 120), new Rectangle2D_F32(0, 0, 0, 0), 0);
check(new Rectangle2D_F32(0, 0, 100, 120), new Rectangle2D_F32(100, 120, 100, 120), 0);
check(new Rectangle2D_F32(0, 0, 100, 120), new Rectangle2D_F32(-10, 0, 0, 120), 0);
check(new Rectangle2D_F32(0, 0, 100, 120), new Rectangle2D_F32(100, 0, 105, 120), 0);
check(new Rectangle2D_F32(0, 0, 100, 120), new Rectangle2D_F32(0, -10, 100, 0), 0);
check(new Rectangle2D_F32(0, 0, 100, 120), new Rectangle2D_F32(0, 120, 100, 125), 0);
}
private void check( Rectangle2D_F32 a , Rectangle2D_F32 b , float expected ) {
assertEquals(expected,Intersection2D_F32.intersectionArea(a,b),GrlConstants.FLOAT_TEST_TOL);
}
@Test
public void line_ellipse() {
// easy cases where the ellipse is at the original aligned to the coordinate axis
EllipseRotated_F32 ellipse = new EllipseRotated_F32(0,0,2,1,0);
checkIntersection(new LineGeneral2D_F32(1,0,0),ellipse); // vertical line
checkIntersection(new LineGeneral2D_F32(0,1,0),ellipse); // horizontal line
checkIntersection(new LineGeneral2D_F32(0.25f,2.0f,1),ellipse); // angled line
checkIntersection(new LineGeneral2D_F32(2.0f,0.25f,1),ellipse); // angled line
checkSingleIntersection(new LineGeneral2D_F32(1,0,-2),ellipse); // single point
checkSingleIntersection(new LineGeneral2D_F32(0,1,-1),ellipse); // single point
checkNoIntersection(new LineGeneral2D_F32(1,0,20),ellipse);// no intersection
// Test to see if the rotation is handled correctly. Still centered at the original but rotated 90 degrees
ellipse = new EllipseRotated_F32(0,0,2,1, GrlConstants.F_PId2);
checkIntersection(new LineGeneral2D_F32(1,0,0),ellipse); // vertical line
checkIntersection(new LineGeneral2D_F32(0,1,0),ellipse); // horizontal line
checkIntersection(new LineGeneral2D_F32(0.25f,2.0f,1),ellipse); // angled line
checkIntersection(new LineGeneral2D_F32(2.0f,0.25f,1),ellipse); // angled line
checkSingleIntersection(new LineGeneral2D_F32(1,0,-1),ellipse); // single point
checkSingleIntersection(new LineGeneral2D_F32(0,1,-2),ellipse); // single point
checkNoIntersection(new LineGeneral2D_F32(1,0,20),ellipse);// no intersection
// Offset it from the original
ellipse = new EllipseRotated_F32(0.1f,0,2,1,0);
checkIntersection(new LineGeneral2D_F32(1,0,0),ellipse); // vertical line
checkIntersection(new LineGeneral2D_F32(0,1,0),ellipse); // horizontal line
// Hardest case. not at origin and rotated an arbitrary amount
ellipse = new EllipseRotated_F32(0.12f,-0.13f,2,1,0.4f);
checkIntersection(new LineGeneral2D_F32(1,0,0),ellipse); // vertical line
checkIntersection(new LineGeneral2D_F32(0,1,0),ellipse); // horizontal line
checkIntersection(new LineGeneral2D_F32(0.25f,2.0f,1),ellipse); // angled line
checkIntersection(new LineGeneral2D_F32(2.0f,0.25f,1),ellipse); // angled line
checkIntersection(new LineGeneral2D_F32(1,0,-2),ellipse); // single point
checkIntersection(new LineGeneral2D_F32(0,1,-1),ellipse); // single point
checkNoIntersection(new LineGeneral2D_F32(1,0,20),ellipse);// no intersection
}
private void checkNoIntersection( LineGeneral2D_F32 line , EllipseRotated_F32 ellipse ) {
Point2D_F32 a = new Point2D_F32();
Point2D_F32 b = new Point2D_F32();
assertEquals(0,Intersection2D_F32.intersection(line,ellipse,a,b,-1));
}
private void checkIntersection( LineGeneral2D_F32 line , EllipseRotated_F32 ellipse ) {
Point2D_F32 a = new Point2D_F32();
Point2D_F32 b = new Point2D_F32();
assertEquals(2,Intersection2D_F32.intersection(line,ellipse,a,b, -1));
// use the line and ellipse definition to check solution
assertEquals(0, line.evaluate(a.x, a.y), GrlConstants.FLOAT_TEST_TOL);
assertEquals(0, line.evaluate(b.x, b.y), GrlConstants.FLOAT_TEST_TOL);
assertEquals(1.0f, UtilEllipse_F32.evaluate(a.x, a.y, ellipse), GrlConstants.FLOAT_TEST_TOL);
assertEquals(1.0f, UtilEllipse_F32.evaluate(b.x, b.y, ellipse), GrlConstants.FLOAT_TEST_TOL);
}
private void checkSingleIntersection( LineGeneral2D_F32 line , EllipseRotated_F32 ellipse ) {
Point2D_F32 a = new Point2D_F32();
Point2D_F32 b = new Point2D_F32();
assertEquals(1,Intersection2D_F32.intersection(line,ellipse,a,b, -1));
assertEquals(0, a.distance(b), GrlConstants.FLOAT_TEST_TOL);
// use the line and ellipse definition to check solution
assertEquals(0, line.evaluate(a.x, a.y), GrlConstants.FLOAT_TEST_TOL);
assertEquals(1.0f, UtilEllipse_F32.evaluate(a.x, a.y, ellipse), GrlConstants.FLOAT_TEST_TOL);
}
}