Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New input and output format defined in GeoJson as Feature sets. #34

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions src/main/java/com/bmwcarit/barefoot/matcher/MatcherKState.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,21 @@

package com.bmwcarit.barefoot.matcher;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Hashtable;
import java.util.Iterator;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.bmwcarit.barefoot.markov.KState;
import com.bmwcarit.barefoot.road.BaseRoad;
import com.bmwcarit.barefoot.road.Heading;
import com.bmwcarit.barefoot.roadmap.Road;
import com.bmwcarit.barefoot.roadmap.RoadMap;
import com.bmwcarit.barefoot.road.RoadOutputPath;
import com.esri.core.geometry.GeometryEngine;
import com.esri.core.geometry.Polyline;
import com.esri.core.geometry.WktExportFlags;
Expand Down Expand Up @@ -156,6 +164,77 @@ public JSONArray toSlimJSON() throws JSONException {
}
return json;
}


/**
* Gets {@link JSONObject} with GeoJSON FeatureCollection format of {@link MatcherKState} matched geometries.
*
* @return {@link JSONObject} with GeoJSON FeatureCollection format of {@link MatcherKState} matched geometries.
* @throws JSONException thrown on JSON extraction or parsing error.
*/
public JSONObject toGeoJSONFeatures() throws JSONException {


JSONObject json = new JSONObject();
json.put("type", "FeatureCollection");

JSONObject jsonFeature = null;
JSONObject jsonFeatureProperties = null;
MatcherCandidate candidate = null;
JSONArray jsonsequenceFeatures = new JSONArray();
Polyline localGeometry = null;
Hashtable<Integer, RoadOutputPath> roadOutputPathList = null;
BaseRoad baseRoad = null;
ArrayList<Integer>keysCollections = null;
Integer pathIndex = null;
Integer featuresIndex = 1;
Iterator<Integer> keyIterator = null;
Heading heading = null;
json.put("features", jsonsequenceFeatures);

if (this.sequence() != null) {
for (int i = 0; i < this.sequence().size(); ++i) {
candidate = this.sequence().get(i);

if (candidate.transition() != null) {

roadOutputPathList = candidate.transition().route().geometryList();
keysCollections = new ArrayList<Integer>(roadOutputPathList.keySet());
Collections.sort(keysCollections);
keyIterator = keysCollections.iterator();
while(keyIterator.hasNext()){
pathIndex = keyIterator.next();
localGeometry = roadOutputPathList.get(pathIndex).getGeometry();
baseRoad = roadOutputPathList.get(pathIndex).getBase();
heading = roadOutputPathList.get(pathIndex).getHeading();
if(localGeometry!=null){
jsonFeature = new JSONObject();
jsonFeature.put("type", "Feature");
jsonFeature.put("geometry", new JSONObject(GeometryEngine.geometryToGeoJson(localGeometry)));

jsonFeatureProperties = new JSONObject();
jsonFeatureProperties.put("id", featuresIndex);
featuresIndex++;

jsonFeatureProperties.put("roadid", baseRoad.refid());
jsonFeatureProperties.put("time", this.samples().get(i).time() / 1000);
jsonFeatureProperties.put("oneway", baseRoad.oneway());
jsonFeatureProperties.put("maxspeed", baseRoad.maxspeed(heading));
jsonFeatureProperties.put("heading", heading.toString());

jsonFeature.put("properties", jsonFeatureProperties);
jsonsequenceFeatures.put(jsonFeature);
}
}

}

}

}

return json;
}

