package aima.gui.swing.applications.robotics.simple;
import aima.core.robotics.IMclRobot;
import aima.core.robotics.impl.datatypes.AbstractRangeReading;
import aima.core.robotics.impl.datatypes.Angle;
import aima.core.robotics.impl.map.MclCartesianPlot2D;
import aima.core.util.math.geom.shapes.Vector2D;
/**
* This class implements functionality for a robot in a virtual environment.<br/>
* It implements {@link IMclRobot}.
*
* @author Arno von Borries
* @author Jan Phillip Kretzschmar
* @author Andreas Walscheid
*
*/
public final class VirtualRobot implements IMclRobot<Angle,SimpleMove,AbstractRangeReading> {
private double maxMoveDistance;
private double minMoveDistance;
private Angle[] rangeReadingAngles;
private MclCartesianPlot2D<SimplePose,SimpleMove,AbstractRangeReading> map;
private SimplePose pose;
/**
* @param map the virtual environment in which the robot "moves" and performs range readings.
*/
public VirtualRobot(MclCartesianPlot2D<SimplePose, SimpleMove, AbstractRangeReading> map) {
this.map = map;
}
/**
* Set the angles at which range readings will be performed.
* @param angles the array of angles to read ranges at.
*/
public void setRangeReadingAngles(Angle[] angles) {
this.rangeReadingAngles = angles;
}
/**
* Sets the maximum distance that the robot moves in one move.
* @param distance the distance that the robot should move at max.
*/
public void setMaxMoveDistance(double distance) {
this.maxMoveDistance = distance;
}
/**
* Sets the minimum distance that the robot moves in one move.
* @param distance the distance that the robot should move at least.
*/
public void setMinMoveDistance(double distance) {
this.minMoveDistance = distance;
}
/**
* Moves the robot to a new random position on the map.
*/
public void setRandomPose() {
pose = map.randomPose();
}
/**
* Gets the current pose of the robot.
* @return the current pose of the robot.
*/
public SimplePose getPose() {
return pose;
}
@Override
public AbstractRangeReading[] getRangeReadings() {
AbstractRangeReading[] ranges = new SimpleRangeReading[rangeReadingAngles.length];
for(int i=0; i<rangeReadingAngles.length;i++) {
SimplePose rangePose = pose.addAngle(rangeReadingAngles[i]);
ranges[i] = map.rayCast(rangePose);
ranges[i] = new SimpleRangeReading(ranges[i].getValue(), rangeReadingAngles[i]);
}
return ranges;
}
/**
* Lets the robot perform a move.<br/>
* As it is hard for a virtual robot to see which of its movements is valid without additional functionality in the map class,<br/>
* a randomly new pose on the map is selected. The rotation and the vector to the pose form the move.
*/
@Override
public SimpleMove performMove() {
SimplePose newPose;
Vector2D vector;
do {
newPose = map.randomPose();
vector = pose.getPosition().vec(newPose.getPosition());
} while(vector.length() > maxMoveDistance || vector.length() < minMoveDistance);
final double vectorAngle = vector.angleTo(Vector2D.X_VECTOR);
final double firstRotation = vectorAngle - pose.getHeading();
final double lastRotation = newPose.getHeading() - vectorAngle;
pose = newPose;
return new SimpleMove(firstRotation,vector.length(),lastRotation);
}
}