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;
}
}
}