diff --git a/CHANGELOG.md b/CHANGELOG.md
index f960cc4..51374ef 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,9 @@
-# CHANGELOG - 5.15 - 2023-12-127
+# CHANGELOG - 5.16 - 2024-02-09
+* [Updated] - Tested through Neo4j 5.16
+* [Added] - Added two new procedures that write to the Neo4j database. These are com.neo4jh3.writeH3NodesRelsToDB and com.neo4jh3.writeH3StringNodesRelsToDB. These procedures take the from node, a list of hex addresses, a Label, a Property and a transaction size and write the H3 address nodes and create relationships between the H3 node and the From Node to the database. If you are using these procedures, it is highly recommended that you have a constraint or index for the Label and Property.
+* [Added] - Added a function com.neo4jh3.angleBetweenPoints to calculate the angle between two points (latitude and longitude).
+
+# CHANGELOG - 5.15 - 2023-12-17
* [Updated] - Tested through Neo4j 5.15
* [Added] - Added MIT license.
* [Added] - Added two new procedures that write to the Neo4j database. These are com.neo4jh3.writeH3StringToDB and com.neo4jh3.writeH3ToDB. These procedures take a list of hex addresses, a Label, a Property and a transaction size and write the results to the database. If you are using these procedures, it is highly recommended that you have a constraint or index for the Label and Property.
diff --git a/Documentation.md b/Documentation.md
index 713b405..a44e0a3 100644
--- a/Documentation.md
+++ b/Documentation.md
@@ -1,4 +1,29 @@
# Documentation
+## com.neo4jh3.angleBetweenPoints( Latitude1, Longitude1, Latitude2, Longitude2 )
+Returns the angle in degrees between two points.
+
+### Syntax
+RETURN com.neo4jh3.angleBetweenPoints( Latitude1, Longitude1, Latitude2, Longitude2 ) as value
+
+### Arguments
+* Latitude1: A DOUBLE expression representing the latitude (in degrees) of the first point
+* Longitude1: A DOUBLE expression representing the longitude (in degrees) of the first point
+* Latitude2: A DOUBLE expression representing the latitude (in degrees) of the second point
+* Longitude2: A DOUBLE expression representing the longitude (in degrees) of the second point
+
+### Returns
+A value of the type DOUBLE representing the angle in degrees between the two points.
+
+### Error conditions
+If any of the latitude or longitude values are invalid, the function returns -1
+
+### Example
+ RETURN com.neo4jh3.angleBetweenPoints(40.123,-78.111,40.555,-78.910) AS value
+ 305.607560
+
+ RETURN com.neo4jh3.angleBetweenPoints(240.123,-78.111,40.555,-78.910) AS value
+ -1.0
+
## com.neo4jh3.boundaryaswkt( h3CellIdExpr )
Returns the polygonal boundary of the input H3 cell in WKT format.
@@ -199,7 +224,7 @@ RETURN com.neo4jh3.cellToLatLng( h3CellId1Expr ) AS value;
A STRING value consisting of the latitude and longitude of the h3CellIdExpr.
### Error conditions
-If h3XellIdExpr is an invalid h3 address, the function returns -1.
+If h3CellIdExpr is an invalid h3 address, the function returns -1.
### Example
RETURN com.neo4jh3.cellToLatLng(635714569676958015) AS value
@@ -221,7 +246,7 @@ RETURN com.neo4jh3.cellToLatLngString( h3CellIdExpr ) AS value;
A STRING value consisting of the latitude and longitude of the h3CellIdExpr.
### Error conditions
-If h3XellIdExpr is an invalid h3 address, the function returns -1.
+If h3CellIdExpr is an invalid h3 address, the function returns -1.
### Example
RETURN com.neo4jh3.cellToLatLngString('892830926cfffff') AS value
@@ -1542,6 +1567,74 @@ If the strLabel or strProperty is empty, the procedure returns "-5"
call com.neo4jh3.writeH3ToDBString(ch3,'','') yield value return value;
"-5"
+## com.neo4jh3.writeH3NodesRelsToDB( From Node, ListOfCells, Neo4j Label, Neo4j Property, Relationships Type, Transaction Size )
+Writes the H3 index values to the Neo4j database as a node using a user provided Label and Property.
+Connects the H3 index values to the From Node using the specified Relationship value.
+
+### Syntax
+CALL com.neo4jh3.writeH3NodesRelsToDB(fromNode, listCells, strLabel, strProperty, relationshipType, txSize) yield value return value;
+
+### Arguments
+* fromNode: An existing Node in the Neo4j database.
+* listCells: A LIST of LONG values representing an H3 cell ID.
+* strLabel: A STRING indicating what Neo4j Label will be applied to the nodes.
+* strProperty: A STRING indicating what Neo4j Property will be applied to the nodes.
+* relationshipType: A STRING indicating what relationship type will be used for the relationships.
+* txSize: A LONG indicating the number of nodes to create in each transaction.
+
+### Returns
+A STRING indicating completion.
+
+### Error conditions
+If the strLabel or strProperty is empty, the procedure returns "-5"
+
+### Example
+ match (cs:CountySubDivision {cousubns:value.COUSUBNS})
+ call com.neo4jh3.polygonToCells(value.Geometry,[],8,'lonlat') yield value as h3
+ with cs, collect(h3) as ch3
+ call com.neo4jh3.writeH3NodesRelsToDB(cs,ch3,'Hex','hexAddress8','HAS_HEXADDRESS', 10000) yield value return value;
+ "Success"
+
+ match (cs:CountySubDivision {cousubns:value.COUSUBNS})
+ call com.neo4jh3.polygonToCells(value.Geometry,[],8,'lonlat') yield value as h3
+ with cs, collect(h3) as ch3
+ call com.neo4jh3.writeH3NodesRelsToDB(cs,ch3,'Hex','','HAS_HEXADDRESS', 10000) yield value return value;
+ "-5"
+
+# com.neo4jh3.writeH3StringNodesRelsToDB( From Node, ListOfCells, Neo4j Label, Neo4j Property, Relationships Type, Transaction Size )
+Writes the H3 index values to the Neo4j database as a node using a user provided Label and Property.
+Connects the H3 index values to the From Node using the specified Relationship value.
+
+### Syntax
+CALL com.neo4jh3.writeH3StringNodesRelsToDB(fromNode, listCells, strLabel, strProperty, relationshipType, txSize) yield value return value;
+
+### Arguments
+* fromNode: An existing Node in the Neo4j database.
+* listCells: A LIST of STRING values representing an H3 cell ID.
+* strLabel: A STRING indicating what Neo4j Label will be applied to the nodes.
+* strProperty: A STRING indicating what Neo4j Property will be applied to the nodes.
+* relationshipType: A STRING indicating what relationship type will be used for the relationships.
+* txSize: A LONG indicating the number of nodes to create in each transaction.
+
+### Returns
+A STRING indicating completion.
+
+### Error conditions
+If the strLabel or strProperty is empty, the procedure returns "-5"
+
+### Example
+ match (cs:CountySubDivision {cousubns:value.COUSUBNS})
+ call com.neo4jh3.polygonToCells(value.Geometry,[],8,'lonlat') yield value as h3
+ with cs, collect(h3) as ch3
+ call com.neo4jh3.writeH3StringNodesRelsToDB(cs,ch3,'Hex','hexAddress8','HAS_HEXADDRESS', 10000) yield value return value;
+ "Success"
+
+ match (cs:CountySubDivision {cousubns:value.COUSUBNS})
+ call com.neo4jh3.polygonToCells(value.Geometry,[],8,'lonlat') yield value as h3
+ with cs, collect(h3) as ch3
+ call com.neo4jh3.writeH3StringNodesRelsToDB(cs,ch3,'Hex','','HAS_HEXADDRESS', 10000) yield value return value;
+ "-5"
+
## Error Codes
* -1 or "-1" : Invalid H3 Address
* -2 or "-2" : Invalid Resolution
diff --git a/README.md b/README.md
index 299474e..2f5c2d9 100644
--- a/README.md
+++ b/README.md
@@ -26,10 +26,11 @@ Edit your Neo4j/conf/neo4j.conf file by adding this line:
(Re)start Neo4j
# Documentation
-Refer to the Documentation.md file for detailed documenation on the functions / procedures.
+Refer to the Documentation.md file for detailed documentation on the functions / procedures.
# Note
The Neo4jH3 plugin requires the ability to write to the temp directory. If the temp directory configured with noexec, then you need to update the neo4j.conf with these two lines:
+
server.jvm.additional=-Djava.io.tmpdir=/path_to_a_new_directory/temp
server.jvm.additional=-Djna.tmpdir=/path_to_a_new_directory/temp
diff --git a/pom.xml b/pom.xml
index b0e1e73..57bbd3c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,10 +6,10 @@
com.neo4jh3
neo4jh3
- 5.15.0
+ 5.16.0
- 5.15.0
+ 5.16.0
1.2
3.13.0
4.1.1
diff --git a/src/main/java/com/neo4jh3/uber/Uberh3.java b/src/main/java/com/neo4jh3/uber/Uberh3.java
index c82c56a..bc43682 100755
--- a/src/main/java/com/neo4jh3/uber/Uberh3.java
+++ b/src/main/java/com/neo4jh3/uber/Uberh3.java
@@ -14,6 +14,8 @@
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Label;
import org.neo4j.graphdb.Node;
+import org.neo4j.graphdb.Relationship;
+import org.neo4j.graphdb.RelationshipType;
import org.neo4j.graphdb.Transaction;
import org.neo4j.procedure.*;
import org.neo4j.procedure.builtin.BuiltInDbmsProcedures.StringResult;
@@ -31,7 +33,7 @@ public class Uberh3 {
public Transaction tx;
private final static int DEFAULT_H3_RESOLUTION = 9;
- private final static String NEO4J_H3_VERSION = "5.15.0";
+ private final static String NEO4J_H3_VERSION = "5.16.0";
private static H3Core h3 = null;
@@ -102,12 +104,12 @@ public Long h3HexAddress(
returnValue = -1L;
}
- if ( latValue>90 || latValue<-90 ){
+ if ( latValue > 90 || latValue < -90 ){
validLatLon = 0;
returnValue = -3L;
}
- if ( longValue>180 || longValue<-180 ){
+ if ( longValue > 180 || longValue < -180 ){
validLatLon = 0;
returnValue = -4L;
}
@@ -124,6 +126,7 @@ public Long h3HexAddress(
return returnValue;
}
+ @SuppressWarnings("null")
@UserFunction(name = "com.neo4jh3.h3HexAddressString")
@Description("com.neo4jh3.h3HexAddressString(latitude, longitude, resolution) - return the hex address for a given latitude.")
public String h3HexAddressString(
@@ -139,12 +142,12 @@ public String h3HexAddressString(
returnString = "NULL";
}
- if ( latValue>90 || latValue<-90 ){
+ if ( latValue > 90 || latValue < -90 ){
validLatLon = 0;
returnString = "-3";
}
- if ( longValue>180 || longValue<-180 ){
+ if ( longValue > 180 || longValue < -180 ){
validLatLon = 0;
returnString = "-4";
}
@@ -162,6 +165,10 @@ public String h3HexAddressString(
+ /**
+ * @param longHex
+ * @return
+ */
@UserFunction(name = "com.neo4jh3.h3tostring")
@Description("com.neo4jh3.h3tostring(longHex) - return the string value of a long hex address.")
public String h3tostringFunction(
@@ -179,7 +186,6 @@ public String h3tostringFunction(
}
return returnString;
} catch (Exception e) {
- // TODO Auto-generated catch block
returnString = "-1";
return returnString;
}
@@ -202,7 +208,6 @@ public Long stringToH3Function(
}
return returnString;
} catch (Exception e) {
- // TODO Auto-generated catch block
returnString = -1L;
return returnString;
}
@@ -225,7 +230,6 @@ public Long h3ResolutionString(
}
return returnString;
} catch (Exception e) {
- // TODO Auto-generated catch block
returnString = -1L;
return returnString;
}
@@ -248,7 +252,6 @@ public Long h3Resolution(
}
return returnString;
} catch (Exception e) {
- // TODO Auto-generated catch block
returnString = -1L;
return returnString;
}
@@ -378,10 +381,7 @@ public Long gridDistance(
}
}
-
- return returnValue;
-
-
+ return returnValue;
}
@UserFunction(name = "com.neo4jh3.gridDistanceString")
@@ -407,8 +407,7 @@ public double gridDistanceString(
returnValue = -1L;
}
}
- return returnValue;
-
+ return returnValue;
}
@UserFunction(name = "com.neo4jh3.toparent")
@@ -479,8 +478,8 @@ public String cellToLatLng(@Name("hexAddress") Long hexAddress) throws Interrupt
} else {
return "-1";
}
-
}
+
@UserFunction(name = "com.neo4jh3.cellToLatLngString")
@Description("CALL com.neo4jh3.cellToLatLngString(hexAddress)")
public String cellToLatLngString(@Name("hexAddress") String hexAddress) throws InterruptedException {
@@ -497,12 +496,12 @@ public String cellToLatLngString(@Name("hexAddress") String hexAddress) throws I
} else {
return "-1";
}
-
}
@UserFunction(name = "com.neo4jh3.distanceBetweenHexes")
@Description("CALL com.neo4jh3.distanceBetweenHexes(fromHexAddress, toHexAddress)")
public double distanceBetweenHexes(@Name("fromHexAddress") Long fromHexAddress, @Name("toHexAddress") Long toHexAddress) throws InterruptedException {
+ double returnDistance = 0.0;
if (h3 == null) {
throw new InterruptedException("h3 failed to initialize");
}
@@ -512,12 +511,10 @@ public double distanceBetweenHexes(@Name("fromHexAddress") Long fromHexAddress,
if (h3.isValidCell(fromHexAddress) && h3.isValidCell(toHexAddress)){
LatLng fromGeoCoord = h3.cellToLatLng(fromHexAddress);
LatLng toGeoCoord = h3.cellToLatLng(toHexAddress);
- return h3.greatCircleDistance(fromGeoCoord, toGeoCoord, LengthUnit.km);
+ return returnDistance = Precision.round(h3.greatCircleDistance(fromGeoCoord, toGeoCoord, LengthUnit.km),6);
} else {
return -1.0;
}
- //double geoDistance = distance(fromGeoCoord.lat, fromGeoCoord.lng, toGeoCoord.lat, toGeoCoord.lng,units);
- //return geoDistance;
}
@UserFunction(name = "com.neo4jh3.distanceBetweenHexesString")
@@ -537,7 +534,6 @@ public double distanceBetweenHexesString(@Name("fromHexAddress") String fromHexA
} else {
return -1.0;
}
-
}
@UserFunction(name = "com.neo4jh3.minChild")
@@ -678,6 +674,35 @@ public String maxChild(@Name("fromHexAddress") String fromHexAddress, @Name("h3R
}
}
+ @UserFunction(name = "com.neo4jh3.angleBetweenPoints")
+ @Description("CALL com.neo4jh3.angleBetweenPoints(latitude1, longitude1, latitude2, longitude2)")
+ public Double angleBetweenPoints(
+ @Name("latitude1") Double lat1Value,
+ @Name("longitude1") Double lon1Value,
+ @Name("latitude2") Double lat2Value,
+ @Name("longitude2") Double lon2Value
+ ) throws InterruptedException {
+ Double returnValue = 0.0;
+ int hasError=0;
+ if (h3 == null) {
+ throw new InterruptedException("h3 failed to initialize");
+ }
+ if ( lat1Value>90 || lat2Value<-90 || lat1Value>90 || lat2Value<-90 ){
+ returnValue = -1.0;
+ hasError = 1;
+ }
+
+ if ( lon1Value>180 || lon1Value<-180 || lon2Value>180 || lon2Value<-180 ){
+ returnValue = -2.0;
+ hasError = 1;
+ }
+ if (hasError < 1){
+ return Precision.round(distance(lat1Value,lon1Value,lat2Value,lon2Value),6);
+ } else {
+ return returnValue;
+ }
+ }
+
// Geography Functions
@UserFunction(name = "com.neo4jh3.pointash3")
@Description("com.neo4jh3.pointash3(wktString, resolution, latlon order) - Provides the distance in grid cells between the two indexes.")
@@ -712,7 +737,6 @@ public Long pointash3(
} catch (Exception e) {
//System.out.println(e);
h3Address = -1L;
- // TODO Auto-generated catch block
//e.printStackTrace();
}
return h3Address;
@@ -749,7 +773,6 @@ public String pointash3String(
} catch (Exception e) {
//System.out.println(e);
h3Address = "-1";
- // TODO Auto-generated catch block
//e.printStackTrace();
}
return h3Address;
@@ -836,7 +859,6 @@ public Stream lineash3(
} catch (Exception e) {
//System.out.println(e);
listh3Address = Collections.singletonList(-1L);
- // TODO Auto-generated catch block
//e.printStackTrace();
}
return listh3Address.stream().map(H3LongAddress::of);
@@ -912,7 +934,6 @@ public Stream lineash3String(
} catch (Exception e) {
//System.out.println(e);
listh3Address = Collections.singletonList("-1");
- // TODO Auto-generated catch block
//e.printStackTrace();
}
return listh3Address.stream().map(H3StringAddress::of);
@@ -926,7 +947,6 @@ public Stream multilineash3(
{
List listh3Address = new ArrayList();
List gpCells = new ArrayList();
- Long h3Address = 0L;
Long h3StartAddress = 0L;
Long h3MidAddress = 0L;
Long h3EndAddress = 0L;
@@ -989,7 +1009,6 @@ public Stream multilineash3(
} catch (Exception e) {
//System.out.println(e);
listh3Address = Collections.singletonList(-1L);
- // TODO Auto-generated catch block
//e.printStackTrace();
}
return listh3Address.stream().map(H3LongAddress::of);
@@ -1065,7 +1084,6 @@ public Stream multilineash3String(
} catch (Exception e) {
//System.out.println(e);
listh3Address = Collections.singletonList("-1");
- // TODO Auto-generated catch block
//e.printStackTrace();
}
return listh3Address.stream().map(H3StringAddress::of);
@@ -1091,7 +1109,6 @@ public String centeraswkb(
Double lng = Precision.round(centerPoint.lng,6);
Point point =new Point(false, false, lng, lat);
byte[] bytes = GeometryWriter.writeGeometry(point);
- String hex = "";
for (byte i : bytes) {
geoJsonString += String.format("%02X", i);
}
@@ -1101,7 +1118,6 @@ public String centeraswkb(
}
} catch (Exception e) {
- // TODO Auto-generated catch block
geoJsonString = "Error getting value";
}
return geoJsonString;
@@ -1125,7 +1141,6 @@ public String centeraswkbString(
Double lng = Precision.round(centerPoint.lng,6);
Point point =new Point(false, false, lng, lat);
byte[] bytes = GeometryWriter.writeGeometry(point);
- String hex = "";
for (byte i : bytes) {
geoJsonString += String.format("%02X", i);
}
@@ -1135,7 +1150,6 @@ public String centeraswkbString(
}
} catch (Exception e) {
- // TODO Auto-generated catch block
geoJsonString = "Error getting value";
}
return geoJsonString;
@@ -1164,7 +1178,6 @@ public String centeraswkt(
}
} catch (Exception e) {
- // TODO Auto-generated catch block
geoJsonString = "Error getting value";
}
return geoJsonString;
@@ -1194,7 +1207,6 @@ public String centeraswktString(
}
} catch (Exception e) {
- // TODO Auto-generated catch block
geoJsonString = "Error getting value";
}
return geoJsonString;
@@ -1206,7 +1218,6 @@ public String boundaryaswkt(
@Name("hexAddress") Long hexAddress) throws InterruptedException
{
String geoJsonString = "";
- LatLng centerPoint = null;
List hexPoints = new ArrayList<>();
if (h3 == null) {
@@ -1239,7 +1250,6 @@ public String boundaryaswkt(
geoJsonString = "-1";
}
} catch (Exception e) {
- // TODO Auto-generated catch block
e.printStackTrace();
}
return geoJsonString;
@@ -1251,7 +1261,6 @@ public String boundaryaswktString(
@Name("hexAddress") String hexAddress) throws InterruptedException
{
String geoJsonString = "";
- LatLng centerPoint = null;
List hexPoints = new ArrayList<>();
if (h3 == null) {
@@ -1284,7 +1293,6 @@ public String boundaryaswktString(
geoJsonString = "-1";
}
} catch (Exception e) {
- // TODO Auto-generated catch block
e.printStackTrace();
}
return geoJsonString;
@@ -1296,7 +1304,6 @@ public String boundaryaswkb(
@Name("hexAddress") Long hexAddress) throws InterruptedException
{
String geoJsonString = "";
- LatLng centerPoint = null;
List hexPoints = new ArrayList<>();
if (h3 == null) {
@@ -1325,7 +1332,6 @@ public String boundaryaswkb(
ring.addPoint(tpfirst);
mil.nga.sf.Polygon polygon = new mil.nga.sf.Polygon(ring);
byte[] bytes = GeometryWriter.writeGeometry(polygon);
- String hex = "";
for (byte bi : bytes) {
geoJsonString += String.format("%02X", bi);
}
@@ -1334,7 +1340,6 @@ public String boundaryaswkb(
geoJsonString = "-1";
}
} catch (Exception e) {
- // TODO Auto-generated catch block
e.printStackTrace();
}
return geoJsonString;
@@ -1346,7 +1351,6 @@ public String boundaryaswkbString(
@Name("hexAddress") String hexAddress) throws InterruptedException
{
String geoJsonString = "";
- LatLng centerPoint = null;
List hexPoints = new ArrayList<>();
if (h3 == null) {
@@ -1375,7 +1379,6 @@ public String boundaryaswkbString(
ring.addPoint(tpfirst);
mil.nga.sf.Polygon polygon = new mil.nga.sf.Polygon(ring);
byte[] bytes = GeometryWriter.writeGeometry(polygon);
- String hex = "";
for (byte bi : bytes) {
geoJsonString += String.format("%02X", bi);
}
@@ -1384,7 +1387,6 @@ public String boundaryaswkbString(
geoJsonString = "-1";
}
} catch (Exception e) {
- // TODO Auto-generated catch block
e.printStackTrace();
}
return geoJsonString;
@@ -1414,7 +1416,6 @@ public String centerasgeojson(
}
} catch (Exception e) {
- // TODO Auto-generated catch block
geoJsonString = "Error getting value";
}
return geoJsonString;
@@ -1443,7 +1444,6 @@ public String centerasgeojsonString(
}
} catch (Exception e) {
- // TODO Auto-generated catch block
geoJsonString = "Error getting value";
}
return geoJsonString;
@@ -1456,7 +1456,6 @@ public String boundaryasgeojson(
@Name("hexAddress") Long hexAddress) throws InterruptedException
{
String geoJsonString = "";
- LatLng centerPoint = null;
List hexPoints = new ArrayList<>();
if (h3 == null) {
@@ -1489,7 +1488,6 @@ public String boundaryasgeojson(
geoJsonString = "-1";
}
} catch (Exception e) {
- // TODO Auto-generated catch block
e.printStackTrace();
}
return geoJsonString;
@@ -1534,7 +1532,6 @@ public String boundaryasgeojsonString(
geoJsonString = "-1";
}
} catch (Exception e) {
- // TODO Auto-generated catch block
e.printStackTrace();
}
return geoJsonString;
@@ -2184,7 +2181,6 @@ public List next() {
}
};
- // XXX Not sure if this is correct...
final Spliterator> spliterator = Spliterators.spliterator(iterator, addresses.size() - 1, Spliterator.ORDERED);
return StreamSupport
@@ -2268,8 +2264,8 @@ public Stream unCompact(@Name("listCells") List listCells,
@Procedure(name = "com.neo4jh3.linepolyIntersection", mode = Mode.READ)
@Description("com.neo4jh3.linepolyIntersection(polyEdges, polyEdgeHoles,wktString, resolution, latlon order) - Provides the distance in grid cells between the two indexes.")
public Stream lineash3(
- @Name("polyEdges") List polyEdges,
- @Name("polyEdgeHoles") List polyEdgeHoles,
+ @Name("polyEdges") List polyEdges,
+ @Name("polyEdgeHoles") List polyEdgeHoles,
@Name("wktString") String wktString,
@Name("h3Res") Long h3Res,
@Name("latlonorder") String latlonorder) throws InterruptedException
@@ -2384,7 +2380,6 @@ public Stream lineash3(
} catch (Exception e) {
//System.out.println(e);
hexListFinal = Collections.singletonList(-1L);
- // TODO Auto-generated catch block
//e.printStackTrace();
}
return hexListFinal.stream().map(H3LongAddress::of);
@@ -2526,7 +2521,173 @@ public Stream writeH3StringToDB(@Name("listCells") List li
}
}
+ // Experimental write to db procedure
+ @Procedure(name = "com.neo4jh3.writeH3NodesRelsToDB", mode = Mode.WRITE)
+ @Description("CALL com.neo4jh3.writeH3NodesRelsToDB(From Node, List of H3 Cells, To Node Label, To Node Property Name, RelationshipType, Transaction Size)")
+ public Stream writeH3NodesRelsToDB(@Name("fromNode") Node fromNode, @Name("listCells") List listCells, @Name("strLabel") String strLabel, @Name("strProperty") String strProperty, @Name("strRelationshipType") String strRelationshipType, @Name("txSize") Long txSize) throws InterruptedException {
+ String returnMessage = "";
+ String fromNodeElmementID = "";
+ if (listCells == null) {
+ throw new InterruptedException("invalid list of hex addresses");
+ }
+ if (strLabel.isBlank() || strProperty.isBlank() || strRelationshipType.isBlank()){
+ returnMessage = "-5";
+ //throw new InterruptedException("Empty Label and/or Property");
+ } else {
+ if (txSize < 1) {
+ txSize = 10000L;
+ }
+ Integer count = 1;
+ Long curRes =0L;
+ Throwable txEx = null;
+ ListIterator iterator = listCells.listIterator();
+ HashMap relNodeList = new HashMap();
+ String endNodeID = "";
+ String qry = "";
+ List hexList = new ArrayList();
+ Map params = new HashMap<>();
+ Transaction tx = db.beginTx();
+
+ try {
+ fromNodeElmementID = fromNode.getElementId();
+ Node tFromNode = tx.getNodeByElementId(fromNodeElmementID);
+ for (Relationship r : tFromNode.getRelationships(RelationshipType.withName(strRelationshipType))) {
+ endNodeID = r.getEndNode().getElementId();
+ relNodeList.put(endNodeID,endNodeID);
+ }
+
+ while (iterator.hasNext()) {
+ curRes = iterator.next();
+ Node h3Node = tx.findNode(Label.label(strLabel), strProperty, curRes);
+ if (h3Node == null) {
+ h3Node = tx.createNode(Label.label(strLabel));
+ h3Node.setProperty(strProperty,curRes);
+ }
+
+ endNodeID = h3Node.getElementId();
+ if (relNodeList.get(endNodeID) == null){
+ hexList.add(endNodeID);
+ relNodeList.put(endNodeID,endNodeID);
+ }
+
+ if (count % txSize == 0) {
+ params.put("fromNode",fromNodeElmementID);
+ params.put("hexList",hexList);
+ qry = "UNWIND $hexList as teid MATCH (t) where elementId(t) = teid MATCH (f) where elementID(f) = $fromNode MERGE (f)-[:" + strRelationshipType + "]->(t);";
+ tx.execute( qry, params);
+ hexList.clear();
+ params.clear();
+ }
+
+ if (count % txSize == 0) {
+ tx.commit();
+ tx = db.beginTx();
+ }
+ count++;
+ }
+ // Run final relationship group
+ params.put("hexList",hexList);
+ params.put("fromNode",fromNodeElmementID);
+ qry = "UNWIND $hexList as teid MATCH (t) where elementId(t) = teid MATCH (f) where elementID(f) = $fromNode MERGE (f)-[:" + strRelationshipType + "]->(t);";
+ tx.execute( qry, params);
+ tx.commit();
+ hexList.clear();
+ params.clear();
+ } catch (Throwable ex) {
+ txEx = ex;
+ System.out.println(ex);
+ }
+ }
+ if (returnMessage.isBlank()){
+ return Stream.of(new StringResult("Finished"));
+ } else {
+ return Stream.of(new StringResult(returnMessage));
+ }
+ }
+
+ // Experimental write to db procedure
+ @Procedure(name = "com.neo4jh3.writeH3StringNodesRelsToDB", mode = Mode.WRITE)
+ @Description("CALL com.neo4jh3.writeH3StringNodesRelsToDB(From Node, List of H3 Cells, To Node Label, To Node Property Name, RelationshipType, Transaction Size)")
+ public Stream writeH3StringNodesRelsToDB(@Name("fromNode") Node fromNode, @Name("listCells") List listCells, @Name("strLabel") String strLabel, @Name("strProperty") String strProperty, @Name("strRelationshipType") String strRelationshipType, @Name("txSize") Long txSize) throws InterruptedException {
+ String returnMessage = "";
+ String fromNodeElmementID = "";
+ if (listCells == null) {
+ throw new InterruptedException("invalid list of hex addresses");
+ }
+ if (strLabel.isBlank() || strProperty.isBlank() || strRelationshipType.isBlank()){
+ returnMessage = "-5";
+ //throw new InterruptedException("Empty Label and/or Property");
+ } else {
+ if (txSize < 1) {
+ txSize = 10000L;
+ }
+ Integer count = 1;
+ String curRes = "";
+ Throwable txEx = null;
+ ListIterator iterator = listCells.listIterator();
+ HashMap relNodeList = new HashMap();
+ String endNodeID = "";
+ String qry = "";
+ List hexList = new ArrayList();
+ Map params = new HashMap<>();
+ Transaction tx = db.beginTx();
+
+ try {
+ fromNodeElmementID = fromNode.getElementId();
+ Node tFromNode = tx.getNodeByElementId(fromNodeElmementID);
+ for (Relationship r : tFromNode.getRelationships(RelationshipType.withName(strRelationshipType))) {
+ endNodeID = r.getEndNode().getElementId();
+ relNodeList.put(endNodeID,endNodeID);
+ }
+
+ while (iterator.hasNext()) {
+ curRes = iterator.next();
+ Node h3Node = tx.findNode(Label.label(strLabel), strProperty, curRes);
+ if (h3Node == null) {
+ h3Node = tx.createNode(Label.label(strLabel));
+ h3Node.setProperty(strProperty,curRes);
+ }
+
+ endNodeID = h3Node.getElementId();
+ if (relNodeList.get(endNodeID) == null){
+ hexList.add(endNodeID);
+ relNodeList.put(endNodeID,endNodeID);
+ }
+ if (count % txSize == 0) {
+ params.put("fromNode",fromNodeElmementID);
+ params.put("hexList",hexList);
+ qry = "UNWIND $hexList as teid MATCH (t) where elementId(t) = teid MATCH (f) where elementID(f) = $fromNode MERGE (f)-[:" + strRelationshipType + "]->(t);";
+ tx.execute( qry, params);
+ hexList.clear();
+ params.clear();
+ }
+
+ if (count % txSize == 0) {
+ tx.commit();
+ tx = db.beginTx();
+ }
+ count++;
+ }
+ // Run final relationship group
+ params.put("hexList",hexList);
+ params.put("fromNode",fromNodeElmementID);
+ qry = "UNWIND $hexList as teid MATCH (t) where elementId(t) = teid MATCH (f) where elementID(f) = $fromNode MERGE (f)-[:" + strRelationshipType + "]->(t);";
+ tx.execute( qry, params);
+ tx.commit();
+ hexList.clear();
+ params.clear();
+ } catch (Throwable ex) {
+ txEx = ex;
+ System.out.println(ex);
+ }
+ }
+ if (returnMessage.isBlank()){
+ return Stream.of(new StringResult("Finished"));
+ } else {
+ return Stream.of(new StringResult(returnMessage));
+ }
+ }
private static double distance(double lat1, double lon1, double lat2, double lon2, String unit) {
if ((lat1 == lat2) && (lon1 == lon2)) {
@@ -2547,4 +2708,21 @@ private static double distance(double lat1, double lon1, double lat2, double lon
}
}
+ private static double distance(double lat1, double lon1, double lat2, double lon2) {
+ if ((lat1 == lat2) && (lon1 == lon2)) {
+ return 0;
+ }
+ else {
+ double longitude1 = lon1;
+ double longitude2 = lon2;
+ double latitude1 = Math.toRadians(lat1);
+ double latitude2 = Math.toRadians(lat2);
+ double longDiff= Math.toRadians(longitude2-longitude1);
+ double y= Math.sin(longDiff)*Math.cos(latitude2);
+ double x=Math.cos(latitude1)*Math.sin(latitude2)-Math.sin(latitude1)*Math.cos(latitude2)*Math.cos(longDiff);
+
+ return (Math.toDegrees(Math.atan2(y, x))+360)%360;
+ }
+ }
+
}
diff --git a/src/test/java/com/neo4jh3/Neo4jH3Test.java b/src/test/java/com/neo4jh3/Neo4jH3Test.java
index 1c220ad..358e68f 100644
--- a/src/test/java/com/neo4jh3/Neo4jH3Test.java
+++ b/src/test/java/com/neo4jh3/Neo4jH3Test.java
@@ -3,10 +3,6 @@
import org.assertj.core.api.Assertions;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.Rule;
import org.junit.Test;
import org.neo4j.driver.Driver;
import org.neo4j.driver.GraphDatabase;
@@ -18,8 +14,6 @@
import com.neo4jh3.uber.Uberh3;
import com.uber.h3core.H3CoreLoader;
-import static org.hamcrest.core.IsEqual.equalTo;
-import static org.junit.Assert.assertThat;
public class Neo4jH3Test {
private static Driver driver;
@@ -45,11 +39,7 @@ public void should_return_hex_address() throws InterruptedException {
*/
if (System.getProperty("os.name").toLowerCase().equalsIgnoreCase("mac os x")){
result = session.run("return com.neo4jh3.distanceBetweenHexes(599686042433355775,599686015589810175) as value");
- String myResult = result.single().get("value").toString();
-
- myResult = myResult.substring(0, 11);
- assertEquals("17.87016346",myResult);
- //assertEquals(17.870163466857925,result.single().get("value").asDouble(),0);
+ assertEquals(17.870163, result.single().get("value").asDouble(),0);
result = session.run("RETURN com.neo4jh3.centeraswkb(599686042433355775) AS value");
assertEquals("\"0000000001C05E7E7CF1C3265B4042AC42F1ED17C6\"", result.single().get("value").toString());
@@ -122,7 +112,7 @@ public void should_return_hex_address() throws InterruptedException {
}
result = session.run("RETURN com.neo4jh3.version() AS value");
- assertEquals("\"5.15.0\"", result.single().get("value").toString());
+ assertEquals("\"5.16.0\"", result.single().get("value").toString());
result = session.run("RETURN com.neo4jh3.cellToLatLngString('892830926cfffff') AS value");
assertEquals("\"37.564248,-122.325306\"", result.single().get("value").toString());
@@ -330,6 +320,9 @@ public void should_return_hex_address() throws InterruptedException {
result = session.run("RETURN com.neo4jh3.h3Resolution(599686042433355775) AS value");
assertEquals(5L, result.single().get("value").asLong(),0);
+ result = session.run("RETURN com.neo4jh3.angleBetweenPoints(40.123,-78.111,40.555,-78.910) AS value");
+ assertEquals(305.607560, result.single().get("value").asDouble(),0);
+
/* Procedures */
result=session.run("call com.neo4jh3.gridDisk(599686042433355775,1) yield value return value limit 1");
diff --git a/src/test/java/com/neo4jh3/TestHierarchy.java b/src/test/java/com/neo4jh3/TestHierarchy.java
index fd2468e..d7870d5 100644
--- a/src/test/java/com/neo4jh3/TestHierarchy.java
+++ b/src/test/java/com/neo4jh3/TestHierarchy.java
@@ -3,11 +3,6 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import com.google.common.collect.ImmutableList;
-import com.uber.h3core.exceptions.H3Exception;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
import java.util.List;
import org.junit.Test;