/*
* $Id$
* This file is a part of the Arakhne Foundation Classes, http://www.arakhne.org/afc
*
* Copyright (c) 2000-2012 Stephane GALLAND.
* Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
* Universite de Technologie de Belfort-Montbeliard.
* Copyright (c) 2013-2016 The original authors, and other authors.
*
* 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 org.arakhne.afc.math.geometry.d2.ai;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Path2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import javax.imageio.ImageIO;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.arakhne.afc.math.AbstractMathTestCase;
import org.arakhne.afc.math.geometry.PathElementType;
import org.arakhne.afc.math.geometry.PathWindingRule;
import org.arakhne.afc.math.geometry.coordinatesystem.CoordinateSystem2DTestRule;
import org.arakhne.afc.math.geometry.d2.Point2D;
import org.arakhne.afc.math.geometry.d2.Vector2D;
@SuppressWarnings("all")
public abstract class AbstractShape2aiTest<T extends Shape2ai<?, ?, ?, ?, ?, B>,
B extends Rectangle2ai<?, ?, ?, ?, ?, B>> extends AbstractMathTestCase {
@Rule
public CoordinateSystem2DTestRule csTestRule = new CoordinateSystem2DTestRule();
/** Is the rectangular shape to test.
*/
protected T shape;
/** Factory of shapes.
*/
protected TestShapeFactory<?, ?, B> factory;
/**
* @throws Exception
*/
@Before
public void setUp() throws Exception {
this.factory = createFactory();
this.shape = createShape();
}
protected abstract TestShapeFactory<?, ? ,B> createFactory();
/** Create the shape to test.
*
* @return the shape to test.
*/
protected abstract T createShape();
public final Segment2ai<?, ?, ?, ?, ?, B> createSegment(int x1, int y1, int x2, int y2) {
return this.factory.createSegment(x1, y1, x2, y2);
}
public final B createRectangle(int x, int y, int width, int height) {
return this.factory.createRectangle(x, y, width, height);
}
public final Circle2ai<?, ?, ?, ?, ?, B> createCircle(int x, int y, int radius) {
return this.factory.createCircle(x, y, radius);
}
public final Point2D createPoint(int x, int y) {
return this.factory.createPoint(x, y);
}
public final Vector2D createVector(int x, int y) {
return this.factory.createVector(x, y);
}
public final Path2ai<?, ?, ?, ?, ?, B> createPath() {
return this.factory.createPath(null);
}
public final Path2ai<?, ?, ?, ?, ?, B> createPath(PathWindingRule rule) {
return this.factory.createPath(rule);
}
public final MultiShape2ai<?, ?, ?, ?, ?, ?, B> createMultiShape() {
return this.factory.createMultiShape();
}
/**
* @throws Exception
*/
@After
public void tearDown() throws Exception {
this.shape = null;
}
/** Assert is the given path iterator has a first element with the
* given information.
*
* @param pi
* @param type
* @param coords
*/
protected void assertElement(PathIterator2ai<?> pi, PathElementType type, int... coords) {
if (!pi.hasNext()) {
fail("expected path element but the iterator is empty"); //$NON-NLS-1$
}
PathElement2ai pe = pi.next();
if (!type.equals(pe.getType())) {
fail("expected: "+type+"; actual: "+pe.getType()); //$NON-NLS-1$ //$NON-NLS-2$
}
int[] c = new int[coords.length];
pe.toArray(c);
if (!isEquals(c, coords)) {
fail("expected: "+Arrays.toString(coords)+"; actual: "+Arrays.toString(c)); //$NON-NLS-1$ //$NON-NLS-2$
}
}
/** Assert that the two shape are intersecting and the closest point on the first shape is also
* on the second shape.
*
* @param shape1 the first shape, on which the closest point is computed.
* @param shape2 the second point.
*/
public void assertClosestPointInBothShapes(Shape2ai shape1, Shape2ai shape2) {
final Point2D<?, ?> point = shape1.getClosestPointTo(shape2);
double distance;
//TODO: The following test may fail since MathConstants#SPLINE_APPROXIMATION_RATIO is too high; see Issue #89.
//distance = shape1.getDistance(point);
//assertEpsilonZero("Closest point " + point + " is not in the first shape: " + shape1 + ". Distance: " + distance, distance);
distance = shape2.getDistance(point);
assertEpsilonZero("Closest point " + point + " is not in the second shape: " + shape2 + ". Distance: " + distance, distance); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
/**
* Replies if two arrays have the same values at epsilon.
*
* @param a
* @param b
* @return <code>true</code> if the two arrays are equal, otherwise
* <code>false</code>.
*/
public boolean isEpsilonEquals(float[] a, float[] b) {
if (a==b) return true;
if (a==null && b!=null) return false;
if (a!=null && b==null) return false;
assert(a!=null && b!=null);
if (a.length!=b.length) return false;
for(int i=0; i<a.length; ++i) {
if (!isEpsilonEquals(a[i], b[i])) return false;
}
return true;
}
/**
* Replies if two arrays have the same values at epsilon.
*
* @param a
* @param b
* @return <code>true</code> if the two arrays are equal, otherwise
* <code>false</code>.
*/
protected boolean isEquals(int[] a, int[] b) {
if (a==b) return true;
if (a==null && b!=null) return false;
if (a!=null && b==null) return false;
assert(a!=null && b!=null);
if (a.length!=b.length) return false;
for(int i=0; i<a.length; ++i) {
if (a[i]!=b[i]) return false;
}
return true;
}
/** Assert is the given path iterator has no element.
*
* @param pi
*/
protected void assertNoElement(PathIterator2ai<?> pi) {
if (pi.hasNext()) {
fail("expected no path element but the iterator is not empty"); //$NON-NLS-1$
}
}
@Test
public abstract void testClone();
@Test
public abstract void equalsObject();
@Test
public abstract void equalsObject_withPathIterator();
@Test
public abstract void equalsToPathIterator();
@Test
public abstract void equalsToShape();
@Test
public abstract void isEmpty();
@Test
public abstract void clear();
@Test
public abstract void containsPoint2D();
@Test
public abstract void getClosestPointTo();
@Test
public abstract void getFarthestPointTo();
@Test
public abstract void getClosestPointToRectangle2ai();
@Test
public abstract void getClosestPointToCircle2ai();
@Test
public abstract void getClosestPointToSegment2ai();
@Test
public abstract void getClosestPointToMultiShape2ai();
@Test
public abstract void getClosestPointToPath2ai();
@Test
public abstract void getDistance();
@Test
public abstract void getDistanceSquared();
@Test
public abstract void getDistanceL1();
@Test
public abstract void getDistanceLinf();
@Test
public abstract void setIT();
@Test
public abstract void getPathIterator();
@Test
public abstract void getPathIteratorTransform2D();
@Test
public abstract void createTransformedShape();
@Test
public abstract void translateVector2D();
@Test
public abstract void toBoundingBox();
@Test
public abstract void toBoundingBoxB();
@Test
public abstract void getPointIterator();
@Test
public abstract void containsRectangle2ai();
@Test
public abstract void containsShape2D();
@Test
public abstract void intersectsRectangle2ai();
@Test
public abstract void intersectsCircle2ai();
@Test
public abstract void intersectsSegment2ai();
@Test
public abstract void intersectsPath2ai();
@Test
public abstract void intersectsPathIterator2ai();
@Test
public abstract void getDistanceSquaredRectangle2ai();
@Test
public abstract void getDistanceSquaredCircle2ai();
@Test
public abstract void getDistanceSquaredMultiShape2ai();
@Test
public abstract void getDistanceSquaredSegment2ai();
@Test
public abstract void getDistanceSquaredPath2ai();
@Test
public abstract void translateIntInt();
@Test
public abstract void containsIntInt();
@Test
public void getGeomFactory() {
assertNotNull(this.shape.getGeomFactory());
}
@Test
public abstract void intersectsShape2D();
@Test
public abstract void operator_addVector2D();
@Test
public abstract void operator_plusVector2D();
@Test
public abstract void operator_removeVector2D();
@Test
public abstract void operator_minusVector2D();
@Test
public abstract void operator_multiplyTransform2D();
@Test
public abstract void operator_andPoint2D();
@Test
public abstract void operator_andShape2D();
@Test
public abstract void operator_upToPoint2D();
/** Generate a bitmap containing the given Shape2D.
*
* @param shape.
* @return the filename
* @throws IOException Input/output exception
*/
public static File generateTestPicture(Shape2ai<?, ?, ?, ?, ?, ?> shape) throws IOException {
File filename = File.createTempFile("testShape", ".png"); //$NON-NLS-1$ //$NON-NLS-2$
Rectangle2ai box = shape.toBoundingBox();
PathIterator2ai<?> iterator = shape.getPathIterator();
Path2D path = new Path2D.Double(
iterator.getWindingRule() == PathWindingRule.NON_ZERO ? Path2D.WIND_NON_ZERO : Path2D.WIND_EVEN_ODD);
while (iterator.hasNext()) {
PathElement2ai element = iterator.next();
int tox = (element.getToX() - box.getMinX()) * 2;
int toy = (box.getMaxY() - (element.getToY() - box.getMinY())) * 2;
switch (element.getType()) {
case LINE_TO:
path.lineTo(tox, toy);
break;
case MOVE_TO:
path.moveTo(tox, toy);
break;
case CLOSE:
path.closePath();
break;
case CURVE_TO:
path.curveTo(
(element.getCtrlX1() - box.getMinX()) * 2,
(box.getMaxY() - (element.getCtrlY1() - box.getMinY())) * 2,
(element.getCtrlX2() - box.getMinX()) * 2,
(box.getMaxY() - (element.getCtrlY2() - box.getMinY())) * 2,
tox, toy);
break;
case ARC_TO:
throw new IllegalStateException();
case QUAD_TO:
path.quadTo(
(element.getCtrlX1() - box.getMinX()) * 2,
(box.getMaxY() - (element.getCtrlY1() - box.getMinY())) * 2,
tox, toy);
break;
default:
}
}
BufferedImage image = new BufferedImage(
box.getWidth() * 2,
box.getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = (Graphics2D) image.getGraphics();
g2d.setColor(Color.BLACK);
g2d.draw(path);
ImageIO.write(image, "png", filename); //$NON-NLS-1$
return filename;
}
}