Unverified Commit 342fea6f authored by Juon Kawakami's avatar Juon Kawakami 🥗
Browse files

init

parent 54f6cedf
package maps.gml.editor;
import javax.swing.JOptionPane;
import java.util.Queue;
import java.util.LinkedList;
import java.util.Collection;
import java.util.HashSet;
import maps.gml.GMLNode;
import maps.gml.GMLEdge;
import maps.gml.GMLTools;
import rescuecore2.log.Logger;
import rescuecore2.misc.geometry.Point2D;
import rescuecore2.misc.geometry.Line2D;
import rescuecore2.misc.geometry.GeometryTools2D;
/**
A function for splitting edges that cover nearby nodes.
*/
public class SplitEdgesFunction extends ProgressFunction {
private static final double DEFAULT_THRESHOLD = 0.001;
private double threshold;
/**
Construct a SplitEdgesFunction.
@param editor The editor instance.
*/
public SplitEdgesFunction(GMLEditor editor) {
super(editor);
}
@Override
public String getName() {
return "Split edges";
}
@Override
public void execute() {
String s = JOptionPane.showInputDialog(editor.getViewer(), "Enter the desired distance threshold (in m)", DEFAULT_THRESHOLD);
if (s == null) {
return;
}
threshold = Double.parseDouble(s);
super.execute();
}
@Override
protected String getTitle() {
return "Splitting edges";
}
@Override
protected void executeImpl() {
// Go through all edges and split any that cover nearby nodes
final Queue<GMLEdge> remaining = new LinkedList<GMLEdge>();
final Collection<GMLNode> nodes = new HashSet<GMLNode>();
synchronized (editor.getMap()) {
remaining.addAll(editor.getMap().getEdges());
nodes.addAll(editor.getMap().getNodes());
}
setProgressLimit(remaining.size());
int count = 0;
while (!remaining.isEmpty()) {
GMLEdge next = remaining.remove();
Line2D line = GMLTools.toLine(next);
// Look for nodes that are close to the line
for (GMLNode node : nodes) {
if (node == next.getStart() || node == next.getEnd()) {
continue;
}
Point2D p = GMLTools.toPoint(node);
Point2D closest = GeometryTools2D.getClosestPointOnSegment(line, p);
if (GeometryTools2D.getDistance(p, closest) < threshold) {
// Split the edge
Collection<GMLEdge> newEdges;
synchronized (editor.getMap()) {
newEdges = editor.getMap().splitEdge(next, node);
editor.getMap().removeEdge(next);
newEdges.removeAll(editor.getMap().getEdges());
}
remaining.addAll(newEdges);
bumpMaxProgress(newEdges.size());
++count;
break;
}
}
bumpProgress();
}
if (count != 0) {
editor.setChanged();
editor.getViewer().repaint();
}
Logger.debug("Split " + count + " edges");
}
}
\ No newline at end of file
package maps.gml.editor;
import java.awt.Color;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import javax.swing.undo.AbstractUndoableEdit;
import maps.gml.GMLBuilding;
import maps.gml.GMLCoordinates;
import maps.gml.GMLEdge;
import maps.gml.GMLNode;
import maps.gml.GMLRoad;
import maps.gml.GMLShape;
import maps.gml.GMLSpace;
import maps.gml.view.LineOverlay;
import maps.gml.view.NodeDecorator;
import maps.gml.view.SquareNodeDecorator;
import rescuecore2.log.Logger;
import rescuecore2.misc.Pair;
import rescuecore2.misc.geometry.GeometryTools2D;
import rescuecore2.misc.geometry.Point2D;
/**
* A tool for creating edges.
*/
public class SplitShapeTool extends AbstractTool {
private static final Color HIGHLIGHT_COLOUR = Color.BLUE;
private static final int HIGHLIGHT_SIZE = 6;
private static final double THRESHOLD = 0.001;
private Listener listener;
private NodeDecorator nodeHighlight;
private LineOverlay overlay;
private GMLNode hover;
private GMLNode start;
private GMLNode end;
// private GMLEdge edge;
/**
* Construct a CreateEdgeTool.
*
* @param editor
* The editor instance.
*/
public SplitShapeTool( GMLEditor editor ) {
super( editor );
listener = new Listener();
nodeHighlight = new SquareNodeDecorator( HIGHLIGHT_COLOUR, HIGHLIGHT_SIZE );
overlay = new LineOverlay( HIGHLIGHT_COLOUR, true );
}
@Override
public String getName() {
return "Split shape";
}
@Override
public void activate() {
editor.getViewer().addMouseListener( listener );
editor.getViewer().addMouseMotionListener( listener );
editor.getViewer().addOverlay( overlay );
hover = null;
start = null;
end = null;
// edge = null;
}
@Override
public void deactivate() {
editor.getViewer().removeMouseListener( listener );
editor.getViewer().removeMouseMotionListener( listener );
editor.getViewer().clearAllNodeDecorators();
editor.getViewer().removeOverlay( overlay );
editor.getViewer().repaint();
}
private void setHover( GMLNode node ) {
if ( hover == node ) {
return;
}
if ( hover != null ) {
editor.getViewer().clearNodeDecorator( hover );
}
hover = node;
if ( hover != null ) {
editor.getViewer().setNodeDecorator( nodeHighlight, hover );
}
editor.getViewer().repaint();
}
private void setStart( GMLNode node ) {
if ( start == node ) {
return;
}
if ( start != null ) {
editor.getViewer().clearNodeDecorator( start );
}
start = node;
if ( start != null ) {
editor.getViewer().setNodeDecorator( nodeHighlight, start );
}
editor.getViewer().repaint();
}
private void setEnd( GMLNode node ) {
if ( start == node || end == node ) {
return;
}
if ( end != null ) {
editor.getViewer().clearNodeDecorator( end );
}
end = node;
if ( end != null ) {
editor.getViewer().setNodeDecorator( nodeHighlight, end );
}
editor.getViewer().repaint();
}
private class Listener implements MouseListener, MouseMotionListener {
@Override
public void mousePressed( MouseEvent e ) {
if ( e.getButton() == MouseEvent.BUTTON1 ) {
Point p = fixEventPoint( e.getPoint() );
GMLCoordinates c = editor.getViewer().getCoordinatesAtPoint( p.x, p.y );
GMLNode node = editor.getMap().findNearestNode( c.getX(), c.getY() );
overlay.setStart( new Point2D( node.getX(), node.getY() ) );
setStart( node );
setHover( null );
}
}
@Override
public void mouseReleased( MouseEvent e ) {
if ( e.getButton() == MouseEvent.BUTTON1 ) {
if ( start != null && end != null ) {
SplitShapeEdit edit = splitByEdge();
editor.setChanged();
if ( edit != null ) {
editor.addEdit( edit );
}
editor.getViewer().clearAllNodeDecorators();
overlay.setStart( null );
overlay.setEnd( null );
editor.getViewer().repaint();
start = null;
end = null;
hover = null;
}
}
}
private SplitShapeEdit splitByEdge() {
Collection<GMLShape> add = new ArrayList<GMLShape>();
Collection<GMLShape> delete = new ArrayList<GMLShape>();
GMLEdge edge = editor.getMap().createEdge( start, end );
Collection<GMLEdge> startEdges = editor.getMap()
.getAttachedEdges( start );
Collection<GMLEdge> endEdges = editor.getMap().getAttachedEdges( end );
Collection<GMLShape> startShapes = new HashSet<GMLShape>();
Collection<GMLShape> endShapes = new HashSet<GMLShape>();
for ( GMLEdge next : startEdges ) {
startShapes.addAll( editor.getMap().getAttachedShapes( next ) );
}
for ( GMLEdge next : endEdges ) {
endShapes.addAll( editor.getMap().getAttachedShapes( next ) );
}
for ( GMLShape shape : startShapes ) {
if ( endShapes.contains( shape ) ) {
Pair<GMLShape, GMLShape> split = splitShape( shape, edge );
if ( split != null ) {
add.add( split.first() );
add.add( split.second() );
delete.add( shape );
}
}
}
if ( !add.isEmpty() ) {
edge.setPassable( true );
return new SplitShapeEdit( edge, add, delete );
} else {
editor.getMap().remove( edge );
return null;
}
}
private Pair<GMLShape, GMLShape> splitShape( GMLShape shape,
GMLEdge edge ) {
List<GMLNode> nodes1 = new ArrayList<GMLNode>();
List<GMLNode> nodes2 = new ArrayList<GMLNode>();
boolean first = true;
for ( GMLNode n : shape.getUnderlyingNodes() ) {
if ( n == edge.getStart() || n == edge.getEnd() ) {
first = !first;
nodes1.add( n );
nodes2.add( n );
} else if ( first ) {
nodes1.add( n );
} else {
nodes2.add( n );
}
}
if ( nodes1.size() <= 2 || nodes2.size() <= 2 ) {
return null;
}
// Check if we really split an interior edge
double oldArea = area( shape.getUnderlyingNodes() );
double area1 = area( nodes1 );
double area2 = area( nodes2 );
if ( area1 + area2 > oldArea + THRESHOLD ) {
return null;
}
GMLShape s1 = null;
GMLShape s2 = null;
if ( shape instanceof GMLBuilding ) {
GMLBuilding b = (GMLBuilding) shape;
GMLBuilding b1 = editor.getMap().createBuildingFromNodes( nodes1 );
GMLBuilding b2 = editor.getMap().createBuildingFromNodes( nodes2 );
b1.setCode( b.getCode() );
b2.setCode( b.getCode() );
b1.setFloors( b.getFloors() );
b2.setFloors( b.getFloors() );
b1.setImportance( b.getImportance() );
b2.setImportance( b.getImportance() );
b1.setCapacity( b.getCapacity() );
b2.setCapacity( b.getCapacity() );
s1 = b1;
s2 = b2;
} else if ( shape instanceof GMLRoad ) {
// GMLBuilding b = (GMLBuilding) shape;
s1 = editor.getMap().createRoadFromNodes( nodes1 );
s2 = editor.getMap().createRoadFromNodes( nodes2 );
} else if ( shape instanceof GMLSpace ) {
// GMLBuilding b = (GMLBuilding) shape;
s1 = editor.getMap().createSpaceFromNodes( nodes1 );
s2 = editor.getMap().createSpaceFromNodes( nodes2 );
} else {
throw new IllegalArgumentException(
"Shape is not a building, road or space" );
}
editor.getMap().remove( shape );
return new Pair<GMLShape, GMLShape>( s1, s2 );
}
private double area( List<GMLNode> nodes ) {
List<Point2D> vertices = new ArrayList<Point2D>();
for ( GMLNode n : nodes ) {
vertices.add( new Point2D( n.getX(), n.getY() ) );
}
return GeometryTools2D.computeArea( vertices );
}
@Override
public void mouseDragged( MouseEvent e ) {
if ( start != null ) {
Point p = fixEventPoint( e.getPoint() );
GMLCoordinates c = editor.getViewer().getCoordinatesAtPoint( p.x, p.y );
GMLNode node = editor.getMap().findNearestNode( c.getX(), c.getY() );
overlay.setEnd( new Point2D( node.getX(), node.getY() ) );
setEnd( node );
}
}
@Override
public void mouseMoved( MouseEvent e ) {
Point p = fixEventPoint( e.getPoint() );
GMLCoordinates c = editor
.snap( editor.getViewer().getCoordinatesAtPoint( p.x, p.y ) );
GMLNode node = editor.getMap().findNearestNode( c.getX(), c.getY() );
setHover( node );
}
@Override
public void mouseClicked( MouseEvent e ) {
}
@Override
public void mouseEntered( MouseEvent e ) {
}
@Override
public void mouseExited( MouseEvent e ) {
}
private Point fixEventPoint( Point p ) {
Insets insets = editor.getViewer().getInsets();
return new Point( p.x - insets.left, p.y - insets.top );
}
}
private class SplitShapeEdit extends AbstractUndoableEdit {
private Collection<GMLShape> add;
private Collection<GMLShape> remove;
private GMLEdge edge;
public SplitShapeEdit( GMLEdge edge, Collection<GMLShape> add, Collection<GMLShape> remove ) {
this.edge = edge;
this.add = add;
this.remove = remove;
}
@Override
public void undo() {
super.undo();
editor.getMap().removeEdge( edge );
editor.getMap().remove( add );
editor.getMap().add( remove );
editor.getViewer().repaint();
}
@Override
public void redo() {
super.redo();
editor.getMap().addEdge( edge );
for ( GMLShape r : remove ) {
Logger.debug( "remove: " + r.toString() );
}
for ( GMLShape r : add ) {
Logger.debug( "add: " + r.toString() );
}
editor.getMap().remove( remove );
editor.getMap().add( add );
editor.getViewer().repaint();
}
}
}
\ No newline at end of file
package maps.gml.editor;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.Color;
import java.awt.Point;
import java.awt.Insets;
import javax.swing.undo.AbstractUndoableEdit;
import java.util.Collection;
import java.util.Iterator;
import maps.gml.GMLEdge;
import maps.gml.GMLShape;
import maps.gml.GMLCoordinates;
import maps.gml.view.EdgeDecorator;
import maps.gml.view.LineEdgeDecorator;
/**
A tool for toggling the passable flag on edges.
*/
public class TogglePassableTool extends AbstractTool {
private static final Color HIGHLIGHT_COLOUR = Color.BLUE;
private Listener listener;
private EdgeDecorator highlight;
private GMLEdge selected;
/**
Construct a TogglePassableTool.
@param editor The editor instance.
*/
public TogglePassableTool(GMLEditor editor) {
super(editor);
highlight = new LineEdgeDecorator(HIGHLIGHT_COLOUR);
listener = new Listener();
}
@Override
public String getName() {
return "Toggle passable";
}
@Override
public void activate() {
editor.getViewer().addMouseListener(listener);
editor.getViewer().addMouseMotionListener(listener);
selected = null;
}
@Override
public void deactivate() {
editor.getViewer().removeMouseListener(listener);
editor.getViewer().removeMouseMotionListener(listener);
editor.getViewer().clearAllEdgeDecorators();
editor.getViewer().repaint();
}
private void highlight(GMLEdge edge) {
if (selected == edge) {
return;
}
if (selected != null) {
editor.getViewer().clearEdgeDecorator(selected);
}
selected = edge;
if (selected != null) {
editor.getViewer().setEdgeDecorator(highlight, selected);
}
editor.getViewer().repaint();
}
private void toggle() {
boolean isPassable = !selected.isPassable();
setPassable(selected, isPassable);
editor.addEdit(new ToggleEdit(selected, isPassable));
}
private void setPassable(GMLEdge edge, boolean passable) {
edge.setPassable(passable);
Collection<GMLShape> attached = editor.getMap().getAttachedShapes(edge);
Iterator<GMLShape> it = attached.iterator();
GMLShape first = it.next();
GMLShape second = it.next();
if (passable) {
first.setNeighbour(edge, second.getID());
second.setNeighbour(edge, first.getID());
}
else {
first.setNeighbour(edge, null);
second.setNeighbour(edge, null);
}
editor.setChanged();
editor.getViewer().repaint();
}
private class Listener implements MouseListener, MouseMotionListener {
@Override
public void mouseMoved(MouseEvent e) {
Point p = fixEventPoint(e.getPoint());
GMLCoordinates c = editor.getViewer().getCoordinatesAtPoint(p.x, p.y);
GMLEdge edge = editor.getMap().findNearestEdge(c.getX(), c.getY());
if (editor.getMap().getAttachedShapes(edge).size() == 2) {
highlight(edge);
}
}
@Override
public void mouseClicked(MouseEvent e) {
if (selected == null) {
return;
}
if (e.getButton() == MouseEvent.BUTTON1) {
toggle();
highlight(null);
}
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseDragged(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
private Point fixEventPoint(Point p) {
Insets insets = editor.getViewer().getInsets();
return new Point(p.x - insets.left, p.y - insets.top);
}
}
private class ToggleEdit extends AbstractUndoableEdit {
private GMLEdge edge;
private boolean newPassable;
public ToggleEdit(GMLEdge edge, boolean newPassable) {
this.edge = edge;
this.newPassable = newPassable;
}
@Override
public void undo() {
super.undo();
setPassable(edge, !newPassable);
editor.getViewer().repaint();
}
@Override
public void redo() {
super.redo();
setPassable(edge, newPassable);
editor.getViewer().repaint();
}
}
}
\ No newline at end of file
package maps.gml.editor;
/**
Interface for an editing tool.
*/
public interface Tool {
/**
Get the name of this tool.
@return The name of the tool.
*/
String getName();
/**
Activate this tool.
*/
void activate();
/**
Deactivate this tool.
*/
void deactivate();
}
\ No newline at end of file
package maps.gml.editor;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Collection;
import maps.gml.GMLBuilding;
import maps.gml.GMLEdge;
import maps.gml.GMLMap;
import maps.gml.GMLNode;
import maps.gml.GMLObject;
import maps.gml.GMLRoad;
import maps.gml.GMLSpace;
import maps.gml.view.DecoratorOverlay;
import maps.gml.view.EdgeDecorator;
import maps.gml.view.FilledShapeDecorator;
import maps.gml.view.LineEdgeDecorator;
import maps.gml.view.NodeDecorator;
import maps.gml.view.SquareNodeDecorator;
import maps.validate.GMLMapValidator;
import maps.validate.MapValidator;
import maps.validate.ValidationError;
import rescuecore2.log.Logger;
/**
* Check the map for errors and highlight them on the map.
*
*/
public class ValidateFunction extends AbstractFunction {
private static final Color HIGHLIGHT_COLOUR = Color.RED;
private static final int NODE_SIZE = 5;
private DecoratorOverlay overlay = new DecoratorOverlay();
private NodeDecorator nodeHighlight;
private EdgeDecorator edgeHighlight;
private FilledShapeDecorator shapeHighlight;
/**
* Create a new ValidateFunction.
* @param editor The editor.
*/
public ValidateFunction(GMLEditor editor) {
super(editor);
nodeHighlight = new SquareNodeDecorator(HIGHLIGHT_COLOUR, NODE_SIZE);
edgeHighlight = new LineEdgeDecorator(HIGHLIGHT_COLOUR);
shapeHighlight = new FilledShapeDecorator(HIGHLIGHT_COLOUR,
HIGHLIGHT_COLOUR, HIGHLIGHT_COLOUR);
}
@Override
public void execute() {
overlay.clearAllDecorators();
Collection<ValidationError> allErrors = new ArrayList<ValidationError>();
for (MapValidator<GMLMap> validator : GMLMapValidator
.getDefaultValidators()) {
Logger.info("Validating " + validator);
Collection<ValidationError> errors = validator.validate(editor
.getMap());
allErrors.addAll(errors);
for (ValidationError e : errors) {
System.out.println(e);
addDecorator(e.getId());
}
}
editor.getInspector().setErrors(allErrors);
editor.getViewer().removeOverlay(overlay);
editor.getViewer().addOverlay(overlay);
editor.getViewer().repaint();
}
/**
* Add a new error decorator for the object with the given id.
* @param id
*/
private void addDecorator(int id) {
GMLObject obj = editor.getMap().getObject(id);
if (obj == null) {
return;
}
if (obj instanceof GMLBuilding) {
overlay.setBuildingDecorator(shapeHighlight, (GMLBuilding) obj);
}
else if (obj instanceof GMLRoad) {
overlay.setRoadDecorator(shapeHighlight, (GMLRoad) obj);
}
else if (obj instanceof GMLSpace) {
overlay.setSpaceDecorator(shapeHighlight, (GMLSpace) obj);
}
else if (obj instanceof GMLEdge) {
overlay.setEdgeDecorator(edgeHighlight, (GMLEdge) obj);
}
else if (obj instanceof GMLNode) {
overlay.setNodeDecorator(nodeHighlight, (GMLNode) obj);
}
}
@Override
public String getName() {
return "Validate map";
}
}
package maps.gml.formats;
import org.dom4j.DocumentHelper;
import org.dom4j.Namespace;
import org.dom4j.QName;
/**
A bunch of common GML format namespaces and qnames.
*/
public final class Common {
// CHECKSTYLE:OFF:JavadocVariable
public static final String GML_NAMESPACE_URI = "http://www.opengis.net/gml";
public static final String GML_3_2_NAMESPACE_URI = "http://www.opengis.net/gml/3.2";
public static final String XLINK_NAMESPACE_URI = "http://www.w3.org/1999/xlink";
public static final Namespace GML_NAMESPACE = DocumentHelper.createNamespace("gml", GML_NAMESPACE_URI);
public static final Namespace GML_3_2_NAMESPACE = DocumentHelper.createNamespace("gml32", GML_3_2_NAMESPACE_URI);
public static final Namespace XLINK_NAMESPACE = DocumentHelper.createNamespace("xlink", XLINK_NAMESPACE_URI);
public static final QName GML_ID_QNAME = DocumentHelper.createQName("id", GML_NAMESPACE);
public static final QName GML_NODE_QNAME = DocumentHelper.createQName("Node", GML_NAMESPACE);
public static final QName GML_EDGE_QNAME = DocumentHelper.createQName("Edge", GML_NAMESPACE);
public static final QName GML_FACE_QNAME = DocumentHelper.createQName("Face", GML_NAMESPACE);
public static final QName GML_POINT_PROPERTY_QNAME = DocumentHelper.createQName("pointProperty", GML_NAMESPACE);
public static final QName GML_POINT_QNAME = DocumentHelper.createQName("Point", GML_NAMESPACE);
public static final QName GML_COORDINATES_QNAME = DocumentHelper.createQName("coordinates", GML_NAMESPACE);
public static final QName GML_ORIENTATION_QNAME = DocumentHelper.createQName("orientation");
public static final QName GML_DIRECTED_NODE_QNAME = DocumentHelper.createQName("directedNode", GML_NAMESPACE);
public static final QName GML_DIRECTED_EDGE_QNAME = DocumentHelper.createQName("directedEdge", GML_NAMESPACE);
public static final QName GML_DIRECTED_FACE_QNAME = DocumentHelper.createQName("directedFace", GML_NAMESPACE);
public static final QName GML_CENTRE_LINE_OF_QNAME = DocumentHelper.createQName("centerLineOf", GML_NAMESPACE);
public static final QName GML_LINE_STRING_QNAME = DocumentHelper.createQName("LineString", GML_NAMESPACE);
public static final QName GML_POLYGON_QNAME = DocumentHelper.createQName("polygon", GML_NAMESPACE);
public static final QName GML_LINEAR_RING_QNAME = DocumentHelper.createQName("LinearRing", GML_NAMESPACE);
public static final QName XLINK_HREF_QNAME = DocumentHelper.createQName("href", XLINK_NAMESPACE);
// CHECKSTYLE:ON:JavadocVariable
private Common() {
}
}
package maps.gml.formats;
import maps.gml.GMLMap;
import maps.gml.GMLNode;
import maps.gml.GMLDirectedEdge;
import maps.gml.GMLCoordinates;
import maps.gml.GMLMapFormat;
import maps.MapTools;
import maps.CoordinateConversion;
import maps.ScaleConversion;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.QName;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.StringTokenizer;
import java.util.Collections;
import rescuecore2.log.Logger;
/**
A MapFormat that can handle maps from Japan's Geospatial Information Authority.
*/
public final class GeospatialInformationAuthorityFormat extends GMLMapFormat {
/** Singleton instance. */
public static final GeospatialInformationAuthorityFormat INSTANCE = new GeospatialInformationAuthorityFormat();
private static final String FGD_NAMESPACE_URI = "http://fgd.gsi.go.jp/spec/2008/FGD_GMLSchema";
private static final Namespace FGD_NAMESPACE = DocumentHelper.createNamespace("fgd", FGD_NAMESPACE_URI);
private static final QName DATASET_QNAME = DocumentHelper.createQName("Dataset", FGD_NAMESPACE);
private static final QName BUILDING_QNAME = DocumentHelper.createQName("BldL", FGD_NAMESPACE);
private static final QName ROAD_QNAME = DocumentHelper.createQName("RdEdg", FGD_NAMESPACE);
private static final QName LOC_QNAME = DocumentHelper.createQName("loc", FGD_NAMESPACE);
private static final QName CURVE_QNAME = DocumentHelper.createQName("Curve", Common.GML_3_2_NAMESPACE);
private static final QName SEGMENTS_QNAME = DocumentHelper.createQName("segments", Common.GML_3_2_NAMESPACE);
private static final QName LINE_STRING_SEGMENT_QNAME = DocumentHelper.createQName("LineStringSegment", Common.GML_3_2_NAMESPACE);
private static final QName POS_LIST_QNAME = DocumentHelper.createQName("posList", Common.GML_3_2_NAMESPACE);
// Map from uri prefix to uri for XPath expressions and for output
private static final Map<String, String> URIS = new HashMap<String, String>();
static {
URIS.put("gml", Common.GML_NAMESPACE_URI);
URIS.put("xlink", Common.XLINK_NAMESPACE_URI);
URIS.put("fgd", FGD_NAMESPACE_URI);
}
private GeospatialInformationAuthorityFormat() {
}
@Override
public String toString() {
return "Japan Geospatial Information Authority";
}
@Override
public Map<String, String> getNamespaces() {
return Collections.unmodifiableMap(URIS);
}
@Override
public boolean isCorrectRootElement(String uri, String localName) {
return FGD_NAMESPACE_URI.equals(uri) && "Dataset".equals(localName);
}
@Override
public GMLMap read(Document doc) {
GMLMap result = new GMLMap();
readBuildings(doc, result);
readRoads(doc, result);
// Convert from lat/lon to metres
double scale = 1.0 / MapTools.sizeOf1Metre((result.getMinY() + result.getMaxY()) / 2, (result.getMinX() + result.getMaxX()) / 2);
CoordinateConversion conversion = new ScaleConversion(result.getMinX(), result.getMinY(), scale, scale);
result.convertCoordinates(conversion);
return result;
}
@Override
public Document write(GMLMap map) {
// Not implemented
throw new RuntimeException("GeospatialInformationAuthorityFormat.write not implemented");
}
private void readBuildings(Document doc, GMLMap result) {
List elements = doc.getRootElement().elements(BUILDING_QNAME);
Logger.debug("Found " + elements.size() + " buildings");
for (Object next : elements) {
Element e = (Element)next;
try {
Element posList = e.element(LOC_QNAME).element(CURVE_QNAME).element(SEGMENTS_QNAME).element(LINE_STRING_SEGMENT_QNAME).element(POS_LIST_QNAME);
String coords = posList.getText();
List<GMLDirectedEdge> edges = readEdges(coords, result);
result.createBuilding(edges);
}
catch (NullPointerException ex) {
Logger.debug("Building with wonky outline found: " + ex);
}
}
}
private void readRoads(Document doc, GMLMap result) {
List elements = doc.getRootElement().elements(ROAD_QNAME);
Logger.debug("Found " + elements.size() + " roads");
for (Object next : elements) {
Element e = (Element)next;
try {
Element posList = e.element(LOC_QNAME).element(CURVE_QNAME).element(SEGMENTS_QNAME).element(LINE_STRING_SEGMENT_QNAME).element(POS_LIST_QNAME);
String coords = posList.getText();
createEdges(coords, result);
}
catch (NullPointerException ex) {
Logger.debug("Road with wonky outline found: " + ex);
}
}
}
private List<GMLDirectedEdge> readEdges(String coordinatesString, GMLMap map) {
List<GMLDirectedEdge> edges = new ArrayList<GMLDirectedEdge>();
StringTokenizer tokens = new StringTokenizer(coordinatesString, " \t\n\r");
GMLCoordinates lastApex = null;
GMLNode fromNode = null;
GMLNode toNode = null;
while (tokens.hasMoreTokens()) {
String north = tokens.nextToken();
String east = tokens.nextToken();
double x = Double.parseDouble(east);
double y = Double.parseDouble(north);
GMLCoordinates nextApex = new GMLCoordinates(x, y);
toNode = map.createNode(nextApex);
if (lastApex != null) {
edges.add(new GMLDirectedEdge(map.createEdge(fromNode, toNode), true));
}
lastApex = nextApex;
fromNode = toNode;
}
return edges;
}
private void createEdges(String coordinatesString, GMLMap map) {
StringTokenizer tokens = new StringTokenizer(coordinatesString, " \t\n\r");
GMLCoordinates lastApex = null;
GMLNode fromNode = null;
GMLNode toNode = null;
while (tokens.hasMoreTokens()) {
String north = tokens.nextToken();
String east = tokens.nextToken();
double x = Double.parseDouble(east);
double y = Double.parseDouble(north);
GMLCoordinates nextApex = new GMLCoordinates(x, y);
toNode = map.createNode(nextApex);
if (lastApex != null) {
map.createEdge(fromNode, toNode);
}
lastApex = nextApex;
fromNode = toNode;
}
}
}
package maps.gml.formats;
import maps.gml.GMLMap;
import maps.gml.GMLCoordinates;
import maps.gml.GMLShape;
import maps.gml.GMLBuilding;
import maps.gml.GMLRoad;
import maps.gml.GMLNode;
import maps.gml.GMLEdge;
import maps.gml.GMLDirectedEdge;
import maps.gml.GMLTools;
import maps.gml.GMLMapFormat;
import maps.ConstantConversion;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Attribute;
import org.dom4j.QName;
import org.dom4j.Namespace;
import org.dom4j.XPath;
import org.dom4j.DocumentHelper;
import org.jaxen.SimpleVariableContext;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Collection;
import java.util.Iterator;
import java.util.Collections;
import rescuecore2.misc.Pair;
import rescuecore2.log.Logger;
/**
A MapFormat that can handle GML maps from Meijo University.
*/
public final class MeijoFormat extends GMLMapFormat {
/** Singleton instance. */
public static final MeijoFormat INSTANCE = new MeijoFormat();
private static final String MEIJO_NAMESPACE_URI = "http://sakura.meijo-u.ac.jp/rcrs";
private static final String GML_APP_NAMESPACE_URI = "http://www.opengis.net/app";
private static final Namespace RCRS_NAMESPACE = DocumentHelper.createNamespace("rcrs", MEIJO_NAMESPACE_URI);
private static final Namespace GML_APP_NAMESPACE = DocumentHelper.createNamespace("app", GML_APP_NAMESPACE_URI);
private static final QName ROOT_QNAME = DocumentHelper.createQName("Topology", GML_APP_NAMESPACE);
private static final QName VERSION_QNAME = DocumentHelper.createQName("Version", RCRS_NAMESPACE);
private static final QName DESCRIPTION_QNAME = DocumentHelper.createQName("Description", RCRS_NAMESPACE);
private static final QName AREA_QNAME = DocumentHelper.createQName("Area", RCRS_NAMESPACE);
private static final QName NODE_LIST_QNAME = DocumentHelper.createQName("NodeList", RCRS_NAMESPACE);
private static final QName EDGE_LIST_QNAME = DocumentHelper.createQName("EdgeList", RCRS_NAMESPACE);
private static final QName FACE_LIST_QNAME = DocumentHelper.createQName("FaceList", RCRS_NAMESPACE);
private static final QName FACE_QNAME = DocumentHelper.createQName("Face", RCRS_NAMESPACE);
private static final QName BUILDING_PROPERTY_QNAME = DocumentHelper.createQName("BuildingProperty", RCRS_NAMESPACE);
// Map from uri prefix to uri for writing XML documents
private static final Map<String, String> URIS = new HashMap<String, String>();
private static final XPath NODE_XPATH = DocumentHelper.createXPath("//app:Topology/rcrs:Area/rcrs:NodeList/gml:Node");
private static final XPath EDGE_XPATH = DocumentHelper.createXPath("//app:Topology/rcrs:Area/rcrs:EdgeList/gml:Edge");
private static final XPath FACE_XPATH = DocumentHelper.createXPath("//app:Topology/rcrs:Area/rcrs:FaceList/rcrs:Face");
private static final XPath NODE_COORDINATES_XPATH = DocumentHelper.createXPath("gml:pointProperty/gml:Point/gml:coordinates");
private static final XPath EDGE_COORDINATES_XPATH = DocumentHelper.createXPath("gml:centerLineOf/gml:LineString/gml:coordinates");
private static final XPath FACE_COORDINATES_XPATH = DocumentHelper.createXPath("gml:polygon/gml:LinearRing/gml:coordinates");
private static final XPath EDGE_START_XPATH = DocumentHelper.createXPath("gml:directedNode[1]//@xlink:href");
private static final XPath EDGE_END_XPATH = DocumentHelper.createXPath("gml:directedNode[2]/@xlink:href");
private static final SimpleVariableContext FACE_NEIGHBOUR_XPATH_CONTEXT = new SimpleVariableContext();
private static final String FACE_NEIGHBOUR_XPATH_STRING = "//rcrs:EdgeList/gml:Edge[@gml:id=\"$edgeid\"]/gml:directedFace[@xlink:href!=\"#$faceid\"]/@xlink:href";
// private static final XPath FACE_NEIGHBOUR_XPATH = DocumentHelper.createXPath("//rcrs:EdgeList/gml:Edge[@gml:id=\"$edgeid\"]/gml:directedFace[@xlink:href!=\"#$faceid\"]/@xlink:href");
// private static final XPath FACE_NEIGHBOUR_XPATH = DocumentHelper.createXPath("//rcrs:EdgeList/gml:Edge[@gml:id=\"$edgeid\"]/gml:directedFace", FACE_NEIGHBOUR_XPATH_CONTEXT);
private static final double THRESHOLD = 0.0001;
static {
URIS.put("gml", Common.GML_NAMESPACE_URI);
URIS.put("app", GML_APP_NAMESPACE_URI);
URIS.put("xlink", Common.XLINK_NAMESPACE_URI);
URIS.put("rcrs", MEIJO_NAMESPACE_URI);
NODE_XPATH.setNamespaceURIs(URIS);
EDGE_XPATH.setNamespaceURIs(URIS);
FACE_XPATH.setNamespaceURIs(URIS);
NODE_COORDINATES_XPATH.setNamespaceURIs(URIS);
EDGE_COORDINATES_XPATH.setNamespaceURIs(URIS);
FACE_COORDINATES_XPATH.setNamespaceURIs(URIS);
EDGE_START_XPATH.setNamespaceURIs(URIS);
EDGE_END_XPATH.setNamespaceURIs(URIS);
// FACE_NEIGHBOUR_XPATH.setNamespaceURIs(URIS);
}
private MeijoFormat() {
}
@Override
public Map<String, String> getNamespaces() {
return Collections.unmodifiableMap(URIS);
}
@Override
public String toString() {
return "Meijo";
}
@Override
public boolean isCorrectRootElement(String uri, String localName) {
return MEIJO_NAMESPACE_URI.equals(uri) && "Topology".equals(localName);
}
@Override
public GMLMap read(Document doc) {
GMLMap result = new GMLMap();
readNodes(doc, result);
// This format has coordinates in mm, so divide by 1000 to convert to m.
// CHECKSTYLE:OFF:MagicNumber
result.convertCoordinates(new ConstantConversion(0.001));
// CHECKSTYLE:ON:MagicNumber
readEdges(doc, result);
readFaces(doc, result);
splitMultipleEdges(result);
// checkEdgeOrderAndDirection(result);
return result;
}
@Override
public Document write(GMLMap map) {
Element root = DocumentHelper.createElement(ROOT_QNAME);
Document result = DocumentHelper.createDocument(root);
writeNodes(map, root.addElement(NODE_LIST_QNAME));
writeEdges(map, root.addElement(EDGE_LIST_QNAME));
writeFaces(map, root.addElement(FACE_LIST_QNAME));
return result;
}
private void writeNodes(GMLMap map, Element parent) {
for (GMLNode next : map.getNodes()) {
Element e = parent.addElement(Common.GML_NODE_QNAME);
e.addAttribute(Common.GML_ID_QNAME, String.valueOf(next.getID()));
e.addElement(Common.GML_POINT_PROPERTY_QNAME).addElement(Common.GML_POINT_QNAME).addElement(Common.GML_COORDINATES_QNAME).setText(next.getCoordinates().toString());
}
}
private void writeEdges(GMLMap map, Element parent) {
for (GMLEdge next : map.getEdges()) {
Element e = parent.addElement(Common.GML_EDGE_QNAME);
e.addAttribute(Common.GML_ID_QNAME, String.valueOf(next.getID()));
e.addElement(Common.GML_DIRECTED_NODE_QNAME).addAttribute(Common.GML_ORIENTATION_QNAME, "+").addAttribute(Common.XLINK_HREF_QNAME, "#" + next.getStart().getID());
e.addElement(Common.GML_DIRECTED_NODE_QNAME).addAttribute(Common.GML_ORIENTATION_QNAME, "+").addAttribute(Common.XLINK_HREF_QNAME, "#" + next.getEnd().getID());
// Add directed faces
// This will be real slow
for (GMLShape shape : map.getAllShapes()) {
for (GMLDirectedEdge edge : shape.getEdges()) {
if (edge.getEdge() == next) {
e.addElement(Common.GML_DIRECTED_FACE_QNAME).addAttribute(Common.GML_ORIENTATION_QNAME, "+").addAttribute(Common.XLINK_HREF_QNAME, "#" + shape.getID());
}
}
}
}
}
private void writeFaces(GMLMap map, Element parent) {
for (GMLShape next : map.getAllShapes()) {
Element e = parent.addElement(FACE_QNAME);
if (next instanceof GMLBuilding) {
parent.addElement(BUILDING_PROPERTY_QNAME);
}
e = e.addElement(Common.GML_FACE_QNAME);
e.addAttribute(Common.GML_ID_QNAME, String.valueOf(next.getID()));
for (GMLDirectedEdge edge : next.getEdges()) {
String orientation = "-";
if (edge.getEdge().isPassable()) {
orientation = "+";
}
e.addElement(Common.GML_DIRECTED_EDGE_QNAME).addAttribute(Common.GML_ORIENTATION_QNAME, orientation).addAttribute(Common.XLINK_HREF_QNAME, "#" + edge.getEdge().getID());
}
e.addElement(Common.GML_POLYGON_QNAME).addElement(Common.GML_LINEAR_RING_QNAME).addElement(Common.GML_COORDINATES_QNAME).setText(GMLTools.getCoordinatesString(next.getCoordinates()));
}
}
private void readNodes(Document doc, GMLMap result) {
for (Object next : NODE_XPATH.selectNodes(doc)) {
Element e = (Element)next;
int id = readID(e);
String coordinates = ((Element)NODE_COORDINATES_XPATH.evaluate(e)).getText();
GMLCoordinates c = new GMLCoordinates(coordinates);
GMLNode node = new GMLNode(id, c);
result.addNode(node);
Logger.debug("Read node " + node);
}
}
private void readEdges(Document doc, GMLMap result) {
for (Object next : EDGE_XPATH.selectNodes(doc)) {
Element e = (Element)next;
int id = readID(e);
// Logger.debug("Children: " + e.elements());
// Logger.debug("Start: " + EDGE_START_XPATH.evaluate(e));
int startID = Integer.parseInt(((Attribute)EDGE_START_XPATH.evaluate(e)).getValue().substring(1));
int endID = Integer.parseInt(((Attribute)EDGE_END_XPATH.evaluate(e)).getValue().substring(1));
GMLEdge edge = new GMLEdge(id, result.getNode(startID), result.getNode(endID), false);
// Read the edge coordinates
edge.setPoints(GMLTools.getCoordinatesList(((Element)EDGE_COORDINATES_XPATH.evaluate(e)).getText()));
result.addEdge(edge);
Logger.debug("Read edge " + edge);
}
}
private void readFaces(Document doc, GMLMap result) {
// Logger.debug("Reading buildings");
for (Object next : FACE_XPATH.selectNodes(doc)) {
// Logger.debug("Reading " + next);
Element e = (Element)next;
String type = e.attributeValue("type");
Element gmlFace = e.element(Common.GML_FACE_QNAME);
int id = readID(gmlFace);
// Logger.debug("ID = " + id);
// Logger.debug("Type = " + type);
Pair<List<GMLDirectedEdge>, List<Integer>> edges = readEdges(gmlFace, result, id);
// Logger.debug("Edges: " + edges);
GMLShape shape = null;
if ("building".equals(type)) {
shape = new GMLBuilding(id, edges.first(), edges.second());
}
else {
shape = new GMLRoad(id, edges.first(), edges.second());
}
// Logger.debug("Computing coordinates");
String coordsString = ((Element)FACE_COORDINATES_XPATH.evaluate(gmlFace)).getText();
// Logger.debug("coordsString = " + coordsString);
List<GMLCoordinates> coords = GMLTools.getCoordinatesList(coordsString);
// Logger.debug("coords = " + coords);
shape.setCoordinates(coords);
result.add(shape);
Logger.debug("Read shape: " + shape);
}
}
private Pair<List<GMLDirectedEdge>, List<Integer>> readEdges(Element e, GMLMap map, int faceID) {
List<GMLDirectedEdge> edges = new ArrayList<GMLDirectedEdge>();
List<Integer> neighbours = new ArrayList<Integer>();
// Logger.debug("Reading edges for face " + faceID);
for (Object next : e.elements(Common.GML_DIRECTED_EDGE_QNAME)) {
Element dEdge = (Element)next;
boolean passable = "+".equals(dEdge.attributeValue(Common.GML_ORIENTATION_QNAME));
int edgeID = Integer.parseInt(dEdge.attributeValue(Common.XLINK_HREF_QNAME).substring(1));
// Logger.debug("Edge ID: " + edgeID);
// Logger.debug("Passable? " + passable);
edges.add(new GMLDirectedEdge(map.getEdge(edgeID), true));
XPath xpath = makeFaceNeighbourXPath(edgeID, faceID);
// FACE_NEIGHBOUR_XPATH_CONTEXT.setVariableValue("edgeid", String.valueOf(edgeID));
// FACE_NEIGHBOUR_XPATH_CONTEXT.setVariableValue("faceid", String.valueOf(faceID));
Object o = xpath.evaluate(e);
// Logger.debug("Neighbours: " + o);
if (o == null) {
neighbours.add(null);
}
else if (o instanceof Collection && ((Collection)o).isEmpty()) {
neighbours.add(null);
}
else {
int neighbourID = Integer.parseInt(((Attribute)o).getValue().substring(1));
neighbours.add(neighbourID);
}
// Logger.debug("Edge list : " + edges);
// Logger.debug("Neighbour list: " + neighbours);
}
// Logger.debug("Finished reading edges for face " + faceID);
return new Pair<List<GMLDirectedEdge>, List<Integer>>(edges, neighbours);
}
private int readID(Element e) {
return Integer.parseInt(e.attributeValue(Common.GML_ID_QNAME));
}
private XPath makeFaceNeighbourXPath(int edgeID, int faceID) {
String path = FACE_NEIGHBOUR_XPATH_STRING.replace("$edgeid", String.valueOf(edgeID)).replace("$faceid", String.valueOf(faceID));
// Logger.debug("Neighbour XPath: " + path);
XPath result = DocumentHelper.createXPath(path);
result.setNamespaceURIs(URIS);
return result;
}
private void splitMultipleEdges(GMLMap map) {
// Look for edges that have more then 2 GMLCoordinates and split them into multiple edges
for (GMLEdge edge : map.getEdges()) {
if (edge.getPoints().size() != 2) {
// Split this edge
Iterator<GMLCoordinates> it = edge.getPoints().iterator();
GMLCoordinates first = it.next();
List<GMLEdge> newEdges = new ArrayList<GMLEdge>();
while (it.hasNext()) {
GMLCoordinates second = it.next();
GMLNode n1 = map.createNode(first);
GMLNode n2 = map.createNode(second);
GMLEdge newEdge = map.createEdge(n1, n2);
newEdges.add(newEdge);
first = second;
}
// Update any shapes that reference the old edge
for (GMLShape shape : map.getAllShapes()) {
replaceEdge(shape, edge, newEdges);
}
map.removeEdge(edge);
// Logger.debug("Split " + edge);
// Logger.debug("New edges: " + newEdges);
}
}
}
private void replaceEdge(GMLShape shape, GMLEdge oldEdge, List<GMLEdge> newEdges) {
List<GMLDirectedEdge> newShapeEdges = new ArrayList<GMLDirectedEdge>();
List<Integer> newShapeNeighbours = new ArrayList<Integer>();
boolean found = false;
for (GMLDirectedEdge e : shape.getEdges()) {
if (e.getEdge().equals(oldEdge)) {
found = true;
GMLNode start = e.getStartNode();
Integer neighbour = shape.getNeighbour(e);
for (GMLEdge next : newEdges) {
GMLDirectedEdge newDEdge = new GMLDirectedEdge(next, start);
newShapeEdges.add(newDEdge);
newShapeNeighbours.add(neighbour);
start = newDEdge.getEndNode();
}
}
else {
newShapeEdges.add(e);
newShapeNeighbours.add(shape.getNeighbour(e));
}
}
if (found) {
shape.setEdges(newShapeEdges);
Iterator<GMLDirectedEdge> it = newShapeEdges.iterator();
Iterator<Integer> ix = newShapeNeighbours.iterator();
while (it.hasNext() && ix.hasNext()) {
shape.setNeighbour(it.next(), ix.next());
}
}
}
/*
private void checkEdgeOrderAndDirection(GMLMap map) {
Set<GMLDirectedEdge> remaining = new HashSet<GMLDirectedEdge>();
List<GMLDirectedEdge> reordered = new ArrayList<GMLDirectedEdge>();
for (GMLShape shape : map.getAllShapes()) {
remaining.clear();
reordered.clear();
remaining.addAll(shape.getEdges());
// Iterator<GMLDirectedEdge> it = shape.getEdges().iterator();
GMLDirectedEdge edge = shape.getEdges().get(0);
GMLNode start = edge.getEndNode();
// Logger.debug("Reordering " + remaining.size() + " edges for " + shape);
// Logger.debug("Original order");
// for (GMLDirectedEdge e : shape.getEdges()) {
// logEdge(e);
// }
// Logger.debug("First edge");
// logEdge(edge);
remaining.remove(edge);
reordered.add(edge);
while (!remaining.isEmpty()) {
edge = null;
// Find the next edge
for (GMLDirectedEdge next : remaining) {
if (closeEnough(next.getStartNode(), start)) {
edge = next;
break;
}
if (closeEnough(next.getEndNode(), start)) {
edge = next;
edge.reverse();
break;
}
}
if (edge == null) {
throw new RuntimeException("Failed to reorder edges: found discontinuity in shape outline");
}
// Logger.debug("Next edge");
// logEdge(edge);
remaining.remove(edge);
reordered.add(edge);
start = edge.getEndNode();
}
// Logger.debug("Reordered");
// for (GMLDirectedEdge e : reordered) {
// logEdge(e);
// }
shape.reorderEdges(reordered);
}
}
*/
// private void logEdge(GMLDirectedEdge e) {
// Logger.debug(e.getEdge().getID() + ": " + e.getStartNode().getID() + " -> " + e.getEndNode().getID());
// }
private boolean closeEnough(GMLNode n1, GMLNode n2) {
if (n1 == n2) {
return true;
}
double dx = n1.getX() - n2.getX();
double dy = n1.getY() - n2.getY();
return (dx > -THRESHOLD
&& dx < THRESHOLD
&& dy > -THRESHOLD
&& dy < THRESHOLD);
}
}
package maps.gml.formats;
import maps.gml.GMLMap;
import maps.gml.GMLNode;
import maps.gml.GMLDirectedEdge;
import maps.gml.GMLCoordinates;
import maps.gml.GMLBuilding;
import maps.gml.GMLRoad;
import maps.gml.GMLMapFormat;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.QName;
import org.dom4j.XPath;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.StringTokenizer;
import java.util.Collection;
import java.util.Collections;
import rescuecore2.log.Logger;
// TO DO: Handle inner boundaries
/**
A MapFormat that can handle maps from the UK Ordnance Survey.
*/
public final class OrdnanceSurveyFormat extends GMLMapFormat {
/** Singleton instance. */
public static final OrdnanceSurveyFormat INSTANCE = new OrdnanceSurveyFormat();
private static final String FEATURE_CODE_BUILDING = "10021";
private static final String FEATURE_CODE_ROAD = "10172";
private static final String FEATURE_CODE_FOOTPATH = "10183";
private static final String FEATURE_CODE_OPEN_SPACE = "10053";
private static final String FEATURE_CODE_GENERAL_SPACE = "10056";
private static final String OSGB_NAMESPACE_URI = "http://www.ordnancesurvey.co.uk/xml/namespaces/osgb";
private static final Namespace OSGB_NAMESPACE = DocumentHelper.createNamespace("osgb", OSGB_NAMESPACE_URI);
private static final QName FEATURE_COLLECTION_QNAME = DocumentHelper.createQName("FeatureCollection", OSGB_NAMESPACE);
private static final QName TOPOGRAPHIC_AREA_QNAME = DocumentHelper.createQName("TopographicArea", OSGB_NAMESPACE);
private static final XPath BUILDING_XPATH = DocumentHelper.createXPath("//osgb:topographicMember/osgb:TopographicArea[osgb:featureCode[text()='" + FEATURE_CODE_BUILDING + "']]");
// private static final XPath ROAD_XPATH = DocumentHelper.createXPath("//osgb:topographicMember/osgb:TopographicArea[osgb:featureCode[text()='" + FEATURE_CODE_ROAD + "' or text()='" + FEATURE_CODE_FOOTPATH + "']]");
private static final XPath ROAD_XPATH = DocumentHelper.createXPath("//osgb:topographicMember/osgb:TopographicArea[osgb:featureCode[text()='" + FEATURE_CODE_ROAD + "']]");
private static final XPath SPACE_XPATH = DocumentHelper.createXPath("//osgb:topographicMember/osgb:TopographicArea[osgb:featureCode[text()='" + FEATURE_CODE_OPEN_SPACE + "' or text()='" + FEATURE_CODE_GENERAL_SPACE + "']]");
private static final XPath SHAPE_XPATH = DocumentHelper.createXPath("osgb:polygon/gml:Polygon/gml:outerBoundaryIs/gml:LinearRing/gml:coordinates");
private static final XPath INNER_RING_XPATH = DocumentHelper.createXPath("osgb:polygon/gml:Polygon/gml:innerBoundaryIs/gml:LinearRing/gml:coordinates");
// Map from uri prefix to uri for XPath expressions
private static final Map<String, String> URIS = new HashMap<String, String>();
private static final int FID_PREFIX_LENGTH = 4;
static {
URIS.put("gml", Common.GML_NAMESPACE_URI);
URIS.put("xlink", Common.XLINK_NAMESPACE_URI);
URIS.put("osgb", OSGB_NAMESPACE_URI);
BUILDING_XPATH.setNamespaceURIs(URIS);
ROAD_XPATH.setNamespaceURIs(URIS);
SPACE_XPATH.setNamespaceURIs(URIS);
SHAPE_XPATH.setNamespaceURIs(URIS);
INNER_RING_XPATH.setNamespaceURIs(URIS);
}
private OrdnanceSurveyFormat() {
}
@Override
public String toString() {
return "Ordnance survey";
}
@Override
public Map<String, String> getNamespaces() {
return Collections.unmodifiableMap(URIS);
}
@Override
public boolean isCorrectRootElement(String uri, String localName) {
return OSGB_NAMESPACE_URI.equals(uri) && "FeatureCollection".equals(localName);
}
@Override
public GMLMap read(Document doc) {
GMLMap result = new GMLMap();
readBuildings(doc, result);
readRoads(doc, result);
readSpaces(doc, result);
return result;
}
@Override
public Document write(GMLMap map) {
// Not implemented
throw new RuntimeException("OrdnanceSurveyFormat.write not implemented");
}
private void readBuildings(Document doc, GMLMap result) {
for (Object next : BUILDING_XPATH.selectNodes(doc)) {
Logger.debug("Found building element: " + next);
Element e = (Element)next;
// String fid = e.attributeValue("fid");
// long id = Long.parseLong(fid.substring(FID_PREFIX_LENGTH)); // Strip off the 'osgb' prefix
String coordinatesString = ((Element)SHAPE_XPATH.evaluate(e)).getText();
List<GMLDirectedEdge> edges = readEdges(coordinatesString, result);
GMLBuilding b = result.createBuilding(edges);
}
}
private void readRoads(Document doc, GMLMap result) {
for (Object next : ROAD_XPATH.selectNodes(doc)) {
Logger.debug("Found road element: " + next);
Element e = (Element)next;
// String fid = e.attributeValue("fid");
// long id = Long.parseLong(fid.substring(FID_PREFIX_LENGTH)); // Strip off the 'osgb' prefix
String coordinatesString = ((Element)SHAPE_XPATH.evaluate(e)).getText();
Object inner = INNER_RING_XPATH.evaluate(e);
if ((inner instanceof Collection) && ((Collection)inner).isEmpty()) {
List<GMLDirectedEdge> edges = readEdges(coordinatesString, result);
GMLRoad road = result.createRoad(edges);
}
else {
Logger.debug("Inner ring found: ignoring");
Logger.debug("Found: " + inner);
}
}
}
private void readSpaces(Document doc, GMLMap result) {
/*
for (Object next : SPACE_XPATH.selectNodes(doc)) {
Logger.debug("Found space element: " + next);
Element e = (Element)next;
String fid = e.attributeValue("fid");
long id = Long.parseLong(fid.substring(4)); // Strip off the 'osgb' prefix
String coordinatesString = ((Element)SHAPE_XPATH.evaluate(e)).getText();
List<GMLEdge> edges = readEdges(coordinatesString, result);
result.createSpace(edges);
}
*/
}
private List<GMLDirectedEdge> readEdges(String coordinatesString, GMLMap map) {
List<GMLDirectedEdge> edges = new ArrayList<GMLDirectedEdge>();
StringTokenizer tokens = new StringTokenizer(coordinatesString, " ");
GMLCoordinates lastApex = null;
GMLNode fromNode = null;
GMLNode toNode = null;
while (tokens.hasMoreTokens()) {
String token = tokens.nextToken();
GMLCoordinates nextApex = new GMLCoordinates(token);
toNode = map.createNode(nextApex);
if (lastApex != null) {
edges.add(new GMLDirectedEdge(map.createEdge(fromNode, toNode), true));
}
lastApex = nextApex;
fromNode = toNode;
}
return edges;
}
}
package maps.gml.formats;
import maps.gml.GMLMap;
import maps.gml.GMLCoordinates;
import maps.gml.GMLObject;
import maps.gml.GMLShape;
import maps.gml.GMLBuilding;
import maps.gml.GMLRoad;
import maps.gml.GMLSpace;
import maps.gml.GMLNode;
import maps.gml.GMLEdge;
import maps.gml.GMLDirectedEdge;
import maps.gml.GMLMapFormat;
import maps.MapException;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.QName;
import org.dom4j.Namespace;
import org.dom4j.DocumentHelper;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import rescuecore2.misc.Pair;
import rescuecore2.log.Logger;
/**
A MapFormat that can handle Robocup Rescue GML maps.
*/
public final class RobocupFormat extends GMLMapFormat {
/** Singleton instance. */
public static final RobocupFormat INSTANCE = new RobocupFormat();
private static final String RCR_NAMESPACE_URI = "urn:roborescue:map:gml";
private static final Namespace RCR_NAMESPACE = DocumentHelper.createNamespace("rcr", RCR_NAMESPACE_URI);
private static final QName RCR_ROOT_QNAME = DocumentHelper.createQName("map", RCR_NAMESPACE);
private static final QName RCR_NODE_LIST_QNAME = DocumentHelper.createQName("nodelist", RCR_NAMESPACE);
private static final QName RCR_EDGE_LIST_QNAME = DocumentHelper.createQName("edgelist", RCR_NAMESPACE);
private static final QName RCR_BUILDING_LIST_QNAME = DocumentHelper.createQName("buildinglist", RCR_NAMESPACE);
private static final QName RCR_ROAD_LIST_QNAME = DocumentHelper.createQName("roadlist", RCR_NAMESPACE);
private static final QName RCR_SPACE_LIST_QNAME = DocumentHelper.createQName("spacelist", RCR_NAMESPACE);
private static final QName RCR_NODE_QNAME = DocumentHelper.createQName("node", RCR_NAMESPACE);
private static final QName RCR_EDGE_QNAME = DocumentHelper.createQName("edge", RCR_NAMESPACE);
private static final QName RCR_BUILDING_QNAME = DocumentHelper.createQName("building", RCR_NAMESPACE);
private static final QName RCR_ROAD_QNAME = DocumentHelper.createQName("road", RCR_NAMESPACE);
private static final QName RCR_SPACE_QNAME = DocumentHelper.createQName("space", RCR_NAMESPACE);
private static final QName RCR_NEIGHBOUR_QNAME = DocumentHelper.createQName("neighbour", RCR_NAMESPACE);
private static final QName RCR_FLOORS_QNAME = DocumentHelper.createQName("floors", RCR_NAMESPACE);
private static final QName RCR_BUILDING_CODE_QNAME = DocumentHelper.createQName("buildingcode", RCR_NAMESPACE);
private static final QName RCR_IMPORTANCE_QNAME = DocumentHelper.createQName("importance", RCR_NAMESPACE);
private static final QName RCR_CAPACITY_QNAME = DocumentHelper.createQName("capacity", RCR_NAMESPACE);
// Map from uri prefix to uri for writing XML documents
private static final Map<String, String> URIS = new HashMap<String, String>();
private static final Comparator<GMLObject> ID_SORTER = new Comparator<GMLObject>() {
@Override
public int compare(GMLObject first, GMLObject second) {
if (first.getID() < second.getID()) {
return -1;
}
if (first.getID() > second.getID()) {
return 1;
}
return 0;
}
};
static {
URIS.put("gml", Common.GML_NAMESPACE_URI);
URIS.put("xlink", Common.XLINK_NAMESPACE_URI);
URIS.put("rcr", RCR_NAMESPACE_URI);
}
private RobocupFormat() {
}
@Override
public Map<String, String> getNamespaces() {
return Collections.unmodifiableMap(URIS);
}
@Override
public String toString() {
return "Robocup rescue";
}
@Override
public boolean isCorrectRootElement(String uri, String localName) {
return RCR_NAMESPACE_URI.equals(uri) && "map".equals(localName);
}
@Override
public GMLMap read(Document doc) throws MapException {
GMLMap result = new GMLMap();
readNodes(doc, result);
readEdges(doc, result);
readBuildings(doc, result);
readRoads(doc, result);
readSpaces(doc, result);
return result;
}
@Override
public Document write(GMLMap map) {
Element root = DocumentHelper.createElement(RCR_ROOT_QNAME);
Document result = DocumentHelper.createDocument(root);
writeNodes(map, root.addElement(RCR_NODE_LIST_QNAME));
writeEdges(map, root.addElement(RCR_EDGE_LIST_QNAME));
writeShapes(map.getBuildings(), RCR_BUILDING_QNAME, root.addElement(RCR_BUILDING_LIST_QNAME));
writeShapes(map.getRoads(), RCR_ROAD_QNAME, root.addElement(RCR_ROAD_LIST_QNAME));
writeShapes(map.getSpaces(), RCR_SPACE_QNAME, root.addElement(RCR_SPACE_LIST_QNAME));
return result;
}
private void writeNodes(GMLMap map, Element parent) {
List<GMLNode> nodes = new ArrayList<GMLNode>(map.getNodes());
Collections.sort(nodes, ID_SORTER);
for (GMLNode next : nodes) {
Element e = parent.addElement(Common.GML_NODE_QNAME);
e.addAttribute(Common.GML_ID_QNAME, String.valueOf(next.getID()));
e.addElement(Common.GML_POINT_PROPERTY_QNAME).addElement(Common.GML_POINT_QNAME).addElement(Common.GML_COORDINATES_QNAME).setText(next.getCoordinates().toString());
}
}
private void writeEdges(GMLMap map, Element parent) {
List<GMLEdge> edges = new ArrayList<GMLEdge>(map.getEdges());
Collections.sort(edges, ID_SORTER);
for (GMLEdge next : edges) {
Element e = parent.addElement(Common.GML_EDGE_QNAME);
e.addAttribute(Common.GML_ID_QNAME, String.valueOf(next.getID()));
e.addElement(Common.GML_DIRECTED_NODE_QNAME).addAttribute(Common.GML_ORIENTATION_QNAME, "-").addAttribute(Common.XLINK_HREF_QNAME, "#" + next.getStart().getID());
e.addElement(Common.GML_DIRECTED_NODE_QNAME).addAttribute(Common.GML_ORIENTATION_QNAME, "+").addAttribute(Common.XLINK_HREF_QNAME, "#" + next.getEnd().getID());
}
}
private void writeShapes(Collection<? extends GMLShape> shapes, QName qname, Element parent) {
List<GMLShape> sorted = new ArrayList<GMLShape>(shapes);
Collections.sort(sorted, ID_SORTER);
for (GMLShape next : sorted) {
Element e = parent.addElement(qname).addAttribute(Common.GML_ID_QNAME, String.valueOf(next.getID())).addElement(Common.GML_FACE_QNAME);
for (GMLDirectedEdge dEdge : next.getEdges()) {
String orientation = dEdge.isForward() ? "+" : "-";
Element dEdgeElement = e.addElement(Common.GML_DIRECTED_EDGE_QNAME).addAttribute(Common.GML_ORIENTATION_QNAME, orientation).addAttribute(Common.XLINK_HREF_QNAME, "#" + dEdge.getEdge().getID());
Integer neighbour = next.getNeighbour(dEdge);
if (neighbour != null) {
dEdgeElement.addAttribute(RCR_NEIGHBOUR_QNAME, String.valueOf(neighbour));
}
}
if (next instanceof GMLBuilding) {
GMLBuilding b = (GMLBuilding)next;
e.addAttribute(RCR_FLOORS_QNAME, String.valueOf(b.getFloors()));
e.addAttribute(RCR_BUILDING_CODE_QNAME, String.valueOf(b.getCode()));
e.addAttribute(RCR_IMPORTANCE_QNAME, String.valueOf(b.getImportance()));
//e.addAttribute(RCR__QNAME, String.valueOf(b.getImportance()));
}
}
}
private void readNodes(Document doc, GMLMap result) throws MapException {
Logger.debug("Reading nodes");
for (Object next : doc.getRootElement().elements(RCR_NODE_LIST_QNAME)) {
Element nodeList = (Element)next;
for (Object nextNode : nodeList.elements(Common.GML_NODE_QNAME)) {
Element e = (Element)nextNode;
int id = readID(e);
String coordinates = readNodeCoordinates(e);
GMLCoordinates c = new GMLCoordinates(coordinates);
GMLNode node = new GMLNode(id, c);
result.addNode(node);
}
}
Logger.debug("Read " + result.getNodes().size() + " nodes");
}
private void readEdges(Document doc, GMLMap result) throws MapException {
Logger.debug("Reading edges");
for (Object next : doc.getRootElement().elements(RCR_EDGE_LIST_QNAME)) {
Element edgeList = (Element)next;
for (Object nextEdge : edgeList.elements(Common.GML_EDGE_QNAME)) {
Element e = (Element)nextEdge;
int id = readID(e);
int startID = -1;
int endID = -1;
for (Object directedNode : e.elements(Common.GML_DIRECTED_NODE_QNAME)) {
Element directedNodeElement = (Element)directedNode;
if ("-".equals(directedNodeElement.attributeValue(Common.GML_ORIENTATION_QNAME))) {
if (startID != -1) {
throw new MapException("Edge has multiple start nodes: " + e);
}
startID = readHref(directedNodeElement, "start node");
}
if ("+".equals(directedNodeElement.attributeValue(Common.GML_ORIENTATION_QNAME))) {
if (endID != -1) {
throw new MapException("Edge has multiple end nodes: " + e);
}
endID = readHref(directedNodeElement, "end node");
}
}
GMLEdge edge = new GMLEdge(id, result.getNode(startID), result.getNode(endID), false);
result.addEdge(edge);
}
}
Logger.debug("Read " + result.getEdges().size() + " edges");
}
private void readBuildings(Document doc, GMLMap result) throws MapException {
Logger.debug("Reading buildings");
for (Object next : doc.getRootElement().elements(RCR_BUILDING_LIST_QNAME)) {
Element buildingList = (Element)next;
for (Object nextBuilding : buildingList.elements(RCR_BUILDING_QNAME)) {
Element e = (Element)nextBuilding;
Pair<List<GMLDirectedEdge>, List<Integer>> edges = readEdges(e, result);
GMLBuilding b = new GMLBuilding(readID(e), edges.first(), edges.second());
Element f = e.element(Common.GML_FACE_QNAME);
int floors = readInt(f, RCR_FLOORS_QNAME, 1);
int code = readInt(f, RCR_BUILDING_CODE_QNAME, 0);
int importance = readInt(f, RCR_IMPORTANCE_QNAME, 1);
int capacity = readInt(f, RCR_CAPACITY_QNAME, 0);
b.setFloors(floors);
b.setCode(code);
b.setImportance(importance);
b.setCapacity(capacity);
result.addBuilding(b);
}
}
Logger.debug("Read " + result.getBuildings().size() + " buildings");
}
private void readRoads(Document doc, GMLMap result) throws MapException {
Logger.debug("Reading roads");
for (Object next : doc.getRootElement().elements(RCR_ROAD_LIST_QNAME)) {
Element roadList = (Element)next;
for (Object nextRoad : roadList.elements(RCR_ROAD_QNAME)) {
Element e = (Element)nextRoad;
Pair<List<GMLDirectedEdge>, List<Integer>> edges = readEdges(e, result);
GMLRoad r = new GMLRoad(readID(e), edges.first(), edges.second());
result.addRoad(r);
}
}
Logger.debug("Read " + result.getRoads().size() + " roads");
}
private void readSpaces(Document doc, GMLMap result) throws MapException {
Logger.debug("Reading spaces");
for (Object next : doc.getRootElement().elements(RCR_SPACE_LIST_QNAME)) {
Element spaceList = (Element)next;
for (Object nextSpace : spaceList.elements(RCR_SPACE_QNAME)) {
Element e = (Element)nextSpace;
Pair<List<GMLDirectedEdge>, List<Integer>> edges = readEdges(e, result);
GMLSpace s = new GMLSpace(readID(e), edges.first(), edges.second());
result.addSpace(s);
}
}
Logger.debug("Read " + result.getSpaces().size() + " spaces");
}
private Pair<List<GMLDirectedEdge>, List<Integer>> readEdges(Element e, GMLMap map) throws MapException {
List<GMLDirectedEdge> edges = new ArrayList<GMLDirectedEdge>();
List<Integer> neighbours = new ArrayList<Integer>();
Element faceElement = e.element(Common.GML_FACE_QNAME);
if (faceElement == null) {
throw new MapException("Shape does not contain a gml:Face: " + e);
}
for (Object nextEdge : faceElement.elements(Common.GML_DIRECTED_EDGE_QNAME)) {
Element directedEdge = (Element)nextEdge;
// Logger.debug("Next directed edge: " + directedEdge);
int nextID = readHref(directedEdge, "underlying edge");
String orientation = directedEdge.attributeValue(Common.GML_ORIENTATION_QNAME);
boolean forward;
if (orientation == null) {
throw new MapException("Directed edge has no orientation attribute: " + e);
}
if ("+".equals(orientation)) {
forward = true;
}
else if ("-".equals(orientation)) {
forward = false;
}
else {
throw new MapException("Directed edge has invalid orientation attribute: " + e);
}
GMLEdge edge = map.getEdge(nextID);
GMLDirectedEdge dEdge = new GMLDirectedEdge(edge, forward);
String neighbourString = directedEdge.attributeValue(RCR_NEIGHBOUR_QNAME);
Integer neighbourID = null;
if (neighbourString != null) {
try {
neighbourID = Integer.valueOf(neighbourString);
}
catch (NumberFormatException ex) {
throw new MapException("Directed edge has invalid neighbour: " + e, ex);
}
edge.setPassable(true);
}
edges.add(dEdge);
neighbours.add(neighbourID);
}
if (edges.isEmpty()) {
throw new MapException("Shape contains no edges: " + e);
}
return new Pair<List<GMLDirectedEdge>, List<Integer>>(edges, neighbours);
}
private int readID(Element e) throws MapException {
String s = e.attributeValue(Common.GML_ID_QNAME);
if (s == null) {
throw new MapException("No ID attribute found: " + e);
}
try {
return Integer.parseInt(s);
}
catch (NumberFormatException ex) {
throw new MapException("Couldn't parse ID attribute", ex);
}
}
private String readNodeCoordinates(Element node) throws MapException {
Element pointProperty = node.element(Common.GML_POINT_PROPERTY_QNAME);
if (pointProperty == null) {
throw new MapException("Couldn't find gml:pointProperty child of node");
}
Element point = pointProperty.element(Common.GML_POINT_QNAME);
if (point == null) {
throw new MapException("Couldn't find gml:Point child of node");
}
Element coords = point.element(Common.GML_COORDINATES_QNAME);
if (coords == null) {
throw new MapException("Couldn't find gml:coordinates child of node");
}
return coords.getText();
}
private int readHref(Element e, String type) throws MapException {
String href = e.attributeValue(Common.XLINK_HREF_QNAME);
if (href == null || href.length() == 0) {
throw new MapException("Edge has no " + type + " ID");
}
try {
return Integer.parseInt(href.substring(1));
}
catch (NumberFormatException ex) {
throw new MapException("Edge has invalid " + type + " ID");
}
}
private int readInt(Element e, QName attributeName, int defaultValue) throws MapException {
String s = e.attributeValue(attributeName);
if (s == null) {
return defaultValue;
}
try {
return Integer.parseInt(s);
}
catch (NumberFormatException ex) {
throw new MapException("Attribute " + attributeName + " is not an integer: " + e);
}
}
}
package maps.gml.generator;
import maps.gml.GMLMap;
import maps.gml.formats.RobocupFormat;
import maps.MapWriter;
import maps.MapException;
import rescuecore2.config.Config;
import rescuecore2.config.ConfigException;
import rescuecore2.log.Logger;
import java.io.File;
/**
A tool for generating GML maps.
*/
public class GMLMapGenerator {
private static final String OUTPUT_FILE_KEY = "generator.output";
private Config config;
/**
Construct a GMLMapGenerator.
@param config The configuration to use.
*/
public GMLMapGenerator(Config config) {
this.config = config;
}
/**
Entry point.
@param args Command line arguments.
*/
public static void main(String[] args) {
try {
Config config = new Config();
for (int i = 0; i < args.length; ++i) {
config.read(new File(args[i]));
}
GMLMap map = new GMLMapGenerator(config).generateMap();
String outFile = config.getValue(OUTPUT_FILE_KEY);
Logger.debug("Writing generated map to " + outFile);
MapWriter.writeMap(map, outFile, RobocupFormat.INSTANCE);
}
catch (MapException e) {
e.printStackTrace();
}
catch (ConfigException e) {
e.printStackTrace();
}
}
/**
Generate a new map.
@return The new map.
*/
public GMLMap generateMap() {
GMLMap result = new GMLMap();
new ManhattanGenerator(config).populate(result);
return result;
}
}
\ No newline at end of file
package maps.gml.generator;
import maps.gml.GMLMap;
import maps.gml.GMLNode;
//import maps.gml.GMLEdge;
import maps.gml.GMLDirectedEdge;
import maps.gml.GMLBuilding;
//import maps.gml.GMLRoad;
import maps.gml.GMLCoordinates;
import rescuecore2.config.Config;
import rescuecore2.misc.geometry.Point2D;
import rescuecore2.misc.geometry.GeometryTools2D;
import rescuecore2.log.Logger;
import org.uncommons.maths.number.NumberGenerator;
import org.uncommons.maths.random.Probability;
import org.uncommons.maths.random.ContinuousUniformGenerator;
import java.util.Collection;
import java.util.List;
import java.util.ArrayList;
import java.util.HashSet;
/**
A MapGenerator that generates a grid world.
*/
public class ManhattanGenerator implements MapGenerator {
private static final String GRID_WIDTH_KEY = "generator.manhattan.grid.width";
private static final String GRID_HEIGHT_KEY = "generator.manhattan.grid.height";
private static final String GRID_SIZE_KEY = "generator.manhattan.grid.size";
private static final String ROAD_WIDTH_KEY = "generator.manhattan.road.width";
private static final String BUILDING_WIDTH_MIN_KEY = "generator.manhattan.building.width.min";
private static final String BUILDING_HEIGHT_MIN_KEY = "generator.manhattan.building.height.min";
private static final String BUILDING_SEPARATION_MIN_KEY = "generator.manhattan.building.separation.min";
private static final String BUILDING_SEPARATION_MAX_KEY = "generator.manhattan.building.separation.max";
private static final String BUILDING_MIN_SIZE_KEY = "generator.manhattan.building.split.min-size";
private static final String BUILDING_MAX_SIZE_KEY = "generator.manhattan.building.split.max-size";
private static final String BUILDING_SPLIT_CHANCE_KEY = "generator.manhattan.building.split.chance";
private Config config;
// private NumberGenerator<Double> widthGenerator;
// private NumberGenerator<Double> heightGenerator;
private NumberGenerator<Double> separationGenerator;
private Probability split;
private double minSize;
private double maxSize;
private double minWidth;
private double minHeight;
private GMLMap map;
/**
Construct a ManhattanGenerator.
@param config The configuration to use.
*/
public ManhattanGenerator(Config config) {
this.config = config;
// widthGenerator = new ContinuousUniformGenerator(config.getFloatValue(BUILDING_WIDTH_MIN_KEY), config.getFloatValue(BUILDING_WIDTH_MAX_KEY), config.getRandom());
// heightGenerator = new ContinuousUniformGenerator(config.getFloatValue(BUILDING_HEIGHT_MIN_KEY), config.getFloatValue(BUILDING_HEIGHT_MAX_KEY), config.getRandom());
// Logger.debug("separation min: " + config.getFloatValue(BUILDING_SEPARATION_MIN_KEY));
// Logger.debug("separation max: " + config.getFloatValue(BUILDING_SEPARATION_MAX_KEY));
separationGenerator = new ContinuousUniformGenerator(config.getFloatValue(BUILDING_SEPARATION_MIN_KEY), config.getFloatValue(BUILDING_SEPARATION_MAX_KEY), config.getRandom());
// Logger.debug("Generator: "+ separationGenerator);
split = new Probability(config.getFloatValue(BUILDING_SPLIT_CHANCE_KEY));
minSize = config.getFloatValue(BUILDING_MIN_SIZE_KEY);
maxSize = config.getFloatValue(BUILDING_MAX_SIZE_KEY);
minWidth = config.getFloatValue(BUILDING_WIDTH_MIN_KEY);
minHeight = config.getFloatValue(BUILDING_HEIGHT_MIN_KEY);
}
@Override
public void populate(GMLMap gmlMap) {
this.map = gmlMap;
int gridWidth = config.getIntValue(GRID_WIDTH_KEY);
int gridHeight = config.getIntValue(GRID_HEIGHT_KEY);
double gridSize = config.getIntValue(GRID_SIZE_KEY);
double roadWidth = config.getIntValue(ROAD_WIDTH_KEY);
Logger.debug("Generating manhattan map: grid size " + gridWidth + " x " + gridHeight);
Logger.debug("Grid cell size: " + gridSize + "m");
Logger.debug("Road width: " + roadWidth + "m");
Collection<GMLBuilding> allBuildings = new ArrayList<GMLBuilding>();
for (int gridX = 0; gridX < gridWidth; ++gridX) {
for (int gridY = 0; gridY < gridHeight; ++gridY) {
double cellXMin = (gridX * gridSize) + roadWidth;
double cellYMin = (gridY * gridSize) + roadWidth;
double cellXMax = ((gridX + 1) * gridSize) - roadWidth;
double cellYMax = ((gridY + 1) * gridSize) - roadWidth;
GMLBuilding base = createBuilding(cellXMin, cellYMin, cellXMax, cellYMax);
allBuildings.addAll(divide(base));
}
}
map.removeAllNodes();
map.removeAllEdges();
map.removeAllBuildings();
for (GMLBuilding next : allBuildings) {
map.add(next);
for (GMLDirectedEdge edge : next.getEdges()) {
map.add(edge.getEdge());
map.add(edge.getEdge().getStart());
map.add(edge.getEdge().getEnd());
}
}
}
private Collection<GMLBuilding> divide(GMLBuilding b) {
// Logger.debug("Possibly dividing building " + b);
Collection<GMLBuilding> result = new HashSet<GMLBuilding>();
List<Point2D> vertices = coordinatesToVertices(b.getUnderlyingCoordinates());
double area = GeometryTools2D.computeArea(vertices);
// Logger.debug("Area: " + area + " sqm");
if (area <= minSize) {
result.add(b);
}
else {
if (area > maxSize || split.nextEvent(config.getRandom())) {
// Split the building
double xMin = b.getBounds().getMinX();
double xMax = b.getBounds().getMaxX();
double yMin = b.getBounds().getMinY();
double yMax = b.getBounds().getMaxY();
double width = xMax - xMin;
double height = yMax - yMin;
// Logger.debug("Width: " + width);
// Logger.debug("Height: " + height);
// Logger.debug("width * height = " + (width * height));
// Logger.debug("Area = " + area);
if (height > width) {
// Logger.debug("Splitting horizontally");
// Horizontal split
double splitY = (yMax + yMin) / 2;
double topOffset = separationGenerator.nextValue();
double bottomOffset = separationGenerator.nextValue();
double topY = splitY + topOffset;
double bottomY = splitY - bottomOffset;
// Logger.debug("yMin = " + yMin);
// Logger.debug("yMax = " + yMax);
// Logger.debug("splitY = " + splitY);
// Logger.debug("topOffset = " + topOffset);
// Logger.debug("bottomOffset = " + bottomOffset);
// Logger.debug("topY = " + topY);
// Logger.debug("bottomY = " + bottomY);
if (yMax - topY < minHeight || bottomY - yMin < minHeight) {
// Logger.debug("Split too thin");
// Logger.debug("Top piece: " + (yMax - topY));
// Logger.debug("Bottom piece: " + (bottomY - yMin));
// Logger.debug("Minimum height: " + minHeight);
result.add(b);
}
else {
result.addAll(divide(createBuilding(xMin, yMin, xMax, bottomY)));
result.addAll(divide(createBuilding(xMin, topY, xMax, yMax)));
}
}
else {
// Logger.debug("Splitting vertically");
// Vertical split
double splitX = (xMax + xMin) / 2;
double leftOffset = separationGenerator.nextValue();
double rightOffset = separationGenerator.nextValue();
double leftX = splitX - leftOffset;
double rightX = splitX + rightOffset;
// Logger.debug("xMin = " + xMin);
// Logger.debug("xMax = " + xMax);
// Logger.debug("splitX = " + splitX);
// Logger.debug("leftOffset = " + leftOffset);
// Logger.debug("rightOffset = " + rightOffset);
// Logger.debug("leftX = " + leftX);
// Logger.debug("rightX = " + rightX);
if (xMax - rightX < minWidth || leftX - xMin < minWidth) {
// Logger.debug("Split too thin");
// Logger.debug("Left piece: " + (leftX - xMin));
// Logger.debug("Right piece: " + (xMax - rightX));
// Logger.debug("Minimum width: " + minWidth);
result.add(b);
}
else {
result.addAll(divide(createBuilding(xMin, yMin, leftX, yMax)));
result.addAll(divide(createBuilding(rightX, yMin, xMax, yMax)));
}
}
}
else {
// Logger.debug("Not splitting");
result.add(b);
}
}
return result;
}
private List<Point2D> coordinatesToVertices(List<GMLCoordinates> coords) {
List<Point2D> result = new ArrayList<Point2D>(coords.size());
for (GMLCoordinates c : coords) {
result.add(new Point2D(c.getX(), c.getY()));
}
return result;
}
private GMLBuilding createBuilding(double xMin, double yMin, double xMax, double yMax) {
List<GMLNode> nodes = new ArrayList<GMLNode>();
nodes.add(map.createNode(xMin, yMin));
nodes.add(map.createNode(xMax, yMin));
nodes.add(map.createNode(xMax, yMax));
nodes.add(map.createNode(xMin, yMax));
return map.createBuildingFromNodes(nodes);
}
}
\ No newline at end of file
package maps.gml.generator;
import maps.gml.GMLMap;
/**
Top-level interface for map generation strategies.
*/
public interface MapGenerator {
/**
Generate a map.
@param map The map object to populate.
*/
void populate(GMLMap map);
}
\ No newline at end of file
package maps.gml.view;
import maps.gml.GMLBuilding;
import rescuecore2.misc.gui.ScreenTransform;
import java.awt.Graphics2D;
/**
Interface for objects that know how to decorate GMLBuildings.
*/
public interface BuildingDecorator {
/**
Decorate a GMLBuilding.
@param building The building to decorate.
@param g The graphics to draw on.
@param transform The screen transform.
*/
void decorate(GMLBuilding building, Graphics2D g, ScreenTransform transform);
}
\ No newline at end of file
package maps.gml.view;
import maps.gml.GMLBuilding;
import rescuecore2.misc.gui.ScreenTransform;
import java.awt.Graphics2D;
/**
Interface for objects that know how to decorate GMLBuildings.
*/
public interface BuildingDecorator {
/**
Decorate a GMLBuilding.
@param building The building to decorate.
@param g The graphics to draw on.
@param transform The screen transform.
*/
void decorate(GMLBuilding building, Graphics2D g, ScreenTransform transform);
}
\ No newline at end of file
package maps.gml.view;
import maps.gml.GMLNode;
import rescuecore2.misc.gui.ScreenTransform;
import java.awt.Graphics2D;
import java.awt.Color;
/**
A NodeDecorator that draws a cross for each node.
*/
public class CrossNodeDecorator implements NodeDecorator {
private Color colour;
private int size;
/**
Construct a CrossNodeDecorator.
@param colour The colour to draw the cross.
@param size The size of each arm of the cross.
*/
public CrossNodeDecorator(Color colour, int size) {
this.colour = colour;
this.size = size;
}
@Override
public void decorate(GMLNode node, Graphics2D g, ScreenTransform transform) {
int x = transform.xToScreen(node.getX());
int y = transform.yToScreen(node.getY());
g.setColor(colour);
g.drawLine(x - size, y - size, x + size, y + size);
g.drawLine(x - size, y + size, x + size, y - size);
}
}
\ No newline at end of file
package maps.gml.view;
import maps.gml.GMLBuilding;
import maps.gml.GMLEdge;
import maps.gml.GMLNode;
import maps.gml.GMLRoad;
import maps.gml.GMLSpace;
import maps.gml.GMLRefuge;
import rescuecore2.misc.gui.ScreenTransform;
import java.awt.Graphics2D;
import java.awt.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
/**
* Draws an overlay consisting of Decorators.
*/
public class DecoratorOverlay implements Overlay {
private transient Map<GMLNode, NodeDecorator> nodeDecorators;
private transient Map<GMLEdge, EdgeDecorator> edgeDecorators;
private transient Map<GMLBuilding, BuildingDecorator> buildingDecorators;
private transient Map<GMLRoad, RoadDecorator> roadDecorators;
private transient Map<GMLSpace, SpaceDecorator> spaceDecorators;
/**
* Construct a DecoratorOverlay.
*/
public DecoratorOverlay() {
nodeDecorators = new HashMap<GMLNode, NodeDecorator>();
edgeDecorators = new HashMap<GMLEdge, EdgeDecorator>();
buildingDecorators = new HashMap<GMLBuilding, BuildingDecorator>();
roadDecorators = new HashMap<GMLRoad, RoadDecorator>();
spaceDecorators = new HashMap<GMLSpace, SpaceDecorator>();
}
/**
* Set the NodeDecorator for a set of GMLNodes.
*
* @param decorator
* The decorator to set.
* @param nodes
* The nodes to set the decorator for.
*/
public void setNodeDecorator( NodeDecorator decorator, GMLNode... nodes ) {
setNodeDecorator( decorator, Arrays.asList( nodes ) );
}
/**
* Set the NodeDecorator for a set of GMLNodes.
*
* @param decorator
* The decorator to set.
* @param nodes
* The nodes to set the decorator for.
*/
public void setNodeDecorator( NodeDecorator decorator,
Collection<? extends GMLNode> nodes ) {
for ( GMLNode next : nodes ) {
nodeDecorators.put( next, decorator );
}
}
/**
* Get the NodeDecorator for a GMLNodes.
*
* @param node
* The node to look up.
* @return The NodeDecorator for that node. This will be null if no custom
* decorator has been set for that node.
*/
public NodeDecorator getNodeDecorator( GMLNode node ) {
NodeDecorator result = nodeDecorators.get( node );
return result;
}
/**
* Remove any custom NodeDecorator for a set of GMLNodes.
*
* @param nodes
* The nodes to remove any custom decorator for.
*/
public void clearNodeDecorator( GMLNode... nodes ) {
clearNodeDecorator( Arrays.asList( nodes ) );
}
/**
* Remove any custom NodeDecorator for a set of GMLNodes.
*
* @param nodes
* The nodes to remove any custom decorator for.
*/
public void clearNodeDecorator( Collection<? extends GMLNode> nodes ) {
for ( GMLNode next : nodes ) {
nodeDecorators.remove( next );
}
}
/**
* Remove any custom NodeDecorators.
*/
public void clearAllNodeDecorators() {
nodeDecorators.clear();
}
/**
* Set the EdgeDecorator for a set of GMLEdges.
*
* @param decorator
* The decorator to set.
* @param edges
* The edges to set the decorator for.
*/
public void setEdgeDecorator( EdgeDecorator decorator, GMLEdge... edges ) {
setEdgeDecorator( decorator, Arrays.asList( edges ) );
}
/**
* Set the EdgeDecorator for a set of GMLEdges.
*
* @param decorator
* The decorator to set.
* @param edges
* The edges to set the decorator for.
*/
public void setEdgeDecorator( EdgeDecorator decorator,
Collection<? extends GMLEdge> edges ) {
for ( GMLEdge next : edges ) {
edgeDecorators.put( next, decorator );
}
}
/**
* Get the EdgeDecorator for a GMLEdge.
*
* @param edge
* The edge to look up.
* @return The EdgeDecorator for that edge. This will be null if no custom
* decorator has been set for that edge.
*/
public EdgeDecorator getEdgeDecorator( GMLEdge edge ) {
EdgeDecorator result = edgeDecorators.get( edge );
return result;
}
/**
* Remove any custom EdgeDecorator for a set of GMLEdges.
*
* @param edges
* The edges to remove any custom decorator for.
*/
public void clearEdgeDecorator( GMLEdge... edges ) {
clearEdgeDecorator( Arrays.asList( edges ) );
}
/**
* Remove any custom EdgeDecorator for a set of GMLEdges.
*
* @param edges
* The edges to remove any custom decorator for.
*/
public void clearEdgeDecorator( Collection<? extends GMLEdge> edges ) {
for ( GMLEdge next : edges ) {
edgeDecorators.remove( next );
}
}
/**
* Remove any custom EdgeDecorators.
*/
public void clearAllEdgeDecorators() {
edgeDecorators.clear();
}
/**
* Set the BuildingDecorator for a set of GMLBuildings.
*
* @param decorator
* The decorator to set.
* @param buildings
* The buildings to set the decorator for.
*/
public void setBuildingDecorator( BuildingDecorator decorator,
GMLBuilding... buildings ) {
setBuildingDecorator( decorator, Arrays.asList( buildings ) );
}
/**
* Set the BuildingDecorator for a set of GMLBuildings.
*
* @param decorator
* The decorator to set.
* @param buildings
* The buildings to set the decorator for.
*/
public void setBuildingDecorator( BuildingDecorator decorator,
Collection<? extends GMLBuilding> buildings ) {
for ( GMLBuilding next : buildings ) {
buildingDecorators.put( next, decorator );
}
}
/**
* Get the BuildingDecorator for a GMLBuildings.
*
* @param building
* The building to look up.
* @return The BuildingDecorator for that building. This will be null if no
* custom decorator has been set for that building.
*/
public BuildingDecorator getBuildingDecorator( GMLBuilding building ) {
BuildingDecorator result = buildingDecorators.get( building );
return result;
}
/**
* Remove any custom BuildingDecorator for a set of GMLBuildings.
*
* @param buildings
* The buildings to remove any custom decorator for.
*/
public void clearBuildingDecorator( GMLBuilding... buildings ) {
clearBuildingDecorator( Arrays.asList( buildings ) );
}
/**
* Remove any custom BuildingDecorator for a set of GMLBuildings.
*
* @param buildings
* The buildings to remove any custom decorator for.
*/
public void
clearBuildingDecorator( Collection<? extends GMLBuilding> buildings ) {
for ( GMLBuilding next : buildings ) {
buildingDecorators.remove( next );
}
}
/**
* Remove any custom BuildingDecorators.
*/
public void clearAllBuildingDecorators() {
buildingDecorators.clear();
}
/**
* Set the RoadDecorator for a set of GMLRoads.
*
* @param decorator
* The decorator to set.
* @param roads
* The roads to set the decorator for.
*/
public void setRoadDecorator( RoadDecorator decorator, GMLRoad... roads ) {
setRoadDecorator( decorator, Arrays.asList( roads ) );
}
/**
* Set the RoadDecorator for a set of GMLRoads.
*
* @param decorator
* The decorator to set.
* @param roads
* The roads to set the decorator for.
*/
public void setRoadDecorator( RoadDecorator decorator,
Collection<? extends GMLRoad> roads ) {
for ( GMLRoad next : roads ) {
roadDecorators.put( next, decorator );
}
}
/**
* Get the RoadDecorator for a GMLRoads.
*
* @param road
* The road to look up.
* @return The RoadDecorator for that road. Will return null if no custom
* decorator has been set for that road.
*/
public RoadDecorator getRoadDecorator( GMLRoad road ) {
RoadDecorator result = roadDecorators.get( road );
return result;
}
/**
* Remove any custom RoadDecorator for a set of GMLRoads.
*
* @param roads
* The roads to remove any custom decorator for.
*/
public void clearRoadDecorator( GMLRoad... roads ) {
clearRoadDecorator( Arrays.asList( roads ) );
}
/**
* Remove any custom RoadDecorator for a set of GMLRoads.
*
* @param roads
* The roads to remove any custom decorator for.
*/
public void clearRoadDecorator( Collection<? extends GMLRoad> roads ) {
for ( GMLRoad next : roads ) {
roadDecorators.remove( next );
}
}
/**
* Remove any custom RoadDecorators.
*/
public void clearAllRoadDecorators() {
roadDecorators.clear();
}
/**
* Set the SpaceDecorator for a set of GMLSpaces.
*
* @param decorator
* The decorator to set.
* @param spaces
* The spaces to set the decorator for.
*/
public void setSpaceDecorator( SpaceDecorator decorator,
GMLSpace... spaces ) {
setSpaceDecorator( decorator, Arrays.asList( spaces ) );
}
/**
* Set the SpaceDecorator for a set of GMLSpaces.
*
* @param decorator
* The decorator to set.
* @param spaces
* The spaces to set the decorator for.
*/
public void setSpaceDecorator( SpaceDecorator decorator,
Collection<? extends GMLSpace> spaces ) {
for ( GMLSpace next : spaces ) {
spaceDecorators.put( next, decorator );
}
}
/**
* Get the SpaceDecorator for a GMLSpaces.
*
* @param space
* The space to look up.
* @return The SpaceDecorator for that space. This will be null if no custom
* decorator has been set for that space.
*/
public SpaceDecorator getSpaceDecorator( GMLSpace space ) {
SpaceDecorator result = spaceDecorators.get( space );
return result;
}
/**
* Remove any custom SpaceDecorator for a set of GMLSpaces.
*
* @param spaces
* The spaces to remove any custom decorator for.
*/
public void clearSpaceDecorator( GMLSpace... spaces ) {
clearSpaceDecorator( Arrays.asList( spaces ) );
}
/**
* Remove any custom SpaceDecorator for a set of GMLSpaces.
*
* @param spaces
* The spaces to remove any custom decorator for.
*/
public void clearSpaceDecorator( Collection<? extends GMLSpace> spaces ) {
for ( GMLSpace next : spaces ) {
spaceDecorators.remove( next );
}
}
/**
* Remove any custom SpaceDecorators.
*/
public void clearAllSpaceDecorators() {
spaceDecorators.clear();
}
/**
* Remove all types of Decorators.
*/
public void clearAllDecorators() {
clearAllBuildingDecorators();
clearAllRoadDecorators();
clearAllSpaceDecorators();
clearAllEdgeDecorators();
clearAllNodeDecorators();
}
@Override
public void render( Graphics2D g, ScreenTransform transform ) {
for ( Entry<GMLRoad, RoadDecorator> e : roadDecorators.entrySet() ) {
e.getValue().decorate( e.getKey(), (Graphics2D) g.create(), transform );
}
for ( Entry<GMLBuilding, BuildingDecorator> e : buildingDecorators
.entrySet() ) {
e.getValue().decorate( e.getKey(), (Graphics2D) g.create(), transform );
if ( e.getKey() instanceof GMLRefuge ) {
int x = transform.xToScreen( e.getKey().getCentreX() );
int y = transform.yToScreen( e.getKey().getCentreY() );
Graphics2D oldg = g;
g.setColor( new Color( 0, 0, 0 ) );
g.setFont( new Font( g.getFont().getName(), Font.BOLD,
g.getFont().getSize() ) );
g.drawString(
String
.valueOf( "C=" + ( (GMLRefuge) e.getKey() ).getBedCapacity() ),
x - 20, y );
// g.drawString(String.valueOf("R " +
// ((GMLRefuge)e.getKey()).getRefillCapacity()), x - 10, y + 10);
g = oldg;
}
}
for ( Entry<GMLSpace, SpaceDecorator> e : spaceDecorators.entrySet() ) {
e.getValue().decorate( e.getKey(), (Graphics2D) g.create(), transform );
}
for ( Entry<GMLEdge, EdgeDecorator> e : edgeDecorators.entrySet() ) {
e.getValue().decorate( e.getKey(), (Graphics2D) g.create(), transform );
}
for ( Entry<GMLNode, NodeDecorator> e : nodeDecorators.entrySet() ) {
e.getValue().decorate( e.getKey(), (Graphics2D) g.create(), transform );
}
}
}
package maps.gml.view;
import maps.gml.GMLEdge;
import rescuecore2.misc.gui.ScreenTransform;
import java.awt.Graphics2D;
/**
Interface for objects that know how to decorate GMLEdges.
*/
public interface EdgeDecorator {
/**
Decorate a GMLEdge.
@param edge The edge to decorate.
@param g The graphics to draw on.
@param transform The screen transform.
*/
void decorate(GMLEdge edge, Graphics2D g, ScreenTransform transform);
}
\ No newline at end of file
package maps.gml.view;
import maps.gml.GMLShape;
import maps.gml.GMLRoad;
import maps.gml.GMLBuilding;
import maps.gml.GMLSpace;
import maps.gml.GMLCoordinates;
import rescuecore2.misc.gui.ScreenTransform;
import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.Polygon;
import java.util.List;
/**
This class knows how to decorate buildings, roads and spaces.
*/
public class FilledShapeDecorator implements BuildingDecorator, RoadDecorator, SpaceDecorator {
private Color buildingColour;
private Color roadColour;
private Color spaceColour;
/**
Construct a FilledShapeDecorator.
@param buildingColour The colour of buildings.
@param roadColour The colour of roads.
@param spaceColour The colour of spaces.
*/
public FilledShapeDecorator(Color buildingColour, Color roadColour, Color spaceColour) {
this.buildingColour = buildingColour;
this.roadColour = roadColour;
this.spaceColour = spaceColour;
}
@Override
public void decorate(GMLBuilding building, Graphics2D g, ScreenTransform transform) {
if (buildingColour == null) {
return;
}
g.setColor(buildingColour);
draw(building, g, transform);
}
@Override
public void decorate(GMLRoad road, Graphics2D g, ScreenTransform transform) {
if (roadColour == null) {
return;
}
g.setColor(roadColour);
draw(road, g, transform);
}
@Override
public void decorate(GMLSpace space, Graphics2D g, ScreenTransform transform) {
if (spaceColour == null) {
return;
}
g.setColor(spaceColour);
draw(space, g, transform);
}
private void draw(GMLShape shape, Graphics2D g, ScreenTransform transform) {
List<GMLCoordinates> coords = shape.getUnderlyingCoordinates();
int n = coords.size();
int[] xs = new int[n];
int[] ys = new int[n];
int i = 0;
for (GMLCoordinates next : coords) {
xs[i] = transform.xToScreen(next.getX());
ys[i] = transform.yToScreen(next.getY());
++i;
}
g.fill(new Polygon(xs, ys, n));
}
public Color getBuildingColour() {
return buildingColour;
}
}
\ No newline at end of file
package maps.gml.view;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.Insets;
import java.awt.Point;
import java.awt.geom.Rectangle2D;
import javax.swing.JComponent;
import java.util.Map;
import java.util.HashMap;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.ArrayList;
import java.util.HashSet;
import rescuecore2.misc.gui.ScreenTransform;
import rescuecore2.misc.gui.PanZoomListener;
import maps.gml.GMLMap;
import maps.gml.GMLNode;
import maps.gml.GMLEdge;
import maps.gml.GMLBuilding;
import maps.gml.GMLRoad;
import maps.gml.GMLSpace;
import maps.gml.GMLObject;
import maps.gml.GMLCoordinates;
import maps.gml.GMLTools;
/**
A component for viewing GML maps.
*/
public class GMLMapViewer extends JComponent {
private static final Color BUILDING_COLOUR = new Color(67, 67, 67, 67); // Transparent dark gray
private static final Color ROAD_COLOUR = new Color(192, 192, 192, 128); // Transparent light gray
private static final Color SPACE_COLOUR = new Color(0, 128, 0, 128); // Transparent green
private static final Color GRID_COLOUR = new Color(0, 255, 0, 128); // Transparent lime
private static final Color NODE_COLOUR = Color.BLACK;
private static final int NODE_SIZE = 3;
private static final Color EDGE_COLOUR = Color.BLACK;
private static final double MIN_ZOOM_BOUNDS_SIZE = 0.1;
private GMLMap map;
private ScreenTransform transform;
private PanZoomListener panZoom;
private transient NodeDecorator defaultNodeDecorator;
private transient Map<GMLNode, NodeDecorator> nodeDecorators;
private transient EdgeDecorator defaultEdgeDecorator;
private transient Map<GMLEdge, EdgeDecorator> edgeDecorators;
private transient BuildingDecorator defaultBuildingDecorator;
private transient Map<GMLBuilding, BuildingDecorator> buildingDecorators;
private transient RoadDecorator defaultRoadDecorator;
private transient Map<GMLRoad, RoadDecorator> roadDecorators;
private transient SpaceDecorator defaultSpaceDecorator;
private transient Map<GMLSpace, SpaceDecorator> spaceDecorators;
private transient List<Overlay> overlays;
private boolean grid;
private double gridResolution;
private boolean paintNodes=true;
/**
Create a GMLMapViewer.
*/
public GMLMapViewer() {
this(null);
}
/**
Create a GMLMapViewer.
@param map The map to view.
*/
public GMLMapViewer(GMLMap map) {
panZoom = new PanZoomListener(this);
defaultNodeDecorator = new CrossNodeDecorator(NODE_COLOUR, NODE_SIZE);
defaultEdgeDecorator = new LineEdgeDecorator(EDGE_COLOUR);
FilledShapeDecorator d = new FilledShapeDecorator(BUILDING_COLOUR, ROAD_COLOUR, SPACE_COLOUR);
defaultBuildingDecorator = d;
defaultRoadDecorator = d;
defaultSpaceDecorator = d;
nodeDecorators = new HashMap<GMLNode, NodeDecorator>();
edgeDecorators = new HashMap<GMLEdge, EdgeDecorator>();
buildingDecorators = new HashMap<GMLBuilding, BuildingDecorator>();
roadDecorators = new HashMap<GMLRoad, RoadDecorator>();
spaceDecorators = new HashMap<GMLSpace, SpaceDecorator>();
grid = false;
gridResolution = 1;
overlays = new ArrayList<Overlay>();
setMap(map);
}
/**
Set the map.
@param map The map to view.
*/
public void setMap(GMLMap map) {
this.map = map;
transform = null;
if (map != null) {
if (!map.hasSize()) {
// CHECKSTYLE:OFF:MagicNumber
transform = new ScreenTransform(0, 0, 100, 100);
// CHECKSTYLE:ON:MagicNumber
}
else {
transform = new ScreenTransform(map.getMinX(), map.getMinY(), map.getMaxX(), map.getMaxY());
}
}
panZoom.setScreenTransform(transform);
}
/**
View a particular set of objects.
@param objects The objects to view.
*/
public void view(GMLObject... objects) {
view(Arrays.asList(objects));
}
/**
View a particular set of objects.
@param objects The objects to view.
*/
public void view(List<? extends GMLObject> objects) {
if (objects == null || objects.isEmpty()) {
return;
}
Rectangle2D bounds = GMLTools.getObjectBounds(objects);
if (bounds == null) {
return;
}
if (bounds.getWidth() < MIN_ZOOM_BOUNDS_SIZE) {
bounds = new Rectangle2D.Double(bounds.getX() - MIN_ZOOM_BOUNDS_SIZE / 2,
bounds.getY(), MIN_ZOOM_BOUNDS_SIZE, bounds.getHeight());
}
if (bounds.getHeight() < MIN_ZOOM_BOUNDS_SIZE) {
bounds = new Rectangle2D.Double(bounds.getX(),
bounds.getY() - MIN_ZOOM_BOUNDS_SIZE / 2,
bounds.getWidth(), MIN_ZOOM_BOUNDS_SIZE);
}
transform.show(bounds);
}
/**
View all objects.
*/
public void viewAll() {
transform.resetZoom();
}
/**
Get the PanZoomListener for this component.
@return The PanZoomListener.
*/
public PanZoomListener getPanZoomListener() {
return panZoom;
}
/**
Set the default node decorator.
@param defaultDecorator The new default node decorator.
*/
public void setDefaultNodeDecorator(NodeDecorator defaultDecorator) {
defaultNodeDecorator = defaultDecorator;
}
/**
Get the default node decorator.
@return The default node decorator.
*/
public NodeDecorator getDefaultNodeDecorator() {
return defaultNodeDecorator;
}
/**
Set the NodeDecorator for a set of GMLNodes.
@param decorator The decorator to set.
@param nodes The nodes to set the decorator for.
*/
public void setNodeDecorator(NodeDecorator decorator, GMLNode... nodes) {
setNodeDecorator(decorator, Arrays.asList(nodes));
}
/**
Set the NodeDecorator for a set of GMLNodes.
@param decorator The decorator to set.
@param nodes The nodes to set the decorator for.
*/
public void setNodeDecorator(NodeDecorator decorator, Collection<? extends GMLNode> nodes) {
for (GMLNode next : nodes) {
nodeDecorators.put(next, decorator);
}
}
/**
Get the NodeDecorator for a GMLNodes.
@param node The node to look up.
@return The NodeDecorator for that node. This will be the default decorator if no custom decorator has been set for that node.
*/
public NodeDecorator getNodeDecorator(GMLNode node) {
NodeDecorator result = nodeDecorators.get(node);
if (result == null) {
result = defaultNodeDecorator;
}
return result;
}
/**
Remove any custom NodeDecorator for a set of GMLNodes.
@param nodes The nodes to remove any custom decorator for.
*/
public void clearNodeDecorator(GMLNode... nodes) {
clearNodeDecorator(Arrays.asList(nodes));
}
/**
Remove any custom NodeDecorator for a set of GMLNodes.
@param nodes The nodes to remove any custom decorator for.
*/
public void clearNodeDecorator(Collection<? extends GMLNode> nodes) {
for (GMLNode next : nodes) {
nodeDecorators.remove(next);
}
}
/**
Remove any custom NodeDecorators.
*/
public void clearAllNodeDecorators() {
nodeDecorators.clear();
}
/**
Set the default edge decorator.
@param defaultDecorator The new default edge decorator.
*/
public void setDefaultEdgeDecorator(EdgeDecorator defaultDecorator) {
defaultEdgeDecorator = defaultDecorator;
}
/**
Get the default edge decorator.
@return The default edge decorator.
*/
public EdgeDecorator getDefaultEdgeDecorator() {
return defaultEdgeDecorator;
}
/**
Set the EdgeDecorator for a set of GMLEdges.
@param decorator The decorator to set.
@param edges The edges to set the decorator for.
*/
public void setEdgeDecorator(EdgeDecorator decorator, GMLEdge... edges) {
setEdgeDecorator(decorator, Arrays.asList(edges));
}
/**
Set the EdgeDecorator for a set of GMLEdges.
@param decorator The decorator to set.
@param edges The edges to set the decorator for.
*/
public void setEdgeDecorator(EdgeDecorator decorator, Collection<? extends GMLEdge> edges) {
for (GMLEdge next : edges) {
edgeDecorators.put(next, decorator);
}
}
/**
Get the EdgeDecorator for a GMLEdge.
@param edge The edge to look up.
@return The EdgeDecorator for that edge. This will be the default decorator if no custom decorator has been set for that edge.
*/
public EdgeDecorator getEdgeDecorator(GMLEdge edge) {
EdgeDecorator result = edgeDecorators.get(edge);
if (result == null) {
result = defaultEdgeDecorator;
}
return result;
}
/**
Remove any custom EdgeDecorator for a set of GMLEdges.
@param edges The edges to remove any custom decorator for.
*/
public void clearEdgeDecorator(GMLEdge... edges) {
clearEdgeDecorator(Arrays.asList(edges));
}
/**
Remove any custom EdgeDecorator for a set of GMLEdges.
@param edges The edges to remove any custom decorator for.
*/
public void clearEdgeDecorator(Collection<? extends GMLEdge> edges) {
for (GMLEdge next : edges) {
edgeDecorators.remove(next);
}
}
/**
Remove any custom EdgeDecorators.
*/
public void clearAllEdgeDecorators() {
edgeDecorators.clear();
}
/**
Set the default building decorator.
@param defaultDecorator The new default building decorator.
*/
public void setDefaultBuildingDecorator(BuildingDecorator defaultDecorator) {
defaultBuildingDecorator = defaultDecorator;
}
/**
Get the default building decorator.
@return The default building decorator.
*/
public BuildingDecorator getDefaultBuildingDecorator() {
return defaultBuildingDecorator;
}
/**
Set the BuildingDecorator for a set of GMLBuildings.
@param decorator The decorator to set.
@param buildings The buildings to set the decorator for.
*/
public void setBuildingDecorator(BuildingDecorator decorator, GMLBuilding... buildings) {
setBuildingDecorator(decorator, Arrays.asList(buildings));
}
/**
Set the BuildingDecorator for a set of GMLBuildings.
@param decorator The decorator to set.
@param buildings The buildings to set the decorator for.
*/
public void setBuildingDecorator(BuildingDecorator decorator, Collection<? extends GMLBuilding> buildings) {
for (GMLBuilding next : buildings) {
buildingDecorators.put(next, decorator);
}
}
/**
Get the BuildingDecorator for a GMLBuildings.
@param building The building to look up.
@return The BuildingDecorator for that building. This will be the default decorator if no custom decorator has been set for that building.
*/
public BuildingDecorator getBuildingDecorator(GMLBuilding building) {
BuildingDecorator result = buildingDecorators.get(building);
if (result == null) {
result = defaultBuildingDecorator;
}
return result;
}
/**
Remove any custom BuildingDecorator for a set of GMLBuildings.
@param buildings The buildings to remove any custom decorator for.
*/
public void clearBuildingDecorator(GMLBuilding... buildings) {
clearBuildingDecorator(Arrays.asList(buildings));
}
/**
Remove any custom BuildingDecorator for a set of GMLBuildings.
@param buildings The buildings to remove any custom decorator for.
*/
public void clearBuildingDecorator(Collection<? extends GMLBuilding> buildings) {
for (GMLBuilding next : buildings) {
buildingDecorators.remove(next);
}
}
/**
Remove any custom BuildingDecorators.
*/
public void clearAllBuildingDecorators() {
buildingDecorators.clear();
}
/**
Set the default road decorator.
@param defaultDecorator The new default road decorator.
*/
public void setDefaultRoadDecorator(RoadDecorator defaultDecorator) {
defaultRoadDecorator = defaultDecorator;
}
/**
Get the default road decorator.
@return The default road decorator.
*/
public RoadDecorator getDefaultRoadDecorator() {
return defaultRoadDecorator;
}
/**
Set the RoadDecorator for a set of GMLRoads.
@param decorator The decorator to set.
@param roads The roads to set the decorator for.
*/
public void setRoadDecorator(RoadDecorator decorator, GMLRoad... roads) {
setRoadDecorator(decorator, Arrays.asList(roads));
}
/**
Set the RoadDecorator for a set of GMLRoads.
@param decorator The decorator to set.
@param roads The roads to set the decorator for.
*/
public void setRoadDecorator(RoadDecorator decorator, Collection<? extends GMLRoad> roads) {
for (GMLRoad next : roads) {
roadDecorators.put(next, decorator);
}
}
/**
Get the RoadDecorator for a GMLRoads.
@param road The road to look up.
@return The RoadDecorator for that road. This will be the default decorator if no custom decorator has been set for that road.
*/
public RoadDecorator getRoadDecorator(GMLRoad road) {
RoadDecorator result = roadDecorators.get(road);
if (result == null) {
result = defaultRoadDecorator;
}
return result;
}
/**
Remove any custom RoadDecorator for a set of GMLRoads.
@param roads The roads to remove any custom decorator for.
*/
public void clearRoadDecorator(GMLRoad... roads) {
clearRoadDecorator(Arrays.asList(roads));
}
/**
Remove any custom RoadDecorator for a set of GMLRoads.
@param roads The roads to remove any custom decorator for.
*/
public void clearRoadDecorator(Collection<? extends GMLRoad> roads) {
for (GMLRoad next : roads) {
roadDecorators.remove(next);
}
}
/**
Remove any custom RoadDecorators.
*/
public void clearAllRoadDecorators() {
roadDecorators.clear();
}
/**
Set the default space decorator.
@param defaultDecorator The new default space decorator.
*/
public void setDefaultSpaceDecorator(SpaceDecorator defaultDecorator) {
defaultSpaceDecorator = defaultDecorator;
}
/**
Get the default space decorator.
@return The default space decorator.
*/
public SpaceDecorator getDefaultSpaceDecorator() {
return defaultSpaceDecorator;
}
/**
Set the SpaceDecorator for a set of GMLSpaces.
@param decorator The decorator to set.
@param spaces The spaces to set the decorator for.
*/
public void setSpaceDecorator(SpaceDecorator decorator, GMLSpace... spaces) {
setSpaceDecorator(decorator, Arrays.asList(spaces));
}
/**
Set the SpaceDecorator for a set of GMLSpaces.
@param decorator The decorator to set.
@param spaces The spaces to set the decorator for.
*/
public void setSpaceDecorator(SpaceDecorator decorator, Collection<? extends GMLSpace> spaces) {
for (GMLSpace next : spaces) {
spaceDecorators.put(next, decorator);
}
}
/**
Get the SpaceDecorator for a GMLSpaces.
@param space The space to look up.
@return The SpaceDecorator for that space. This will be the default decorator if no custom decorator has been set for that space.
*/
public SpaceDecorator getSpaceDecorator(GMLSpace space) {
SpaceDecorator result = spaceDecorators.get(space);
if (result == null) {
result = defaultSpaceDecorator;
}
return result;
}
/**
Remove any custom SpaceDecorator for a set of GMLSpaces.
@param spaces The spaces to remove any custom decorator for.
*/
public void clearSpaceDecorator(GMLSpace... spaces) {
clearSpaceDecorator(Arrays.asList(spaces));
}
/**
Remove any custom SpaceDecorator for a set of GMLSpaces.
@param spaces The spaces to remove any custom decorator for.
*/
public void clearSpaceDecorator(Collection<? extends GMLSpace> spaces) {
for (GMLSpace next : spaces) {
spaceDecorators.remove(next);
}
}
/**
Remove any custom SpaceDecorators.
*/
public void clearAllSpaceDecorators() {
spaceDecorators.clear();
}
/**
Set whether to draw the grid or not.
@param b True to draw the grid.
*/
public void setGridEnabled(boolean b) {
grid = b;
}
/**
Set the grid resolution.
@param resolution The new grid resolution.
*/
public void setGridResolution(double resolution) {
gridResolution = resolution;
}
/**
Add an overlay to the view.
@param overlay The overlay to add.
*/
public void addOverlay(Overlay overlay) {
overlays.add(overlay);
}
/**
Remove an overlay from the view.
@param overlay The overlay to remove.
*/
public void removeOverlay(Overlay overlay) {
overlays.remove(overlay);
}
@Override
public void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
Graphics copy = graphics.create();
copy.setColor(getBackground());
copy.fillRect(0, 0, getWidth(), getHeight());
if (map == null) {
return;
}
Insets insets = getInsets();
int width = getWidth() - insets.left - insets.right;
int height = getHeight() - insets.top - insets.bottom;
Graphics2D g = (Graphics2D)graphics.create(insets.left, insets.top, width + 1 , height + 1);
transform.rescale(width, height);
Collection<GMLRoad> roads;
Collection<GMLBuilding> buildings;
Collection<GMLSpace> spaces;
Collection<GMLEdge> edges;
Collection<GMLNode> nodes;
synchronized (map) {
roads = new HashSet<GMLRoad>(map.getRoads());
buildings = new HashSet<GMLBuilding>(map.getBuildings());
spaces = new HashSet<GMLSpace>(map.getSpaces());
edges = new HashSet<GMLEdge>(map.getEdges());
nodes = new HashSet<GMLNode>(map.getNodes());
}
for (GMLRoad next : roads) {
RoadDecorator d = getRoadDecorator(next);
if (d != null) {
d.decorate(next, (Graphics2D)g.create(), transform);
}
}
for (GMLBuilding next : buildings) {
BuildingDecorator d = getBuildingDecorator(next);
if (d != null) {
d.decorate(next, (Graphics2D)g.create(), transform);
}
}
for (GMLSpace next : spaces) {
SpaceDecorator d = getSpaceDecorator(next);
if (d != null) {
d.decorate(next, (Graphics2D)g.create(), transform);
}
}
for (GMLEdge next : edges) {
EdgeDecorator e = getEdgeDecorator(next);
if (e != null) {
e.decorate(next, (Graphics2D)g.create(), transform);
}
}
for (GMLNode next : nodes) {
NodeDecorator n = getNodeDecorator(next);
if (paintNodes&&n != null) {
n.decorate(next, (Graphics2D)g.create(), transform);
}
}
for (Overlay next : overlays) {
next.render((Graphics2D)g.create(), transform);
}
if (grid) {
double xMin = roundDownToGrid(transform.screenToX(0));
double xMax = roundUpToGrid(transform.screenToX(width));
double yMin = roundDownToGrid(transform.screenToY(height));
double yMax = roundUpToGrid(transform.screenToY(0));
g.setColor(GRID_COLOUR);
for (double worldX = xMin; worldX <= xMax; worldX += gridResolution) {
int x = transform.xToScreen(worldX);
g.drawLine(x, 0, x, height);
}
for (double worldY = yMin; worldY <= yMax; worldY += gridResolution) {
int y = transform.yToScreen(worldY);
g.drawLine(0, y, width, y);
}
}
}
@Override
public boolean isOpaque() {
return true;
}
/**
Enable or disable the pan/zoom feature.
@param enabled Whether pan/zoom should be enabled or not.
*/
public void setPanZoomEnabled(boolean enabled) {
panZoom.setEnabled(enabled);
}
/**
Get the coordinates of a point on screen.
@param x The screen x coordinate.
@param y The screen y coordinate.
@return The coordinates in the GML map under the screen point.
*/
public GMLCoordinates getCoordinatesAtPoint(int x, int y) {
double cx = transform.screenToX(x);
double cy = transform.screenToY(y);
return new GMLCoordinates(cx, cy);
}
/**
Get the on-screen coordinates for a point.
@param c The GML coordinates to look up.
@return The on-screen coordinates of the point.
*/
public Point getScreenCoordinates(GMLCoordinates c) {
int x = transform.xToScreen(c.getX());
int y = transform.yToScreen(c.getY());
return new Point(x, y);
}
private double roundDownToGrid(double d) {
return Math.floor(d / gridResolution) * gridResolution;
}
private double roundUpToGrid(double d) {
return Math.ceil(d / gridResolution) * gridResolution;
}
public void setPaintNodes(boolean paintNodes) {
this.paintNodes = paintNodes;
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment