/** * H2GIS is a library that brings spatial support to the H2 Database Engine * <http://www.h2database.com>. H2GIS is developed by CNRS * <http://www.cnrs.fr/>. * * This code is part of the H2GIS project. H2GIS is free software; * you can redistribute it and/or modify it under the terms of the GNU * Lesser General Public License as published by the Free Software Foundation; * version 3.0 of the License. * * H2GIS 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 Lesser General Public License * for more details <http://www.gnu.org/licenses/>. * * * For more information, please consult: <http://www.h2gis.org/> * or contact directly: info_at_h2gis.org */ package org.h2gis.network.functions; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import org.h2.jdbc.JdbcSQLException; import org.h2gis.functions.factory.H2GISDBFactory; import org.h2gis.functions.factory.H2GISFunctions; import static org.h2gis.unitTest.GeometryAsserts.assertGeometryEquals; import org.junit.*; import static org.junit.Assert.assertEquals; /** * @author Adam Gouge * @author Erwan Bocher */ public class ST_ShortestPathTest { private static Connection connection; private Statement st; private static final double TOLERANCE = 0.0; private static final String DO = "'directed - edge_orientation'"; private static final String RO = "'reversed - edge_orientation'"; private static final String U = "'undirected'"; private static final String W = "'weight'"; private static final PathEdge[] EMPTY = new PathEdge[]{}; @BeforeClass public static void setUp() throws Exception { // Keep a connection alive to not close the DataBase on each unit test connection = H2GISDBFactory.createSpatialDataBase("ST_ShortestPathTest", true); H2GISFunctions.registerFunction(connection.createStatement(), new ST_ShortestPath(), ""); GraphCreatorTest.registerCormenGraph(connection); } @Before public void setUpStatement() throws Exception { st = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); } @After public void tearDownStatement() throws Exception { st.close(); } @AfterClass public static void tearDown() throws Exception { connection.close(); } // ************************** One-to-One **************************************** @Test public void oneToOneDO() throws Exception { // Nodes // | 1 | 2 | 3 | 4 | 5 | // |-----------|------------------|---------|------------------|---------| // | * | (1,2) | (1,3) | (1,3,4), (1,5,4) | (1,5) | // | (2,3,5,1) | * | (2,3) | (2,3,4) | (2,3,5) | // | (3,5,1) | (3,2) | * | (3,4) | (3,5) | // | (4,5,1) | (4,2) | (4,2,3) | * | (4,5) | // | (5,1) | (5,1,2), (5,4,2) | (5,1,3) | (5,4) | * | // // Edges // | 1 | 2 | 3 | 4 | 5 | // |----------|---------------|--------|----------------|-------| // | * | (1) | (5) | (5,6), (-10,9) | (-10) | // | (3,7,10) | * | (3) | (3,6) | (3,7) | // | (7,10) | (4) | * | (6) | (7) | // | (8,10) | (2) | (2,3) | * | (8) | // | (10) | (10,1), (9,2) | (10,5) | (9) | * | // // SELECT * FROM ST_ShortestPath('CORMEN_EDGES_ALL', // 'directed - edge_orientation', i, j) check(oneToOne(DO, 1, 1), EMPTY); check(oneToOne(DO, 1, 2), new PathEdge[]{ new PathEdge("LINESTRING (0 1, 1 2)", 1, 1, 1, 1, 2, 1.0)}); check(oneToOne(DO, 1, 3), new PathEdge[]{ new PathEdge("LINESTRING (0 1, 1 0)", 5, 1, 1, 1, 3, 1.0)}); final ResultSet rs14 = oneToOne(DO, 1, 4); try { check(rs14, new PathEdge[]{ new PathEdge("LINESTRING (1 0, 2 2)", 6, 1, 1, 3, 4, 1.0), new PathEdge("LINESTRING (0 1, 1 0)", 5, 1, 2, 1, 3, 1.0), new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 2, 1, 5, 4, 1.0), new PathEdge("LINESTRING (2 0, 0 1)", -10, 2, 2, 1, 5, 1.0)}); } catch (AssertionError e) { rs14.beforeFirst(); check(rs14, new PathEdge[]{ new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 1, 1, 5, 4, 1.0), new PathEdge("LINESTRING (2 0, 0 1)", -10, 1, 2, 1, 5, 1.0), new PathEdge("LINESTRING (1 0, 2 2)", 6, 2, 1, 3, 4, 1.0), new PathEdge("LINESTRING (0 1, 1 0)", 5, 2, 2, 1, 3, 1.0)}); } rs14.close(); check(oneToOne(DO, 1, 5), new PathEdge[]{ new PathEdge("LINESTRING (2 0, 0 1)", -10, 1, 1, 1, 5, 1.0)}); check(oneToOne(DO, 2, 1), new PathEdge[]{ new PathEdge("LINESTRING (2 0, 0 1)", 10, 1, 1, 5, 1, 1.0), new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 2, 3, 5, 1.0), new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 3, 2, 3, 1.0)}); check(oneToOne(DO, 2, 2), EMPTY); check(oneToOne(DO, 2, 3), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 1, 2, 3, 1.0)}); check(oneToOne(DO, 2, 4), new PathEdge[]{ new PathEdge("LINESTRING (1 0, 2 2)", 6, 1, 1, 3, 4, 1.0), new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 2, 2, 3, 1.0)}); check(oneToOne(DO, 2, 5), new PathEdge[]{ new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 1, 3, 5, 1.0), new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 2, 2, 3, 1.0)}); check(oneToOne(DO, 3, 1), new PathEdge[]{ new PathEdge("LINESTRING (2 0, 0 1)", 10, 1, 1, 5, 1, 1.0), new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 2, 3, 5, 1.0)}); check(oneToOne(DO, 3, 2), new PathEdge[]{ new PathEdge("LINESTRING (1 0, 1.25 1, 1 2)", 4, 1, 1, 3, 2, 1.0)}); check(oneToOne(DO, 3, 3), EMPTY); check(oneToOne(DO, 3, 4), new PathEdge[]{ new PathEdge("LINESTRING (1 0, 2 2)", 6, 1, 1, 3, 4, 1.0)}); check(oneToOne(DO, 3, 5), new PathEdge[]{ new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 1, 3, 5, 1.0)}); check(oneToOne(DO, 4, 1), new PathEdge[]{ new PathEdge("LINESTRING (2 0, 0 1)", 10, 1, 1, 5, 1, 1.0), new PathEdge("LINESTRING (2 2, 1.75 1, 2 0)", 8, 1, 2, 4, 5, 1.0)}); check(oneToOne(DO, 4, 2), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 2 2)", 2, 1, 1, 4, 2, 1.0)}); check(oneToOne(DO, 4, 3), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 1, 2, 3, 1.0), new PathEdge("LINESTRING (1 2, 2 2)", 2, 1, 2, 4, 2, 1.0)}); check(oneToOne(DO, 4, 4), EMPTY); check(oneToOne(DO, 4, 5), new PathEdge[]{ new PathEdge("LINESTRING (2 2, 1.75 1, 2 0)", 8, 1, 1, 4, 5, 1.0)}); check(oneToOne(DO, 5, 1), new PathEdge[]{ new PathEdge("LINESTRING (2 0, 0 1)", 10, 1, 1, 5, 1, 1.0)}); final ResultSet rs52 = oneToOne(DO, 5, 2); try { check(rs52, new PathEdge[]{ new PathEdge("LINESTRING (0 1, 1 2)", 1, 1, 1, 1, 2, 1.0), new PathEdge("LINESTRING (2 0, 0 1)", 10, 1, 2, 5, 1, 1.0), new PathEdge("LINESTRING (1 2, 2 2)", 2, 2, 1, 4, 2, 1.0), new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 2, 2, 5, 4, 1.0)}); } catch (AssertionError e) { rs52.beforeFirst(); check(rs52, new PathEdge[]{ new PathEdge("LINESTRING (1 2, 2 2)", 2, 1, 1, 4, 2, 1.0), new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 1, 2, 5, 4, 1.0), new PathEdge("LINESTRING (0 1, 1 2)", 1, 2, 1, 1, 2, 1.0), new PathEdge("LINESTRING (2 0, 0 1)", 10, 2, 2, 5, 1, 1.0)}); } rs52.close(); check(oneToOne(DO, 5, 3), new PathEdge[]{ new PathEdge("LINESTRING (0 1, 1 0)", 5, 1, 1, 1, 3, 1.0), new PathEdge("LINESTRING (2 0, 0 1)", 10, 1, 2, 5, 1, 1.0)}); check(oneToOne(DO, 5, 4), new PathEdge[]{ new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 1, 1, 5, 4, 1.0)}); check(oneToOne(DO, 5, 5), EMPTY); } @Test public void oneToOneWDO() throws Exception { // Nodes // | 1 | 2 | 3 | 4 | 5 | // |-----------|---------|-----------|--------------------|----------------| // | * | (1,3,2) | (1,3) | (1,3,5,4), (1,5,4) | (1,5), (1,3,5) | // | (2,3,5,1) | * | (2,3) | (2,3,5,4) | (2,3,5) | // | (3,5,1) | (3,2) | * | (3,5,4) | (3,5) | // | (4,5,1) | (4,2) | (4,2,3) | * | (4,5) | // | (5,1) | (5,4,2) | (5,4,2,3) | (5,4) | * | // // Edges // | 1 | 2 | 3 | 4 | 5 | // |----------|-------|---------|------------------|--------------| // | * | (5,4) | (5) | (5,7,9), (-10,9) | (5,7), (-10) | // | (3,7,10) | * | (3) | (3,7,9) | (3,7) | // | (7,10) | (4) | * | (7,9) | (7) | // | (8,10) | (2) | (2,3) | * | (8) | // | (10) | (9,2) | (9,2,3) | (9) | * | // // SELECT * FROM ST_ShortestPath('CORMEN_EDGES_ALL', // 'directed - edge_orientation', 'weight', i, j) check(oneToOne(DO, W, 1, 1), EMPTY); check(oneToOne(DO, W, 1, 2), new PathEdge[]{ new PathEdge("LINESTRING (1 0, 1.25 1, 1 2)", 4, 1, 1, 3, 2, 3.0), new PathEdge("LINESTRING (0 1, 1 0)", 5, 1, 2, 1, 3, 5.0)}); check(oneToOne(DO, W, 1, 3), new PathEdge[]{ new PathEdge("LINESTRING (0 1, 1 0)", 5, 1, 1, 1, 3, 5.0)}); final ResultSet rs14 = oneToOne(DO, W, 1, 4); try { check(rs14, new PathEdge[]{ new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 1, 1, 5, 4, 6.0), new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 2, 3, 5, 2.0), new PathEdge("LINESTRING (0 1, 1 0)", 5, 1, 3, 1, 3, 5.0), new PathEdge("LINESTRING (2 0, 0 1)", -10, 2, 2, 1, 5, 7.0)}); } catch (AssertionError e) { rs14.beforeFirst(); check(rs14, new PathEdge[]{ new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 1, 1, 5, 4, 6.0), new PathEdge("LINESTRING (2 0, 0 1)", -10, 1, 2, 1, 5, 7.0), new PathEdge("LINESTRING (1 0, 2 0)", 7, 2, 2, 3, 5, 2.0), new PathEdge("LINESTRING (0 1, 1 0)", 5, 2, 3, 1, 3, 5.0)}); } rs14.close(); final ResultSet rs15 = oneToOne(DO, W, 1, 5); try { check(rs15, new PathEdge[]{ new PathEdge("LINESTRING (2 0, 0 1)", -10, 1, 1, 1, 5, 7.0), new PathEdge("LINESTRING (1 0, 2 0)", 7, 2, 1, 3, 5, 2.0), new PathEdge("LINESTRING (0 1, 1 0)", 5, 2, 2, 1, 3, 5.0)}); } catch (AssertionError e) { rs15.beforeFirst(); check(rs15, new PathEdge[]{ new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 1, 3, 5, 2.0), new PathEdge("LINESTRING (0 1, 1 0)", 5, 1, 2, 1, 3, 5.0), new PathEdge("LINESTRING (2 0, 0 1)", -10, 2, 1, 1, 5, 7.0)}); } rs15.close(); check(oneToOne(DO, W, 2, 1), new PathEdge[]{ new PathEdge("LINESTRING (2 0, 0 1)", 10, 1, 1, 5, 1, 7.0), new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 2, 3, 5, 2.0), new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 3, 2, 3, 2.0)}); check(oneToOne(DO, W, 2, 2), EMPTY); check(oneToOne(DO, W, 2, 3), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 1, 2, 3, 2.0)}); check(oneToOne(DO, W, 2, 4), new PathEdge[]{ new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 1, 1, 5, 4, 6.0), new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 2, 3, 5, 2.0), new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 3, 2, 3, 2.0)}); check(oneToOne(DO, W, 2, 5), new PathEdge[]{ new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 1, 3, 5, 2.0), new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 2, 2, 3, 2.0)}); check(oneToOne(DO, W, 3, 1), new PathEdge[]{ new PathEdge("LINESTRING (2 0, 0 1)", 10, 1, 1, 5, 1, 7.0), new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 2, 3, 5, 2.0)}); check(oneToOne(DO, W, 3, 2), new PathEdge[]{ new PathEdge("LINESTRING (1 0, 1.25 1, 1 2)", 4, 1, 1, 3, 2, 3.0)}); check(oneToOne(DO, W, 3, 3), EMPTY); check(oneToOne(DO, W, 3, 4), new PathEdge[]{ new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 1, 1, 5, 4, 6.0), new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 2, 3, 5, 2.0)}); check(oneToOne(DO, W, 3, 5), new PathEdge[]{ new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 1, 3, 5, 2.0)}); check(oneToOne(DO, W, 4, 1), new PathEdge[]{ new PathEdge("LINESTRING (2 0, 0 1)", 10, 1, 1, 5, 1, 7.0), new PathEdge("LINESTRING (2 2, 1.75 1, 2 0)", 8, 1, 2, 4, 5, 4.0)}); check(oneToOne(DO, W, 4, 2), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 2 2)", 2, 1, 1, 4, 2, 1.0)}); check(oneToOne(DO, W, 4, 3), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 1, 2, 3, 2.0), new PathEdge("LINESTRING (1 2, 2 2)", 2, 1, 2, 4, 2, 1.0)}); check(oneToOne(DO, W, 4, 4), EMPTY); check(oneToOne(DO, W, 4, 5), new PathEdge[]{ new PathEdge("LINESTRING (2 2, 1.75 1, 2 0)", 8, 1, 1, 4, 5, 4.0)}); check(oneToOne(DO, W, 5, 1), new PathEdge[]{ new PathEdge("LINESTRING (2 0, 0 1)", 10, 1, 1, 5, 1, 7.0)}); check(oneToOne(DO, W, 5, 2), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 2 2)", 2, 1, 1, 4, 2, 1.0), new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 1, 2, 5, 4, 6.0)}); check(oneToOne(DO, W, 5, 4), new PathEdge[]{ new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 1, 1, 5, 4, 6.0)}); check(oneToOne(DO, W, 5, 3), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 1, 2, 3, 2.0), new PathEdge("LINESTRING (1 2, 2 2)", 2, 1, 2, 4, 2, 1.0), new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 1, 3, 5, 4, 6.0)}); check(oneToOne(DO, W, 5, 5), EMPTY); } @Test public void oneToOneRO() throws Exception { // Nodes // | 1 | 2 | 3 | 4 | 5 | // |------------------|-----------|---------|---------|------------------| // | * | (1,5,3,2) | (1,5,3) | (1,5,4) | (1,5) | // | (2,1) | * | (2,3) | (2,4) | (2,1,5), (2,4,5) | // | (3,1) | (3,2) | * | (3,2,4) | (3,1,5) | // | (4,3,1), (4,5,1) | (4,3,2) | (4,3) | * | (4,5) | // | (5,1) | (5,3,2) | (5,3) | (5,4) | * | // // Edges // | 1 | 2 | 3 | 4 | 5 | // |----------------|----------|--------|--------|---------------| // | * | (10,7,3) | (10,7) | (10,8) | (10) | // | (1) | * | (4) | (2) | (1,10), (2,9) | // | (5) | (3) | * | (3,2) | (5,10) | // | (6,5), (9,-10) | (6,3) | (6) | * | (9) | // | (-10) | (7,3) | (7) | (8) | * | // // SELECT * FROM ST_ShortestPath('CORMEN_EDGES_ALL', // 'reversed - edge_orientation', i, j) check(oneToOne(RO, 1, 1), EMPTY); check(oneToOne(RO, 1, 2), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 1, 3, 2, 1.0), new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 2, 5, 3, 1.0), new PathEdge("LINESTRING (2 0, 0 1)", 10, 1, 3, 1, 5, 1.0)}); check(oneToOne(RO, 1, 3), new PathEdge[]{ new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 1, 5, 3, 1.0), new PathEdge("LINESTRING (2 0, 0 1)", 10, 1, 2, 1, 5, 1.0)}); check(oneToOne(RO, 1, 4), new PathEdge[]{ new PathEdge("LINESTRING (2 2, 1.75 1, 2 0)", 8, 1, 1, 5, 4, 1.0), new PathEdge("LINESTRING (2 0, 0 1)", 10, 1, 2, 1, 5, 1.0)}); check(oneToOne(RO, 1, 5), new PathEdge[]{ new PathEdge("LINESTRING (2 0, 0 1)", 10, 1, 1, 1, 5, 1.0)}); check(oneToOne(RO, 2, 1), new PathEdge[]{ new PathEdge("LINESTRING (0 1, 1 2)", 1, 1, 1, 2, 1, 1.0)}); check(oneToOne(RO, 2, 2), EMPTY); check(oneToOne(RO, 2, 3), new PathEdge[]{ new PathEdge("LINESTRING (1 0, 1.25 1, 1 2)", 4, 1, 1, 2, 3, 1.0)}); check(oneToOne(RO, 2, 4), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 2 2)", 2, 1, 1, 2, 4, 1.0)}); final ResultSet rs25 = oneToOne(RO, 2, 5); try { check(rs25, new PathEdge[]{ new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 1, 1, 4, 5, 1.0), new PathEdge("LINESTRING (1 2, 2 2)", 2, 1, 2, 2, 4, 1.0), new PathEdge("LINESTRING (2 0, 0 1)", 10, 2, 1, 1, 5, 1.0), new PathEdge("LINESTRING (0 1, 1 2)", 1, 2, 2, 2, 1, 1.0)}); } catch (AssertionError e) { rs25.beforeFirst(); check(rs25, new PathEdge[]{ new PathEdge("LINESTRING (2 0, 0 1)", 10, 1, 1, 1, 5, 1.0), new PathEdge("LINESTRING (0 1, 1 2)", 1, 1, 2, 2, 1, 1.0), new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 2, 1, 4, 5, 1.0), new PathEdge("LINESTRING (1 2, 2 2)", 2, 2, 2, 2, 4, 1.0)}); } rs25.close(); check(oneToOne(RO, 3, 1), new PathEdge[]{ new PathEdge("LINESTRING (0 1, 1 0)", 5, 1, 1, 3, 1, 1.0)}); check(oneToOne(RO, 3, 2), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 1, 3, 2, 1.0)}); check(oneToOne(RO, 3, 3), EMPTY); check(oneToOne(RO, 3, 4), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 2 2)", 2, 1, 1, 2, 4, 1.0), new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 2, 3, 2, 1.0)}); check(oneToOne(RO, 3, 5), new PathEdge[]{ new PathEdge("LINESTRING (2 0, 0 1)", 10, 1, 1, 1, 5, 1.0), new PathEdge("LINESTRING (0 1, 1 0)", 5, 1, 2, 3, 1, 1.0)}); final ResultSet rs41 = oneToOne(RO, 4, 1); try { check(rs41, new PathEdge[]{ new PathEdge("LINESTRING (2 0, 0 1)", -10, 1, 1, 5, 1, 1.0), new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 1, 2, 4, 5, 1.0), new PathEdge("LINESTRING (0 1, 1 0)", 5, 2, 1, 3, 1, 1.0), new PathEdge("LINESTRING (1 0, 2 2)", 6, 2, 2, 4, 3, 1.0)}); } catch (AssertionError e) { rs41.beforeFirst(); check(rs41, new PathEdge[]{ new PathEdge("LINESTRING (0 1, 1 0)", 5, 1, 1, 3, 1, 1.0), new PathEdge("LINESTRING (1 0, 2 2)", 6, 1, 2, 4, 3, 1.0), new PathEdge("LINESTRING (2 0, 0 1)", -10, 2, 1, 5, 1, 1.0), new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 2, 2, 4, 5, 1.0)}); } rs41.close(); check(oneToOne(RO, 4, 2), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 1, 3, 2, 1.0), new PathEdge("LINESTRING (1 0, 2 2)", 6, 1, 2, 4, 3, 1.0)}); check(oneToOne(RO, 4, 3), new PathEdge[]{ new PathEdge("LINESTRING (1 0, 2 2)", 6, 1, 1, 4, 3, 1.0)}); check(oneToOne(RO, 4, 4), EMPTY); check(oneToOne(RO, 4, 5), new PathEdge[]{ new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 1, 1, 4, 5, 1.0)}); check(oneToOne(RO, 5, 1), new PathEdge[]{ new PathEdge("LINESTRING (2 0, 0 1)", -10, 1, 1, 5, 1, 1.0)}); check(oneToOne(RO, 5, 2), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 1, 3, 2, 1.0), new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 2, 5, 3, 1.0)}); check(oneToOne(RO, 5, 3), new PathEdge[]{ new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 1, 5, 3, 1.0)}); check(oneToOne(RO, 5, 4), new PathEdge[]{ new PathEdge("LINESTRING (2 2, 1.75 1, 2 0)", 8, 1, 1, 5, 4, 1.0)}); check(oneToOne(RO, 5, 5), EMPTY); } @Test public void oneToOneWRO() throws Exception { // Nodes // | 1 | 2 | 3 | 4 | 5 | // |--------------------|-----------|---------|---------|-----------| // | * | (1,5,3,2) | (1,5,3) | (1,5,4) | (1,5) | // | (2,3,1) | * | (2,3) | (2,4) | (2,4,5) | // | (3,1) | (3,2) | * | (3,2,4) | (3,2,4,5) | // | (4,5,1), (4,5,3,1) | (4,5,3,2) | (4,5,3) | * | (4,5) | // | (5,1), (5,3,1) | (5,3,2) | (5,3) | (5,4) | * | // // Edges // | 1 | 2 | 3 | 4 | 5 | // |------------------|----------|--------|--------|---------| // | * | (10,7,3) | (10,7) | (10,8) | (10) | // | (4,5) | * | (4) | (2) | (2,9) | // | (5) | (3) | * | (3,2) | (3,2,9) | // | (9,-10), (9,7,5) | (9,7,3) | (9,7) | * | (9) | // | (-10), (7,5) | (7,3) | (7) | (8) | * | // // SELECT * FROM ST_ShortestPath('CORMEN_EDGES_ALL', // 'reversed - edge_orientation', 'weight', i, j) check(oneToOne(RO, W, 1, 1), EMPTY); check(oneToOne(RO, W, 1, 2), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 1, 3, 2, 2.0), new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 2, 5, 3, 2.0), new PathEdge("LINESTRING (2 0, 0 1)", 10, 1, 3, 1, 5, 7.0)}); check(oneToOne(RO, W, 1, 3), new PathEdge[]{ new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 1, 5, 3, 2.0), new PathEdge("LINESTRING (2 0, 0 1)", 10, 1, 2, 1, 5, 7.0)}); check(oneToOne(RO, W, 1, 4), new PathEdge[]{ new PathEdge("LINESTRING (2 2, 1.75 1, 2 0)", 8, 1, 1, 5, 4, 4.0), new PathEdge("LINESTRING (2 0, 0 1)", 10, 1, 2, 1, 5, 7.0)}); check(oneToOne(RO, W, 1, 5), new PathEdge[]{ new PathEdge("LINESTRING (2 0, 0 1)", 10, 1, 1, 1, 5, 7.0)}); check(oneToOne(RO, W, 2, 1), new PathEdge[]{ new PathEdge("LINESTRING (0 1, 1 0)", 5, 1, 1, 3, 1, 5.0), new PathEdge("LINESTRING (1 0, 1.25 1, 1 2)", 4, 1, 2, 2, 3, 3.0)}); check(oneToOne(RO, W, 2, 2), EMPTY); check(oneToOne(RO, W, 2, 3), new PathEdge[]{ new PathEdge("LINESTRING (1 0, 1.25 1, 1 2)", 4, 1, 1, 2, 3, 3.0)}); check(oneToOne(RO, W, 2, 4), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 2 2)", 2, 1, 1, 2, 4, 1.0)}); check(oneToOne(RO, W, 2, 5), new PathEdge[]{ new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 1, 1, 4, 5, 6.0), new PathEdge("LINESTRING (1 2, 2 2)", 2, 1, 2, 2, 4, 1.0)}); check(oneToOne(RO, W, 3, 1), new PathEdge[]{ new PathEdge("LINESTRING (0 1, 1 0)", 5, 1, 1, 3, 1, 5.0)}); check(oneToOne(RO, W, 3, 2), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 1, 3, 2, 2.0)}); check(oneToOne(RO, W, 3, 3), EMPTY); check(oneToOne(RO, W, 3, 4), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 2 2)", 2, 1, 1, 2, 4, 1.0), new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 2, 3, 2, 2.0)}); check(oneToOne(RO, W, 3, 5), new PathEdge[]{ new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 1, 1, 4, 5, 6.0), new PathEdge("LINESTRING (1 2, 2 2)", 2, 1, 2, 2, 4, 1.0), new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 3, 3, 2, 2.0)}); final ResultSet rs41 = oneToOne(RO, W, 4, 1); try { check(rs41, new PathEdge[]{ new PathEdge("LINESTRING (0 1, 1 0)", 5, 1, 1, 3, 1, 5.0), new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 2, 5, 3, 2.0), new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 1, 3, 4, 5, 6.0), new PathEdge("LINESTRING (2 0, 0 1)", -10, 2, 1, 5, 1, 7.0), new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 2, 2, 4, 5, 6.0)}); } catch (AssertionError e) { rs41.beforeFirst(); check(rs41, new PathEdge[]{ new PathEdge("LINESTRING (2 0, 0 1)", -10, 1, 1, 5, 1, 7.0), new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 1, 2, 4, 5, 6.0), new PathEdge("LINESTRING (0 1, 1 0)", 5, 2, 1, 3, 1, 5.0), new PathEdge("LINESTRING (1 0, 2 0)", 7, 2, 2, 5, 3, 2.0), new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 2, 3, 4, 5, 6.0)}); } rs41.close(); check(oneToOne(RO, W, 4, 2), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 1, 3, 2, 2.0), new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 2, 5, 3, 2.0), new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 1, 3, 4, 5, 6.0)}); check(oneToOne(RO, W, 4, 3), new PathEdge[]{ new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 1, 5, 3, 2.0), new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 1, 2, 4, 5, 6.0)}); check(oneToOne(RO, W, 4, 4), EMPTY); check(oneToOne(RO, W, 4, 5), new PathEdge[]{ new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 1, 1, 4, 5, 6.0)}); final ResultSet rs51 = oneToOne(RO, W, 5, 1); try { check(rs51, new PathEdge[]{ new PathEdge("LINESTRING (2 0, 0 1)", -10, 1, 1, 5, 1, 7.0), new PathEdge("LINESTRING (0 1, 1 0)", 5, 2, 1, 3, 1, 5.0), new PathEdge("LINESTRING (1 0, 2 0)", 7, 2, 2, 5, 3, 2.0)}); } catch (AssertionError e) { rs51.beforeFirst(); check(rs51, new PathEdge[]{ new PathEdge("LINESTRING (0 1, 1 0)", 5, 1, 1, 3, 1, 5.0), new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 2, 5, 3, 2.0), new PathEdge("LINESTRING (2 0, 0 1)", -10, 2, 1, 5, 1, 7.0)}); } rs51.close(); check(oneToOne(RO, W, 5, 2), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 1, 3, 2, 2.0), new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 2, 5, 3, 2.0)}); check(oneToOne(RO, W, 5, 3), new PathEdge[]{ new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 1, 5, 3, 2.0)}); check(oneToOne(RO, W, 5, 4), new PathEdge[]{ new PathEdge("LINESTRING (2 2, 1.75 1, 2 0)", 8, 1, 1, 5, 4, 4.0)}); check(oneToOne(RO, W, 5, 5), EMPTY); } @Test public void oneToOneU() throws Exception { // Nodes // | 1 | 2 | // |------------------------------------|---------------------------------------------| // | * | (1,2) | // | (2,1) | * | // | (3,1) | (3,2) | // | (4,2,1), (4,3,1), (4,5,1), (4,5,1) | (4,2) | // | (5,1) | (5,1,2), (5,3,2), (5,3,2), (5,4,2), (5,4,2) | // // | 3 | 4 | 5 | // |--------------|------------------------------------|---------------------------------------------| // | (1,3) | (1,2,4), (1,3,4), (1,5,4), (1,5,4) | (1,5) | // | (2,3), (2,3) | (2,4) | (2,1,5), (2,3,5), (2,3,5), (2,4,5), (2,4,5) | // | * | (3,4) | (3,5) | // | (4,3) | * | (4,5), (4,5) | // | (5,3) | (5,4), (5,4) | * | // // Edges // | 1 | 2 | // |------------------------------|------------------------------------| // | * | (1) | // | (1) | * | // | (5) | (3), (4) | // | (2,1), (6,5), (8,10), (9,10) | (2) | // | (10) | (10,1), (7,3), (7,4), (8,2), (9,2) | // // | 3 | 4 | 5 | // |----------|------------------------------|------------------------------------| // | (5) | (1,2), (5,6), (10,8), (10,9) | (10) | // | (3), (4) | (2) | (1,10), (3,7), (4,7), (2,8), (2,9) | // | * | (6) | (7) | // | (6) | * | (8), (9) | // | (7) | (8), (9) | * | // // SELECT * FROM ST_ShortestPath('CORMEN_EDGES_ALL', // 'undirected', i, j) check(oneToOne(U, 1, 1), EMPTY); check(oneToOne(U, 1, 2), new PathEdge[]{ new PathEdge("LINESTRING (0 1, 1 2)", 1, 1, 1, 1, 2, 1.0), }); check(oneToOne(U, 1, 3), new PathEdge[]{ new PathEdge("LINESTRING (0 1, 1 0)", 5, 1, 1, 1, 3, 1.0)}); // // Note: This test has several possible (4!) numberings of the shortest paths. // // We run it until the following numbering is given. // check(oneToOne(U, st, 1, 4), new PathEdge[]{ // new PathEdge("LINESTRING (2 2, 1.75 1, 2 0)", 8, 1, 1, 5, 4, 1.0), // new PathEdge("LINESTRING (2 0, 0 1)", 10, 1, 2, 1, 5, 1.0), // new PathEdge("LINESTRING (1 0, 2 2)", 6, 2, 1, 3, 4, 1.0), // new PathEdge("LINESTRING (0 1, 1 0)", 5, 2, 2, 1, 3, 1.0), // new PathEdge("LINESTRING (1 2, 2 2)", 2, 3, 1, 2, 4, 1.0), // new PathEdge("LINESTRING (0 1, 1 2)", 1, 3, 2, 1, 2, 1.0), // new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 4, 1, 5, 4, 1.0), // new PathEdge("LINESTRING (2 0, 0 1)", 10, 4, 2, 1, 5, 1.0) // }); check(oneToOne(U, 1, 5), new PathEdge[]{ new PathEdge("LINESTRING (2 0, 0 1)", 10, 1, 1, 1, 5, 1.0)}); check(oneToOne(U, 2, 1), new PathEdge[]{ new PathEdge("LINESTRING (0 1, 1 2)", 1, 1, 1, 2, 1, 1.0)}); check(oneToOne(U, 2, 2), EMPTY); ResultSet rs23 = oneToOne(U, 2, 3); try { check(rs23, new PathEdge[]{ new PathEdge("LINESTRING (1 0, 1.25 1, 1 2)", 4, 1, 1, 2, 3, 1.0), new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 2, 1, 2, 3, 1.0)}); } catch (AssertionError e) { rs23.beforeFirst(); check(rs23, new PathEdge[]{ new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 1, 2, 3, 1.0), new PathEdge("LINESTRING (1 0, 1.25 1, 1 2)", 4, 2, 1, 2, 3, 1.0)}); } rs23.close(); check(oneToOne(U, 2, 4), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 2 2)", 2, 1, 1, 2, 4, 1.0)}); // Note: This test has several possible (5!) numberings of the shortest paths. // check(oneToOne(U, st, 2, 5), new PathEdge[]{ // new PathEdge("LINESTRING (2 0, 0 1)", 10, 1, 1, 1, 5, 1.0), // new PathEdge("LINESTRING (0 1, 1 2)", 1, 1, 2, 2, 1, 1.0), // new PathEdge("LINESTRING (1 0, 2 0)", 7, 2, 1, 3, 5, 1.0), // new PathEdge("LINESTRING (1 0, 1.25 1, 1 2)", 4, 2, 2, 2, 3, 1.0), // new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 3, 2, 2, 3, 1.0), // new PathEdge("LINESTRING (2 2, 1.75 1, 2 0)", 8, 4, 1, 4, 5, 1.0), // new PathEdge("LINESTRING (1 2, 2 2)", 2, 4, 2, 2, 4, 1.0), // new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 5, 1, 4, 5, 1.0), // new PathEdge("LINESTRING (1 2, 2 2)", 2, 5, 2, 2, 4, 1.0)}); check(oneToOne(U, 3, 1), new PathEdge[]{ new PathEdge("LINESTRING (0 1, 1 0)", 5, 1, 1, 3, 1, 1.0)}); ResultSet rs32 = oneToOne(U, 3, 2); try { check(rs32, new PathEdge[]{ new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 1, 3, 2, 1.0), new PathEdge("LINESTRING (1 0, 1.25 1, 1 2)", 4, 2, 1, 3, 2, 1.0)}); } catch (AssertionError e) { rs32.beforeFirst(); check(rs32, new PathEdge[]{ new PathEdge("LINESTRING (1 0, 1.25 1, 1 2)", 4, 1, 1, 3, 2, 1.0), new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 2, 1, 3, 2, 1.0)}); } rs32.close(); check(oneToOne(U, 3, 3), EMPTY); check(oneToOne(U, 3, 4), new PathEdge[]{ new PathEdge("LINESTRING (1 0, 2 2)", 6, 1, 1, 3, 4, 1.0)}); check(oneToOne(U, 3, 5), new PathEdge[]{ new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 1, 3, 5, 1.0)}); // // Note: This test has several possible (4!) numberings of the shortest paths. // check(oneToOne(U, st, 4, 1), new PathEdge[]{ // new PathEdge("LINESTRING (0 1, 1 2)", 1, 1, 1, 2, 1, 1.0), // new PathEdge("LINESTRING (1 2, 2 2)", 2, 1, 2, 4, 2, 1.0), // new PathEdge("LINESTRING (0 1, 1 0)", 5, 2, 1, 3, 1, 1.0), // new PathEdge("LINESTRING (1 0, 2 2)", 6, 2, 2, 4, 3, 1.0), // new PathEdge("LINESTRING (2 0, 0 1)", 10, 3, 1, 5, 1, 1.0), // new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 3, 2, 4, 5, 1.0), // new PathEdge("LINESTRING (2 2, 1.75 1, 2 0)", 8, 4, 2, 4, 5, 1.0)}); check(oneToOne(U, 4, 2), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 2 2)", 2, 1, 1, 4, 2, 1.0)}); check(oneToOne(U, 4, 3), new PathEdge[]{ new PathEdge("LINESTRING (1 0, 2 2)", 6, 1, 1, 4, 3, 1.0)}); check(oneToOne(U, 4, 4), EMPTY); ResultSet rs45 = oneToOne(U, 4, 5); try { check(rs45, new PathEdge[]{ new PathEdge("LINESTRING (2 2, 1.75 1, 2 0)", 8, 1, 1, 4, 5, 1.0), new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 2, 1, 4, 5, 1.0)}); } catch (AssertionError e) { rs45.beforeFirst(); check(rs45, new PathEdge[]{ new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 1, 1, 4, 5, 1.0), new PathEdge("LINESTRING (2 2, 1.75 1, 2 0)", 8, 2, 1, 4, 5, 1.0)}); } rs45.close(); check(oneToOne(U, 5, 1), new PathEdge[]{ new PathEdge("LINESTRING (2 0, 0 1)", 10, 1, 1, 5, 1, 1.0)}); // // Note: This test has several possible (5!) numberings of the shortest paths. // check(oneToOne(U, st, 5, 2), new PathEdge[]{ // new PathEdge("LINESTRING (0 1, 1 2)", 1, 1, 1, 1, 2, 1.0), // new PathEdge("LINESTRING (2 0, 0 1)", 10, 1, 2, 5, 1, 1.0), // new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 2, 1, 3, 2, 1.0), // new PathEdge("LINESTRING (1 0, 2 0)", 7, 2, 2, 5, 3, 1.0), // new PathEdge("LINESTRING (1 2, 2 2)", 2, 3, 1, 4, 2, 1.0), // new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 3, 2, 5, 4, 1.0), // new PathEdge("LINESTRING (2 2, 1.75 1, 2 0)", 8, 4, 2, 5, 4, 1.0), // new PathEdge("LINESTRING (1 0, 1.25 1, 1 2)", 4, 5, 1, 3, 2, 1.0), // new PathEdge("LINESTRING (1 0, 2 0)", 7, 5, 2, 5, 3, 1.0)}); check(oneToOne(U, 5, 3), new PathEdge[]{ new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 1, 5, 3, 1.0)}); ResultSet rs54 = oneToOne(U, 5, 4); try { check(rs54, new PathEdge[]{ new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 1, 1, 5, 4, 1.0), new PathEdge("LINESTRING (2 2, 1.75 1, 2 0)", 8, 2, 1, 5, 4, 1.0)}); } catch (AssertionError e) { rs54.beforeFirst(); check(rs54, new PathEdge[]{ new PathEdge("LINESTRING (2 2, 1.75 1, 2 0)", 8, 1, 1, 5, 4, 1.0), new PathEdge("LINESTRING (2 0, 2.25 1, 2 2)", 9, 2, 1, 5, 4, 1.0)}); } rs54.close(); check(oneToOne(U, 5, 5), EMPTY); } @Test public void oneToOneWU() throws Exception { // Nodes // | 1 | 2 | 3 | 4 | 5 | // |----------------|---------|---------|-----------|----------------| // | * | (1,3,2) | (1,3) | (1,3,2,4) | (1,5), (1,3,5) | // | (2,3,1) | * | (2,3) | (2,4) | (2,3,5) | // | (3,1) | (3,2) | * | (3,2,4) | (3,5) | // | (4,2,3,1) | (4,2) | (4,2,3) | * | (4,5) | // | (5,1), (5,3,1) | (5,3,2) | (5,3) | (5,4) | * | // // Edges // | 1 | 2 | 3 | 4 | 5 | // |-------------|-------|-------|---------|-------------| // | * | (5,3) | (5) | (5,3,2) | (10), (5,7) | // | (3,5) | * | (3) | (2) | (3,7) | // | (5) | (3) | * | (3,2) | (7) | // | (2,3,5) | (2) | (2,3) | * | (8) | // | (10), (7,5) | (7,3) | (7) | (8) | * | // // SELECT * FROM ST_ShortestPath('CORMEN_EDGES_ALL', // 'undirected', 'weight', i, j) check(oneToOne(U, W, 1, 1), EMPTY); check(oneToOne(U, W, 1, 2), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 1, 3, 2, 2.0), new PathEdge("LINESTRING (0 1, 1 0)", 5, 1, 2, 1, 3, 5.0)}); check(oneToOne(U, W, 1, 3), new PathEdge[]{ new PathEdge("LINESTRING (0 1, 1 0)", 5, 1, 1, 1, 3, 5.0)}); check(oneToOne(U, W, 1, 4), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 2 2)", 2, 1, 1, 2, 4, 1.0), new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 2, 3, 2, 2.0), new PathEdge("LINESTRING (0 1, 1 0)", 5, 1, 3, 1, 3, 5.0)}); ResultSet rs15 = oneToOne(U, W, 1, 5); try { check(rs15, new PathEdge[]{ new PathEdge("LINESTRING (2 0, 0 1)", 10, 1, 1, 1, 5, 7.0), new PathEdge("LINESTRING (1 0, 2 0)", 7, 2, 1, 3, 5, 2.0), new PathEdge("LINESTRING (0 1, 1 0)", 5, 2, 2, 1, 3, 5.0)}); } catch (AssertionError e) { rs15.beforeFirst(); check(rs15, new PathEdge[]{ new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 1, 3, 5, 2.0), new PathEdge("LINESTRING (0 1, 1 0)", 5, 1, 2, 1, 3, 5.0), new PathEdge("LINESTRING (2 0, 0 1)", 10, 2, 1, 1, 5, 7.0)}); } rs15.close(); check(oneToOne(U, W, 2, 1), new PathEdge[]{ new PathEdge("LINESTRING (0 1, 1 0)", 5, 1, 1, 3, 1, 5.0), new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 2, 2, 3, 2.0)}); check(oneToOne(U, W, 2, 2), EMPTY); check(oneToOne(U, W, 2, 3), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 1, 2, 3, 2.0)}); check(oneToOne(U, W, 2, 4), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 2 2)", 2, 1, 1, 2, 4, 1.0)}); check(oneToOne(U, W, 2, 5), new PathEdge[]{ new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 1, 3, 5, 2.0), new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 2, 2, 3, 2.0)}); check(oneToOne(U, W, 3, 1), new PathEdge[]{ new PathEdge("LINESTRING (0 1, 1 0)", 5, 1, 1, 3, 1, 5.0)}); check(oneToOne(U, W, 3, 2), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 1, 3, 2, 2.0)}); check(oneToOne(U, W, 3, 3), EMPTY); check(oneToOne(U, W, 3, 4), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 2 2)", 2, 1, 1, 2, 4, 1.0), new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 2, 3, 2, 2.0)}); check(oneToOne(U, W, 3, 5), new PathEdge[]{ new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 1, 3, 5, 2.0)}); check(oneToOne(U, W, 4, 1), new PathEdge[]{ new PathEdge("LINESTRING (0 1, 1 0)", 5, 1, 1, 3, 1, 5.0), new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 2, 2, 3, 2.0), new PathEdge("LINESTRING (1 2, 2 2)", 2, 1, 3, 4, 2, 1.0)}); check(oneToOne(U, W, 4, 2), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 2 2)", 2, 1, 1, 4, 2, 1.0)}); check(oneToOne(U, W, 4, 3), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 1, 2, 3, 2.0), new PathEdge("LINESTRING (1 2, 2 2)", 2, 1, 2, 4, 2, 1.0)}); check(oneToOne(U, W, 4, 4), EMPTY); check(oneToOne(U, W, 4, 5), new PathEdge[]{ new PathEdge("LINESTRING (2 2, 1.75 1, 2 0)", 8, 1, 1, 4, 5, 4.0)}); ResultSet rs51 = oneToOne(U, W, 5, 1); try { check(rs51, new PathEdge[]{ new PathEdge("LINESTRING (0 1, 1 0)", 5, 1, 1, 3, 1, 5.0), new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 2, 5, 3, 2.0), new PathEdge("LINESTRING (2 0, 0 1)", 10, 2, 1, 5, 1, 7.0)}); } catch (AssertionError e) { rs51.beforeFirst(); check(rs51, new PathEdge[]{ new PathEdge("LINESTRING (2 0, 0 1)", 10, 1, 1, 5, 1, 7.0), new PathEdge("LINESTRING (0 1, 1 0)", 5, 2, 1, 3, 1, 5.0), new PathEdge("LINESTRING (1 0, 2 0)", 7, 2, 2, 5, 3, 2.0)}); } rs51.close(); check(oneToOne(U, W, 5, 2), new PathEdge[]{ new PathEdge("LINESTRING (1 2, 0.75 1, 1 0)", 3, 1, 1, 3, 2, 2.0), new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 2, 5, 3, 2.0)}); check(oneToOne(U, W, 5, 3), new PathEdge[]{ new PathEdge("LINESTRING (1 0, 2 0)", 7, 1, 1, 5, 3, 2.0)}); check(oneToOne(U, W, 5, 4), new PathEdge[]{ new PathEdge("LINESTRING (2 2, 1.75 1, 2 0)", 8, 1, 1, 5, 4, 4.0)}); check(oneToOne(U, W, 5, 5), EMPTY); } @Test(expected = IllegalArgumentException.class) public void testNonexistantSourceVertex() throws Throwable { try { // The graph does not contain vertex 6. check(oneToOne(U, W, 6, 1), null); } catch (JdbcSQLException e) { assertTrue(e.getMessage().contains("Source vertex not found")); throw e.getOriginalCause(); } } @Test(expected = IllegalArgumentException.class) public void testNonexistantDestinationVertex() throws Throwable { try { // The graph does not contain vertex 6. check(oneToOne(U, W, 1, 6), null); } catch (JdbcSQLException e) { assertTrue(e.getMessage().contains("Target vertex not found")); throw e.getOriginalCause(); } } @Test public void testUnreachableVertices() throws SQLException { // Vertices 3 and 6 are in different connected components. assertTrue(!oneToOne("COPY_EDGES_ALL", DO, W, 3, 6).next()); // 7 is reachable from 6. check(oneToOne("COPY_EDGES_ALL", DO, W, 6, 7), new PathEdge[]{ new PathEdge("LINESTRING (3 1, 4 2)", 11, 1, 1, 6, 7, 1.0)}); // But 6 is not reachable from 7 in a directed graph. assertTrue(!oneToOne("COPY_EDGES_ALL", DO, W, 7, 6).next()); // It is, however, in an undirected graph. check(oneToOne("COPY_EDGES_ALL", U, W, 7, 6), new PathEdge[]{ new PathEdge("LINESTRING (3 1, 4 2)", 11, 1, 1, 7, 6, 1.0)}); } private ResultSet oneToOne(String table, String orientation, String weight, int source, int destination) throws SQLException { return st.executeQuery( "SELECT * FROM ST_ShortestPath('" + table + "', " + orientation + ((weight != null) ? ", " + weight : "") + ", " + source + ", " + destination + ")"); } private ResultSet oneToOne(String orientation, String weight, int source, int destination) throws SQLException { return oneToOne("CORMEN_EDGES_ALL", orientation, weight, source, destination); } private ResultSet oneToOne(String orientation, int source, int destination) throws SQLException { return oneToOne(orientation, null, source, destination); } private void check(ResultSet rs, PathEdge[] pathEdges) throws SQLException { check(rs, pathEdges, true); } private void checkNoGeom(ResultSet rs, PathEdge[] pathEdges) throws SQLException { check(rs, pathEdges, false); } private void check(ResultSet rs, PathEdge[] pathEdges, boolean checkGeom) throws SQLException { for (int i = 0; i < pathEdges.length; i++) { assertTrue(rs.next()); PathEdge e = pathEdges[i]; if (checkGeom) { assertGeometryEquals(e.getGeom(), rs.getBytes(GraphConstants.THE_GEOM)); } assertEquals(e.getEdgeID(), rs.getInt(GraphConstants.EDGE_ID)); assertEquals(e.getPathID(), rs.getInt(GraphConstants.PATH_ID)); assertEquals(e.getPathedgeID(), rs.getInt(GraphConstants.PATH_EDGE_ID)); assertEquals(e.getSource(), rs.getInt(GraphConstants.SOURCE)); assertEquals(e.getDestination(), rs.getInt(GraphConstants.DESTINATION)); assertEquals(e.getWeight(), rs.getDouble(GraphConstants.WEIGHT), TOLERANCE); } assertFalse(rs.next()); rs.close(); } @Test public void testNoGeometryField() throws Throwable { // This test shows that if the input has no geometry column, // neither will the output. st.execute("DROP TABLE IF EXISTS NO_GEOM;" + "CREATE TABLE NO_GEOM AS " + "SELECT EDGE_ID, START_NODE, END_NODE, WEIGHT " + "FROM CORMEN_EDGES_ALL;"); final ResultSet resultSet = st.executeQuery("SELECT * FROM ST_ShortestPath(" + "'NO_GEOM', 'UNDIRECTED', 3, 4);"); checkNoGeom(resultSet, new PathEdge[]{ new PathEdge(6, 1, 1, 3, 4, 1.0)}); } @Test public void testNoGeometryFieldDifferentCCs() throws Throwable { // This test shows that if the input has no geometry column, // neither will the output. st.execute("DROP TABLE IF EXISTS NO_GEOM;" + "CREATE TABLE NO_GEOM AS " + "SELECT EDGE_ID, START_NODE, END_NODE, WEIGHT " + "FROM COPY_EDGES_ALL;"); final ResultSet resultSet = st.executeQuery("SELECT * FROM ST_ShortestPath(" + "'NO_GEOM', 'UNDIRECTED', 1, 8);"); assertTrue(!resultSet.next()); } private class PathEdge { private String geom; private int edgeID; private int pathID; private int pathedgeID; private int source; private int destination; private double weight; public PathEdge(int edgeID, int pathID, int pathedgeID, int source, int destination, double weight) { this(null, edgeID, pathID, pathedgeID, source, destination, weight); } public PathEdge(String geom, int edgeID, int pathID, int pathedgeID, int source, int destination, double weight) { this.geom = geom; this.edgeID = edgeID; this.pathID = pathID; this.pathedgeID = pathedgeID; this.source = source; this.destination = destination; this.weight = weight; } public String getGeom() { return geom; } public int getEdgeID() { return edgeID; } public int getPathID() { return pathID; } public int getPathedgeID() { return pathedgeID; } public int getSource() { return source; } public int getDestination() { return destination; } public double getWeight() { return weight; } } }