package nl.tudelft.simulation.dsol.animation.D2;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.io.Serializable;
import java.rmi.RemoteException;
import org.djutils.draw.bounds.Bounds;
import org.djutils.draw.bounds.Bounds2d;
import org.djutils.draw.bounds.Bounds3d;
import org.djutils.draw.point.OrientedPoint3d;
import org.djutils.draw.point.Point;
import org.djutils.draw.point.Point2d;
import org.djutils.draw.point.Point3d;
import org.djutils.exceptions.Try;
import org.junit.Test;
import nl.tudelft.simulation.dsol.SimRuntimeException;
import nl.tudelft.simulation.dsol.animation.Locatable;
import nl.tudelft.simulation.dsol.experiment.Replication;
import nl.tudelft.simulation.dsol.experiment.ReplicationMode;
import nl.tudelft.simulation.dsol.model.AbstractDSOLModel;
import nl.tudelft.simulation.dsol.model.DSOLModel;
import nl.tudelft.simulation.dsol.simulators.DEVSAnimator;
import nl.tudelft.simulation.dsol.simulators.DEVSSimulator;
import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
/**
* Unit tests for the Renderable2D class.
*
* Copyright (c) 2020-2021 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
* for project information DSOL Manual. The DSOL
* project is distributed under a three-clause BSD-style license, which can be found at
* DSOL License.
*
* @author Alexander Verbraeck
*/
public class Renderable2DTest
{
/**
* Test the flags for a Rendeable2D.
*/
@Test
public void testFlags()
{
LocatableAngle locatable = new LocatableAngle();
SimulatorInterface.TimeDouble simulator = createAnimator();
Renderable2D renderable = new Renderable2D(locatable, simulator)
{
/** */
private static final long serialVersionUID = 1L;
@Override
public void paint(final Graphics2D graphics, final ImageObserver observer)
{
// placeholder
}
};
assertEquals(locatable, renderable.getSource());
assertTrue(renderable.getId() > 0); // 0 means not incremented
assertTrue(renderable.toString().contains("Renderable2D"));
BufferedImage img = new BufferedImage(200, 100, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = img.createGraphics();
Bounds2d extent = new Bounds2d(0, 200, 0, 100);
Dimension screenSize = new Dimension(200, 100);
RenderableScale renderableScale = new RenderableScale();
for (boolean translate : new boolean[] {true, false})
{
renderable.setTranslate(translate);
for (boolean flip : new boolean[] {true, false})
{
renderable.setFlip(flip);
for (boolean rotate : new boolean[] {true, false})
{
renderable.setRotate(rotate);
for (boolean scale : new boolean[] {true, false})
{
renderable.setScale(scale);
for (boolean scaleY : new boolean[] {true, false})
{
renderable.setScaleY(scaleY);
for (boolean scaleObject : new boolean[] {true, false})
{
renderable.setScaleObject(scaleObject);
assertEquals(translate, renderable.isTranslate());
assertEquals(flip, renderable.isFlip());
assertEquals(rotate, renderable.isRotate());
assertEquals(scale, renderable.isScale());
assertEquals(scaleY, renderable.isScaleY());
assertEquals(scaleObject, renderable.isScaleObject());
for (double angle : new double[] {0.0, Math.PI / 4.0, 1.5 * Math.PI})
{
// test if no exceptions happen when we paint
// if an exception occurred, the transform will not have been reset
AffineTransform transform = graphics.getTransform();
locatable.setAngle(angle);
renderable.paintComponent(graphics, extent, screenSize, renderableScale, null);
assertEquals(transform, graphics.getTransform());
}
}
}
}
}
}
}
assertTrue(renderable.contains(new Point2d(10, 20), new Bounds2d(0, 40, 0, 80)));
assertFalse(renderable.contains(new Point2d(5, 10), new Bounds2d(0, 40, 0, 80)));
renderable.contains(new Point2d(10, 20), new Bounds2d(0, 5, 0, 10));
renderable.destroy(simulator);
// Test if contains fails when there is no z-intersect. We give the Locatable a fake getZ() method.
Try.testFail(new Try.Execution()
{
@Override
public void execute() throws Throwable
{
new Renderable2D(createLocatable3dFakeZ(), createAnimator())
{
/** */
private static final long serialVersionUID = 1L;
@Override
public void paint(final Graphics2D g, final ImageObserver o)
{
// placeholder
}
}.contains(new Point2d(10, 20), new Bounds2d(0, 5, 0, 10));
}
}, IllegalStateException.class);
}
/** Locatable with a settable dirZ. */
class LocatableAngle implements Locatable
{
/** the angle. */
private double angle;
@Override
public Point, ?> getLocation() throws RemoteException
{
return new OrientedPoint3d(10, 20, 0, 0, 0, this.angle);
}
@Override
public Bounds, ?, ?> getBounds() throws RemoteException
{
return new Bounds3d(4, 4, 4);
}
/**
* Set the angle.
* @param angle double; the new angle
*/
public void setAngle(final double angle)
{
this.angle = angle;
}
}
/**
* @return a Locatable3d.
*/
Locatable createLocatable3dFakeZ()
{
return new Locatable()
{
@Override
public Point, ?> getLocation() throws RemoteException
{
return new Point3d(10, 20, 10);
}
@Override
public Bounds, ?, ?> getBounds() throws RemoteException
{
return new Bounds3d(4, 4, 4);
}
/** {@inheritDoc} */
@Override
public double getZ() throws RemoteException
{
return -10.0;
}
};
}
/**
* @return a Animator.
*/
SimulatorInterface.TimeDouble createAnimator()
{
try
{
SimulatorInterface.TimeDouble simulator = new DEVSAnimator.TimeDouble("animator");
DSOLModel.TimeDouble model =
new AbstractDSOLModel.TimeDouble(simulator)
{
/** */
private static final long serialVersionUID = 1L;
@Override
public void constructModel() throws SimRuntimeException
{
// placeholder
}
@Override
public Serializable getSourceId()
{
return "model";
}
};
Replication.TimeDouble replication =
Replication.TimeDouble.create("rep1", 0.0, 0.0, 1000000.0, model);
simulator.initialize(replication, ReplicationMode.TERMINATING);
return simulator;
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
/**
* @return a Simulator.
*/
SimulatorInterface.TimeDouble createSimulator()
{
try
{
SimulatorInterface.TimeDouble simulator = new DEVSSimulator.TimeDouble("simulator");
DSOLModel.TimeDouble model =
new AbstractDSOLModel.TimeDouble(simulator)
{
/** */
private static final long serialVersionUID = 1L;
@Override
public void constructModel() throws SimRuntimeException
{
// placeholder
}
@Override
public Serializable getSourceId()
{
return "model";
}
};
Replication.TimeDouble replication =
Replication.TimeDouble.create("rep1", 0.0, 0.0, 1000000.0, model);
simulator.initialize(replication, ReplicationMode.TERMINATING);
return simulator;
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
/**
* Test a Rendeable2D without an animator.
*/
@Test
public void testNoAnimator()
{
Locatable locatable = new LocatableAngle();
SimulatorInterface.TimeDouble simulator = createSimulator();
Renderable2D renderable = new Renderable2D(locatable, simulator)
{
/** */
private static final long serialVersionUID = 1L;
@Override
public void paint(final Graphics2D graphics, final ImageObserver observer)
{
// placeholder
}
};
assertEquals(locatable, renderable.getSource());
assertEquals(0, renderable.getId()); // 0 means not incremented and not bound
}
}