package maps.convert.legacy2gml;
import maps.legacy.LegacyBuilding;
import maps.gml.GMLMap;
import maps.gml.GMLBuilding;
import maps.gml.GMLRoad;
import maps.gml.GMLNode;
import maps.gml.GMLDirectedEdge;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.Collection;
import java.util.HashSet;
import rescuecore2.misc.geometry.Point2D;
import rescuecore2.misc.geometry.Line2D;
import rescuecore2.misc.geometry.GeometryTools2D;
import rescuecore2.misc.geometry.Vector2D;
import rescuecore2.misc.Pair;
import rescuecore2.log.Logger;
/**
Container for building information during conversion.
*/
public class BuildingInfo {
/**
* Width of a generated entrance road.
*/
public static final int ENTRANCE_SIZE = 3000;
private Point2D roadLeft;
private Point2D roadRight;
private LegacyBuilding building;
private List<GMLNode> apexes;
/**
Construct a BuildingInfo object.
@param b The LegacyBuilding to store info about.
*/
public BuildingInfo(LegacyBuilding b) {
building = b;
}
/**
Set the left corner at the road end.
@param newRoadLeft The new head-left corner.
*/
public void setRoadLeft(Point2D newRoadLeft) {
roadLeft = newRoadLeft;
}
/**
Set the right corner at the road end.
@param newRoadRight The new head-right corner.
*/
public void setRoadRight(Point2D newRoadRight) {
roadRight = newRoadRight;
}
/**
Process the building and create a GMLBuilding.
@param gml The GML map.
@param nodeInfo Information about the legacy nodes.
@param roadInfo Information about the legacy roads.
*/
public void process(GMLMap gml, Map<Integer, NodeInfo> nodeInfo, Map<Integer, RoadInfo> roadInfo) {
apexes = new ArrayList<GMLNode>();
int[] coords = building.getApexes();
for (int i = 0; i < coords.length; i += 2) {
int x = coords[i];
int y = coords[i + 1];
GMLNode node = gml.createNode(x, y);
apexes.add(node);
}
GMLBuilding b = gml.createBuildingFromNodes(apexes);
b.setFloors(building.getFloors());
b.setCode(building.getCode());
// Create an entrance
// Logger.debug("Creating entrance for " + building);
if (building.getEntrances().length == 0) {
return;
}
Point2D entrancePoint = nodeInfo.get(building.getEntrances()[0]).getLocation();
Point2D centre = new Point2D(building.getX(), building.getY());
Line2D centreLine = new Line2D(centre, entrancePoint);
Vector2D centreVector = centreLine.getDirection();
Vector2D leftVector = centreVector.getNormal().normalised().scale(ENTRANCE_SIZE / 2.0);
Vector2D rightVector = leftVector.scale(-1);
Line2D left = new Line2D(centre.plus(leftVector), centreVector);
Line2D right = new Line2D(centre.plus(rightVector), centreVector);
// Logger.debug("Entrance point: " + entrancePoint);
// Logger.debug("Building centre: " + centre);
// Logger.debug("Left line: " + left);
// Logger.debug("Right line: " + right);
Pair<Line2D, GMLDirectedEdge> leftEntrance = getEntrancePoint(left, centreLine, b.getEdges(), true, true);
if (leftEntrance == null) {
Logger.warn(b + ": Left entrance line does not intersect any walls");
return;
}
GMLNode leftNode = gml.createNode(leftEntrance.first().getOrigin().getX(), leftEntrance.first().getOrigin().getY());
// Logger.debug("New left node: " + leftNode);
gml.splitEdge(leftEntrance.second().getEdge(), leftNode);
Pair<Line2D, GMLDirectedEdge> rightEntrance = getEntrancePoint(right, centreLine, b.getEdges(), false, true);
if (rightEntrance == null) {
Logger.warn(b + ": Right entrance line does not intersect any walls");
return;
}
GMLNode rightNode = gml.createNode(rightEntrance.first().getOrigin().getX(), rightEntrance.first().getOrigin().getY());
// Logger.debug("New right node: " + rightNode);
gml.splitEdge(rightEntrance.second().getEdge(), rightNode);
gml.removeEdge(leftEntrance.second().getEdge());
gml.removeEdge(rightEntrance.second().getEdge());
// Now create the new road segment
// Pair<Line2D, GMLDirectedEdge> leftRoad = getEntrancePoint(left, centreLine, getAllRoadEdges(nodeInfo.values(), roadInfo.values()), true, false);
// if (leftRoad == null) {
// Logger.warn(b + ": Left entrance line does not intersect any roads");
// return;
// }
GMLNode roadLeftNode = gml.createNode(roadLeft.getX(), roadLeft.getY());
// Logger.debug("New road left node: " + roadLeftNode);
// gml.splitEdge(leftRoad.second().getEdge(), roadLeftNode);
// Pair<Line2D, GMLDirectedEdge> rightRoad = getEntrancePoint(right, centreLine, getAllRoadEdges(nodeInfo.values(), roadInfo.values()), false, false);
// if (rightRoad == null) {
// Logger.warn(b + ": Right entrance line does not intersect any roads");
// return;
// }
GMLNode roadRightNode = gml.createNode(roadRight.getX(), roadRight.getY());
// Logger.debug("New road left node: " + roadRightNode);
// gml.splitEdge(rightRoad.second().getEdge(), roadRightNode);
// Create the road
gml.createRoad(gml.apexesToEdges(roadLeftNode, roadRightNode, rightNode, leftNode));
}
/**
Trim a line to a set of walls and return the trimmed line and intersecting wall. Returns null if the line does not intersect any walls.
@param line The line to trim.
@param walls The walls to trim to.
@param trimStart True to trim the start of the line, false to trim the end.
*/
private Pair<Line2D, GMLDirectedEdge> trim(Line2D line, Collection<GMLDirectedEdge> walls, boolean trimStart) {
GMLDirectedEdge wall = null;
for (GMLDirectedEdge next : walls) {
Point2D p = GeometryTools2D.getSegmentIntersectionPoint(line, Tools.gmlDirectedEdgeToLine(next));
if (p != null) {
if (trimStart) {
line = new Line2D(p, line.getEndPoint());
}
else {
line = new Line2D(line.getOrigin(), p);
}
wall = next;
}
}
if (wall == null) {
return null;
}
return new Pair<Line2D, GMLDirectedEdge>(line, wall);
}
private Pair<Line2D, GMLDirectedEdge> getEntrancePoint(Line2D line, Line2D centre, Collection<GMLDirectedEdge> walls, boolean left, boolean trimStart) {
Pair<Line2D, GMLDirectedEdge> trimmed = trim(line, walls, trimStart);
if (trimmed == null) {
// Entrance line does not intersect with the building outline. Snap it back to the endpoint of the wall the centre line intersects with.
trimmed = trim(centre, walls, trimStart);
if (trimmed == null) {
// Entrance does not intersect with any walls!
return null;
}
GMLDirectedEdge wall = trimmed.second();
Line2D wallLine = Tools.gmlDirectedEdgeToLine(wall);
Vector2D centreNormal = centre.getDirection().getNormal().normalised();
if (!left) {
centreNormal = centreNormal.scale(-1);
}
Vector2D wallDirection = wallLine.getDirection().normalised();
Point2D end;
if (wallDirection.dot(centreNormal) > 0) {
// Same direction: end point is the end of the wall
end = wallLine.getEndPoint();
}
else {
// Opposite directions: end point is the start of the wall
end = wallLine.getOrigin();
}
return new Pair<Line2D, GMLDirectedEdge>(new Line2D(end, line.getEndPoint()), wall);
}
else {
return trimmed;
}
}
private Collection<GMLDirectedEdge> getAllRoadEdges(Collection<NodeInfo> nodes, Collection<RoadInfo> roads) {
Collection<GMLDirectedEdge> all = new HashSet<GMLDirectedEdge>();
for (NodeInfo next : nodes) {
GMLRoad r = next.getRoad();
if (r != null) {
all.addAll(r.getEdges());
}
}
for (RoadInfo next : roads) {
all.addAll(next.getRoad().getEdges());
}
return all;
}
}