diff --git a/.checkstyle b/.checkstyle deleted file mode 100644 index 94a347e7e932eac3fe2888ac4c1fc43b29a36955..0000000000000000000000000000000000000000 --- a/.checkstyle +++ /dev/null @@ -1,7 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<fileset-config file-format-version="1.2.0" simple-config="true" sync-formatter="false"> - <fileset name="all" enabled="true" check-config-name="NKrChecks" local="false"> - <file-match-pattern match-pattern="." include-pattern="true"/> - </fileset> -</fileset-config> diff --git a/src/main/java/it/unibz/inf/isochrone/algorithm/Isochrone.java b/src/main/java/it/unibz/inf/isochrone/algorithm/Isochrone.java index 20290977fb13ef80f792745e6593e895aca51711..ee83cfc86c07b6b8ebcb56a4385b6e1fb71dae2a 100644 --- a/src/main/java/it/unibz/inf/isochrone/algorithm/Isochrone.java +++ b/src/main/java/it/unibz/inf/isochrone/algorithm/Isochrone.java @@ -2,14 +2,17 @@ package it.unibz.inf.isochrone.algorithm; import it.unibz.inf.isochrone.config.ConfigDataset; import it.unibz.inf.isochrone.db.Database; +import it.unibz.inf.isochrone.network.AbstractOutput; +import it.unibz.inf.isochrone.network.IOutput; import it.unibz.inf.isochrone.network.Link; import it.unibz.inf.isochrone.network.Location; import it.unibz.inf.isochrone.network.MemoryOutput; import it.unibz.inf.isochrone.network.Node; -import it.unibz.inf.isochrone.network.Output; import it.unibz.inf.isochrone.util.EnumContainer.Direction; import it.unibz.inf.isochrone.util.Query; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.HashSet; @@ -38,7 +41,7 @@ public abstract class Isochrone { * Instantiates a new isochrone object. * * @param config the configuration of the dataset for the isochrone - * @param db the databse object used for db communication + * @param db used for database communication * @param query the parameters for the isochrone * @throws AlgorithmException thrown if there are no date codes in the database for the specified query */ @@ -117,41 +120,34 @@ public abstract class Isochrone { * @param output the output in which the computed nodes and links are stored. * @return the computed output (stored in the output given by the parameter) */ - // TODO: Add some more tests for this method. If isochrone gets too small (2points for 15min isochrone from FUB) nothing fails ;-( - public <T extends Output> T compute(final T output) { + // TODO: Add some more tests for this method. If isochrones get too small (2points for 15min isochrone from FUB) nothing fails ;-( + public <T extends AbstractOutput> T compute(final T output) { + final boolean isNodeExpires = query.isExpireNodes(); output.beforeCalculation(); - if (!query.getStartNodes().isEmpty()) { - initializeStartNodes(query.getStartNodes()); - } else { + final Collection<Integer> startNodes = query.getStartNodes(); + if (startNodes.isEmpty()) { initializeStartLocations(output, query.getStartLocations()); + } else { + initializeStartNodes(startNodes); } Node node = null; - // TODO: Would it make sense to bulk-load the adjLinks? (not id by id, but the whole queue or the next 1000 ids?) while ((node = queue.poll()) != null) { - final Collection<Link> adjacents = calcAdjLinks(node.getID()); + final int nodeId = node.getID(); + final Collection<Link> adjacents = calcAdjLinks(nodeId); output.addNode(node); node.close(); - for (final Link link : adjacents) { - if (link.isContinuous()) { - updateNodeQueue(expandContinuousLink(node, link)); - addLinks(output, link); - } else { - updateNodeQueue(expandDiscreteLink(node, link)); - } - } + updateNodeQueue(expandLinks(node, adjacents)); + addLinks(output, adjacents); - if (query.isExpireNodes() && node.isExpired()) { - removeNode(node.getID()); + if (isNodeExpires && node.isExpired()) { + removeNode(nodeId); } } - for (final Node n : getNodes()) { - output.addNode(n); - } - + output.addNodes(getNodes()); output.afterCalculation(); return output; @@ -185,82 +181,75 @@ public abstract class Isochrone { // Private methods - private <T extends Output> void addLinks(final T output, final Link link) { - if (Math.abs(link.getStartOffset() - Double.MIN_VALUE) < COMPARE_PRECISION) { - output.addLink(link); + private <T extends IOutput> void addLinks(final T output, final Collection<Link> links) { + for (final Link link : links) { + if (link.isContinuous() && Math.abs(link.getStartOffset() - Double.MIN_VALUE) < COMPARE_PRECISION) { + output.addLink(link); + } } } /** - * Expand the given continuous link (that is connected to the given node) + * Expand the given link (that is connected to the given node) * and adjusts the link offsets based on the distance of the current Node * and the maximum duration of the query. * * @param node current node - * @param link continuous link, that is connected to the node - * @return another node, if it can be reached in the available time (or null if time has run out) + * @param links links that are connected to the node + * @return nodes that can be reached in the available time (or an empty list if time has run out/no nodes are reachable) */ - private Node expandContinuousLink(final Node node, final Link link) { - final int duration = query.getDuration().intValue(); + private Collection<Node> expandLinks(final Node node, final Collection<Link> links) { + final long duration = query.getDuration().longValue(); final double walkingSpeed = query.getWalkingSpeed(); - double destinationOffset; - - final Node adjacentNode = getNode(link.getOppositeOf(node)); - adjacentNode.visitNrAdjacentLinks((short) 1); - - if (query.getDir() == Direction.INCOMING) { - destinationOffset = Math.max(0, link.getLength() - (query.getDuration() - node.getDistance()) * walkingSpeed); - link.setStartOffset(destinationOffset); - link.setEndOffset(link.getLength()); - } else { - final double remainingDistance = query.getDuration() - node.getDistance() < 0 ? 0 : query.getDuration() - node.getDistance(); - destinationOffset = Math.min(link.getLength(), remainingDistance * walkingSpeed); - link.setStartOffset(0); - link.setEndOffset(destinationOffset); - } - - if (!adjacentNode.isClosed()) { - final double newDistance = node.getDistance() + link.getLength() / walkingSpeed; - if (newDistance <= duration && newDistance < adjacentNode.getDistance()) { - adjacentNode.setDistance(newDistance); - return adjacentNode; + final boolean isExpiring = query.isExpireNodes(); + final boolean isIncoming = (Direction.INCOMING == query.getDir()); + + final Collection<Node> resultNodes = new ArrayList<>(links.size()); + for (final Link link : links) { + final Node adjacentNode = getNode(link.getOppositeOf(node)); + adjacentNode.visitNrAdjacentLinks((short) 1); + + final double linkLength = link.getLength(); + final boolean isContinuous = link.isContinuous(); + final double nodeDistance = node.getDistance(); + + if (isContinuous) { + double remainingDistance = duration - nodeDistance; + if (isIncoming) { + link.setStartOffset(Math.max(0, linkLength - (remainingDistance * walkingSpeed))); + link.setEndOffset(linkLength); + } else { + remainingDistance = Math.max(0, duration - nodeDistance); + link.setStartOffset(0); + link.setEndOffset(Math.min(linkLength, remainingDistance * walkingSpeed)); + } } - } else if (query.isExpireNodes() && adjacentNode.isExpired() && node.getID() != adjacentNode.getID()) { - removeNode(adjacentNode.getID()); - } - return null; - } + if (adjacentNode.isClosed()) { + if (isExpiring && adjacentNode.isExpired()) { + final int adjId = adjacentNode.getID(); + if (!isContinuous || adjId != node.getID()) { + removeNode(adjId); + } + } + } else { + final double newDistance; + if (isContinuous) { + newDistance = nodeDistance + linkLength / walkingSpeed; + } else { + final Set<Short> routes = new HashSet<>(); + routes.add((short) link.getRoute()); + newDistance = getAdjNodeCost(node, adjacentNode, Arrays.asList(new Short[] {(short) link.getRoute()})); + } - /** - * Expand the given discrete link (that is connected to the - * given node and adjust the link offsets based on the - * distance of the current Node and the maximum duration of - * the query. - * - * @param node current Node - * @param link discrete link connected to the node - * @return another node, if it can be reached in the available time (or null if there is no time to reach another node) - */ - private Node expandDiscreteLink(final Node node, final Link link) { - final Long duration = query.getDuration(); - final Node adjacentNode = getNode(link.getOppositeOf(node)); - adjacentNode.visitNrAdjacentLinks((short) 1); - - if (!adjacentNode.isClosed()) { - final Set<Short> routes = new HashSet<>(); - routes.add((short) link.getRoute()); - - final double newDistance = getAdjNodeCost(node, adjacentNode, routes); - if (newDistance <= duration && newDistance < adjacentNode.getDistance()) { - adjacentNode.setDistance(newDistance); - return adjacentNode; + if (newDistance <= duration && newDistance < adjacentNode.getDistance()) { + adjacentNode.setDistance(newDistance); + resultNodes.add(adjacentNode); + } } - } else if (query.isExpireNodes() && adjacentNode.isExpired()) { - removeNode(adjacentNode.getID()); } - return null; + return resultNodes; } /** @@ -281,7 +270,7 @@ public abstract class Isochrone { * @param routeIds the routes that should be considered * @return the cost of traveling from the node to adjNode */ - private double getAdjNodeCost(final Node node, final Node adjNode, final Set<Short> routeIds) { + private double getAdjNodeCost(final Node node, final Node adjNode, final Collection<Short> routeIds) { return database.getAdjNodeCost(node, adjNode, routeIds, codes, query.getFromTime(), query.getToTime()); } @@ -293,7 +282,7 @@ public abstract class Isochrone { private void initDateCodes() throws AlgorithmException { codes = getDateCodes(query.getTime()); - if (codes.size() == 0) { + if (codes.isEmpty()) { // was solved in uniBz version by switching to unimodal mode... we do not do this any more // (since user does not get informated about the change) throw new AlgorithmException("Couldn't find datecodes in the databse for the given date"); @@ -306,32 +295,36 @@ public abstract class Isochrone { * @param output the output class in which the initial links are stored * @param locations The locations from which the isochrone should start. */ - private void initializeStartLocations(final Output output, final Collection<Location> locations) { + private void initializeStartLocations(final IOutput output, final Collection<Location> locations) { + final long duration = query.getDuration().longValue(); + final double walkingSpeed = query.getWalkingSpeed(); + final boolean isIncoming = (Direction.INCOMING == query.getDir()); + for (final Location location : locations) { final Link link = getLink(location.getLinkId()); final double locationOffset = location.getOffset(); double distance; Node node; - if (query.getDir() == Direction.INCOMING) { + if (isIncoming) { node = getNode(link.getStartNode()); - distance = locationOffset / query.getWalkingSpeed(); + distance = locationOffset / walkingSpeed; if (locationOffset > 0 && locationOffset < link.getLength()) { - link.setStartOffset(Math.max(0, locationOffset - query.getDuration() * query.getWalkingSpeed())); + link.setStartOffset(Math.max(0, locationOffset - duration * walkingSpeed)); link.setEndOffset(locationOffset); output.addLink(link); } } else { node = getNode(link.getEndNode()); - distance = (link.getLength() - locationOffset) / query.getWalkingSpeed(); + distance = (link.getLength() - locationOffset) / walkingSpeed; if (locationOffset > 0 && locationOffset < link.getLength()) { link.setStartOffset(locationOffset); - link.setEndOffset(Math.min(link.getLength(), Math.abs(link.getLength() - locationOffset - query.getDuration() * query.getWalkingSpeed()))); + link.setEndOffset(Math.min(link.getLength(), Math.abs(link.getLength() - locationOffset - duration * walkingSpeed))); output.addLink(link); } } - if (distance <= query.getDuration() && distance < node.getDistance()) { + if (distance <= duration && distance < node.getDistance()) { node.setDistance(distance); updateNodeQueue(node); } @@ -361,4 +354,15 @@ public abstract class Isochrone { queue.offer(node); } } + + /** + * Sets updated nodes into the right place in the priority queue. + * + * @param nodes The nodes that were changed + */ + private void updateNodeQueue(final Collection<Node> nodes) { + for (final Node node : nodes) { + updateNodeQueue(node); + } + } } diff --git a/src/main/java/it/unibz/inf/isochrone/db/Database.java b/src/main/java/it/unibz/inf/isochrone/db/Database.java index ab7ffa21ac760d9419bd5d037b571bc43ee0f761..caf37f15ed65ae29938dbc5829a69c3ef45b979a 100644 --- a/src/main/java/it/unibz/inf/isochrone/db/Database.java +++ b/src/main/java/it/unibz/inf/isochrone/db/Database.java @@ -225,7 +225,7 @@ public class Database { * @param toTime the latest time for which we want to calculate the departure time * @return the cost of for traveling from the start node to the end node */ - public double getAdjNodeCost(final Node node, final Node adjNode, final Set<Short> routeIds, final Set<Integer> dateCodes, final long fromTime, final long toTime) { + public double getAdjNodeCost(final Node node, final Node adjNode, final Collection<Short> routeIds, final Set<Integer> dateCodes, final long fromTime, final long toTime) { double minDistance = Double.POSITIVE_INFINITY; ResultSet rs = null; @@ -332,14 +332,14 @@ public class Database { * @param sourceId the id of the source node * @param targetId the id of the target node * @param routeIds the identifiers (as set) of the routes that should be considered - * @param dateCodes the date codes for which the times are calculated + * @param dates the date codes for which the times are calculated * @param from the earliest time for which we want to calculate the departure time * @param to the latest time for which we want to calculate the departure time * @throws SQLException thrown is the DB update statement can not be executed (or the prepared statement parameters could not be set) * @return a resultSet with all the times that come into consideration */ - public ResultSet getEarliestArrivalTime(final int sourceId, final int targetId, final Set<Short> routeIds, final Set<Integer> dateCodes, final long from, final long to) throws SQLException { - final String sql = String.format(queryEarliestArrivalTimeHomo, preparePlaceHolders(routeIds.size()), preparePlaceHolders(dateCodes.size())); + public ResultSet getEarliestArrivalTime(final int sourceId, final int targetId, final Collection<Short> routeIds, final Set<Integer> dates, final long from, final long to) throws SQLException { + final String sql = String.format(queryEarliestArrivalTimeHomo, preparePlaceHolders(routeIds.size()), preparePlaceHolders(dates.size())); final PreparedStatement statement = getPstmt(sql); // CHECKSTYLE:OFF MagicNumber @@ -348,7 +348,7 @@ public class Database { int idx = setValues(3, statement, routeIds.toArray()); statement.setLong(idx++, from); statement.setLong(idx++, to); - idx = setValues(idx, statement, dateCodes.toArray()); + idx = setValues(idx, statement, dates.toArray()); statement.setLong(idx, to); // CHECKSTYLE:ON MagicNumber @@ -361,14 +361,14 @@ public class Database { * @param sourceId the id of the source node * @param targetId the id of the target node * @param routeIds the identifiers (as set) of the routes that should be considered - * @param dateCodes the date codes for which the times are calculated + * @param dates the date codes for which the times are calculated * @param from the earliest time for which we want to calculate the departure time * @param to the latest time for which we want to calculate the departure time * @throws SQLException thrown is the DB update statement can not be executed (or the prepared statement parameters could not be set) * @return a resultSet with all the times that come into consideration */ - public ResultSet getLatestDepartureTime(final int sourceId, final int targetId, final Set<Short> routeIds, final Set<Integer> dateCodes, final long from, final long to) throws SQLException { - final String sql = String.format(queryLatestDepartureTimeHomo, preparePlaceHolders(routeIds.size()), preparePlaceHolders(dateCodes.size())); + public ResultSet getLatestDepartureTime(final int sourceId, final int targetId, final Collection<Short> routeIds, final Set<Integer> dates, final long from, final long to) throws SQLException { + final String sql = String.format(queryLatestDepartureTimeHomo, preparePlaceHolders(routeIds.size()), preparePlaceHolders(dates.size())); final PreparedStatement statement = getPstmt(sql); // CHECKSTYLE:OFF MagicNumber @@ -377,7 +377,7 @@ public class Database { int idx = setValues(3, statement, routeIds.toArray()); statement.setLong(idx++, from); statement.setLong(idx++, to); - idx = setValues(idx, statement, dateCodes.toArray()); + idx = setValues(idx, statement, dates.toArray()); statement.setLong(idx, from); // CHECKSTYLE:ON MagicNumber diff --git a/src/main/java/it/unibz/inf/isochrone/network/AbstractOutput.java b/src/main/java/it/unibz/inf/isochrone/network/AbstractOutput.java new file mode 100644 index 0000000000000000000000000000000000000000..35af77965d146918de516d522514aebd6988a4a0 --- /dev/null +++ b/src/main/java/it/unibz/inf/isochrone/network/AbstractOutput.java @@ -0,0 +1,31 @@ +package it.unibz.inf.isochrone.network; + +import java.util.Collection; + +public abstract class AbstractOutput implements IOutput { + + /** + * This is called after all links and nodes are stored in this output. + * Can be useful to save results in the database (or similar) + */ + public void afterCalculation() { } + + /** + * This is called before links and/or nodes are stored in this output. + * Can be useful to set up some datatypes (clear maps, ...). + */ + public void beforeCalculation() { } + + public void addLinks(final Collection<Link> links) { + for (final Link link : links) { + addLink(link); + } + } + + public void addNodes(final Collection<Node> nodes) { + for (final Node node : nodes) { + addNode(node); + } + } + +} diff --git a/src/main/java/it/unibz/inf/isochrone/network/Output.java b/src/main/java/it/unibz/inf/isochrone/network/IOutput.java similarity index 51% rename from src/main/java/it/unibz/inf/isochrone/network/Output.java rename to src/main/java/it/unibz/inf/isochrone/network/IOutput.java index a69f87b1707e474d38e347f3fa98ab743b0de550..f135a417f6e2a11f956e1f9a3685ef2b8c957363 100644 --- a/src/main/java/it/unibz/inf/isochrone/network/Output.java +++ b/src/main/java/it/unibz/inf/isochrone/network/IOutput.java @@ -1,9 +1,10 @@ package it.unibz.inf.isochrone.network; + /** * Stores all the output links from the isochrone algorithm. */ -public interface Output { +public interface IOutput { /** * Stores a link which belongs to the network. @@ -19,16 +20,4 @@ public interface Output { */ void addNode(Node node); - /** - * This is called after all links and nodes are stored in this output. - * Can be useful to save results in the database (or similar) - */ - void afterCalculation(); - - /** - * This is called before links and/or nodes are stored in this output. - * Can be useful to set up some datatypes (clear maps, ...). - */ - void beforeCalculation(); - } diff --git a/src/main/java/it/unibz/inf/isochrone/network/MemoryOutput.java b/src/main/java/it/unibz/inf/isochrone/network/MemoryOutput.java index 2e8fbeaafc0387f716ad30a1f9a23c9f11ef2f33..013b9a122bde3f6a2007a878523e503b307c98f0 100644 --- a/src/main/java/it/unibz/inf/isochrone/network/MemoryOutput.java +++ b/src/main/java/it/unibz/inf/isochrone/network/MemoryOutput.java @@ -1,5 +1,6 @@ package it.unibz.inf.isochrone.network; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -9,7 +10,7 @@ import java.util.Set; * A sample output class, which simply stores all nodes and returns if needed. * This is mainly used for testing purposes. */ -public class MemoryOutput implements Output { +public class MemoryOutput extends AbstractOutput { private final Map<Integer, Link> links; private final Set<Node> nodes; @@ -43,13 +44,8 @@ public class MemoryOutput implements Output { } @Override - public void afterCalculation() { - // No post-processing of calculated isochrone - } - - @Override - public void beforeCalculation() { - // No pre-processing of calculated isochrone + public void addNodes(final Collection<Node> node) { + nodes.addAll(nodes); } } diff --git a/src/main/java/it/unibz/inf/isochrone/network/Offset.java b/src/main/java/it/unibz/inf/isochrone/network/Offset.java index ab331a4c2902f9b43df3a8a1b1b6c121a7774407..d28f4f30c685066d2ae997ec4537a0dd474c6052 100644 --- a/src/main/java/it/unibz/inf/isochrone/network/Offset.java +++ b/src/main/java/it/unibz/inf/isochrone/network/Offset.java @@ -7,7 +7,7 @@ package it.unibz.inf.isochrone.network; * A link offset consists of a distance from the link start node and a distance from the link end node. The distances * indicate the two outer link segments that cannot be reached. Moreover, these two segments delimit the reachable, * inner part of this link. - * + * * @author Gytis Tumas * @author Willi Cometti * @version 2.0 @@ -19,7 +19,7 @@ public class Offset { /** * Class Constructor that uses two distances to create the <code>Offset * </code>. - * + * * @param startOffset the distance from the start node * @param endOffset the distance from the end node */ @@ -30,7 +30,7 @@ public class Offset { /** * Returns the beginning of the offset in respect to the start node. - * + * * @return the start node offset */ public double getStartOffset() { @@ -39,10 +39,11 @@ public class Offset { /** * Returns the ending of the offset in respect to the start node. - * + * * @return the end node offset */ public double getEndOffset() { return endOffset; } + } diff --git a/src/main/java/it/unibz/inf/isochrone/network/Schedule.java b/src/main/java/it/unibz/inf/isochrone/network/Schedule.java index ea56c9a74be63c058f5a92b204998d787963d604..3ee3a28a69e8fb8a6c85247ac20fecf7eae3aedd 100644 --- a/src/main/java/it/unibz/inf/isochrone/network/Schedule.java +++ b/src/main/java/it/unibz/inf/isochrone/network/Schedule.java @@ -1,20 +1,17 @@ package it.unibz.inf.isochrone.network; /** - * Represents a Schedule for Transport systems in memory. + * Represents a Schedule for Transport systems (in memory). */ public class Schedule { - private long departureTime, arrivalTime; + private long arrivalTime; + private long departureTime; + + // Constructors public Schedule() { } - public void setDepartureTime(final long departureTime) { - this.departureTime = departureTime; - } - - public void setArrivalTime(final long arrivalTime) { - this.arrivalTime = arrivalTime; - } + // Getters public long getArrivalTime() { return arrivalTime; @@ -24,4 +21,14 @@ public class Schedule { return departureTime; } + // Setters + + public void setArrivalTime(final long arrivalTime) { + this.arrivalTime = arrivalTime; + } + + public void setDepartureTime(final long departureTime) { + this.departureTime = departureTime; + } + }