/*
* 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.algs;
import georegression.geometry.UtilPolygons2D_F32;
import georegression.metric.Intersection2D_F32;
import georegression.misc.GrlConstants;
import georegression.struct.point.Point2D_F32;
import georegression.struct.shapes.Polygon2D_F32;
import org.junit.Test;
import java.util.Random;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* @author Peter Abeles
*/
public class TestAndrewMonotoneConvexHull_F32 {
Random rand = new Random(2355);
@Test
public void triangle() {
// all points are in hull
Point2D_F32 []input = new Point2D_F32[3];
input[0] = new Point2D_F32(2,3);
input[1] = new Point2D_F32(7,8);
input[2] = new Point2D_F32(8,3);
Polygon2D_F32 output = new Polygon2D_F32();
AndrewMonotoneConvexHull_F32 alg = new AndrewMonotoneConvexHull_F32();
alg.process(input,input.length,output);
containsOnceEach(input,output);
// add a point inside
Point2D_F32 []input2 = new Point2D_F32[4];
System.arraycopy(input,0,input2,0,3);
input2[3] = new Point2D_F32(4,4);
alg.process(input2,input.length,output);
containsOnceEach(input,output);
}
@Test
public void rectangle() {
// all points are in hull
Point2D_F32 []input = new Point2D_F32[4];
input[0] = new Point2D_F32(2,3);
input[1] = new Point2D_F32(2,8);
input[2] = new Point2D_F32(7,8);
input[3] = new Point2D_F32(7,3);
Polygon2D_F32 output = new Polygon2D_F32();
AndrewMonotoneConvexHull_F32 alg = new AndrewMonotoneConvexHull_F32();
alg.process(input,input.length,output);
containsOnceEach(input,output);
// add a point inside
Point2D_F32 []input2 = new Point2D_F32[5];
System.arraycopy(input,0,input2,0,4);
input2[4] = new Point2D_F32(4,4);
alg.process(input2,input.length,output);
containsOnceEach(input,output);
}
@Test
public void pentagon() {
// all points are in hull
Point2D_F32 []input = new Point2D_F32[4];
input[0] = new Point2D_F32(2,3);
input[1] = new Point2D_F32(2,8);
input[2] = new Point2D_F32(7,8);
input[3] = new Point2D_F32(7,3);
input[3] = new Point2D_F32(4,10);
Polygon2D_F32 output = new Polygon2D_F32();
AndrewMonotoneConvexHull_F32 alg = new AndrewMonotoneConvexHull_F32();
alg.process(input,input.length,output);
containsOnceEach(input,output);
// add a point inside
Point2D_F32 []input2 = new Point2D_F32[6];
System.arraycopy(input,0,input2,0,input.length);
input2[5] = new Point2D_F32(4,4);
alg.process(input2,input.length,output);
containsOnceEach(input,output);
}
@Test
public void randomPoints() {
AndrewMonotoneConvexHull_F32 alg = new AndrewMonotoneConvexHull_F32();
Polygon2D_F32 output = new Polygon2D_F32();
for (int numPoints = 10; numPoints < 20; numPoints++) {
Point2D_F32 data[] = new Point2D_F32[numPoints];
for (int i = 0; i < numPoints; i++) {
float x = (float)rand.nextGaussian()*5;
float y = (float)rand.nextGaussian()*5;
data[i] = new Point2D_F32(x,y);
}
alg.process(data,numPoints,output);
// check some of the properties of the convex hull
assertTrue(output.size() <= numPoints);
assertTrue(output.isCCW());
assertTrue(output.isConvex());
for (int i = 0; i < numPoints; i++) {
Intersection2D_F32.containConvex(output,data[i]);
}
}
}
@Test
public void grid() {
AndrewMonotoneConvexHull_F32 alg = new AndrewMonotoneConvexHull_F32();
Polygon2D_F32 output = new Polygon2D_F32();
int numRows = 5;
int numCols = 6;
float w = 1.2f;
Point2D_F32 points[] = new Point2D_F32[numRows*numCols];
for (int row = 0; row < numRows; row++) {
float y = row*w - 2.1f;
for (int col = 0; col < numCols; col++) {
float x = col*w - 2.6f;
points[ row*numCols + col ] = new Point2D_F32(x,y);
}
}
alg.process(points,points.length,output);
// check some of the properties of the convex hull
assertTrue(output.size() <= points.length);
assertTrue(output.isCCW());
assertTrue(output.isConvex());
for (int i = 0; i < points.length; i++) {
Intersection2D_F32.containConvex(output,points[i]);
}
}
private void containsOnceEach( Point2D_F32[] expected , Polygon2D_F32 output ) {
assertTrue(UtilPolygons2D_F32.isConvex(output));
int count[] = new int[expected.length];
assertEquals(expected.length,output.size());
for (int i = 0; i < expected.length; i++) {
for (int j = 0; j < output.size(); j++) {
if( expected[i].distance2(output.get(j)) <= GrlConstants.FLOAT_TEST_TOL ) {
count[i]++;
}
}
}
for (int i = 0; i < count.length; i++) {
assertEquals(1, count[i]);
}
}
}