package trafficdefinition;
import classes.Pair;
import classes.Project;
import classes.TypeSelection;
import enums.MotionRestriction;
import helpers.RandomNumberProvider;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import shapes.AreaExt;
import shapes.Rectangle2DExt;
import simulation.JobType;
import tdl.XMLHelpers;
/**
* @author PapaleonLe01
*/
public class TrafficArea extends TrafficDefinitionElement implements Serializable {
private static final long serialVersionUID = 1L;
/**
* The area's color.
*/
private Color color = new Color((float) Math.random(), (float) Math.random(), (float) Math.random());
/**
* The area's population
*/
private int population = 0;
/**
* The jobs of the people living in this area
* @uml.property name="residentsJobSelection"
* @uml.associationEnd
*/
private TypeSelection<JobType> residentsJobSelection;
/**
* The shape defining the area
*/
private AreaExt shape;
/**
* The jobs of the people working in this area
* @uml.property name="workersJobSelection"
* @uml.associationEnd
*/
private TypeSelection<JobType> workersJobSelection;
/**
* The total number of work positions
*/
private int workPositions = 0;
/**
* The average adults per house
*/
float averageAdultsPerHouse = 3f;
/**
* The average children per house
*/
float averageChildrenPerHouse = 2f;
/**
* The possibility that an adult is has a job
*/
float possibilityAdultHasJob = 0.98f;
/**
* The possibility that an adult is a driver
*/
float possibilityAdultIsDriver = 0.8f;
/**
* The possibility that a driver has a car
*/
float possibilityDriverHasCar = 0.8f;
/**
* Class constructor.
*
* @param area
*/
public TrafficArea(Shape area) {
super();
name = "Area " + String.valueOf(increment++);
shape = new AreaExt(area);
List<Handle> handles = new ArrayList<Handle>();
handles.add(new Handle(new Point2D.Double(area.getBounds2D().getCenterX(), area.getBounds2D().getCenterY()), "location", MotionRestriction.None));
addHandles(handles);
// Add the default job type to the area's residents job selection
residentsJobSelection = new TypeSelection<JobType>();
residentsJobSelection.add(new Pair<JobType, Float>(Project.getCurrentlyLoadedProject().getDefaultJobType(), 1.f));
// Add the default job type to the area's worker job selection
workersJobSelection = new TypeSelection<JobType>();
workersJobSelection.add(new Pair<JobType, Float>(Project.getCurrentlyLoadedProject().getDefaultJobType(), 1.f));
// Set the default value to true to export the area shape to SUMO
exportPolygon = true;
}
/**
* Class constructor that creates a new traffic area as a copy of the
* specified traffic area
*
* @param source
*/
public TrafficArea(TrafficArea source) {
super(source);
color = new Color(source.color.getRGB());
population = source.population;
workPositions = source.workPositions;
shape = new AreaExt(source.shape);
}
public Rectangle2DExt getBounds() {
return new Rectangle2DExt((Rectangle2D.Double)shape.getBounds2D());
}
@Override
public void Draw(Graphics2D g, double zoomFactor, boolean isDeleted, boolean isSelected) {
// Save the previous color to restore it later
Color prev = g.getColor();
if (!isSelected) {
g.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), 100));
}
if (isSelected) {
g.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), 200));
}
if (shape != null) {
g.fill(shape);
}
super.Draw(g, zoomFactor, isDeleted, isSelected);
g.setColor(prev);
}
@Override
public TrafficDefinitionElement elementClone() {
return new TrafficArea(this);
}
/**
* @return the averageAdultsPerHouse
* @uml.property name="averageAdultsPerHouse"
*/
public float getAverageAdultsPerHouse() {
return averageAdultsPerHouse;
}
/**
* @return the averageChildrenPerHouse
* @uml.property name="averageChildrenPerHouse"
*/
public float getAverageChildrenPerHouse() {
return averageChildrenPerHouse;
}
/**
* @return the color
* @uml.property name="color"
*/
public Color getColor() {
return color;
}
/**
* @return the population
* @uml.property name="population"
*/
public int getPopulation() {
return population;
}
/**
* @return the possibilityAdultHasJob
* @uml.property name="possibilityAdultHasJob"
*/
public float getPossibilityAdultHasJob() {
return possibilityAdultHasJob;
}
/**
* @return the possibilityAdultIsDriver
* @uml.property name="possibilityAdultIsDriver"
*/
public float getPossibilityAdultIsDriver() {
return possibilityAdultIsDriver;
}
/**
* @return the possibilityDriverHasCar
* @uml.property name="possibilityDriverHasCar"
*/
public float getPossibilityDriverHasCar() {
return possibilityDriverHasCar;
}
/**
* Returns a random point that is located inside the area
*
* @return
*/
public Point2D.Double getRandomPointInArea() {
Point2D.Double result = null;
Random r = RandomNumberProvider.getRandom();
do {
// Get the area's bounds
double areaWidth = shape.getBounds2D().getMaxX() - shape.getBounds2D().getMinX();
double areaHeight = shape.getBounds2D().getMaxY() - shape.getBounds2D().getMinY();
// Get a random point inside the traffic area's bounds
double x = r.nextDouble() * areaWidth + shape.getBounds2D().getMinX();
double y = r.nextDouble() * areaHeight + shape.getBounds2D().getMinY();
result = new Point2D.Double(x, y);
// If the point lies within the area
if (shape.contains(result)) {
return result;
}
} while (true);
}
/**
* @return the residentsJobSelection
* @uml.property name="residentsJobSelection"
*/
public TypeSelection<JobType> getResidentsJobSelection() {
return residentsJobSelection;
}
/**
* @return the shape
* @uml.property name="shape"
*/
public AreaExt getShape() {
return shape;
}
@Override
public String getToolTip() {
return "<html>" + "<b>Area: </b> " + name + "<br>" + "<b>Population:</b> " + population + "<br>" + "<b>Work positions:</b> " + workPositions + "</html>";
}
/**
* @return the workersJobSelection
* @uml.property name="workersJobSelection"
*/
public TypeSelection<JobType> getWorkersJobSelection() {
return workersJobSelection;
}
/**
* @return the workPositions
* @uml.property name="workPositions"
*/
public int getWorkPositions() {
return workPositions;
}
public void handleLocationChanged(Handle h) {
if (h.getName().equals("location")) {
Point2D.Double previousCenter = new Point2D.Double(shape.getBounds2D().getCenterX(), shape.getBounds2D().getCenterY());
double x = h.getLocation().x - previousCenter.x;
double y = h.getLocation().y - previousCenter.y;
AffineTransform tx = new AffineTransform();
tx.translate(x, y);
shape.transform(tx);
}
}
@Override
public boolean Hit(Point p) {
return shape.contains(p);
}
@Override
public boolean Hit(Rectangle r) {
return shape.intersects(r);
}
/**
* @param averageAdultsPerHouse the averageAdultsPerHouse to set
* @uml.property name="averageAdultsPerHouse"
*/
public void setAverageAdultsPerHouse(float averageAdultsPerHouse) {
this.averageAdultsPerHouse = averageAdultsPerHouse;
}
/**
* @param averageChildrenPerHouse the averageChildrenPerHouse to set
* @uml.property name="averageChildrenPerHouse"
*/
public void setAverageChildrenPerHouse(float averageChildrenPerHouse) {
this.averageChildrenPerHouse = averageChildrenPerHouse;
}
/**
* @param color the color to set
* @uml.property name="color"
*/
public void setColor(Color color) {
this.color = color;
}
/**
* @param population the population to set
* @uml.property name="population"
*/
public void setPopulation(int population) {
this.population = population;
}
/**
* @param possibilityAdultHasJob the possibilityAdultHasJob to set
* @uml.property name="possibilityAdultHasJob"
*/
public void setPossibilityAdultHasJob(float possibilityAdultHasJob) {
this.possibilityAdultHasJob = possibilityAdultHasJob;
}
/**
* @param possibilityAdultIsDriver the possibilityAdultIsDriver to set
* @uml.property name="possibilityAdultIsDriver"
*/
public void setPossibilityAdultIsDriver(float possibilityAdultIsDriver) {
this.possibilityAdultIsDriver = possibilityAdultIsDriver;
}
/**
* @param possibilityDriverHasCar the possibilityDriverHasCar to set
* @uml.property name="possibilityDriverHasCar"
*/
public void setPossibilityDriverHasCar(float possibilityDriverHasCar) {
this.possibilityDriverHasCar = possibilityDriverHasCar;
}
/**
* @param residentsJobSelection the residentsJobSelection to set
* @uml.property name="residentsJobSelection"
*/
public void setResidentsJobSelection(TypeSelection<JobType> residentsJobSelection) {
this.residentsJobSelection = residentsJobSelection;
}
/**
* @param workersJobSelection the workersJobSelection to set
* @uml.property name="workersJobSelection"
*/
public void setWorkersJobSelection(TypeSelection<JobType> workersJobSelection) {
this.workersJobSelection = workersJobSelection;
}
/**
* @param workPositions the workPositions to set
* @uml.property name="workPositions"
*/
public void setWorkPositions(int workPositions) {
this.workPositions = workPositions;
}
/* (non-Javadoc)
* @see trafficdefinition.TrafficDefinitionElement#getGeometryXML()
*/
@Override
public String getGeometryXML() {
StringBuilder polyBuilder = new StringBuilder();
String colorString = new Float(color.getRed() / 255f).toString() + "," + new Float(color.getGreen() / 255f).toString() + "," + new Float(color.getBlue() / 255f).toString();
polyBuilder.append("<poly id=\"" + "Traffic Area " + name + "\" type=\"Traffic Area\" color=\""+colorString+"\" fill=\"true\" layer=\"-3\">");
polyBuilder.append(XMLHelpers.shapeToXML(shape));
polyBuilder.append("</poly>\n");
return polyBuilder.toString();
}
@Override
public String toXML() {
StringBuilder sb=new StringBuilder();
sb.append("<trafficArea name=\""+name+"\" possibilityAdultIsDriver=\""+String.valueOf(possibilityAdultIsDriver)+"\" possibilityDriverHasCar=\""+String.valueOf(possibilityDriverHasCar)+"\" workingPositions=\""+String.valueOf(workPositions)+"\" possibilityAdultHasJob=\""+String.valueOf(possibilityAdultHasJob)+"\" averageChildrenPerHouse=\""+String.valueOf(averageChildrenPerHouse)+"\" population=\""+String.valueOf(population)+"\" averageAdultsPerHouse=\""+String.valueOf(averageAdultsPerHouse)+"\">\n");
sb.append(tdl.XMLHelpers.jobSelectionToXML("residentsJobSelection", residentsJobSelection));
sb.append(tdl.XMLHelpers.jobSelectionToXML("workersJobSelection", workersJobSelection));
sb.append("<shape>");
sb.append(tdl.XMLHelpers.shapeToXML(shape));
sb.append("</shape>\n");
sb.append("</trafficArea>\n");
return sb.toString();
}
}