package org.djutils.draw.bounds;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.Collection;
import org.djutils.draw.DrawException;
import org.djutils.draw.line.PolyLine3d;
import org.djutils.draw.point.Point3d;
import org.junit.Test;
/**
* Bounds3dText.java.
*
* Copyright (c) 2020-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
* BSD-style license. See DJUTILS License.
*
* @author Alexander Verbraeck
* @author Peter Knoppers
*/
public class Bounds3dTest
{
/**
* Test the bounding box constructor.
* @throws DrawException if that happens uncaught; this test has failed
* @throws IllegalArgumentException on unexpected error
*/
@Test
public void constructorTest() throws IllegalArgumentException, DrawException
{
try
{
new Bounds3d(Double.NaN, 0, 0, 0, 0, 0);
fail("Nan should have thrown an IllegalArgumentException");
}
catch (IllegalArgumentException iae)
{
// Ignore expected exception
}
try
{
new Bounds3d(0, Double.NaN, 0, 0, 0, 0);
fail("Nan should have thrown an IllegalArgumentException");
}
catch (IllegalArgumentException iae)
{
// Ignore expected exception
}
try
{
new Bounds3d(0, 0, Double.NaN, 0, 0, 0);
fail("Nan should have thrown an IllegalArgumentException");
}
catch (IllegalArgumentException iae)
{
// Ignore expected exception
}
try
{
new Bounds3d(0, 0, 0, Double.NaN, 0, 0);
fail("Nan should have thrown an IllegalArgumentException");
}
catch (IllegalArgumentException iae)
{
// Ignore expected exception
}
try
{
new Bounds3d(0, 0, 0, 0, Double.NaN, 0);
fail("Nan should have thrown an IllegalArgumentException");
}
catch (IllegalArgumentException iae)
{
// Ignore expected exception
}
try
{
new Bounds3d(0, 0, 0, 0, 0, Double.NaN);
fail("Nan should have thrown an IllegalArgumentException");
}
catch (IllegalArgumentException iae)
{
// Ignore expected exception
}
try
{
new Bounds3d(2, -2, 0, 0, 0, 0);
fail("Negative x-range should have thrown an IllegalArgumentException");
}
catch (IllegalArgumentException iae)
{
// Ignore expected exception
}
try
{
new Bounds3d(0, 0, 2, -2, 0, 0);
fail("Negative y-range should have thrown an IllegalArgumentException");
}
catch (IllegalArgumentException iae)
{
// Ignore expected exception
}
try
{
new Bounds3d(0, 0, 0, 0, 2, -2);
fail("Negative z-range should have thrown an IllegalArgumentException");
}
catch (IllegalArgumentException iae)
{
// Ignore expected exception
}
Bounds3d bb = new Bounds3d(1, 2, 3, 4, 5, 6);
assertEquals("minX", 1, bb.getMinX(), 0);
assertEquals("maxX", 2, bb.getMaxX(), 0);
assertEquals("minY", 3, bb.getMinY(), 0);
assertEquals("maxY", 4, bb.getMaxY(), 0);
assertEquals("minZ", 5, bb.getMinZ(), 0);
assertEquals("maxZ", 6, bb.getMaxZ(), 0);
try
{
new Bounds3d(Double.NaN, 0, 0);
fail("Nan should have thrown an IllegalArgumentException");
}
catch (IllegalArgumentException iae)
{
// Ignore expected exception
}
try
{
new Bounds3d(0, Double.NaN, 0);
fail("Nan should have thrown an IllegalArgumentException");
}
catch (IllegalArgumentException iae)
{
// Ignore expected exception
}
try
{
new Bounds3d(0, 0, Double.NaN);
fail("Nan should have thrown an IllegalArgumentException");
}
catch (IllegalArgumentException iae)
{
// Ignore expected exception
}
try
{
new Bounds3d(-3, 0, 0);
fail("Negative x-range should have thrown an IllegalArgumentException");
}
catch (IllegalArgumentException iae)
{
// Ignore expected exception
}
try
{
new Bounds3d(0, -3, 0);
fail("Negative y-range should have thrown an IllegalArgumentException");
}
catch (IllegalArgumentException iae)
{
// Ignore expected exception
}
try
{
new Bounds3d(0, 0, -3);
fail("Negative z-range should have thrown an IllegalArgumentException");
}
catch (IllegalArgumentException iae)
{
// Ignore expected exception
}
bb = new Bounds3d(20, 30, 40);
assertEquals("minX", -10, bb.getMinX(), 0);
assertEquals("maxX", 10, bb.getMaxX(), 0);
assertEquals("minY", -15, bb.getMinY(), 0);
assertEquals("maxY", 15, bb.getMaxY(), 0);
assertEquals("minZ", -20, bb.getMinZ(), 0);
assertEquals("maxZ", 20, bb.getMaxZ(), 0);
assertEquals("deltaX", 20, bb.getDeltaX(), 0);
assertEquals("deltaY", 30, bb.getDeltaY(), 0);
assertEquals("deltaZ", 40, bb.getDeltaZ(), 0);
assertEquals("volume", 20 * 30 * 40, bb.getVolume(), 0);
assertFalse("contains does not include boundaries", bb.contains(-10, 0, 0));
assertFalse("contains does not include boundaries", bb.contains(10, 0, 0));
assertFalse("contains does not include boundaries", bb.contains(0, -15, 0));
assertFalse("contains does not include boundaries", bb.contains(0, 15, 0));
assertFalse("contains does not include boundaries", bb.contains(0, 0, -20));
assertFalse("contains does not include boundaries", bb.contains(0, 0, 20));
assertTrue("contains", bb.contains(-0.999, 0, 0));
assertTrue("contains", bb.contains(0.999, 0, 0));
assertTrue("contains", bb.contains(0, -14.999, 0));
assertTrue("contains", bb.contains(0, 14.999, 0));
assertTrue("contains", bb.contains(0, 0, -19.999));
assertTrue("contains", bb.contains(0, 0, 19.999));
assertTrue("covers includes boundaries", bb.covers(-10, 0, 0));
assertTrue("covers includes boundaries", bb.covers(10, 0, 0));
assertTrue("covers includes boundaries", bb.covers(0, -15, 0));
assertTrue("covers includes boundaries", bb.covers(0, 15, 0));
assertTrue("covers includes boundaries", bb.covers(0, 0, -20));
assertTrue("covers includes boundaries", bb.covers(0, 0, 20));
assertFalse("covers", bb.covers(-10.001, 0, 0));
assertFalse("covers", bb.covers(10.001, 0, 0));
assertFalse("covers", bb.covers(0, -15.001, 0));
assertFalse("covers", bb.covers(0, 15.001, 0));
assertFalse("covers", bb.covers(0, 0, -20.001));
assertFalse("covers", bb.covers(0, 0, 20.001));
Collection pointCollection = new ArrayList<>();
try
{
new Bounds3d(pointCollection);
fail("Empty point collection should have thrown an IllegalArgumentException");
}
catch (IllegalArgumentException iae)
{
// Ignore expected exception
}
pointCollection.add(new Point3d(10, 20, 30));
bb = new Bounds3d(pointCollection);
assertEquals("minX", 10, bb.getMinX(), 0);
assertEquals("maxX", 10, bb.getMaxX(), 0);
assertEquals("minY", 20, bb.getMinY(), 0);
assertEquals("maxY", 20, bb.getMaxY(), 0);
assertEquals("minZ", 30, bb.getMinZ(), 0);
assertEquals("maxZ", 30, bb.getMaxZ(), 0);
pointCollection.add(new Point3d(-5, -6, -7));
bb = new Bounds3d(pointCollection);
assertEquals("minX", -5, bb.getMinX(), 0);
assertEquals("maxX", 10, bb.getMaxX(), 0);
assertEquals("minY", -6, bb.getMinY(), 0);
assertEquals("maxY", 20, bb.getMaxY(), 0);
assertEquals("minZ", -7, bb.getMinZ(), 0);
assertEquals("maxZ", 30, bb.getMaxZ(), 0);
assertTrue("toString returns something descriptive", bb.toString().startsWith("Bounds3d "));
pointCollection.add(new Point3d(40, 50, 60));
// This collection is an ArrayList, so the elements are stored in the order in which they were added
bb = new Bounds3d(pointCollection);
assertEquals("minX", -5, bb.getMinX(), 0);
assertEquals("maxX", 40, bb.getMaxX(), 0);
assertEquals("minY", -6, bb.getMinY(), 0);
assertEquals("maxY", 50, bb.getMaxY(), 0);
assertEquals("minZ", -7, bb.getMinZ(), 0);
assertEquals("maxZ", 60, bb.getMaxZ(), 0);
bb = new Bounds3d(pointCollection.toArray((new Point3d[0])));
assertEquals("minX", -5, bb.getMinX(), 0);
assertEquals("maxX", 40, bb.getMaxX(), 0);
assertEquals("minY", -6, bb.getMinY(), 0);
assertEquals("maxY", 50, bb.getMaxY(), 0);
assertEquals("minZ", -7, bb.getMinZ(), 0);
assertEquals("maxZ", 60, bb.getMaxZ(), 0);
Bounds3d bb2 = new Bounds3d(-100, -90, -100, -90, -100, -90);
assertNull("empty bounding box", bb.intersection(bb2));
PolyLine3d line = new PolyLine3d(new Point3d(1, 12, 23), new Point3d(3, 12, 21), new Point3d(2, 11, 23));
bb = new Bounds3d(line);
assertEquals("minX", 1, bb.getMinX(), 0);
assertEquals("minY", 11, bb.getMinY(), 0);
assertEquals("minZ", 21, bb.getMinZ(), 0);
assertEquals("maxX", 3, bb.getMaxX(), 0);
assertEquals("maxY", 12, bb.getMaxY(), 0);
assertEquals("maxZ", 23, bb.getMaxZ(), 0);
assertEquals("bounding box of reversed line", bb, new Bounds3d(line.reverse()));
Point3d p3d = new Point3d(123, 456, 789);
bb = new Bounds3d(p3d);
assertEquals("minX", 123, bb.getMinX(), 0);
assertEquals("maxX", 123, bb.getMaxX(), 0);
assertEquals("minY", 456, bb.getMinY(), 0);
assertEquals("maxY", 456, bb.getMaxY(), 0);
assertEquals("minZ", 789, bb.getMinZ(), 0);
assertEquals("maxZ", 789, bb.getMaxZ(), 0);
assertFalse("contains does not include boundaries", bb.contains(p3d));
assertTrue("covers includes boundaries", bb.covers(p3d));
assertEquals("size of a Bounds3d is always 8", 8, bb.size());
}
/**
* Test various methods of a Bounds2d.
* @throws DrawException when that happens uncaught; this test has failed
* @throws IllegalArgumentException when that happens uncaught; this test has failed
* @throws NullPointerException when that happens uncaught; this test has failed
*/
@Test
public void methodTest() throws NullPointerException, IllegalArgumentException, DrawException
{
PolyLine3d l3d = new PolyLine3d(new Point3d(10, 10, 10), new Point3d(30, -20, 40), new Point3d(-40, 100, 0));
Bounds3d bb = new Bounds3d(l3d);
assertEquals("minX", -40, bb.getMinX(), 0);
assertEquals("maxX", 30, bb.getMaxX(), 0);
assertEquals("minY", -20, bb.getMinY(), 0);
assertEquals("maxY", 100, bb.getMaxY(), 0);
assertEquals("minZ", 0, bb.getMinZ(), 0);
assertEquals("maxZ", 40, bb.getMaxZ(), 0);
try
{
bb.contains(Double.NaN, 0, 0);
fail("NaN should have thrown an IllegalArgumentException");
}
catch (IllegalArgumentException iae)
{
// Ignore expected exception
}
try
{
bb.contains(0, Double.NaN, 0);
fail("NaN should have thrown an IllegalArgumentException");
}
catch (IllegalArgumentException iae)
{
// Ignore expected exception
}
try
{
bb.contains(0, 0, Double.NaN);
fail("NaN should have thrown an IllegalArgumentException");
}
catch (IllegalArgumentException iae)
{
// Ignore expected exception
}
assertFalse("boundingbox does not contain itself", bb.contains(bb));
Bounds3d bb2 = new Bounds3d(bb.getMinX() - 0.0001, bb.getMaxX() + 0.0001, bb.getMinY() - 0.0001, bb.getMaxY() + 0.0001,
bb.getMinZ() - 0.0001, bb.getMaxZ() + 0.0001);
assertTrue("Slightly enlarged bounding box contains non-enlarged version", bb2.contains(bb));
try
{
bb.covers((Bounds3d) null);
fail("Should have thrown a NullPointerException");
}
catch (NullPointerException npe)
{
// Ignore expected exception
}
try
{
bb.covers(Double.NaN, 0, 0);
fail("Should have thrown an IllegalArgumentException");
}
catch (IllegalArgumentException iae)
{
// Ignore expected exception
}
try
{
bb.covers(0, Double.NaN, 0);
fail("Should have thrown an IllegalArgumentException");
}
catch (IllegalArgumentException iae)
{
// Ignore expected exception
}
try
{
bb.covers(0, 0, Double.NaN);
fail("Should have thrown an IllegalArgumentException");
}
catch (IllegalArgumentException iae)
{
// Ignore expected exception
}
assertTrue("Bounds2d covers itself", bb.covers(bb));
assertFalse("Bounds2d does not cover slightly enlarged version of itself", bb.covers(bb2));
bb2 = new Bounds3d(bb.getMinX() + 0.0001, bb.getMaxX() + 0.0001, bb.getMinY() + 0.0001, bb.getMaxY() + 0.0001,
bb.getMinZ() + 0.0001, bb.getMaxZ() + 0.0001);
assertFalse("Bounds2d does not cover slightly moved version of itself", bb.covers(bb2));
assertFalse("Overlapping Bounds2d is not disjoint", bb.disjoint(bb2));
assertTrue("Overlapping Bounds2d is not disjoint", bb.intersects(bb2));
bb2 = new Bounds3d(bb.getMinX() + 1000, bb.getMaxX() + 1000, bb.getMinY() + 1000, bb.getMaxY() + 1000,
bb.getMinZ() + 1000, bb.getMaxZ() + 1000);
assertFalse("No intersection", bb.intersects(bb2));
assertTrue("Disjoint", bb.disjoint(bb2));
bb2 = new Bounds3d(bb.getMaxX(), bb.getMaxX() + 0.0001, bb.getMinY() + 0.0001, bb.getMaxY() + 0.0001,
bb.getMinZ() + 0.0001, bb.getMaxZ() + 0.0001);
assertTrue("Only touching at vertical line is disjoint", bb.disjoint(bb2));
assertTrue("Only touching at vertical line is disjoint", bb2.disjoint(bb));
try
{
bb.intersection(null);
fail("Should have thrown a NullPointerException");
}
catch (NullPointerException npe)
{
// Ignore expected exception
}
double[] shifts = new double[] { -200, -5, 0, 5, 200 };
for (double dx : shifts)
{
for (double dy : shifts)
{
for (double dz : shifts)
{
bb2 = new Bounds3d(bb.getMinX() + dx, bb.getMaxX() + dx, bb.getMinY() + dy, bb.getMaxY() + dy,
bb.getMinZ() + dz, bb.getMaxZ() + dz);
Bounds3d intersection = bb.intersection(bb2);
if (Math.abs(dx) >= 200 || Math.abs(dy) >= 200 || Math.abs(dz) >= 200)
{
assertNull("intersection is null", intersection);
}
else
{
assertEquals("min x", Math.max(bb.getMinX(), bb2.getMinX()), intersection.getMinX(), 0);
assertEquals("max x", Math.min(bb.getMaxX(), bb2.getMaxX()), intersection.getMaxX(), 0);
assertEquals("min y", Math.max(bb.getMinY(), bb2.getMinY()), intersection.getMinY(), 0);
assertEquals("max y", Math.min(bb.getMaxY(), bb2.getMaxY()), intersection.getMaxY(), 0);
assertEquals("min z", Math.max(bb.getMinZ(), bb2.getMinZ()), intersection.getMinZ(), 0);
assertEquals("max z", Math.min(bb.getMaxZ(), bb2.getMaxZ()), intersection.getMaxZ(), 0);
}
}
}
}
assertEquals("getBounds returns this", bb, bb.getBounds());
assertNotEquals("HashCode uses minX", bb.hashCode(),
new Bounds3d(bb.getMinX() + 1, bb.getMaxX(), bb.getMinY(), bb.getMaxY(), bb.getMinZ(), bb.getMaxZ()));
assertNotEquals("HashCode uses maxX", bb.hashCode(),
new Bounds3d(bb.getMinX(), bb.getMaxX() + 1, bb.getMinY(), bb.getMaxY(), bb.getMinZ(), bb.getMaxZ()));
assertNotEquals("HashCode uses minY", bb.hashCode(),
new Bounds3d(bb.getMinX(), bb.getMaxX(), bb.getMinY() + 1, bb.getMaxY(), bb.getMinZ(), bb.getMaxZ()));
assertNotEquals("HashCode uses maxY", bb.hashCode(),
new Bounds3d(bb.getMinX(), bb.getMaxX(), bb.getMinY(), bb.getMaxY() + 1, bb.getMinZ(), bb.getMaxZ()));
assertNotEquals("HashCode uses minZ", bb.hashCode(),
new Bounds3d(bb.getMinX(), bb.getMaxX(), bb.getMinY(), bb.getMaxY(), bb.getMinZ() + 1, bb.getMaxZ()));
assertNotEquals("HashCode uses maxZ", bb.hashCode(),
new Bounds3d(bb.getMinX(), bb.getMaxX(), bb.getMinY(), bb.getMaxY() + 1, bb.getMinZ(), bb.getMaxZ() + 1));
assertFalse("equals checks for null", bb.equals(null));
assertFalse("equals checks for different kind of object", bb.equals("string"));
assertFalse("equals checks minX", bb
.equals(new Bounds3d(bb.getMinX() + 1, bb.getMaxX(), bb.getMinY(), bb.getMaxY(), bb.getMinZ(), bb.getMaxZ())));
assertFalse("equals checks maxX", bb
.equals(new Bounds3d(bb.getMinX(), bb.getMaxX() + 1, bb.getMinY(), bb.getMaxY(), bb.getMinZ(), bb.getMaxZ())));
assertFalse("equals checks minY", bb
.equals(new Bounds3d(bb.getMinX(), bb.getMaxX(), bb.getMinY() + 1, bb.getMaxY(), bb.getMinZ(), bb.getMaxZ())));
assertFalse("equals checks maxy", bb
.equals(new Bounds3d(bb.getMinX(), bb.getMaxX(), bb.getMinY(), bb.getMaxY() + 1, bb.getMinZ(), bb.getMaxZ())));
assertFalse("equals checks minZ", bb
.equals(new Bounds3d(bb.getMinX(), bb.getMaxX(), bb.getMinY(), bb.getMaxY(), bb.getMinZ() + 1, bb.getMaxZ())));
assertFalse("equals checks maxZ", bb
.equals(new Bounds3d(bb.getMinX(), bb.getMaxX(), bb.getMinY(), bb.getMaxY(), bb.getMinZ(), bb.getMaxZ() + 1)));
assertTrue("equals to copy of itself", bb.equals(new Bounds3d(bb)));
Bounds2d projection = bb.project();
assertEquals("projection minX", projection.getMinX(), bb.getMinX(), 0);
assertEquals("projection maxX", projection.getMaxX(), bb.getMaxX(), 0);
assertEquals("projection minY", projection.getMinY(), bb.getMinY(), 0);
assertEquals("projection maxY", projection.getMaxY(), bb.getMaxY(), 0);
}
}