Package business

Source Code of business.CalculateRoutes

package business;

import com.vividsolutions.jts.geom.*;
import org.geotools.data.DataUtilities;
import org.geotools.data.FeatureSource;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureCollections;
import org.geotools.feature.FeatureIterator;
import org.geotools.feature.SchemaException;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.geometry.jts.FactoryFinder;
import org.geotools.geometry.jts.JTS;
import org.geotools.graph.build.feature.FeatureGraphGenerator;
import org.geotools.graph.build.line.LineStringGraphGenerator;
import org.geotools.graph.path.DijkstraShortestPathFinder;
import org.geotools.graph.path.Path;
import org.geotools.graph.structure.Graph;
import org.geotools.graph.structure.Node;
import org.geotools.graph.structure.basic.BasicEdge;
import org.geotools.graph.traverse.standard.DijkstraIterator.EdgeWeighter;
import org.opengis.feature.Feature;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.TransformException;
import utilities.Logger;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Vector;

public class CalculateRoutes {

    private Graph networkGraph;
    private LineStringGraphGenerator lineStringGen = new LineStringGraphGenerator();
    private FeatureCollection<SimpleFeatureType, SimpleFeature> routeFeatures = FeatureCollections.newCollection();
    private DijkstraShortestPathFinder shortestPathFinder;
    private ArrayList<Double> Costs = new ArrayList<Double>();
    private Double distanceOriginToGraph = 0.0;
    private static CoordinateReferenceSystem coordinateReferenceSystem;
    private NodeHelper nodeHelper = new NodeHelper();

    // Compiles successfully when using geotools-2.7-RC2
    // http://sourceforge.net/projects/geotools/files/GeoTools%202.7%20Releases/

    public void buildNetwork(FeatureCollection networkFC, Point originPoint) throws TransformException {
        coordinateReferenceSystem = networkFC.getSchema().getCoordinateReferenceSystem();
        //get the object to generate the graph from line string objects
        LineStringGraphGenerator lineStringGen = new LineStringGraphGenerator();
        //wrap it in a feature graph generator
        FeatureGraphGenerator featureGen = new FeatureGraphGenerator(lineStringGen);
        //throw all the features into the graph generator
        FeatureIterator featureIterator = networkFC.features();
        try {
            while (featureIterator.hasNext()) {
                Feature feature = featureIterator.next();
                featureGen.add(feature);
            }
        } finally {
            featureIterator.close();
        }
        //build the graph
        networkGraph = featureGen.getGraph();

        //find the node of the graph closest to the origin point and returns the node
        Node source = nodeHelper.getNearestGraphNode(lineStringGen, networkGraph, originPoint, coordinateReferenceSystem);
        //distance between the origin location and the nearest graph node
        distanceOriginToGraph = nodeHelper.getDistanceFromGraphNode();

        //weight the edges of the graph using the distance of each linestring
        EdgeWeighter edgeWeighter = new EdgeWeighter() {
            public double getWeight(org.geotools.graph.structure.Edge edge) {
                SimpleFeature aLineString = (SimpleFeature) edge.getObject();
                Geometry geom = (Geometry) aLineString.getDefaultGeometry();
                return geom.getLength();
            }
        };

        //calculate the cost(distance) of each graph node to the node closest to the origin
        shortestPathFinder = new DijkstraShortestPathFinder(networkGraph, source, edgeWeighter);
        shortestPathFinder.calculate();
    }

    public boolean calculateRouteFeature(Point originPoint, Point destinationPoint, int id) throws SchemaException, TransformException {
        //this calculates the route and builds a FeatureCollection of route objects, to do this the geometries of the various
        //linestrings contained within a path object (e.g. each road that makes up the route) must be merged to make one feature

        //get the graph node closest to the destination point object
        Node destination = nodeHelper.getNearestGraphNode(lineStringGen, networkGraph, destinationPoint, coordinateReferenceSystem);
        //get the path (route) from origin to destination
        Logger.d("Calc route feature, destination: " + destination);
        Path path = shortestPathFinder.getPath(destination);
        //Logger.d("Calc route feature, path: " + path);

        //this happens if the closest node is the endpoint of a disconnected line
        if (path == null) {
            Logger.w("Could not calculate the route to this destination" +
                    ". There is probably a problem with the network data set (dangles etc ...)");
            return false;
        }

        //create a vector object to store all the edges
        Vector result = new Vector();
        Node previous = null;
        Node node;

        //iterate through the path object getting each node and it's neighbour and build edge objects from them
        for (Iterator iterator = path.riterator(); iterator.hasNext();) {
            node = (Node) iterator.next();
            if (previous != null) {
                // Adds the resulting edge into the vector
                result.add(node.getEdge(previous));
            }
            previous = node;
        }

        //create an array to store the geometry of each Edge linestring that will need to be merged into one Route object
        Geometry[] geomArray = new Geometry[result.size()];

        //populate the geometry array with the route edges
        for (int i = 0; i < result.size(); i++) {
            BasicEdge eg = (BasicEdge) result.get(i);
            SimpleFeature feature = (SimpleFeature) eg.getObject();
            Geometry geom = (Geometry) feature.getDefaultGeometry();
            geomArray[i] = geom;
        }

        //call the function to merge the geometries into one feature
        Geometry routeGeometry = buildRouteGeometry(geomArray);

        //checks to see if the Route object is valid, If the origin and destinaton are so close to each other
        //that they share the same closest graph node then no path is created and the resulting geometry is null.
        //This causes all sorts of errors when the FeatureStore is built i.e. it returns nothing when the
        //getBounds() function is called on it which a map renderer needs to draw the layer. Therefore a straight line
        //between the two objects is drawn and the cost is the straight line distance

        if (shortestPathFinder.getCost(destination) != 0) {
            //path is not null
            Double distanceDestinationToGraph = nodeHelper.getDistanceFromGraphNode();
            SimpleFeature routeFeature = buildNewRouteFeature(routeGeometry, shortestPathFinder, destination, distanceDestinationToGraph + distanceOriginToGraph, id);
            routeFeatures.add(routeFeature);
            Logger.i("Shortest path exists " + routeFeatures.size());
        } else {
            Logger.w("Shortest path NULL");
            //path is null
            SimpleFeature routeFeature = buildNullFeature(originPoint, destinationPoint, id);
            routeFeatures.add(routeFeature);
        }
        return true;
    }

