| @@ -0,0 +1,220 @@ | ||
| /** | ||
| * Copyright (C) 2012, Emergya (http://www.emergya.es) | ||
| * | ||
| * @author <a href="mailto:marias@emergya.com">María Arias de Reyna</a> | ||
| * | ||
| * This file is part of GoFleet | ||
| * | ||
| * This software is free software; you can redistribute it and/or modify | ||
| * it under the terms of the GNU General Public License as published by | ||
| * the Free Software Foundation; either version 2 of the License, or (at | ||
| * your option) any later version. | ||
| * | ||
| * This software is distributed in the hope that it will be useful, but | ||
| * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| * General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU General Public License | ||
| * along with this library; if not, write to the Free Software | ||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| * 02110-1301 USA | ||
| * | ||
| * As a special exception, if you link this library with other files to | ||
| * produce an executable, this library does not by itself cause the | ||
| * resulting executable to be covered by the GNU General Public License. | ||
| * This exception does not however invalidate any other reasons why the | ||
| * executable file might be covered by the GNU General Public License. | ||
| */ | ||
| package org.emergya.backtrackTSP; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| import java.util.concurrent.ExecutorService; | ||
| import java.util.concurrent.Executors; | ||
| import java.util.concurrent.TimeUnit; | ||
|
|
||
| import org.apache.commons.logging.Log; | ||
| import org.apache.commons.logging.LogFactory; | ||
| import org.gofleet.openLS.tsp.TSPAlgorithm; | ||
| import org.gofleet.openLS.tsp.TSPStop; | ||
| import org.gofleet.openLS.tsp.TSPStopBag; | ||
|
|
||
| public class BackTrackingTSP implements TSPAlgorithm { | ||
| private static Log LOG = LogFactory.getLog(BackTrackingTSP.class); | ||
|
|
||
| private Boolean partialSolution = false; | ||
| private Integer seconds = 18; | ||
|
|
||
| private ExecutorService executor; | ||
| private ExecutorService executor2; | ||
|
|
||
| public BackTrackingTSP() { | ||
| } | ||
|
|
||
| /** | ||
| * If we cannot find a solution, do you like to get the best partial | ||
| * solution reached? | ||
| * | ||
| * @param partialSolution | ||
| */ | ||
| public BackTrackingTSP(Boolean partialSolution, Integer seconds) { | ||
| this(); | ||
| if (partialSolution != null) | ||
| this.partialSolution = partialSolution; | ||
| this.seconds = seconds; | ||
| } | ||
|
|
||
| public List<TSPStop> order(TSPStopBag _bag) { | ||
| long time = System.currentTimeMillis(); | ||
|
|
||
| Runtime runtime = Runtime.getRuntime(); | ||
| int numthreads = runtime.availableProcessors() * 10; | ||
|
|
||
| executor = Executors.newFixedThreadPool(numthreads); | ||
|
|
||
| DistanceMatrix distances = new DistanceMatrix(); | ||
|
|
||
| initializeMatrix(distances, _bag); | ||
|
|
||
| SolutionContainer solutions = new SolutionContainer(distances); | ||
|
|
||
| if (_bag.size() > 7) { | ||
| if (_bag.hasLast()) { | ||
| // run(executor, new AStar(_bag, distances, solutions)); | ||
| run(executor, new HeuristicBacktracking(_bag, distances, | ||
| solutions)); | ||
| } else { | ||
| for (TSPStop stop : _bag.getAll()) { | ||
| List<TSPStop> stops = new ArrayList<TSPStop>(); | ||
| stops.addAll(_bag.getAll()); | ||
| stops.remove(stop); | ||
|
|
||
| BacktrackStopBag bag = new BacktrackStopBag(stops, | ||
| _bag.getFirst(), stop); | ||
| // run(executor, new AStar(bag, distances, solutions)); | ||
| run(executor, new HeuristicBacktracking(bag, distances, | ||
| solutions)); | ||
| } | ||
| } | ||
| } | ||
| run(executor, new Backtracking(_bag, distances, solutions)); | ||
|
|
||
| executor.shutdown(); | ||
|
|
||
| try { | ||
| if (!executor.awaitTermination( | ||
| this.seconds - (System.currentTimeMillis() - time) / 1000, | ||
| TimeUnit.SECONDS)) { | ||
| stop(); | ||
| } | ||
| } catch (InterruptedException e) { | ||
| if (!this.partialSolution) { | ||
| throw new RuntimeException( | ||
| "Timeout reached. I couldn't find a solution on a proper time. " | ||
| + "Please, give me another chance with more time or" | ||
| + " accept a partial solution. I won't fail you, I promise.", | ||
| e); | ||
| } | ||
| } | ||
|
|
||
| return getBest(solutions, distances, _bag.size()); | ||
| } | ||
|
|
||
| private void run(final ExecutorService executor, final Runnable aStar) { | ||
| executor.execute(aStar); | ||
| } | ||
|
|
||
| private List<TSPStop> getBest(SolutionContainer solutions, | ||
| DistanceMatrix distances, Integer size) { | ||
|
|
||
| BackTrackSolution solution = solutions.getSolution(); | ||
|
|
||
| if (solution == null) | ||
| throw new RuntimeException( | ||
| "I'm embarrased, I was unable to find a solution for you. " | ||
| + "Please, forgive me. I am just a machine."); | ||
|
|
||
| return solution.getStack(); | ||
|
|
||
| } | ||
|
|
||
| /** | ||
| * Initialices the distance matrix on background while tsp is running. | ||
| * | ||
| * @param distances | ||
| * @param bag | ||
| */ | ||
| private void initializeMatrix(DistanceMatrix distances, TSPStopBag bag) { | ||
|
|
||
| Runtime runtime = Runtime.getRuntime(); | ||
| int numthreads = runtime.availableProcessors() * 3; | ||
|
|
||
| executor2 = Executors.newFixedThreadPool(numthreads); | ||
|
|
||
| List<BacktrackStop> candidates = null; | ||
| candidates = new ArrayList<BacktrackStop>(); | ||
| for (TSPStop stop : bag.getAll()) | ||
| candidates.add((BacktrackStop) stop); | ||
|
|
||
| for (BacktrackStop from : candidates) { | ||
| executor2.execute(new InitializeDistances(from, candidates, | ||
| distances)); | ||
| } | ||
| executor2.shutdown(); | ||
| Thread t = new Thread() { | ||
| @Override | ||
| public void run() { | ||
| try { | ||
| executor2.awaitTermination(6, TimeUnit.SECONDS); | ||
| } catch (InterruptedException e) { | ||
| LOG.error(e, e); | ||
| } | ||
| } | ||
| }; | ||
| t.start(); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean stop() { | ||
| LOG.info("Shutting down backtracking"); | ||
|
|
||
| if (executor2 != null) | ||
| executor2.shutdownNow(); | ||
| if (executor != null) | ||
| executor.shutdownNow(); | ||
| else | ||
| return false; | ||
|
|
||
| LOG.info("Backtracking shut down"); | ||
|
|
||
| return true; | ||
| } | ||
| } | ||
|
|
||
| class SolutionContainer { | ||
| private BackTrackSolution solution = null; | ||
| private DistanceMatrix distances = null; | ||
|
|
||
| public SolutionContainer(DistanceMatrix distances) { | ||
| this.distances = distances; | ||
| } | ||
|
|
||
| public BackTrackSolution getSolution() { | ||
| synchronized (this) { | ||
| return this.solution; | ||
| } | ||
| } | ||
|
|
||
| public void add(BackTrackSolution solution) { | ||
| synchronized (this) { | ||
| if (this.solution == null) | ||
| this.solution = solution; | ||
| else { | ||
| if (this.solution.getDistance(distances) > solution | ||
| .getDistance(distances)) | ||
| this.solution = solution; | ||
| } | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,63 @@ | ||
| /** | ||
| * Copyright (C) 2012, Emergya (http://www.emergya.es) | ||
| * | ||
| * @author <a href="mailto:marias@emergya.com">María Arias de Reyna</a> | ||
| * | ||
| * This file is part of GoFleet | ||
| * | ||
| * This software is free software; you can redistribute it and/or modify | ||
| * it under the terms of the GNU General Public License as published by | ||
| * the Free Software Foundation; either version 2 of the License, or (at | ||
| * your option) any later version. | ||
| * | ||
| * This software is distributed in the hope that it will be useful, but | ||
| * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| * General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU General Public License | ||
| * along with this library; if not, write to the Free Software | ||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| * 02110-1301 USA | ||
| * | ||
| * As a special exception, if you link this library with other files to | ||
| * produce an executable, this library does not by itself cause the | ||
| * resulting executable to be covered by the GNU General Public License. | ||
| * This exception does not however invalidate any other reasons why the | ||
| * executable file might be covered by the GNU General Public License. | ||
| */ | ||
|
|
||
| package org.emergya.backtrackTSP; | ||
|
|
||
| import org.gofleet.openLS.tsp.TSPStop; | ||
|
|
||
| import com.vividsolutions.jts.geom.Geometry; | ||
| import com.vividsolutions.jts.geom.Point; | ||
|
|
||
| public class BacktrackStop implements TSPStop { | ||
|
|
||
| protected Integer id; | ||
| private Geometry position; | ||
|
|
||
| public Integer getId() { | ||
| return this.id; | ||
| } | ||
|
|
||
| public Point getPosition() { | ||
| return this.position.getCentroid(); | ||
| } | ||
|
|
||
| public BacktrackStop(Integer id, Geometry position) { | ||
| super(); | ||
| this.id = id; | ||
| this.position = position; | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return "{" + this.getId() | ||
| // + "->" + this.getPosition().toText() | ||
| + "}"; | ||
| } | ||
|
|
||
| } |
| @@ -0,0 +1,106 @@ | ||
| /** | ||
| * Copyright (C) 2012, Emergya (http://www.emergya.es) | ||
| * | ||
| * @author <a href="mailto:marias@emergya.com">María Arias de Reyna</a> | ||
| * | ||
| * This file is part of GoFleet | ||
| * | ||
| * This software is free software; you can redistribute it and/or modify | ||
| * it under the terms of the GNU General Public License as published by | ||
| * the Free Software Foundation; either version 2 of the License, or (at | ||
| * your option) any later version. | ||
| * | ||
| * This software is distributed in the hope that it will be useful, but | ||
| * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| * General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU General Public License | ||
| * along with this library; if not, write to the Free Software | ||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| * 02110-1301 USA | ||
| * | ||
| * As a special exception, if you link this library with other files to | ||
| * produce an executable, this library does not by itself cause the | ||
| * resulting executable to be covered by the GNU General Public License. | ||
| * This exception does not however invalidate any other reasons why the | ||
| * executable file might be covered by the GNU General Public License. | ||
| */ | ||
|
|
||
| package org.emergya.backtrackTSP; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.Collection; | ||
| import java.util.Collections; | ||
| import java.util.List; | ||
|
|
||
| import org.gofleet.openLS.tsp.TSPStop; | ||
| import org.gofleet.openLS.tsp.TSPStopBag; | ||
|
|
||
| public class BacktrackStopBag implements TSPStopBag { | ||
|
|
||
| private TSPStop first = null; | ||
| private TSPStop last = null; | ||
| private List<TSPStop> bag = Collections | ||
| .synchronizedList(new ArrayList<TSPStop>()); | ||
|
|
||
| public TSPStop getFirst() { | ||
| return this.first; | ||
| } | ||
|
|
||
| public TSPStop getLast() { | ||
| return this.last; | ||
| } | ||
|
|
||
| public Collection<TSPStop> getAll() { | ||
| return this.bag; | ||
| } | ||
|
|
||
| public Boolean hasFirst() { | ||
| return getFirst() != null; | ||
| } | ||
|
|
||
| public Boolean hasLast() { | ||
| return getLast() != null; | ||
| } | ||
|
|
||
| public BacktrackStopBag(List<TSPStop> stops) { | ||
| super(); | ||
| this.bag.addAll(stops); | ||
| } | ||
|
|
||
| public BacktrackStopBag(List<TSPStop> stops, TSPStop first, TSPStop last) { | ||
| this(stops); | ||
| this.first = first; | ||
| this.last = last; | ||
| } | ||
|
|
||
| public void removeStop(TSPStop stop) { | ||
| this.bag.remove(stop); | ||
| } | ||
|
|
||
| public void addStop(TSPStop stop) { | ||
| this.bag.add(stop); | ||
| } | ||
|
|
||
| public Integer size() { | ||
| Integer size = 0; | ||
| if (this.hasFirst()) | ||
| size++; | ||
| if (this.hasLast()) | ||
| size++; | ||
| return size + this.bag.size(); | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| String s = "{"; | ||
|
|
||
| for (TSPStop stop : this.bag) | ||
| s += stop.getPosition().toText() + " "; | ||
|
|
||
| s += "}"; | ||
|
|
||
| return s; | ||
| } | ||
| } |
| @@ -0,0 +1,124 @@ | ||
| package org.emergya.backtrackTSP; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.Collection; | ||
| import java.util.LinkedList; | ||
| import java.util.List; | ||
| import java.util.Stack; | ||
|
|
||
| import org.apache.commons.logging.Log; | ||
| import org.apache.commons.logging.LogFactory; | ||
| import org.gofleet.openLS.tsp.TSPStop; | ||
| import org.gofleet.openLS.tsp.TSPStopBag; | ||
|
|
||
| class Backtracking extends Thread { | ||
| private static Log LOG = LogFactory.getLog(Backtracking.class); | ||
|
|
||
| private BackTrackSolution current; | ||
| private BacktrackStopBag bag; | ||
| private DistanceMatrix distances; | ||
| private SolutionContainer best; | ||
|
|
||
| public Backtracking(TSPStopBag _bag, DistanceMatrix distances, | ||
| SolutionContainer best) { | ||
| this.current = initializeResBag(_bag); | ||
| this.bag = getBacktrackingBag(_bag); | ||
| this.distances = distances; | ||
| this.best = best; | ||
| } | ||
|
|
||
| @Override | ||
| public void run() { | ||
| BackTrackSolution solution = backtrack(this.current, this.bag, | ||
| this.distances, new BackTrackSolution(new Stack<TSPStop>())); | ||
| this.best.add(solution); | ||
| } | ||
|
|
||
| /** | ||
| * Recursive main procedure | ||
| * | ||
| * @param current | ||
| * @param bag | ||
| * @param distances | ||
| * @param partialSolution | ||
| * @return | ||
| */ | ||
| @SuppressWarnings("unchecked") | ||
| private BackTrackSolution backtrack(BackTrackSolution current, | ||
| BacktrackStopBag bag, DistanceMatrix distances, | ||
| BackTrackSolution partialSolution) { | ||
|
|
||
| if (Thread.interrupted()) | ||
| return partialSolution; | ||
|
|
||
| Collection<? super TSPStop> all = bag.getAll(); | ||
| if (all.size() > 0) { | ||
| List<TSPStop> candidates = null; | ||
| candidates = new ArrayList<TSPStop>(); | ||
| candidates.addAll((Collection<? extends TSPStop>) all); | ||
|
|
||
| // We try with all the candidates | ||
| for (TSPStop stop : candidates) { | ||
| bag.removeStop(stop); | ||
| current.push(stop); | ||
|
|
||
| // If we already have a solution candidate, is the current way | ||
| // worse than it? If not, just use current solution as better | ||
| if (!(partialSolution != null && current.getDistance(distances) > partialSolution | ||
| .getDistance(distances))) { | ||
|
|
||
| // Maybe another thread found a better solution | ||
| if (partialSolution != null | ||
| && this.best.getSolution() != null) { | ||
| if (partialSolution.getDistance(distances) < this.best | ||
| .getSolution().getDistance(distances)) | ||
| partialSolution = (BackTrackSolution) this.best | ||
| .getSolution().clone(); | ||
|
|
||
| } | ||
| backtrack(current, bag, distances, partialSolution); | ||
| } | ||
| if (LOG.isTraceEnabled()) | ||
| LOG.trace("Current: " + current); | ||
|
|
||
| current.pop(); | ||
| bag.addStop(stop); | ||
| } | ||
| } else { // We have reached the end of the way | ||
| if (bag.hasLast()) { | ||
| current.push(bag.getLast()); | ||
|
|
||
| if (current.getDistance(distances) < partialSolution | ||
| .getDistance(distances)) { | ||
| partialSolution.setStack(current.getStack()); | ||
| } | ||
|
|
||
| current.pop(); | ||
| } else { | ||
| if (current.getDistance(distances) < partialSolution | ||
| .getDistance(distances)) { | ||
| partialSolution.setStack(current.getStack()); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| partialSolution.getDistance(distances); | ||
| return partialSolution; | ||
| } | ||
|
|
||
| private BackTrackSolution initializeResBag(TSPStopBag bag) { | ||
| BackTrackSolution res = new BackTrackSolution(new Stack<TSPStop>()); | ||
|
|
||
| if (bag.hasFirst()) { | ||
| res.push(bag.getFirst()); | ||
| } | ||
| return res; | ||
| } | ||
|
|
||
| private BacktrackStopBag getBacktrackingBag(TSPStopBag _bag) { | ||
| List<TSPStop> all = new LinkedList<TSPStop>(); | ||
| all.addAll((Collection<? extends TSPStop>) _bag.getAll()); | ||
| return new BacktrackStopBag(all, _bag.getFirst(), _bag.getLast()); | ||
| } | ||
|
|
||
| } |
| @@ -0,0 +1,214 @@ | ||
| /** | ||
| * Copyright (C) 2012, Emergya (http://www.emergya.es) | ||
| * | ||
| * @author <a href="mailto:marias@emergya.com">María Arias de Reyna</a> | ||
| * | ||
| * This file is part of GoFleet | ||
| * | ||
| * This software is free software; you can redistribute it and/or modify | ||
| * it under the terms of the GNU General Public License as published by | ||
| * the Free Software Foundation; either version 2 of the License, or (at | ||
| * your option) any later version. | ||
| * | ||
| * This software is distributed in the hope that it will be useful, but | ||
| * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| * General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU General Public License | ||
| * along with this library; if not, write to the Free Software | ||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| * 02110-1301 USA | ||
| * | ||
| * As a special exception, if you link this library with other files to | ||
| * produce an executable, this library does not by itself cause the | ||
| * resulting executable to be covered by the GNU General Public License. | ||
| * This exception does not however invalidate any other reasons why the | ||
| * executable file might be covered by the GNU General Public License. | ||
| */ | ||
| package org.emergya.backtrackTSP; | ||
|
|
||
| import java.io.IOException; | ||
| import java.text.ParseException; | ||
| import java.util.HashMap; | ||
| import java.util.Locale; | ||
| import java.util.Map; | ||
|
|
||
| import javax.xml.bind.JAXBElement; | ||
| import javax.xml.bind.JAXBException; | ||
| import javax.xml.namespace.QName; | ||
|
|
||
| import net.opengis.gml.v_3_1_1.DirectPositionType; | ||
| import net.opengis.gml.v_3_1_1.PointType; | ||
| import net.opengis.xls.v_1_2_0.AbstractLocationType; | ||
| import net.opengis.xls.v_1_2_0.DetermineRouteRequestType; | ||
| import net.opengis.xls.v_1_2_0.DetermineRouteResponseType; | ||
| import net.opengis.xls.v_1_2_0.PositionType; | ||
| import net.opengis.xls.v_1_2_0.RoutePlanType; | ||
| import net.opengis.xls.v_1_2_0.WayPointListType; | ||
| import net.opengis.xls.v_1_2_0.WayPointType; | ||
|
|
||
| import org.apache.commons.logging.Log; | ||
| import org.apache.commons.logging.LogFactory; | ||
| import org.emergya.osrm.OSRM; | ||
| import org.gofleet.openLS.tsp.TSPStop; | ||
|
|
||
| import com.vividsolutions.jts.geom.Point; | ||
|
|
||
| public class DistanceMatrix { | ||
|
|
||
| private Map<Key, Double> distances = new HashMap<Key, Double>(); | ||
| private static Log LOG = LogFactory.getLog(DistanceMatrix.class); | ||
|
|
||
| private OSRM osrm; | ||
| private org.gofleet.configuration.Configuration configuration; | ||
|
|
||
| public DistanceMatrix() { | ||
| this.osrm = new OSRM(); | ||
| } | ||
|
|
||
| public DistanceMatrix(OSRM osrm, | ||
| org.gofleet.configuration.Configuration configuration) { | ||
| super(); | ||
| this.osrm = osrm; | ||
| this.configuration = configuration; | ||
| } | ||
|
|
||
| public Double distance(BacktrackStop from, BacktrackStop to) | ||
| throws InterruptedException { | ||
| Key k = new Key(from.id, to.id); | ||
| Double d = null; | ||
| synchronized (distances) { | ||
| d = distances.get(k); | ||
| } | ||
| if (d != null) { | ||
| return d; | ||
| } else { | ||
| if (LOG.isDebugEnabled()) | ||
| LOG.debug("DistanceMatrix.distance(" + k + ")"); | ||
| return calculateDistance(from, to, k); | ||
| } | ||
| } | ||
|
|
||
| private Double calculateDistance(TSPStop from, TSPStop to, Key k) | ||
| throws InterruptedException { | ||
| String host_port = "localhost:5000"; | ||
| String http = "http"; | ||
| if (configuration != null) { | ||
| if (configuration.get("OSRM_SSL", "off").equals("on")) | ||
| http = "https"; | ||
| host_port = configuration.get("OSRM_HOST", "localhost:5000"); | ||
| } | ||
| DetermineRouteRequestType param = new DetermineRouteRequestType(); | ||
|
|
||
| if (param.getRoutePlan() == null) | ||
| param.setRoutePlan(new RoutePlanType()); | ||
|
|
||
| if (param.getRoutePlan().getWayPointList() == null) | ||
| param.getRoutePlan().setWayPointList(new WayPointListType()); | ||
|
|
||
| WayPointListType waypointList = param.getRoutePlan().getWayPointList(); | ||
|
|
||
| WayPointType start = getWayPoint(from.getPosition()); | ||
| WayPointType end = getWayPoint(to.getPosition()); | ||
|
|
||
| waypointList.setStartPoint(start); | ||
| waypointList.setEndPoint(end); | ||
|
|
||
| try { | ||
| DetermineRouteResponseType res = (DetermineRouteResponseType) osrm | ||
| .routePlan(param, host_port, http, Locale.ROOT); | ||
| double cost = res.getRouteSummary().getTotalDistance().getValue() | ||
| .doubleValue(); | ||
| synchronized (distances) { | ||
| distances.put(k, cost); | ||
| } | ||
| return cost; | ||
| } catch (IOException e) { | ||
| LOG.error("Error extracting distance from " + from + " to " + to); | ||
| return Double.MAX_VALUE; | ||
| } catch (ParseException e) { | ||
| LOG.error("Error extracting distance from " + from + " to " + to); | ||
| return Double.MAX_VALUE; | ||
| } catch (JAXBException e) { | ||
| LOG.error("Error extracting distance from " + from + " to " + to); | ||
| return Double.MAX_VALUE; | ||
| } | ||
| } | ||
|
|
||
| @SuppressWarnings("restriction") | ||
| private WayPointType getWayPoint(Point position) { | ||
| WayPointType point = new WayPointType(); | ||
| point.setStop(Boolean.TRUE); | ||
|
|
||
| PositionType postype = new PositionType(); | ||
| PointType pointtype = new PointType(); | ||
| DirectPositionType directPosition = new DirectPositionType(); | ||
|
|
||
| directPosition.setSrsName("EPSG:" + position.getSRID()); | ||
| directPosition.getValue().add(position.getX()); | ||
| directPosition.getValue().add(position.getY()); | ||
|
|
||
| pointtype.setPos(directPosition); | ||
| postype.setPoint(pointtype); | ||
| JAXBElement<? extends AbstractLocationType> value = new JAXBElement<PositionType>( | ||
| new QName("http://www.opengis.net/gml", "pos", "gml"), | ||
| PositionType.class, postype); | ||
| point.setLocation(value); | ||
|
|
||
| return point; | ||
| } | ||
|
|
||
| } | ||
|
|
||
| class Key { | ||
|
|
||
| protected Key(Integer from, Integer to) { | ||
| super(); | ||
| this.from = from; | ||
| this.to = to; | ||
| } | ||
|
|
||
| private Integer from; | ||
| private Integer to; | ||
|
|
||
| public Integer getFrom() { | ||
| return from; | ||
| } | ||
|
|
||
| public void setFrom(Integer from) { | ||
| this.from = from; | ||
| } | ||
|
|
||
| public Integer getTo() { | ||
| return to; | ||
| } | ||
|
|
||
| public void setTo(Integer to) { | ||
| this.to = to; | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| final int prime = 31; | ||
| int result = 1; | ||
| result = prime * result + ((from == null) ? 0 : from.hashCode()); | ||
| result = prime * result + ((to == null) ? 0 : to.hashCode()); | ||
| return result; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(Object obj) { | ||
| if (!(obj instanceof Key)) | ||
| return false; | ||
| Key other = (Key) obj; | ||
| return other.getFrom().equals(this.from) | ||
| && other.getTo().equals(this.to); | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return "{ K<" + this.getFrom() + "->" + this.getTo() + ">}"; | ||
| } | ||
|
|
||
| } |
| @@ -0,0 +1,183 @@ | ||
| package org.emergya.backtrackTSP; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.Collection; | ||
| import java.util.Collections; | ||
| import java.util.Comparator; | ||
| import java.util.LinkedList; | ||
| import java.util.List; | ||
| import java.util.Stack; | ||
|
|
||
| import org.apache.commons.logging.Log; | ||
| import org.apache.commons.logging.LogFactory; | ||
| import org.gofleet.openLS.tsp.TSPStop; | ||
| import org.gofleet.openLS.tsp.TSPStopBag; | ||
|
|
||
| import com.vividsolutions.jts.geom.Point; | ||
|
|
||
| /** | ||
| * Like Backtracking but a simple heuristic which order the candidates to try | ||
| * | ||
| * @author marias | ||
| * | ||
| */ | ||
| class HeuristicBacktracking extends Thread { | ||
| private static Log LOG = LogFactory.getLog(HeuristicBacktracking.class); | ||
|
|
||
| private BackTrackSolution current; | ||
| private BacktrackStopBag bag; | ||
| private DistanceMatrix distances; | ||
| private SolutionContainer best; | ||
|
|
||
| public HeuristicBacktracking(TSPStopBag _bag, DistanceMatrix distances, | ||
| SolutionContainer best) { | ||
| this.current = initializeResBag(_bag); | ||
| this.bag = getBacktrackingBag(_bag); | ||
| this.distances = distances; | ||
| this.best = best; | ||
| } | ||
|
|
||
| @Override | ||
| public void run() { | ||
| BackTrackSolution solution = heuristicBacktracking(this.current, | ||
| this.bag, this.distances, new BackTrackSolution( | ||
| new Stack<TSPStop>())); | ||
| best.add(solution); | ||
| } | ||
|
|
||
| private BackTrackSolution heuristicBacktracking(BackTrackSolution current, | ||
| BacktrackStopBag bag, DistanceMatrix distances, | ||
| BackTrackSolution partialSolution) { | ||
|
|
||
| if (Thread.interrupted()) | ||
| return partialSolution; | ||
|
|
||
| Collection<? super TSPStop> all = bag.getAll(); | ||
| if (all.size() > 0) { | ||
|
|
||
| List<BacktrackStop> candidates = null; | ||
| candidates = new ArrayList<BacktrackStop>(); | ||
| for (Object s : all) | ||
| candidates.add((BacktrackStop) s); | ||
|
|
||
| BacktrackStop from = null; | ||
| if (current.getStack().size() > 0) | ||
| from = (BacktrackStop) current.getStack().peek(); | ||
| BacktrackStop end = (BacktrackStop) bag.getLast(); | ||
| HeuristicComparator heuristicComparator = new HeuristicComparator( | ||
| distances, from, end); | ||
| Collections.sort(candidates, heuristicComparator); | ||
|
|
||
| for (TSPStop next : candidates) { | ||
| bag.removeStop(next); | ||
| current.push(next); | ||
|
|
||
| // If we already have a solution candidate, is the current way | ||
| // worse than it? If not, just use current solution as better | ||
| if (!(partialSolution != null && current.getDistance(distances) > partialSolution | ||
| .getDistance(distances))) { | ||
| heuristicBacktracking(current, bag, distances, | ||
| partialSolution); | ||
| } | ||
| if (LOG.isTraceEnabled()) | ||
| LOG.trace("Current: " + current); | ||
|
|
||
| current.pop(); | ||
| bag.addStop(next); | ||
| } | ||
|
|
||
| } else { | ||
| current.push(bag.getLast()); | ||
|
|
||
| // Maybe another thread found a better solution | ||
| partialSolution = checkIfBetterAnotherThread(distances, | ||
| partialSolution); | ||
|
|
||
| if (current.getDistance(distances) < partialSolution | ||
| .getDistance(distances)) { | ||
| partialSolution.setStack(current.getStack()); | ||
| this.best.add(partialSolution); | ||
| } | ||
|
|
||
| current.pop(); | ||
| } | ||
|
|
||
| partialSolution.getDistance(distances); | ||
| return partialSolution; | ||
| } | ||
|
|
||
| private BackTrackSolution checkIfBetterAnotherThread( | ||
| DistanceMatrix distances, BackTrackSolution partialSolution) { | ||
|
|
||
| // Maybe another thread found a better solution | ||
| if (partialSolution != null && this.best.getSolution() != null) { | ||
| if (partialSolution.getDistance(distances) < this.best | ||
| .getSolution().getDistance(distances)) | ||
| partialSolution = (BackTrackSolution) this.best.getSolution() | ||
| .clone(); | ||
|
|
||
| } | ||
| return partialSolution; | ||
| } | ||
|
|
||
| private BackTrackSolution initializeResBag(TSPStopBag bag) { | ||
| BackTrackSolution res = new BackTrackSolution(new Stack<TSPStop>()); | ||
|
|
||
| if (bag.hasFirst()) { | ||
| res.push(bag.getFirst()); | ||
| } | ||
| return res; | ||
| } | ||
|
|
||
| private BacktrackStopBag getBacktrackingBag(TSPStopBag _bag) { | ||
| List<TSPStop> all = new LinkedList<TSPStop>(); | ||
| all.addAll((Collection<? extends TSPStop>) _bag.getAll()); | ||
| return new BacktrackStopBag(all, _bag.getFirst(), _bag.getLast()); | ||
| } | ||
|
|
||
| } | ||
|
|
||
| class HeuristicComparator implements Comparator<BacktrackStop> { | ||
| private static Log LOG = LogFactory.getLog(HeuristicComparator.class); | ||
| private BacktrackStop end = null; | ||
| private DistanceMatrix distances = null; | ||
| private BacktrackStop from = null; | ||
|
|
||
| protected HeuristicComparator(DistanceMatrix distances, BacktrackStop from, | ||
| BacktrackStop end) { | ||
| this.end = end; | ||
| this.distances = distances; | ||
| this.from = from; | ||
| } | ||
|
|
||
| public int compare(BacktrackStop o1, BacktrackStop o2) { | ||
| if (from != null) { | ||
| Double dist1 = Double.MAX_VALUE; | ||
| Double dist2 = Double.MAX_VALUE; | ||
| try { | ||
| dist1 = (distances.distance(from, o1) + heuristic(o1, end)); | ||
|
|
||
| } catch (InterruptedException e) { | ||
| LOG.info("distance interrupted"); | ||
| } | ||
| try { | ||
| dist2 = (distances.distance(from, o2) + heuristic(o2, end)); | ||
| } catch (InterruptedException e) { | ||
| LOG.info("distance interrupted"); | ||
| } | ||
| return dist1.compareTo(dist2); | ||
| } else { | ||
| Double dist1 = heuristic(o1, end); | ||
| Double dist2 = heuristic(o2, end); | ||
| return dist1.compareTo(dist2); | ||
| } | ||
| } | ||
|
|
||
| private Double heuristic(BacktrackStop from, BacktrackStop to) { | ||
| Point a = from.getPosition(); | ||
| Point b = to.getPosition(); | ||
|
|
||
| return a.distance(b); | ||
| } | ||
|
|
||
| } |
| @@ -0,0 +1,38 @@ | ||
| package org.emergya.backtrackTSP; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| import org.apache.commons.logging.Log; | ||
| import org.apache.commons.logging.LogFactory; | ||
|
|
||
| public class InitializeDistances extends Thread { | ||
| private static Log LOG = LogFactory.getLog(InitializeDistances.class); | ||
|
|
||
| private BacktrackStop from; | ||
| private List<BacktrackStop> to; | ||
| private DistanceMatrix distance; | ||
|
|
||
| public InitializeDistances(BacktrackStop from, List<BacktrackStop> to, | ||
| DistanceMatrix distance) { | ||
| super(); | ||
| this.from = from; | ||
| this.to = to; | ||
| this.distance = distance; | ||
| } | ||
|
|
||
| public void run() { | ||
| for (BacktrackStop i : to) { | ||
| if (Thread.interrupted()) | ||
| return; | ||
|
|
||
| if (i != from) | ||
| try { | ||
| distance.distance(from, i); | ||
| } catch (InterruptedException e) { | ||
| throw new RuntimeException(e); | ||
| } | ||
| } | ||
| LOG.trace("Done with " + from.getId()); | ||
| } | ||
|
|
||
| } |
| @@ -0,0 +1,211 @@ | ||
| /** | ||
| * Copyright (C) 2012, Emergya (http://www.emergya.es) | ||
| * | ||
| * @author <a href="mailto:marias@emergya.com">María Arias de Reyna</a> | ||
| * | ||
| * This file is part of GoFleet | ||
| * | ||
| * This software is free software; you can redistribute it and/or modify | ||
| * it under the terms of the GNU General Public License as published by | ||
| * the Free Software Foundation; either version 2 of the License, or (at | ||
| * your option) any later version. | ||
| * | ||
| * This software is distributed in the hope that it will be useful, but | ||
| * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| * General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU General Public License | ||
| * along with this library; if not, write to the Free Software | ||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| * 02110-1301 USA | ||
| * | ||
| * As a special exception, if you link this library with other files to | ||
| * produce an executable, this library does not by itself cause the | ||
| * resulting executable to be covered by the GNU General Public License. | ||
| * This exception does not however invalidate any other reasons why the | ||
| * executable file might be covered by the GNU General Public License. | ||
| */ | ||
| package org.emergya.backtrackTSP; | ||
|
|
||
| import static org.junit.Assert.assertNotNull; | ||
| import static org.junit.Assert.assertTrue; | ||
|
|
||
| import java.util.LinkedList; | ||
| import java.util.List; | ||
| import java.util.Random; | ||
|
|
||
| import org.gofleet.openLS.tsp.TSPStop; | ||
| import org.junit.Test; | ||
|
|
||
| import com.vividsolutions.jts.geom.Coordinate; | ||
| import com.vividsolutions.jts.geom.GeometryFactory; | ||
|
|
||
| public class BackTrackingTSPTest { | ||
|
|
||
| private GeometryFactory gf = new GeometryFactory(); | ||
|
|
||
| @Test | ||
| public void simpleTest() { | ||
| BackTrackingTSP backtracking = new BackTrackingTSP(); | ||
| List<TSPStop> stops = new LinkedList<TSPStop>(); | ||
|
|
||
| stops.add(new BacktrackStop(1, gf.createPoint(new Coordinate( | ||
| -3.7091297753d, 40.40085892d)))); | ||
| stops.add(new BacktrackStop(2, gf.createPoint(new Coordinate( | ||
| -3.7234753d, 40.401237892d)))); | ||
| stops.add(new BacktrackStop(3, gf.createPoint(new Coordinate( | ||
| -3.724762553d, 40.40543562d)))); | ||
| stops.add(new BacktrackStop(4, gf.createPoint(new Coordinate( | ||
| -3.7578463d, 40.40462346252d)))); | ||
| stops.add(new BacktrackStop(5, gf.createPoint(new Coordinate( | ||
| -3.726525635453d, 40.422222456252d)))); | ||
| stops.add(new BacktrackStop(6, gf.createPoint(new Coordinate( | ||
| -3.722566553d, 40.425624492d)))); | ||
| stops.add(new BacktrackStop(7, gf.createPoint(new Coordinate( | ||
| -3.7223562453d, 40.40434567456692d)))); | ||
| stops.add(new BacktrackStop(9, gf.createPoint(new Coordinate( | ||
| -3.722362543d, 40.40262352d)))); | ||
| stops.add(new BacktrackStop(10, gf.createPoint(new Coordinate( | ||
| -3.724567456753d, 40.402345234592d)))); | ||
|
|
||
| BacktrackStopBag bag = new BacktrackStopBag(stops); | ||
|
|
||
| long time = System.currentTimeMillis(); | ||
| final List<TSPStop> order = backtracking.order(bag); | ||
| System.out.println(System.currentTimeMillis() - time + "ms"); | ||
| assertNotNull(order); | ||
| System.out.println(order); | ||
| } | ||
|
|
||
| @Test | ||
| public void firstLastTest() { | ||
| BackTrackingTSP backtracking = new BackTrackingTSP(); | ||
| List<TSPStop> stops = new LinkedList<TSPStop>(); | ||
|
|
||
| stops.add(new BacktrackStop(1, gf.createPoint(new Coordinate( | ||
| -3.7091297753d, 40.40085892d)))); | ||
| stops.add(new BacktrackStop(2, gf.createPoint(new Coordinate( | ||
| -3.7234753d, 40.401237892d)))); | ||
| stops.add(new BacktrackStop(3, gf.createPoint(new Coordinate( | ||
| -3.724762553d, 40.40543562d)))); | ||
| stops.add(new BacktrackStop(5, gf.createPoint(new Coordinate( | ||
| -3.726525635453d, 40.422222456252d)))); | ||
| stops.add(new BacktrackStop(6, gf.createPoint(new Coordinate( | ||
| -3.722566553d, 40.425624492d)))); | ||
| stops.add(new BacktrackStop(7, gf.createPoint(new Coordinate( | ||
| -3.7223562453d, 40.40434567456692d)))); | ||
| stops.add(new BacktrackStop(8, gf.createPoint(new Coordinate( | ||
| -3.722362543d, 40.40262352d)))); | ||
|
|
||
| BacktrackStopBag bag = new BacktrackStopBag(stops, new BacktrackStop(9, | ||
| gf.createPoint(new Coordinate(-3.724567456753d, | ||
| 40.402345234592d))), new BacktrackStop(4, | ||
| gf.createPoint(new Coordinate(-3.7578463d, 40.40462346252d)))); | ||
|
|
||
| long time = System.currentTimeMillis(); | ||
| final List<TSPStop> order = backtracking.order(bag); | ||
| System.out.println(System.currentTimeMillis() - time + "ms"); | ||
| assertNotNull(order); | ||
| System.out.println(order); | ||
| } | ||
|
|
||
| @Test | ||
| public void performance() { | ||
|
|
||
| Random r = new Random(); | ||
| Double x = -4.6d; | ||
| Double y = 37.5d; | ||
|
|
||
| int max = 4; | ||
| int numparadas = 20; | ||
|
|
||
| long totaltime = 0; | ||
|
|
||
| for (int k = 3; k < numparadas; k++) { | ||
|
|
||
| for (int i = 0; i < max; i++) { | ||
|
|
||
| BackTrackingTSP backtracking = new BackTrackingTSP(); | ||
| List<TSPStop> stops = new LinkedList<TSPStop>(); | ||
|
|
||
| for (int j = 0; j < k; j++) | ||
| stops.add(new BacktrackStop(j, gf | ||
| .createPoint(new Coordinate(x | ||
| + (r.nextFloat() * ((r.nextBoolean()) ? -1 | ||
| : 1)), y | ||
| + (r.nextFloat() * ((r.nextBoolean()) ? -1 | ||
| : 1)))))); | ||
|
|
||
| BacktrackStopBag bag = new BacktrackStopBag(stops); | ||
|
|
||
| long time = System.currentTimeMillis(); | ||
| final List<TSPStop> order = backtracking.order(bag); | ||
| totaltime += System.currentTimeMillis() - time; | ||
| assertNotNull(order); | ||
| assertTrue(order.size() == k); | ||
| // System.out.println(order); | ||
| } | ||
| System.out.println("Time for " + k + " stops: " + (totaltime / max) | ||
| + "ms"); | ||
| } | ||
| } | ||
|
|
||
| @Test | ||
| public void performanceWithLast() { | ||
|
|
||
| Random r = new Random(); | ||
| Double x = -4.6d; | ||
| Double y = 37.5d; | ||
|
|
||
| int max = 4; | ||
| int numparadas = 20; | ||
|
|
||
| for (int k = 3; k < numparadas; k++) { | ||
|
|
||
| long totaltime = 0; | ||
|
|
||
| for (int i = 0; i < max; i++) { | ||
|
|
||
| BackTrackingTSP backtracking = new BackTrackingTSP(); | ||
| List<TSPStop> stops = new LinkedList<TSPStop>(); | ||
|
|
||
| for (int j = 0; j < k - 2; j++) | ||
| stops.add(new BacktrackStop(j, gf | ||
| .createPoint(new Coordinate(x | ||
| + (r.nextFloat() * ((r.nextBoolean()) ? -1 | ||
| : 1)), y | ||
| + (r.nextFloat() * ((r.nextBoolean()) ? -1 | ||
| : 1)))))); | ||
|
|
||
| BacktrackStopBag bag = new BacktrackStopBag(stops, | ||
| new BacktrackStop(k - 1, | ||
| gf.createPoint(new Coordinate( | ||
| x | ||
| + (r.nextFloat() * ((r | ||
| .nextBoolean()) ? -1 | ||
| : 1)), y | ||
| + (r.nextFloat() * ((r | ||
| .nextBoolean()) ? -1 | ||
| : 1))))), | ||
| new BacktrackStop(k, | ||
| gf.createPoint(new Coordinate( | ||
| x | ||
| + (r.nextFloat() * ((r | ||
| .nextBoolean()) ? -1 | ||
| : 1)), y | ||
| + (r.nextFloat() * ((r | ||
| .nextBoolean()) ? -1 | ||
| : 1)))))); | ||
|
|
||
| long time = System.currentTimeMillis(); | ||
| final List<TSPStop> order = backtracking.order(bag); | ||
| totaltime += System.currentTimeMillis() - time; | ||
| assertNotNull(order); | ||
| assertTrue(order.size() == k); | ||
| } | ||
| System.out.println("Time for " + k + " stops: " + (totaltime / max) | ||
| + "ms"); | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,96 @@ | ||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
| <modelVersion>4.0.0</modelVersion> | ||
| <groupId>org.emergya</groupId> | ||
| <artifactId>osrm-connector</artifactId> | ||
| <version>0.1.0</version> | ||
| <name>osrm-connector</name> | ||
| <description>Connector to OSRM routing</description> | ||
|
|
||
|
|
||
| <distributionManagement> | ||
| <repository> | ||
| <id>gofleet</id> | ||
| <url>http://nexus.emergya.es/nexus/content/repositories/gofleet</url> | ||
| </repository> | ||
| <snapshotRepository> | ||
| <id>gofleet-snap</id> | ||
| <url>http://nexus.emergya.es/nexus/content/repositories/gofleet-snapshots</url> | ||
| </snapshotRepository> | ||
| </distributionManagement> | ||
|
|
||
|
|
||
| <build> | ||
| <plugins> | ||
| <plugin> | ||
|
|
||
| <!-- Maven compiler plugin --> | ||
| <artifactId>maven-compiler-plugin</artifactId> | ||
| <configuration> | ||
| <source>1.6</source> | ||
| <target>1.6</target> | ||
| <optimize>true</optimize> | ||
| </configuration> | ||
| </plugin> | ||
| </plugins> | ||
| </build> | ||
|
|
||
| <dependencies> | ||
| <dependency> | ||
| <groupId>org.geotools</groupId> | ||
| <artifactId>gt-opengis</artifactId> | ||
| <version>${geotools.version}</version> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.geotools</groupId> | ||
| <artifactId>gt-epsg-hsql</artifactId> | ||
| <version>${geotools.version}</version> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.geotools</groupId> | ||
| <artifactId>gt-api</artifactId> | ||
| <version>${geotools.version}</version> | ||
| </dependency> | ||
|
|
||
| <!-- Internacionalization --> | ||
| <dependency> | ||
| <groupId>org.gofleet</groupId> | ||
| <artifactId>internacionalization</artifactId> | ||
| <version>1.1.0</version> | ||
| </dependency> | ||
|
|
||
| <!-- Log --> | ||
| <dependency> | ||
| <groupId>commons-logging</groupId> | ||
| <artifactId>commons-logging</artifactId> | ||
| <version>1.1.1</version> | ||
| </dependency> | ||
|
|
||
| <!-- JSON parser --> | ||
| <dependency> | ||
| <groupId>org.codehaus.jackson</groupId> | ||
| <artifactId>jackson-core-lgpl</artifactId> | ||
| <version>1.9.4</version> | ||
| </dependency> | ||
|
|
||
| <!-- OpenLS classes --> | ||
| <dependency> | ||
| <groupId>org.jvnet.ogc</groupId> | ||
| <artifactId>ols-v_1_2_0-schema</artifactId> | ||
| <version>1.0.3</version> | ||
| </dependency> | ||
|
|
||
| <!-- Http connection to OSRM --> | ||
| <dependency> | ||
| <groupId>org.apache.httpcomponents</groupId> | ||
| <artifactId>httpclient</artifactId> | ||
| <version>4.1.3</version> | ||
| </dependency> | ||
|
|
||
| </dependencies> | ||
|
|
||
| <properties> | ||
| <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||
| <geotools.version>8.0-M4</geotools.version> | ||
| </properties> | ||
| </project> |
| @@ -0,0 +1,154 @@ | ||
| package org.emergya.osrm; | ||
|
|
||
| import java.util.LinkedList; | ||
| import java.util.List; | ||
|
|
||
| import net.opengis.gml.v_3_1_1.AbstractRingPropertyType; | ||
| import net.opengis.gml.v_3_1_1.CoordType; | ||
| import net.opengis.gml.v_3_1_1.DirectPositionType; | ||
| import net.opengis.gml.v_3_1_1.LinearRingType; | ||
| import net.opengis.gml.v_3_1_1.PointType; | ||
| import net.opengis.gml.v_3_1_1.PolygonType; | ||
| import net.opengis.xls.v_1_2_0.PositionType; | ||
| import net.opengis.xls.v_1_2_0.WayPointType; | ||
|
|
||
| import org.apache.commons.logging.Log; | ||
| import org.apache.commons.logging.LogFactory; | ||
| import org.geotools.geometry.jts.JTS; | ||
| import org.geotools.referencing.CRS; | ||
| import org.opengis.referencing.crs.CoordinateReferenceSystem; | ||
| import org.opengis.referencing.operation.MathTransform; | ||
|
|
||
| import com.vividsolutions.jts.geom.Coordinate; | ||
| import com.vividsolutions.jts.geom.Geometry; | ||
| import com.vividsolutions.jts.geom.GeometryFactory; | ||
| import com.vividsolutions.jts.geom.LinearRing; | ||
|
|
||
| /* | ||
| * Copyright (C) 2011, Emergya (http://www.emergya.es) | ||
| * | ||
| * @author <a href="mailto:marias@emergya.es">María Arias</a> | ||
| * | ||
| * This file is part of GoFleet | ||
| * | ||
| * This software is free software; you can redistribute it and/or modify | ||
| * it under the terms of the GNU General Public License as published by | ||
| * the Free Software Foundation; either version 2 of the License, or | ||
| * (at your option) any later version. | ||
| * | ||
| * This software is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| * GNU General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU General Public License | ||
| * along with this library; if not, write to the Free Software | ||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| * | ||
| * As a special exception, if you link this library with other files to | ||
| * produce an executable, this library does not by itself cause the | ||
| * resulting executable to be covered by the GNU General Public License. | ||
| * This exception does not however invalidate any other reasons why the | ||
| * executable file might be covered by the GNU General Public License. | ||
| */ | ||
| public class GeoUtil { | ||
| static Log LOG = LogFactory.getLog(GeoUtil.class); | ||
| static GeometryFactory geomFact = new GeometryFactory(); | ||
|
|
||
| @SuppressWarnings("restriction") | ||
| public static com.vividsolutions.jts.geom.Point getPoint( | ||
| WayPointType startPoint, CoordinateReferenceSystem targetCRS) { | ||
|
|
||
| // TODO what if we don't receive coordinates? | ||
| PositionType ptype = (PositionType) startPoint.getLocation().getValue(); | ||
| PointType pointType = ptype.getPoint(); | ||
| DirectPositionType ctype = pointType.getPos(); | ||
|
|
||
| CoordinateReferenceSystem sourceCRS = getSRS(startPoint); | ||
|
|
||
| LOG.trace(sourceCRS.toWKT()); | ||
| LOG.trace("(" + ctype.getValue().get(0) + ", " | ||
| + ctype.getValue().get(1) + ")"); | ||
|
|
||
| com.vividsolutions.jts.geom.Point p = geomFact | ||
| .createPoint(new Coordinate(ctype.getValue().get(0), ctype | ||
| .getValue().get(1))); | ||
|
|
||
| LOG.debug(p); | ||
| if (targetCRS != null && !sourceCRS.equals(targetCRS)) { | ||
| try { | ||
| MathTransform transform = CRS.findMathTransform(sourceCRS, | ||
| targetCRS); | ||
| p = JTS.transform(p, transform).getCentroid(); | ||
|
|
||
| p = geomFact.createPoint(new Coordinate(p.getY(), p.getX())); | ||
|
|
||
| LOG.info(p); | ||
| } catch (Throwable t) { | ||
| LOG.error("Error converting coordinates", t); | ||
| } | ||
| } | ||
|
|
||
| return p; | ||
| } | ||
|
|
||
| public static CoordinateReferenceSystem getSRS(WayPointType point) { | ||
| // TODO what if we don't receive coordinates? | ||
| PositionType ptype = (PositionType) point.getLocation().getValue(); | ||
| PointType pointType = ptype.getPoint(); | ||
| try { | ||
| return CRS.decode(pointType.getSrsName()); | ||
| } catch (Throwable e) { | ||
| LOG.trace(e, e); | ||
| try { | ||
| return CRS.decode("EPSG:4326"); | ||
| } catch (Throwable t) { | ||
| LOG.trace(t); | ||
| return null; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public static com.vividsolutions.jts.geom.Geometry getGeometry( | ||
| PositionType position) { | ||
|
|
||
| Geometry g = null; | ||
|
|
||
| if (position.getPoint() != null) { | ||
| if (position.getPoint().getCoord() != null | ||
| && position.getPoint().getCoord().getX() != null) { | ||
| g = geomFact.createPoint(new Coordinate(position.getPoint() | ||
| .getCoord().getX().doubleValue(), position.getPoint() | ||
| .getCoord().getY().doubleValue())); | ||
| } else if (position.getPoint().getPos() != null | ||
| && position.getPoint().getPos().getValue() != null | ||
| && position.getPoint().getPos().getValue().size() == 2) { | ||
| g = geomFact.createPoint(new Coordinate(position.getPoint() | ||
| .getPos().getValue().get(0), position.getPoint() | ||
| .getPos().getValue().get(1))); | ||
| } | ||
| } else if (position.getPolygon() != null) { | ||
| PolygonType polygon = position.getPolygon(); | ||
|
|
||
| List<LinearRing> interiorRings = new LinkedList<LinearRing>(); | ||
| polygon.getInterior(); | ||
| // TODO | ||
| LinearRing[] holes = interiorRings.toArray(new LinearRing[] {}); | ||
|
|
||
| List<Coordinate> coordinateList = new LinkedList<Coordinate>(); | ||
| AbstractRingPropertyType exterior = polygon.getExterior() | ||
| .getValue(); | ||
| LinearRingType ring = (LinearRingType) exterior.getRing() | ||
| .getValue(); | ||
| for (CoordType coord : ring.getCoord()) { | ||
| coordinateList.add(new Coordinate(coord.getX().doubleValue(), | ||
| coord.getY().doubleValue())); | ||
| } | ||
| Coordinate[] coordinates = coordinateList | ||
| .toArray(new Coordinate[] {}); | ||
| LinearRing shell = geomFact.createLinearRing(coordinates); | ||
| g = geomFact.createPolygon(shell, holes); | ||
| } | ||
| return g; | ||
| } | ||
| } |
| @@ -0,0 +1,8 @@ | ||
| @XmlSchema(namespace = "http://www.opengis.net/xls", elementFormDefault = XmlNsForm.QUALIFIED, xmlns = { | ||
| @javax.xml.bind.annotation.XmlNs(prefix = "xls", namespaceURI = "http://www.opengis.net/xls"), | ||
| @javax.xml.bind.annotation.XmlNs(prefix = "xs", namespaceURI = "http://www.w3.org/2001/XMLSchema") }) | ||
| package net.opengis.xls.v_1_2_0; | ||
|
|
||
| import javax.xml.bind.annotation.XmlNsForm; | ||
| import javax.xml.bind.annotation.XmlSchema; | ||
|
|
| @@ -104,7 +104,7 @@ | ||
| </bean> | ||
|
|
||
|
|
||
| <bean id="osrmConnector" class="org.emergya.osrm.OSRM"> | ||
| <property name="i18n" ref="i18n" /> | ||
| </bean> | ||
|
|
||
| @@ -1,5 +1,5 @@ | ||
| jdbc.driverClassName=org.postgis.DriverWrapper | ||
| jdbc.url=jdbc\:postgresql_postGIS\://localhost\:5432/gofleetls | ||
| jdbc.username=gofleetls | ||
| jdbc.password=gofleetls | ||
| jdbc.hibernate.dialect=org.gofleet.openLS.ddbb.dialect.GoFleetDialect |
| @@ -1,38 +1,34 @@ | ||
| <xls:XLS xmlns:xls="http://www.opengis.net/xls" | ||
| xsi:schemaLocation="http://www.opengis.net/xls http://schemas.opengis.net/ols/1.2.0/ADT.xsd http://schemas.opengis.net/ols/1.2.0/LocationUtilityService.xsd http://schemas.opengis.net/ols/1.2.0/RouteService.xsd" | ||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | ||
| <xls:RequestHeader /> | ||
| <xls:Request methodName="RouteRequest"> | ||
| <xls:DetermineRouteRequest> | ||
| <xls:RoutePlan> | ||
| <xls:RoutePreference>Fastest</xls:RoutePreference> | ||
| <xls:WayPointList> | ||
|
|
||
| <xls:StartPoint> | ||
| <xls:Position> | ||
| <gml:Point srsName="EPSG:23030" xmlns:gml="http://www.opengis.net/gml"> | ||
| <gml:pos>444227 4474647.25</gml:pos> | ||
| </gml:Point> | ||
| </xls:Position> | ||
| </xls:StartPoint> | ||
|
|
||
| <xls:EndPoint> | ||
| <xls:Position> | ||
| <gml:Point srsName="EPSG:23030" xmlns:gml="http://www.opengis.net/gml"> | ||
| <gml:pos>443984 4474719.25</gml:pos> | ||
| </gml:Point> | ||
| </xls:Position> | ||
| </xls:EndPoint> | ||
|
|
||
| </xls:WayPointList> | ||
| </xls:RoutePlan> | ||
| <xls:RouteInstructionsRequest /> | ||
| <xls:RouteGeometryRequest /> | ||
| <xls:RouteMapRequest /> | ||
| </xls:DetermineRouteRequest> | ||
| </xls:Request> | ||
| </xls:XLS> |
| @@ -0,0 +1,50 @@ | ||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
| <modelVersion>4.0.0</modelVersion> | ||
| <groupId>org.emergya</groupId> | ||
| <artifactId>tsp</artifactId> | ||
| <version>0.1.1</version> | ||
| <name>tsp</name> | ||
| <description>TSP interfaces and utilities.</description> | ||
|
|
||
|
|
||
| <distributionManagement> | ||
| <repository> | ||
| <id>gofleet</id> | ||
| <url>http://nexus.emergya.es/nexus/content/repositories/gofleet</url> | ||
| </repository> | ||
| <snapshotRepository> | ||
| <id>gofleet-snap</id> | ||
| <url>http://nexus.emergya.es/nexus/content/repositories/gofleet-snapshots</url> | ||
| </snapshotRepository> | ||
| </distributionManagement> | ||
|
|
||
|
|
||
| <build> | ||
| <plugins> | ||
| <plugin> | ||
|
|
||
| <!-- Maven compiler plugin --> | ||
| <artifactId>maven-compiler-plugin</artifactId> | ||
| <configuration> | ||
| <source>1.6</source> | ||
| <target>1.6</target> | ||
| <optimize>true</optimize> | ||
| </configuration> | ||
| </plugin> | ||
| </plugins> | ||
| </build> | ||
|
|
||
| <dependencies> | ||
| <dependency> | ||
| <groupId>org.geotools</groupId> | ||
| <artifactId>gt-api</artifactId> | ||
| <version>${geotools.version}</version> | ||
| </dependency> | ||
| </dependencies> | ||
|
|
||
| <properties> | ||
| <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||
| <geotools.version>8.0-M4</geotools.version> | ||
| </properties> | ||
| </project> |
| @@ -0,0 +1,59 @@ | ||
|
|
||
| /** | ||
| * Copyright (C) 2012, Emergya (http://www.emergya.es) | ||
| * | ||
| * @author <a href="mailto:marias@emergya.com">María Arias de Reyna</a> | ||
| * | ||
| * This file is part of GoFleet | ||
| * | ||
| * This software is free software; you can redistribute it and/or modify | ||
| * it under the terms of the GNU General Public License as published by | ||
| * the Free Software Foundation; either version 2 of the License, or (at | ||
| * your option) any later version. | ||
| * | ||
| * This software is distributed in the hope that it will be useful, but | ||
| * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| * General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU General Public License | ||
| * along with this library; if not, write to the Free Software | ||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| * 02110-1301 USA | ||
| * | ||
| * As a special exception, if you link this library with other files to | ||
| * produce an executable, this library does not by itself cause the | ||
| * resulting executable to be covered by the GNU General Public License. | ||
| * This exception does not however invalidate any other reasons why the | ||
| * executable file might be covered by the GNU General Public License. | ||
| */ | ||
|
|
||
| package org.gofleet.openLS.tsp; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public interface TSPAlgorithm { | ||
|
|
||
| /** | ||
| * Returns the optimum TSP of the bag. | ||
| * | ||
| * The list contains all the stops of the bag. | ||
| * | ||
| * If {@link TSPStopBag#hasLast()}, {@link TSPStopBag#getLast()} is the last | ||
| * {@link TSPStop} of the list. | ||
| * | ||
| * If {@link TSPStopBag#hasFirst()}, {@link TSPStopBag#getFirst()} is the | ||
| * first {@link TSPStop} of the list. | ||
| * | ||
| * @param bag | ||
| * @return | ||
| */ | ||
| List<TSPStop> order(TSPStopBag bag); | ||
|
|
||
| /** | ||
| * Cancels the execution of the ordering. Useful for expensive algorithms. | ||
| * @return | ||
| */ | ||
| boolean stop(); | ||
|
|
||
| } |
| @@ -0,0 +1,48 @@ | ||
|
|
||
| /** | ||
| * Copyright (C) 2012, Emergya (http://www.emergya.es) | ||
| * | ||
| * @author <a href="mailto:marias@emergya.com">María Arias de Reyna</a> | ||
| * | ||
| * This file is part of GoFleet | ||
| * | ||
| * This software is free software; you can redistribute it and/or modify | ||
| * it under the terms of the GNU General Public License as published by | ||
| * the Free Software Foundation; either version 2 of the License, or (at | ||
| * your option) any later version. | ||
| * | ||
| * This software is distributed in the hope that it will be useful, but | ||
| * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| * General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU General Public License | ||
| * along with this library; if not, write to the Free Software | ||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| * 02110-1301 USA | ||
| * | ||
| * As a special exception, if you link this library with other files to | ||
| * produce an executable, this library does not by itself cause the | ||
| * resulting executable to be covered by the GNU General Public License. | ||
| * This exception does not however invalidate any other reasons why the | ||
| * executable file might be covered by the GNU General Public License. | ||
| */ | ||
|
|
||
| package org.gofleet.openLS.tsp; | ||
|
|
||
| import com.vividsolutions.jts.geom.Point; | ||
|
|
||
| public interface TSPStop { | ||
|
|
||
| /** | ||
| * Returns the unique id (on this bag) for this stop. | ||
| * @return | ||
| */ | ||
| Integer getId(); | ||
|
|
||
| /** | ||
| * Returns the position of this stop. | ||
| * @return | ||
| */ | ||
| Point getPosition(); | ||
| } |
| @@ -0,0 +1,83 @@ | ||
|
|
||
| /** | ||
| * Copyright (C) 2012, Emergya (http://www.emergya.es) | ||
| * | ||
| * @author <a href="mailto:marias@emergya.com">María Arias de Reyna</a> | ||
| * | ||
| * This file is part of GoFleet | ||
| * | ||
| * This software is free software; you can redistribute it and/or modify | ||
| * it under the terms of the GNU General Public License as published by | ||
| * the Free Software Foundation; either version 2 of the License, or (at | ||
| * your option) any later version. | ||
| * | ||
| * This software is distributed in the hope that it will be useful, but | ||
| * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| * General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU General Public License | ||
| * along with this library; if not, write to the Free Software | ||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| * 02110-1301 USA | ||
| * | ||
| * As a special exception, if you link this library with other files to | ||
| * produce an executable, this library does not by itself cause the | ||
| * resulting executable to be covered by the GNU General Public License. | ||
| * This exception does not however invalidate any other reasons why the | ||
| * executable file might be covered by the GNU General Public License. | ||
| */ | ||
| package org.gofleet.openLS.tsp; | ||
|
|
||
| import java.util.Collection; | ||
|
|
||
| public interface TSPStopBag { | ||
| /** | ||
| * If {@link #hasFirst()} returns true, returns the stop which has to be | ||
| * first | ||
| * | ||
| * Otherwise, returns null. | ||
| * | ||
| * @return | ||
| */ | ||
| TSPStop getFirst(); | ||
|
|
||
| /** | ||
| * If {@link #hasLast()} returns true, returns the stop which has to be last | ||
| * | ||
| * Otherwise, returns null. | ||
| * | ||
| * @return | ||
| */ | ||
| TSPStop getLast(); | ||
|
|
||
| /** | ||
| * Returns, unordered, all the stops. | ||
| * | ||
| * @return | ||
| */ | ||
| Collection<TSPStop> getAll(); | ||
|
|
||
| /** | ||
| * Returns if this bag has a stop which must be the first stop | ||
| * | ||
| * @return | ||
| */ | ||
| Boolean hasFirst(); | ||
|
|
||
| /** | ||
| * Returns if this bag has a stop which must be the last stop | ||
| * | ||
| * @return | ||
| */ | ||
| Boolean hasLast(); | ||
|
|
||
| /** | ||
| * Returns the number of stops the solution has to have (which means, the | ||
| * total number of stops of this bag). | ||
| * | ||
| * @return | ||
| */ | ||
| Integer size(); | ||
|
|
||
| } |