package iamrescue.routing.costs;
import iamrescue.belief.IAMWorldModel;
import iamrescue.belief.entities.BlockInfoRoad;
import iamrescue.belief.entities.RoutingInfoBlockade;
import iamrescue.util.PositionXY;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javolution.util.FastMap;
import javolution.util.FastSet;
import rescuecore2.config.Config;
import rescuecore2.misc.geometry.Line2D;
import rescuecore2.misc.geometry.Point2D;
import rescuecore2.standard.entities.Area;
import rescuecore2.standard.entities.Blockade;
import rescuecore2.standard.entities.Building;
import rescuecore2.worldmodel.EntityID;
public class ClearingCostFunction extends AbstractRoutingCostFunction {
private IAMWorldModel worldModel;
private double clearRate;
private Set<EntityID> ignored;
private Map<EntityID, Integer> alreadyClearing;
private double defaultCostPerMetre = 0.2;
public ClearingCostFunction(IAMWorldModel worldModel, Config config) {
this.worldModel = worldModel;
// clearRate = config.getIntValue("misc.clear.rate");
clearRate = config.getIntValue("clear.repair.rate");
ignored = new FastSet<EntityID>();
alreadyClearing = new FastMap<EntityID, Integer>();
}
public void addIgnored(EntityID id) {
this.ignored.add(id);
}
/**
* @param defaultCost
* the defaultCost to set
*/
public void setDefaultCostPerMetre(double defaultCost) {
this.defaultCostPerMetre = defaultCost;
}
public void addAlreadyClearing(EntityID id) {
Integer integer = alreadyClearing.get(id);
if (integer == null) {
alreadyClearing.put(id, 1);
} else {
alreadyClearing.put(id, integer + 1);
}
}
public void setAlreadyClearing(EntityID id, int already) {
if (already == 0) {
alreadyClearing.remove(id);
} else {
alreadyClearing.put(id, already);
}
}
public int getAlreadyClearing(EntityID id) {
Integer already = alreadyClearing.get(id);
if (already == null) {
return 0;
} else {
return already;
}
}
public void clearIgnored() {
this.ignored.clear();
}
public void removeIgnored(EntityID id) {
this.ignored.remove(id);
}
@Override
public double getTravelCost(Area area, PositionXY from, PositionXY to) {
if (ignored.size() > 0 && ignored.contains(area.getID())) {
return 0;
}
if (area instanceof Building) {
return 0;
}
double cost = 0;
if (area.isBlockadesDefined()) {
Line2D path = new Line2D(from.toPoint2D(), to.toPoint2D());
List<EntityID> blockades = area.getBlockades();
for (EntityID id : blockades) {
if (ignored.size() > 0 && ignored.contains(id)) {
continue;
}
Blockade blockade = (Blockade) worldModel.getEntity(id);
if (blockade == null) {
continue;
}
double thisClearCost = 0;
if (blockade.isRepairCostDefined()) {
if (blockade instanceof RoutingInfoBlockade
&& BlockCheckerUtil
.shouldPreferCommunicatedBlocked(blockade,
worldModel)) {
if (BlockCheckerUtil.checkIfCommunicatedBlocked(
(RoutingInfoBlockade) blockade, worldModel
.getDefaultConverter(), from, to)) {
thisClearCost = (int) (blockade.getRepairCost() / clearRate);
}
} else if (blockade.isApexesDefined()) {
int[] apexes = blockade.getApexes();
for (int i = 0; i < apexes.length; i = i + 2) {
Line2D edge = new Line2D(new Point2D(apexes[i],
apexes[i + 1]), new Point2D(apexes[(i + 2)
% apexes.length], apexes[(i + 3)
% apexes.length]));
double intersection1 = edge.getIntersection(path);
if (intersection1 >= 0 && intersection1 <= 1) {
double intersection2 = path
.getIntersection(edge);
if (intersection2 >= 0 && intersection2 <= 1) {
thisClearCost = (int) (blockade
.getRepairCost() / clearRate);
break;
}
}
}
}
}
if (alreadyClearing.size() > 0) {
Integer alreadyClearingBlock = alreadyClearing.get(blockade
.getID());
if (alreadyClearingBlock != null) {
thisClearCost = thisClearCost
/ (alreadyClearingBlock + 1.0);
}
}
// ceil is expensive, so bit of a hack here.
cost += (int) (thisClearCost + 0.999999);
}
} else {
if (area instanceof BlockInfoRoad) {
BlockInfoRoad road = (BlockInfoRoad) area;
if (road.isHasBeenPassedDefined() && road.hasBeenPassed()) {
cost = 0;
} else {
cost = defaultCostPerMetre * from.distanceTo(to) / 1000.0;
}
} else {
cost = defaultCostPerMetre * from.distanceTo(to) / 1000.0;
}
}
// Already clearing?
if (alreadyClearing.size() > 0) {
Integer already = alreadyClearing.get(area.getID());
if (already != null) {
cost = cost / (already + 1);
}
}
return cost;
}
}