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

[SEDONA-132] Move some functions to a common module #647

Merged
merged 12 commits into from
Aug 16, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

sedona_jar_files () {
local subdir
for subdir in 'core' 'sql' 'viz'; do
for subdir in 'common' 'core' 'sql' 'viz'; do
local artifact_id="$(
mvn \
org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate \
Expand Down
2 changes: 1 addition & 1 deletion R/tests/testthat/helper-initialize.R
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ expect_geom_equal <- function(sc, lhs, rhs) {
testthat::expect_true(
invoke_static(
sc,
"org.apache.sedona.core.utils.GeomUtils",
"org.apache.sedona.common.utils.GeomUtils",
"equalsExactGeom",
lhs[[i]],
rhs[[i]]
Expand Down
9 changes: 9 additions & 0 deletions common/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/target/
/.settings/
/.classpath
/.project
/dependency-reduced-pom.xml
/doc/
/.idea/
*.iml
/latest/
55 changes: 55 additions & 0 deletions common/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<!--
~ Licensed to the Apache Software Foundation (ASF) under one
~ or more contributor license agreements. See the NOTICE file
~ distributed with this work for additional information
~ regarding copyright ownership. The ASF licenses this file
~ to you under the Apache License, Version 2.0 (the
~ "License"); you may not use this file except in compliance
~ with the License. You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
-->

<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>
<parent>
<groupId>org.apache.sedona</groupId>
<artifactId>sedona-parent</artifactId>
<version>1.2.1-incubating-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>sedona-common</artifactId>

<name>${project.groupId}:${project.artifactId}</name>
<description>A cluster computing system for processing large-scale spatial data: Common API. Apache Sedona is an effort undergoing incubation at The Apache Software Foundation (ASF), sponsored by the Apache Incubator. Incubation is required of all newly accepted projects until a further review indicates that the infrastructure, communications, and decision making process have stabilized in a manner consistent with other successful ASF projects. While incubation status is not necessarily a reflection of the completeness or stability of the code, it does indicate that the project has yet to be fully endorsed by the ASF.</description>
<url>http://sedona.apache.org/</url>
<packaging>jar</packaging>

<properties>
<maven.deploy.skip>false</maven.deploy.skip>
</properties>

<dependencies>
</dependencies>
<build>
<sourceDirectory>src/main/java</sourceDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

1 change: 1 addition & 0 deletions common/src/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.DS_Store
1 change: 1 addition & 0 deletions common/src/main/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.DS_Store
132 changes: 132 additions & 0 deletions common/src/main/java/org/apache/sedona/common/Functions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/**
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.sedona.common;

import java.util.Optional;
import org.apache.sedona.common.utils.GeomUtils;
import org.apache.sedona.common.utils.GeometryGeoHashEncoder;
import org.geotools.geometry.jts.JTS;
import org.geotools.referencing.CRS;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.LineString;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;



public class Functions {
public static Geometry buffer(Geometry geometry, double radius) {
return geometry.buffer(radius);
}

public static double distance(Geometry left, Geometry right) {
return left.distance(right);
}

public static double xMin(Geometry geometry) {
Coordinate[] points = geometry.getCoordinates();
double min = Double.MAX_VALUE;
for(int i=0; i < points.length; i++){
min = Math.min(points[i].getX(), min);
}
return min;
}

public static double xMax(Geometry geometry) {
Coordinate[] points = geometry.getCoordinates();
double max = Double.MIN_VALUE;
for (int i=0; i < points.length; i++) {
max = Math.max(points[i].getX(), max);
}
return max;
}

public static double yMin(Geometry geometry) {
Coordinate[] points = geometry.getCoordinates();
double min = Double.MAX_VALUE;
for(int i=0; i < points.length; i++){
min = Math.min(points[i].getY(), min);
}
return min;
}

public static double yMax(Geometry geometry) {
Coordinate[] points = geometry.getCoordinates();
double max = Double.MIN_VALUE;
for (int i=0; i < points.length; i++) {
max = Math.max(points[i].getY(), max);
}
return max;
}

public static Geometry transform(Geometry geometry, String sourceCRS, String targetCRS)
throws FactoryException, TransformException {
return transform(geometry, sourceCRS, targetCRS, false);
}

public static Geometry transform(Geometry geometry, String sourceCRS, String targetCRS, boolean lenient)
throws FactoryException, TransformException {
CoordinateReferenceSystem sourceCRScode = CRS.decode(sourceCRS);
CoordinateReferenceSystem targetCRScode = CRS.decode(targetCRS);
MathTransform transform = CRS.findMathTransform(sourceCRScode, targetCRScode, lenient);
return JTS.transform(geometry, transform);
}

public static Geometry flipCoordinates(Geometry geometry) {
GeomUtils.flipCoordinates(geometry);
return geometry;
}

public static String geohash(Geometry geometry, int precision) {
return GeometryGeoHashEncoder.calculate(geometry, precision);
}

public static Geometry pointOnSurface(Geometry geometry) {
return GeomUtils.getInteriorPoint(geometry);
}

public static Geometry reverse(Geometry geometry) {
return geometry.reverse();
}

public static Geometry pointN(Geometry geometry, int n) {
if(!(geometry instanceof LineString)) {
return null;
}
return GeomUtils.getNthPoint((LineString)geometry, n);
}

public static Geometry exteriorRing(Geometry geometry) {
return GeomUtils.getExteriorRing(geometry);
}

public static String asEWKT(Geometry geometry) {
return GeomUtils.getEWKT(geometry);
}

public static Geometry force2D(Geometry geometry) {
return GeomUtils.get2dGeom(geometry);
}

public static boolean isEmpty(Geometry geometry) {
return geometry.isEmpty();
}

public static Geometry buildArea(Geometry geometry) {
return GeomUtils.buildArea(geometry);
}
}
60 changes: 60 additions & 0 deletions common/src/main/java/org/apache/sedona/common/utils/BBox.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.sedona.common.utils;

import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.Polygon;

public class BBox {
double startLon;
double endLon;
double startLat;
double endLat;

static GeometryFactory geometryFactory = new GeometryFactory();

public BBox(double startLon, double endLon, double startLat, double endLat) {
this.startLon = startLon;
this.endLon = endLon;
this.startLat = startLat;
this.endLat = endLat;
}

public BBox(BBox other) {
this(other.startLon, other.endLon, other.startLat, other.endLat);
}

public Point getCentroid() {
double lon = this.startLon + ((this.startLon + this.endLon)/2);
double lat = this.startLat + ((this.startLat + this.endLat)/2);
return geometryFactory.createPoint(new Coordinate(lon, lat));
}

public Polygon toPolygon() {
return geometryFactory.createPolygon(new Coordinate[] {
new Coordinate(this.startLon, this.startLat),
new Coordinate(this.startLon, this.endLat),
new Coordinate(this.endLon, this.endLat),
new Coordinate(this.endLon, this.startLat),
new Coordinate(this.startLon, this.startLat)
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.sedona.core.utils;
package org.apache.sedona.common.utils;

import org.locationtech.jts.geom.*;
import org.locationtech.jts.geom.impl.CoordinateArraySequence;
Expand All @@ -27,8 +27,7 @@

import static org.locationtech.jts.geom.Coordinate.NULL_ORDINATE;

public class GeomUtils
{
public class GeomUtils {
public static String printGeom(Geometry geom) {
if(geom.getUserData()!=null) return geom.toText() + "\t" + geom.getUserData();
else return geom.toText();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,28 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.spark.sql.sedona_sql.expressions.geohash
package org.apache.sedona.common.utils;

import org.locationtech.jts.geom.{Coordinate, Geometry, GeometryFactory}
import java.util.Optional;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;

object GeometryGeoHashEncoder {
private val geometryFactory = new GeometryFactory()
def calculate(geom: Geometry, precision: Int): Option[String] = {
val gbox = geom.getEnvelope.getEnvelopeInternal
public class GeometryGeoHashEncoder {
private static GeometryFactory geometryFactory = new GeometryFactory();

public static String calculate(Geometry geom, int precision) {
Envelope gbox = geom.getEnvelope().getEnvelopeInternal();
// Latitude can take values in [-90, 90]
// Longitude can take values in [-180, 180]
if (gbox.getMinX < -180 || gbox.getMinY < -90 || gbox.getMaxX > 180 || gbox.getMaxY > 90) None
else {
val lon = gbox.getMinX + (gbox.getMaxX - gbox.getMinX) / 2
val lat = gbox.getMinY + (gbox.getMaxY - gbox.getMinY) / 2

Some(PointGeoHashEncoder.calculateGeoHash(geometryFactory.createPoint(new Coordinate(lon, lat)), precision))
if (gbox.getMinX() < -180 || gbox.getMinY() < -90 || gbox.getMaxX() > 180 || gbox.getMaxY() > 90) {
return null;
}

double lon = gbox.getMinX() + (gbox.getMaxX() - gbox.getMinX()) / 2;
double lat = gbox.getMinY() + (gbox.getMaxY() - gbox.getMinY()) / 2;

return PointGeoHashEncoder.calculateGeoHash(geometryFactory.createPoint(new Coordinate(lon, lat)), precision);
}
}
Loading