    //function that combines the geometries of the path into one single route geometry
    private Geometry buildRouteGeometry(Geometry[] geomArray) {
        Geometry all = null;
        int length = geomArray.length;
        Geometry geomToAddTemp;
        for (int i = 0; i < length; i++) {
            geomToAddTemp = geomArray[i];
            if (all == null) {
                all = geomToAddTemp;
            } else {
                all = all.union(geomToAddTemp);
            }
        }
        return all;
    }

    //function that builds the route feature
    private static SimpleFeature buildNewRouteFeature(Geometry routeGeometry, DijkstraShortestPathFinder dijkstraShortestPathFinder,
                                                      Node destination, Double distanceToGraph, int objectId) throws SchemaException {
        //builds a feature containing geometry, Cost and ID of the Route with a Swiss SRID
        final SimpleFeatureType TYPE = DataUtilities.createType("Location",
                "the_geom:MultiLineString:srid=4326," + // <- the geometry attribute: Polyline type
                        "travel_distance_m:Double," + "objectid:Integer"// <- a String attribute
        );

        //populates the new feature object, builds it and returns it
        SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE);
        featureBuilder.add(routeGeometry);
        //Cost is calculates here using the cost (Distance) of the route plus the straight line distances between the closest graph nodes
        //and the origin and destination points
        featureBuilder.add(dijkstraShortestPathFinder.getCost(destination) + distanceToGraph);
        featureBuilder.add(objectId);

        return featureBuilder.buildFeature(null);
    }

    private static SimpleFeature buildNullFeature(Point originPoint, Point destinationPoint, int objectId) throws SchemaException, TransformException {
        //builds a feature containing geometry, Cost and ID of the Route with a Swiss SRID when no path is returned because the objects are too close
        final SimpleFeatureType TYPE = DataUtilities.createType("Location",
                "the_geom:MultiLineString:srid=4326," + // <- the geometry attribute: Polyline type
                        "travel_distance_m:Double," + "objectid:String"// <- a String attribute
        );

        SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE);

        //builds the line between the two locations
        GeometryFactory factory = FactoryFinder.getGeometryFactory(null);
        Coordinate[] coordList = new Coordinate[2];
        coordList[0] = new Coordinate(originPoint.getX(), originPoint.getY());
        coordList[1] = new Coordinate(destinationPoint.getX(), destinationPoint.getY());
        LineString routeLs = factory.createLineString(coordList);

        //populates the new feature object, builds it and returns it
        featureBuilder.add(routeLs);
        featureBuilder.add(calculateDistance(originPoint.getX(), originPoint.getY(), destinationPoint.getCoordinate().x, destinationPoint.getCoordinate().y, coordinateReferenceSystem));
        featureBuilder.add(objectId);

        return featureBuilder.buildFeature(null);
    }

    public FeatureSource<SimpleFeatureType, SimpleFeature> getRouteFeatureSource() throws IOException {
        // returns the feature collection of routes as a feature source
        return DataUtilities.source(routeFeatures);
    }

    public void calculateCostArrayList(Point originPoint, Point destinationPoint) throws SchemaException, TransformException {
        //calculates the cost between an origin and destination point
        Node destination = nodeHelper.getNearestGraphNode(lineStringGen, networkGraph, destinationPoint, coordinateReferenceSystem);
        Costs.add(shortestPathFinder.getCost(destination));
    }

    public ArrayList<Double> getCostArray() {
        //returns the costarray
        return (ArrayList<Double>) Costs.clone();
    }

    private static double calculateDistance(double xOrig, double yOrig, double xDest, double yDest,
                                            CoordinateReferenceSystem crs) throws TransformException {
        // Calculates straight line distance
        Coordinate start = new Coordinate(xOrig, yOrig);
        Coordinate end = new Coordinate(xDest, yDest);
        double distance = JTS.orthodromicDistance(start, end, crs);
        Logger.i("Straight distance: " + distance);
        return distance;
    }
}
TOP

Related Classes of business.CalculateRoutes

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.