Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add two new functions ST_LineInterpolatePoint and ST_LineSubstring #1350

Merged
merged 2 commits into from
Jul 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@
+ Add ST_ConcaveHull function
+ Improve ST_Graph function to keep a list of columns for the edges
+ Upgrade H2 database from 2.1.214 to 2.2.220
+ Add ST_LineSubstring and ST_LineInterpolatePoint functions

Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@
import org.h2gis.functions.spatial.generalize.ST_PrecisionReducer;
import org.h2gis.functions.spatial.generalize.ST_Simplify;
import org.h2gis.functions.spatial.generalize.ST_SimplifyPreserveTopology;
import org.h2gis.functions.spatial.linear_referencing.ST_LineInterpolatePoint;
import org.h2gis.functions.spatial.linear_referencing.ST_LineSubstring;
import org.h2gis.functions.spatial.mesh.ST_ConstrainedDelaunay;
import org.h2gis.functions.spatial.mesh.ST_Delaunay;
import org.h2gis.functions.spatial.mesh.ST_Tessellate;
Expand Down Expand Up @@ -320,7 +322,9 @@ public static Function[] getBuiltInsFunctions() {
new ST_MemSize(),
new ST_Multi(),
new ST_AsEWKB(),
new ST_ConcaveHull()
new ST_ConcaveHull(),
new ST_LineSubstring(),
new ST_LineInterpolatePoint()
};
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/**
* H2GIS is a library that brings spatial support to the H2 Database Engine
* <a href="http://www.h2database.com">http://www.h2database.com</a>. H2GIS is developed by CNRS
* <a href="http://www.cnrs.fr/">http://www.cnrs.fr/</a>.
*
* 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: <a href="http://www.h2gis.org/">http://www.h2gis.org/</a>
* or contact directly: info_at_h2gis.org
*/
package org.h2gis.functions.spatial.linear_referencing;

import org.h2gis.api.DeterministicScalarFunction;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.geom.MultiLineString;
import org.locationtech.jts.linearref.LengthIndexedLine;

import java.sql.SQLException;
import java.util.ArrayList;

