Skip to content

Commit

Permalink
basic vanilla extract loader/server in Java
Browse files Browse the repository at this point in the history
  • Loading branch information
abyrd committed Feb 27, 2015
1 parent 7339dad commit d5d0ef0
Show file tree
Hide file tree
Showing 8 changed files with 288 additions and 74 deletions.
17 changes: 0 additions & 17 deletions src/main/java/org/opentripplanner/osm/FullParser.java

This file was deleted.

3 changes: 3 additions & 0 deletions src/main/java/org/opentripplanner/osm/NodeTracker.java
Expand Up @@ -12,6 +12,9 @@
* Each block is 64 64-bit longs. At 512 bytes long, it tracks 4096 IDs. * Each block is 64 64-bit longs. At 512 bytes long, it tracks 4096 IDs.
* Node numbers in OSM tend to be contiguous so maybe the blocks should be bigger. * Node numbers in OSM tend to be contiguous so maybe the blocks should be bigger.
* Disabled debug statements have no measurable effect on speed (verified). * Disabled debug statements have no measurable effect on speed (verified).
*
* MapDB TreeSets are much faster than MapDB HashSets, but in-memory NodeTrackers are
* much faster than MapDB TreeSets.
*/ */
public class NodeTracker { public class NodeTracker {


Expand Down
61 changes: 22 additions & 39 deletions src/main/java/org/opentripplanner/osm/OSM.java
@@ -1,15 +1,16 @@
package org.opentripplanner.osm; package org.opentripplanner.osm;


import java.io.File; import com.google.common.collect.Maps;
import java.util.Map; import com.vividsolutions.jts.geom.Envelope;

import org.mapdb.DB; import org.mapdb.DB;
import org.mapdb.DBMaker; import org.mapdb.DBMaker;
import org.mapdb.Fun.Tuple3;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;


import com.google.common.collect.Maps; import java.io.File;
import com.vividsolutions.jts.geom.Envelope; import java.util.Map;
import java.util.NavigableSet;


/** /**
* OTP representation of a subset of OpenStreetMap. One or more PBF files can be loaded into this * OTP representation of a subset of OpenStreetMap. One or more PBF files can be loaded into this
Expand All @@ -22,46 +23,47 @@ public class OSM {
public Map<Long, Node> nodes; public Map<Long, Node> nodes;
public Map<Long, Way> ways; public Map<Long, Way> ways;
public Map<Long, Relation> relations; public Map<Long, Relation> relations;
public NavigableSet<Tuple3<Integer, Integer, Long>> index; // (x, y, wayId)


/** The nodes which are referenced more than once by ways in this OSM. */
public NodeTracker intersections;

/** The MapDB backing this OSM, if any. */ /** The MapDB backing this OSM, if any. */
DB db = null; // db.close(); ? DB db = null; // db.close(); ?


public OSM(boolean diskBacked) { /** If diskPath is null, OSM will be loaded into memory. */
public OSM(String diskPath) {
// Using DB TreeMaps is observed not to be slower than memory. // Using DB TreeMaps is observed not to be slower than memory.
// HashMaps are both bigger and slower. // HashMaps are both bigger and slower.
// It lets you run in 400MB instead of a few GB. // It lets you run in 400MB instead of a few GB.
if (diskBacked) { if (diskPath != null) {
LOG.info("OSM backed by temporary file."); LOG.info("OSM backed by file.");
DB db = DBMaker.newFileDB(new File("/mnt/ssd2/vex/osmdb")) // use newMemoryDB for higher speed? DB db = DBMaker.newFileDB(new File(diskPath))
.transactionDisable() .transactionDisable()
.asyncWriteEnable() .asyncWriteEnable()
.compressionEnable() .compressionEnable()
.make(); .make();
nodes = db.getTreeMap("nodes"); nodes = db.getTreeMap("nodes");
ways = db.getTreeMap("ways"); ways = db.getTreeMap("ways");
relations = db.getTreeMap("relations"); relations = db.getTreeMap("relations");
index = db.getTreeSet("spatial_index");
} else { } else {
// In-memory version // In-memory version
// use newMemoryDB for higher speed?
nodes = Maps.newHashMap(); nodes = Maps.newHashMap();
ways = Maps.newHashMap(); ways = Maps.newHashMap();
relations = Maps.newHashMap(); relations = Maps.newHashMap();
} }
} }


// boolean filterTags // boolean filterTags
public static OSM fromPBF(String pbfFile) { public static OSM fromPBF(String pbfFile) {
LOG.info("Reading entire PBF file '{}'", pbfFile); LOG.info("Reading entire PBF file '{}'", pbfFile);
FullParser fp = new FullParser(); Parser parser = new Parser(null);
fp.parse(pbfFile); parser.parse(pbfFile);
return fp.osm; return parser.osm;
} }


public static OSM fromPBF(String pbfFile, Envelope env) { public static OSM fromPBF(String pbfFile, Envelope env) {
LOG.info("Reading PBF file '{}' filtering with envelope {}", pbfFile, env); LOG.info("Reading PBF file '{}' filtering with envelope {}", pbfFile, env);
OSM osm = new OSM(true); OSM osm = new OSM("/var/vex/osm");
LOG.info("Finding nodes within the bounding geometry."); LOG.info("Finding nodes within the bounding geometry.");
NodeGeomFilter ngf = new NodeGeomFilter(env); NodeGeomFilter ngf = new NodeGeomFilter(env);
ngf.parse(pbfFile); ngf.parse(pbfFile);
Expand All @@ -74,26 +76,7 @@ public static OSM fromPBF(String pbfFile, Envelope env) {
LOG.info("Loading relations (which ones?)"); LOG.info("Loading relations (which ones?)");
return osm; return osm;
} }


/**
* Find nodes referenced by more than one way. NodeTracker intersections will be null until this
* is called. MapDB TreeSets are much faster than MapDB HashSets, but in-memory NodeTrackers are
* much faster than MapDB TreeSets.
*/
public void findIntersections() {
LOG.info("Finding intersections.");
intersections = new NodeTracker();
NodeTracker referenced = new NodeTracker();
for (Way way : ways.values()) {
for (long nid : way.nodes) {
if (referenced.contains(nid)) {
intersections.add(nid); // seen more than once
} else {
referenced.add(nid); // seen for the first time
}
}
}
LOG.info("Done finding intersections.");
}


} }
8 changes: 2 additions & 6 deletions src/main/java/org/opentripplanner/osm/OSMMain.java
Expand Up @@ -3,7 +3,6 @@
import com.google.common.collect.HashMultimap; import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.google.protobuf.ByteString;
import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Envelope;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -38,9 +37,6 @@
public class OSMMain { public class OSMMain {


private static final Logger LOG = LoggerFactory.getLogger(OSMMain.class); private static final Logger LOG = LoggerFactory.getLogger(OSMMain.class);
//static final String INPUT = "/var/otp/graphs/ny/new-york-latest.osm.pbf";
//static final String INPUT = "/var/otp/graphs/nl/netherlands-latest.osm.pbf";
//static final String INPUT = "/var/otp/graphs/trimet/portland.osm.pbf";
static final Envelope ENV = new Envelope(4.4, 5.5, 52.2, 53.3); static final Envelope ENV = new Envelope(4.4, 5.5, 52.2, 53.3);


public static void main(String[] args) { public static void main(String[] args) {
Expand Down Expand Up @@ -85,7 +81,7 @@ public static void analyzeTags(OSM osm) {
} }


public static List<Edge> makeEdges(OSM osm) { public static List<Edge> makeEdges(OSM osm) {
osm.findIntersections(); // osm.findIntersections();
LOG.info("Making edges from Ways."); LOG.info("Making edges from Ways.");
List<Edge> edges = Lists.newArrayList(); List<Edge> edges = Lists.newArrayList();
for (Entry<Long, Way> e : osm.ways.entrySet()) { for (Entry<Long, Way> e : osm.ways.entrySet()) {
Expand All @@ -98,7 +94,7 @@ public static List<Edge> makeEdges(OSM osm) {
if (n == (way.nodes.length - 1)) { if (n == (way.nodes.length - 1)) {
edge.to = node; edge.to = node;
edges.add(edge); edges.add(edge);
} else if (osm.intersections.contains(node)) { // } else if (osm.intersections.contains(node)) {
edge.to = node; edge.to = node;
edges.add(edge); edges.add(edge);
edge = new Edge(); edge = new Edge();
Expand Down
61 changes: 61 additions & 0 deletions src/main/java/org/opentripplanner/osm/OSMTextOutput.java
@@ -0,0 +1,61 @@
package org.opentripplanner.osm;

import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Locale;

/**
* Write OSM ways and nodes out to a simple human-readable text format.
*/
public class OSMTextOutput {

OutputStream out;
PrintStream print;
OSM osm;
NodeTracker nodesSeen;

public OSMTextOutput (OutputStream out, OSM osm) {
this.osm = osm;
this.out = out;
this.print = new PrintStream(out);
nodesSeen = new NodeTracker();
}

public void printWay(long wayId) {
Way way = osm.ways.get(wayId);
print.print("W ");
print.print(wayId);
print.print(' ');
print.print(way.tags);
print.print('\n');
for (long nodeId : way.nodes) {
if (nodesSeen.contains(nodeId)) {
printNodeFull(nodeId);
// printNodeRef(nodeId);
} else {
printNodeFull(nodeId);
nodesSeen.add(nodeId);
}
}
}

public void printNodeRef(long nodeId) {
print.print("N ");
print.print(nodeId);
print.print('\n');
}

public void printNodeFull(long nodeId) {
print.print("N ");
print.print(nodeId);
print.print(' ');
Node node = osm.nodes.get(nodeId);
print.printf(Locale.US, "%2.6f", node.lat);
print.print(' ');
print.printf(Locale.US, "%3.6f", node.lon);
print.print(' ');
print.print(node.tags);
print.print('\n');
}

}
29 changes: 17 additions & 12 deletions src/main/java/org/opentripplanner/osm/Parser.java
Expand Up @@ -13,19 +13,16 @@
* not, see <http://www.gnu.org/licenses/>. * not, see <http://www.gnu.org/licenses/>.
*/ */


import java.io.FileInputStream; import crosby.binary.BinaryParser;
import java.io.IOException; import crosby.binary.Osmformat;
import java.util.List; import crosby.binary.file.BlockInputStream;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import org.opentripplanner.osm.Relation.Type; import org.opentripplanner.osm.Relation.Type;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;


import crosby.binary.BinaryParser; import java.io.FileInputStream;
import crosby.binary.Osmformat; import java.io.IOException;
import crosby.binary.file.BlockInputStream; import java.util.List;


/** /**
* Parser for the OpenStreetMap PBF Format. Implements callbacks for the crosby.binary OSMPBF * Parser for the OpenStreetMap PBF Format. Implements callbacks for the crosby.binary OSMPBF
Expand All @@ -38,7 +35,7 @@
* parseDense, etc. rather than the corresponding handle* methods to avoid ever converting the * parseDense, etc. rather than the corresponding handle* methods to avoid ever converting the
* low-level PBF objects into objects using OTP's internal OSM model. * low-level PBF objects into objects using OTP's internal OSM model.
*/ */
public abstract class Parser extends BinaryParser { public class Parser extends BinaryParser {


protected static final Logger LOG = LoggerFactory.getLogger(Parser.class); protected static final Logger LOG = LoggerFactory.getLogger(Parser.class);


Expand All @@ -47,7 +44,15 @@ public abstract class Parser extends BinaryParser {
// private Map<String, String> stringTable = new HashMap<String, String>(); // private Map<String, String> stringTable = new HashMap<String, String>();
long nodeCount = 0; long nodeCount = 0;
long wayCount = 0; long wayCount = 0;


public Parser () {
osm = new OSM(null);
}

public Parser (String diskPath) {
osm = new OSM(diskPath);
}

private static final String[] retainKeys = new String[] { private static final String[] retainKeys = new String[] {
"highway", "parking", "bicycle" "highway", "parking", "bicycle"
}; };
Expand All @@ -61,7 +66,7 @@ private boolean retainTag(String key) {
// Not storing elements that lack interesting tags // Not storing elements that lack interesting tags
// reduces size by 80%. // reduces size by 80%.
// return true; // return true;
return false; return true;
} }


// Load ways first, then skip loading all nodes which are not tracked. // Load ways first, then skip loading all nodes which are not tracked.
Expand Down

0 comments on commit d5d0ef0

Please sign in to comment.