/*
* Copyright (C) 2011-2015, 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.geometry;
import georegression.metric.UtilAngle;
import georegression.misc.GrlConstants;
import georegression.struct.line.LineGeneral2D_F64;
import georegression.struct.line.LineParametric2D_F64;
import georegression.struct.line.LinePolar2D_F64;
import georegression.struct.line.LineSegment2D_F64;
import georegression.struct.point.Point2D_F64;
import org.junit.Test;
import java.util.Random;
import static georegression.geometry.UtilLine2D_F64.acuteAngle;
import static georegression.geometry.UtilLine2D_F64.acuteAngleN;
import static org.junit.Assert.assertEquals;
/**
* @author Peter Abeles
*/
public class TestUtilLine2D_F64 {
Random rand = new Random(234234);
@Test
public void acuteAngle_general() {
assertEquals(0, acuteAngle(new LineGeneral2D_F64(1, 0, 0.5), new LineGeneral2D_F64(1, 0, 6)),
GrlConstants.DOUBLE_TEST_TOL);
assertEquals(0, acuteAngle(new LineGeneral2D_F64(0, 2, 0.5), new LineGeneral2D_F64(0, 2, 6)),
GrlConstants.DOUBLE_TEST_TOL);
assertEquals(Math.PI, acuteAngle(new LineGeneral2D_F64(2, 2, 0.5), new LineGeneral2D_F64(-3, -3, 6)),
GrlConstants.DOUBLE_TEST_TOL);
assertEquals(Math.PI/2, acuteAngle(new LineGeneral2D_F64(2, 2, 0.5), new LineGeneral2D_F64(-4, 4, 6)),
GrlConstants.DOUBLE_TEST_TOL);
// pathological cause with numerical round off. acos( -1.000000000123 )
double a = Math.cos(Math.PI/4.0);
assertEquals(Math.PI, acuteAngle(new LineGeneral2D_F64(a, a, 0.5), new LineGeneral2D_F64(-a, -a, 6)),
GrlConstants.DOUBLE_TEST_TOL);
}
@Test
public void acuteAngleN_general() {
double a = Math.cos(Math.PI/4.0);
double tol = GrlConstants.DOUBLE_TEST_TOL*10.0;// float case needs more tolerance
assertEquals(0, acuteAngleN(new LineGeneral2D_F64(1, 0, 0.5), new LineGeneral2D_F64(1, 0, 6)),tol);
assertEquals(0, acuteAngleN(new LineGeneral2D_F64(0, 1, 0.5), new LineGeneral2D_F64(0, 1, 6)),tol);
assertEquals(Math.PI, acuteAngleN(new LineGeneral2D_F64(a, a, 0.5), new LineGeneral2D_F64(-a, -a, 6)),tol);
assertEquals(Math.PI/2, acuteAngleN(new LineGeneral2D_F64(a, a, 0.5), new LineGeneral2D_F64(-a, a, 6)),tol);
}
@Test
public void convert_segment_parametric() {
LineSegment2D_F64 segment = new LineSegment2D_F64();
LineParametric2D_F64 para = new LineParametric2D_F64();
segment.a.set(0,0);
segment.b.set(5,0);
UtilLine2D_F64.convert(segment,para);
assertEquals(para.p.x,0, GrlConstants.DOUBLE_TEST_TOL);
assertEquals(para.p.y,0, GrlConstants.DOUBLE_TEST_TOL);
assertEquals(Math.abs(para.slope.x),5, GrlConstants.DOUBLE_TEST_TOL);
assertEquals(para.slope.y,0, GrlConstants.DOUBLE_TEST_TOL);
}
@Test
public void convert_segment_general() {
LineSegment2D_F64 segment = new LineSegment2D_F64();
segment.a.set(0,2);
segment.b.set(5,6);
LineGeneral2D_F64 general = UtilLine2D_F64.convert(segment,(LineGeneral2D_F64)null);
// see if the two end points lie on the general line
assertEquals(0,general.evaluate(segment.a.x,segment.a.y), GrlConstants.DOUBLE_TEST_TOL);
assertEquals(0,general.evaluate(segment.b.x,segment.b.y), GrlConstants.DOUBLE_TEST_TOL);
}
@Test
public void convert_segment2pt_general() {
Point2D_F64 a = new Point2D_F64(2,6);
Point2D_F64 b = new Point2D_F64(7,8);
LineGeneral2D_F64 general = UtilLine2D_F64.convert(a,b,(LineGeneral2D_F64)null);
// see if the two end points lie on the general line
assertEquals(0,general.evaluate(a.x,a.y), GrlConstants.DOUBLE_TEST_TOL);
assertEquals(0,general.evaluate(b.x,b.y), GrlConstants.DOUBLE_TEST_TOL);
}
@Test
public void convert_polar_parametric() {
LinePolar2D_F64 polar = new LinePolar2D_F64();
LineParametric2D_F64 para = new LineParametric2D_F64();
polar.distance = 5;
polar.angle = Math.PI/2;
UtilLine2D_F64.convert(polar,para);
assertEquals(para.p.x,0, GrlConstants.DOUBLE_TEST_TOL);
assertEquals(para.p.y,5, GrlConstants.DOUBLE_TEST_TOL);
assertEquals(Math.abs(para.slope.x),1, GrlConstants.DOUBLE_TEST_TOL);
assertEquals(para.slope.y,0, GrlConstants.DOUBLE_TEST_TOL);
}
@Test
public void convert_polar_general() {
LinePolar2D_F64 polar = new LinePolar2D_F64();
polar.distance = 5;
polar.angle = Math.PI/3.0;
LineGeneral2D_F64 found = UtilLine2D_F64.convert(polar,(LineGeneral2D_F64)null);
LineParametric2D_F64 para = UtilLine2D_F64.convert(polar,(LineParametric2D_F64)null);
LineGeneral2D_F64 expected = UtilLine2D_F64.convert(para,(LineGeneral2D_F64)null);
expected.normalize();
// handle the sign ambiguity
if( expected.A*found.A < 0 || expected.B*found.B < 0) {
found.A *= -1;
found.B *= -1;
found.C *= -1;
}
assertEquals(expected.A,found.A,GrlConstants.DOUBLE_TEST_TOL);
assertEquals(expected.B,found.B,GrlConstants.DOUBLE_TEST_TOL);
assertEquals(expected.C,found.C,GrlConstants.DOUBLE_TEST_TOL);
}
@Test
public void convert_general_polar() {
LineGeneral2D_F64 general = new LineGeneral2D_F64(2,-3,-5);
LinePolar2D_F64 found = UtilLine2D_F64.convert(general,(LinePolar2D_F64)null);
// find two points on the line using the polar equation
double c = (double) Math.cos(found.angle);
double s = (double) Math.sin(found.angle);
double x0 = c*found.distance;
double y0 = s*found.distance;
double x1 = x0 - s;
double y1 = y0 + c;
// see if they are also on the general line equation
assertEquals(0,general.evaluate(x0,y0), GrlConstants.DOUBLE_TEST_TOL);
assertEquals(0,general.evaluate(x1,y1), GrlConstants.DOUBLE_TEST_TOL);
}
@Test
public void convert_parametric_polar() {
LineParametric2D_F64 para = new LineParametric2D_F64();
LinePolar2D_F64 polar = new LinePolar2D_F64();
para.slope.set(1,0);
para.setPoint(0,5);
UtilLine2D_F64.convert(para,polar);
assertEquals(polar.distance,5, GrlConstants.DOUBLE_TEST_TOL);
assertEquals(polar.angle,Math.PI/2, GrlConstants.DOUBLE_TEST_TOL);
para.slope.set(1,-1);
para.setPoint(-5,-5);
UtilLine2D_F64.convert(para,polar);
assertEquals(polar.distance,5*Math.sqrt(2), GrlConstants.DOUBLE_TEST_TOL);
assertEquals(polar.angle,-Math.PI+Math.PI/4, GrlConstants.DOUBLE_TEST_TOL);
}
@Test
public void convert_BackAndForth_parametric_polar() {
LineParametric2D_F64 para = new LineParametric2D_F64();
LinePolar2D_F64 polar = new LinePolar2D_F64();
LinePolar2D_F64 found = new LinePolar2D_F64();
for (int i = 0; i < 100; i++) {
polar.distance = (rand.nextDouble() - 0.5) * 3;
polar.angle = 2.0*(rand.nextDouble() - 0.5) * Math.PI;
UtilLine2D_F64.convert(polar, para);
UtilLine2D_F64.convert(para, found);
normalize(polar);
normalize(found);
assertEquals(polar.angle, found.angle, GrlConstants.DOUBLE_TEST_TOL);
assertEquals(polar.distance,found.distance,GrlConstants.DOUBLE_TEST_TOL);
}
}
private void normalize( LinePolar2D_F64 l ) {
if( l.distance < 0 ) {
l.distance = -l.distance;
l.angle = UtilAngle.bound(l.angle + Math.PI);
}
}
@Test
public void convert_parametric_general() {
LineParametric2D_F64 para = new LineParametric2D_F64();
LineGeneral2D_F64 general = new LineGeneral2D_F64();
para.slope.set(1,0.5);
para.p.set(0.75,0.34);
// pick a point on the line
Point2D_F64 p = new Point2D_F64(para.p.x + para.slope.x*2,para.p.y + para.slope.y*2);
// convert to general notation
UtilLine2D_F64.convert(para,general);
// test the basic properties of this line equation
double val = general.A*p.x + general.B*p.y + general.C;
assertEquals(0,val, GrlConstants.DOUBLE_TEST_TOL);
}
@Test
public void convert_general_parametric() {
LineGeneral2D_F64 general = new LineGeneral2D_F64();
LineParametric2D_F64 para = new LineParametric2D_F64();
// pick some arbitrary line
general.set(1,2,3);
// convert to parametric notation
UtilLine2D_F64.convert(general,para);
// pick a point on the parametric line
Point2D_F64 p = new Point2D_F64(para.p.x + para.slope.x*2,para.p.y + para.slope.y*2);
// See if that same point is on the general equation
double val = general.A*p.x + general.B*p.y + general.C;
assertEquals(0,val, GrlConstants.DOUBLE_TEST_TOL);
}
}