/**
* Returns a point interpolate along the input LineString or MultiLineString starting at the given fraction.
* @author Erwan Bocher, CNRS (2023)
*/
public class ST_LineInterpolatePoint extends DeterministicScalarFunction {

public ST_LineInterpolatePoint(){
addProperty(PROP_REMARKS, "Returns a point interpolate along the input LineString or MultiLineString starting at the given fraction.");
}

@Override
public String getJavaStaticMethod() {
return "execute";
}

/**
* Returns a point interpolate along the input LineString or MultiLineString starting at the given fractions.
* @param geometry the input lines
* @param start the start fraction between 0 and 1
* @return single or multiparts lines
* @throws SQLException
*/
public static Geometry execute(Geometry geometry, double start) throws SQLException {
if(geometry==null){
return null;
}
if ( start < 0 || start > 1 ){
throw new SQLException("Allowed between 0 and 1");
}

if(geometry.isEmpty()){
return geometry;
}

if(geometry instanceof LineString){
double length = geometry.getLength();
LengthIndexedLine ll = new LengthIndexedLine(geometry);
return geometry.getFactory().createPoint(ll.extractPoint(start*length));
} else if (geometry instanceof MultiLineString) {
int nb = geometry.getNumGeometries();
ArrayList<Coordinate> points = new ArrayList<>();
for (int i = 0; i < nb; i++) {
Geometry line = geometry.getGeometryN(i);
double length = line.getLength();
LengthIndexedLine ll = new LengthIndexedLine(geometry.getGeometryN(i));
points.add(ll.extractPoint(start*length));
}
return geometry.getFactory().createMultiPointFromCoords(points.toArray(new Coordinate[0]));
}
throw new SQLException("Only LineString or MultiLineString are supported");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/**
* H2GIS is a library that brings spatial support to the H2 Database Engine
* <a href="http://www.h2database.com">http://www.h2database.com</a>. H2GIS is developed by CNRS
* <a href="http://www.cnrs.fr/">http://www.cnrs.fr/</a>.
*
* 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: <a href="http://www.h2gis.org/">http://www.h2gis.org/</a>
* or contact directly: info_at_h2gis.org
*/

package org.h2gis.functions.spatial.linear_referencing;

import org.h2gis.api.DeterministicScalarFunction;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.geom.MultiLineString;
import org.locationtech.jts.linearref.LengthIndexedLine;

import java.sql.SQLException;
import java.util.ArrayList;

/**
* @author Erwan Bocher, CNRS (2023)
* Extract a section of the input line starting and ending at the given fractions.
*/
public class ST_LineSubstring extends DeterministicScalarFunction {


public ST_LineSubstring(){
addProperty(PROP_REMARKS, "Extract a section of the input LineString or MultiLineString starting and ending at the given fractions.");
}

@Override
public String getJavaStaticMethod() {
return "execute";
}

/**
* Extract a section of the input LineString or MultiLineString starting and ending at the given fractions.
* @param geometry the input lines
* @param start the start fraction between 0 and 1
* @param end the end fraction between 0 and 1
* @return single or multiparts lines
* @throws SQLException
*/
public static Geometry execute(Geometry geometry, double start, double end) throws SQLException {
if(geometry==null){
return null;
}
if ( start < 0 || start > 1 ){
throw new SQLException("Allowed between 0 and 1");
}

if ( end < 0 || end > 1 ){
throw new SQLException("Allowed between 0 and 1");
}

if(start> end){
throw new SQLException("Start fraction must be smaller than end fraction");
}
if(geometry.isEmpty()){
return geometry;
}

if(geometry instanceof LineString){
double length = geometry.getLength();
LengthIndexedLine ll = new LengthIndexedLine(geometry);
return ll.extractLine(start*length, end*length);
} else if (geometry instanceof MultiLineString) {
int nb = geometry.getNumGeometries();
ArrayList<LineString> lines = new ArrayList<>();
for (int i = 0; i < nb; i++) {
Geometry line = geometry.getGeometryN(i);
double length = line.getLength();
LengthIndexedLine ll = new LengthIndexedLine(geometry.getGeometryN(i));
lines.add((LineString) ll.extractLine(start*length, end*length));
}
return geometry.getFactory().createMultiLineString(lines.toArray(new LineString[0]));
}
throw new SQLException("Only LineString or MultiLineString are supported");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/**
* H2GIS is a library that brings spatial support to the H2 Database Engine
* <a href="http://www.h2database.com">http://www.h2database.com</a>. H2GIS is developed by CNRS
* <a href="http://www.cnrs.fr/">http://www.cnrs.fr/</a>.
*
* 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: <a href="http://www.h2gis.org/">http://www.h2gis.org/</a>
* or contact directly: info_at_h2gis.org
*/
package org.h2gis.functions.spatial.linear_referencing;

import org.h2gis.functions.factory.H2GISDBFactory;
import org.junit.jupiter.api.*;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import static org.h2gis.unitTest.GeometryAsserts.assertGeometryEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

/**
* @author Erwan Bocher, CNRS (2023)
*/
public class LinearReferencingTest {

private static Connection connection;
private Statement st;

@BeforeAll
public static void tearUp() throws Exception {
connection = H2GISDBFactory.createSpatialDataBase(LinearReferencingTest.class.getSimpleName());
}

@AfterAll
public static void tearDown() throws Exception {
connection.close();
}

@BeforeEach
public void setUpStatement() throws Exception {
st = connection.createStatement();
}

@AfterEach
public void tearDownStatement() throws Exception {
st.close();
}

@Test
public void test_ST_LineSubstring1() throws Exception {
ResultSet rs = st.executeQuery("SELECT ST_LineSubstring('LINESTRING(0 0, 10 0)'::GEOMETRY, 0, 0.5)");
assertTrue(rs.next());
assertGeometryEquals("LINESTRING(0 0, 5 0)", rs.getObject(1));
rs.close();
}

@Test
public void test_ST_LineSubstring2() throws Exception {
assertThrows(SQLException.class, () -> {
st.executeQuery("SELECT ST_LineSubstring('LINESTRING(0 0, 10 0)'::GEOMETRY, 1, 10)");
});
}

@Test
public void test_ST_LineSubstring3() throws Exception {
ResultSet rs = st.executeQuery("SELECT ST_LineSubstring('MULTILINESTRING((0 0, 10 0), (10 10, 10 20))'::GEOMETRY, 0, 0.5)");
assertTrue(rs.next());
assertGeometryEquals("MULTILINESTRING ((0 0, 5 0), (10 10, 10 15))", rs.getObject(1));
rs.close();
}

@Test
public void test_ST_LineSubstring4() throws Exception {
ResultSet rs = st.executeQuery("SELECT ST_LineSubstring('LINESTRINGZ(0 0 0, 10 0 10)'::GEOMETRY, 0, 0.5)");
assertTrue(rs.next());
assertGeometryEquals("LINESTRING Z (0 0 0, 5 0 5)", rs.getObject(1));
rs.close();
}

@Test
public void test_ST_LineInterpolatePoint1() throws Exception {
ResultSet rs = st.executeQuery("SELECT ST_LineInterpolatePoint('LINESTRING(0 0, 10 0)'::GEOMETRY, 0.5)");
assertTrue(rs.next());
assertGeometryEquals("POINT(5 0)", rs.getObject(1));
rs.close();
}

@Test
public void test_ST_LineInterpolatePoint2() throws Exception {
ResultSet rs = st.executeQuery("SELECT ST_LineInterpolatePoint('MULTILINESTRING((0 0, 10 0), (10 10, 10 20))'::GEOMETRY,0.5)");
assertTrue(rs.next());
assertGeometryEquals("MULTIPOINT ((5 0), (10 15))", rs.getObject(1));
rs.close();
}

@Test
public void test_ST_LineInterpolatePoint3() throws Exception {
ResultSet rs = st.executeQuery("SELECT ST_LineInterpolatePoint('LINESTRINGZ(0 0 0, 10 0 10)'::GEOMETRY, 0.5)");
assertTrue(rs.next());
assertGeometryEquals("POINT Z (5 0 5)", rs.getObject(1));
rs.close();
}

}