private Polyline monitorRoute(MatcherCandidate candidate) {
Polyline routes = new Polyline();
Expand Down
70 changes: 70 additions & 0 deletions src/main/java/com/bmwcarit/barefoot/matcher/MatcherServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import com.bmwcarit.barefoot.topology.Dijkstra;
import com.bmwcarit.barefoot.util.AbstractServer;
import com.bmwcarit.barefoot.util.Stopwatch;
import com.esri.core.geometry.Point;

/**
* Matcher server (stand-alone) for Hidden Markov Model offline map matching. It is a
Expand Down Expand Up @@ -94,6 +95,56 @@ public List<MatcherSample> format(String input) {
}
}


/**
* Input formatter for writing map matched positions, represented be road id and fraction, and
* the geometry of the routes into a GeoJSON FeatureCollection format response message.
*/
public static class GeoJSONFeaturesInputFormatter extends InputFormatter {
@Override
public List<MatcherSample> format(String input) {
List<MatcherSample> samples = new LinkedList<MatcherSample>();
try{
Object jsoninput = new JSONTokener(input).nextValue();
JSONArray jsonsamples = null;
JSONArray coordinates = null;
Point point = null;
String id = null;
Long time = null;



if (jsoninput instanceof JSONObject) {
jsonsamples = ((JSONObject) jsoninput).getJSONArray("features");
} else {
jsonsamples = ((JSONArray) jsoninput);
}


Set<Long> times = new HashSet<Long>();
for (int i = 0; i < jsonsamples.length(); ++i) {
coordinates = jsonsamples.getJSONObject(i).getJSONObject("geometry").getJSONArray("coordinates");
point = new Point(coordinates.getDouble(0), coordinates.getDouble(1));
id = jsonsamples.getJSONObject(i).getJSONObject("properties").getString("id");
time = jsonsamples.getJSONObject(i).getJSONObject("properties").getLong("time");
MatcherSample sample = new MatcherSample(id, time, point);
samples.add(sample);
if (times.contains(sample.time())) {
throw new RuntimeException("multiple samples for same time");
} else {
times.add(sample.time());
}
}


} catch (JSONException e) {
e.printStackTrace();
throw new RuntimeException("parsing JSON request: " + e.getMessage());
}
return samples;
}
}

/**
* Default output formatter for writing the JSON representation of a {@link KState} object with
* map matching of the input into a response message.
Expand Down Expand Up @@ -130,6 +181,7 @@ public String format(String request, MatcherKState output) {
}
}


/**
* Output formatter for writing the geometries of a map matched paths into GeoJSON response
* message.
Expand All @@ -144,6 +196,22 @@ public String format(String request, MatcherKState output) {
}
}
}


/**
* Output formatter for writing the geometries of a map matched paths into
* GeoJSON FeatureCollection format response message.
*/
public static class GeoJSONFeaturesOutputFormatter extends OutputFormatter {
@Override
public String format(String request, MatcherKState output) {
try {
return output.toGeoJSONFeatures().toString();
} catch (JSONException e) {
throw new RuntimeException("creating GeoJSONFeatures response");
}
}
}

/**
* Output formatter for writing extensive format of input and output of map matching in a JSON
Expand Down Expand Up @@ -182,6 +250,8 @@ public String format(String request, MatcherKState output) {
return new SlimJSONOutputFormatter().format(request, output);
case "geojson":
return new GeoJSONOutputFormatter().format(request, output);
case "geojsonfeatures":
return new GeoJSONFeaturesOutputFormatter().format(request, output);
case "debug":
return new DebugJSONOutputFormatter().format(request, output);
default:
Expand Down
10 changes: 9 additions & 1 deletion src/main/java/com/bmwcarit/barefoot/matcher/ServerControl.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import org.slf4j.LoggerFactory;

import com.bmwcarit.barefoot.matcher.MatcherServer.DebugJSONOutputFormatter;
import com.bmwcarit.barefoot.matcher.MatcherServer.GeoJSONFeaturesOutputFormatter;
import com.bmwcarit.barefoot.matcher.MatcherServer.GeoJSONFeaturesInputFormatter;
import com.bmwcarit.barefoot.matcher.MatcherServer.GeoJSONOutputFormatter;
import com.bmwcarit.barefoot.matcher.MatcherServer.InputFormatter;
import com.bmwcarit.barefoot.matcher.MatcherServer.OutputFormatter;
Expand Down Expand Up @@ -126,7 +128,7 @@ public static void stopServer() {
public static void main(String[] args) {
if (args.length < 2 || args.length > 3) {
logger.error(
"missing arguments\nusage: [--slimjson|--debug|--geojson] /path/to/server/properties /path/to/mapserver/properties");
"missing arguments\nusage: [--slimjson|--debug|--geojson|--geojsonfeatures] [--geojsonfeaturesinput] /path/to/server/properties /path/to/mapserver/properties");
System.exit(1);
}

Expand All @@ -145,6 +147,12 @@ public static void main(String[] args) {
case "--geojson":
output = new GeoJSONOutputFormatter();
break;
case "--geojsonfeatures":
output = new GeoJSONFeaturesOutputFormatter();
break;
case "--geojsonfeaturesinput":
input = new GeoJSONFeaturesInputFormatter();
break;
default:
logger.warn("invalid option {} ignored", args[i]);
break;
Expand Down
84 changes: 84 additions & 0 deletions src/main/java/com/bmwcarit/barefoot/road/RoadOutputPath.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright (C) 2016
*
* Author: Jody Marca <[email protected]>
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in
* writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*/

package com.bmwcarit.barefoot.road;

import com.bmwcarit.barefoot.road.BaseRoad;
import com.bmwcarit.barefoot.road.Heading;
import com.esri.core.geometry.Polyline;

/**
* RoadOutputPath data structure for a openpenstreetmap road segment.
*
* Provade a geometry (subset or equals to openpenstreetmap geometry) and
* a link to {@link BaseRoad} with relative {@link Heading}
*/
public class RoadOutputPath {

private BaseRoad base = null;
private Polyline geometry = null;
private Heading heading = null;

/**
* Constructs {@link RoadOutputPath} object.
*
* @param base {@link BaseRoad} object associated
* @param geometry It's a part of Road geometry as {@link Polyline} object.
* @param heading {@link Heading} needed for speed computation
*/
public RoadOutputPath(BaseRoad base, Polyline geometry, Heading heading) {
this.base = base;
this.geometry = geometry;
this.heading = heading;
}

/**
* Gets {@link BaseRoad} object associated
* @return baseRoad object associated
*/
public BaseRoad getBase() {
return base;
}

/**
* Gets road's geometry as a {@link Polyline} as part of Road geometry.
*
* @return Road's geometry as {@link Polyline} as part of Road geometry.
*/
public Polyline getGeometry() {
return geometry;
}

/**
* Gets the {@link BaseRoad} identifier if presents
*
* @return baseroad identifier or null
*/
public Long getId(){
if(base == null){
return null;
}else{
return base.refid();
}
}

/**
* Gets {@link Heading} needed for speed computation
* @return heading associated to the instance
*/
public Heading getHeading() {
return heading;
}


}
Loading