I. Basic Introduction
Spatial4j is an open source library for spatial computing written in java. It supports ASL open source protocol and geospatial computing.
Spatial4j has three main functions: 1) it supports several graphics based on plane geometry or geospatial; 2) Support distance calculation and shape calculation: calculate the relationship between bounding box, area and graphics. 3) analyze spatial description standard formats such as WKT and GeoJSON
Spatial4j makes use of some JTS capabilities (JTS is the most popular java spatial computing library). For example, polygons are implemented based on JTS. Compared with JTS, spatial4j also supports circle and geospatial computing. With JTS, polygon approximation is usually used to replace the calculation of circle, which will cause some errors to the results, and spatial4j supports circle; In addition, geospatial computing is now widely used, and it will be more convenient to use spatial 4J.
Since there are only some brief introductions on the official website, this paper introduces some practical use cases to help students in need get started faster.
Biplane geometry
2.1 pom dependency
If polygons are involved, JTS needs to be referenced; If you use GeoJSON serialization or deserialization described in Section 4, you need to rely on noggit
<dependency> <groupId>org.locationtech.spatial4j</groupId> <artifactId>spatial4j</artifactId> <version>0.8</version> </dependency> <dependency> <groupId>org.locationtech.jts</groupId> <artifactId>jts-core</artifactId> <version>1.18.1</version> </dependency> <dependency> <groupId>org.noggit</groupId> <artifactId>noggit</artifactId> <version>0.8</version> </dependency>
2.2 basic graphics
Next, go directly to the actual combat, and start with the example of plane geometry.
Firstly, it defines simple graphics such as point, circle and rectangle, and calculates the area, boundary box and the relationship between graphics.

void testEuclidean() { // Generate the context of plane geometry SpatialContextFactory nonGeoContextFactory = new SpatialContextFactory(); nonGeoContextFactory.geo = false; SpatialContext nonGeoContext = new SpatialContext(nonGeoContextFactory); // Define two points Point pointA = new PointImpl(2,6, nonGeoContext); Point pointB = new PointImpl(6,5, nonGeoContext); // Define circle Circle circleA = new CircleImpl(new PointImpl(6,4, nonGeoContext), 2, nonGeoContext); // Judge the relationship between circle and point System.out.println("circleA relate pointA: " + circleA.relate(pointA)); System.out.println("circleA relate pointB: " + circleA.relate(pointB)); // Calculate the area of the circle and the bounding box of the circle System.out.println(String.format("circleA area: %.2f", circleA.getArea(nonGeoContext))); Rectangle boundingBoxA = circleA.getBoundingBox(); System.out.println(String.format("circleA bounding box leftDown(%.2f, %.2f), rightUp:(%.2f, %.2f)", boundingBoxA.getMinX(), boundingBoxA.getMinY(), boundingBoxA.getMaxX(), boundingBoxA.getMaxY())); // Define rectangle and calculate the relationship between rectangle and circle Rectangle rectangleA = new RectangleImpl(3,5,4,8,nonGeoContext); System.out.println("rectangleA relate circleA: " + rectangleA.relate(circleA)); } Output results: circleA relate pointA:DISJOINT circleA relate pointB:CONTAINS circleA area:12.57 circleA bounding box leftDown(4.00, 2.00), rightUp:(8.00, 6.00) rectangleA relate circleA:INTERSECTS
2.3 polygon
spatial4j utilizes the polygon computing power of JTS.
The following sub examples define a concave polygon and a convex polygon respectively, and calculate the area of the polygon and the relationship between the polygons.

void testPolygon() { // JTS based context JtsSpatialContextFactory jtsSpatialContextFactory = new JtsSpatialContextFactory(); jtsSpatialContextFactory.geo = false; JtsSpatialContext jtsSpatialContext = jtsSpatialContextFactory.newSpatialContext(); JtsShapeFactory jtsShapeFactory = jtsSpatialContext.getShapeFactory(); // Define concave polygon A ShapeFactory.PolygonBuilder polygonBuilderA = jtsShapeFactory.polygon(); Shape polygonA = polygonBuilderA .pointXY(1, 1) .pointXY(2, 2) .pointXY(3, 1) .pointXY(5,3) .pointXY(3,5) .pointXY(2, 4) .pointXY(1,5) .pointXY(1, 1) .build(); // Define convex polygon B ShapeFactory.PolygonBuilder polygonBuilderB = jtsShapeFactory.polygon(); Shape polygonB = polygonBuilderB .pointXY(3, 3) .pointXY(5, 1) .pointXY(6, 3) .pointXY(5, 5) .pointXY(3, 3) .build(); // Calculate polygon area and polygon relationship System.out.println(String.format("polygonA area: %.2f", polygonA.getArea(jtsSpatialContext))); System.out.println("polygonA relate polygonB: " + polygonA.relate(polygonB)); } Output results: polygonA area:10.00 polygonA relate polygonB:INTERSECTS
III. geographical space
Geospatial is a sphere with dimensions of - 90, + 90, longitude of - 180, + 180. The calculation of distance and spatial position relationship are very different from plane geometry. Spatial4j supports geospatial computing, which is one of its core selling points.
3.1 tool kit
DistanceUtils provides some distance conversion tools, such as radian conversion to distance and distance conversion to radian.
void testDistanceUtils() { // Convert physical distance into radians int equatorLengthKm = 40075; double equatorDegree = DistanceUtils.dist2Degrees(equatorLengthKm, DistanceUtils.EARTH_EQUATORIAL_RADIUS_KM); System.out.println(String.format("equator length to degree: %.2f", equatorDegree)); // Distance per longitude on the equator double distPerDegreeKm = DistanceUtils.degrees2Dist(1, DistanceUtils.EARTH_EQUATORIAL_RADIUS_KM); System.out.println(String.format("distance per degree: %.2fkm", distPerDegreeKm)); } Output results: equator length to degree:360.00 distance per degree:111.32km
In addition, Spatial4j also provides GeoHASH codec and other toolkits, which can be further understood by students in need
3.2 distance calculation
The distance calculation of geospatial is different from that of plane geometry. As can be seen from the following example, if the plane set algorithm is used to calculate the geospatial distance, there will be errors.
void testGeodesicDistance() { SpatialContextFactory nonGeoContextFactory = new SpatialContextFactory(); nonGeoContextFactory.geo = false; SpatialContext nonGeoContext = new SpatialContext(nonGeoContextFactory); // Distance in plane coordinate system Point nonGeoCenter = new PointImpl(0, 0, nonGeoContext); CartesianDistCalc cartesianDistCalc = new CartesianDistCalc(); System.out.println(String.format("cartesian distance: %.2f", cartesianDistCalc.distance(nonGeoCenter, 30, 40))); // The geospatial distance (radian) is calculated by Haversine formula Point geoCenter = new PointImpl(0,0, SpatialContext.GEO); GeodesicSphereDistCalc geodesicSphereDistCalc = new GeodesicSphereDistCalc.Haversine(); System.out.println(String.format("geodesic distance: %.2f", geodesicSphereDistCalc.distance(geoCenter, 30, 40))); } Output results: cartesian distance: 50.00 geodesic distance: 48.44
3.3 relationship between graphs
The relationship between geospatial graphics and plane coordinate system is also different. In the following example, a circle crosses a 180 degree longitude. Two circles with the same parameters do not intersect in the plane coordinate system and intersect in geospatial space. If the algorithm of plane coordinate system is used, conversion is required.


void testGeodesicRelate() { SpatialContextFactory nonGeoContextFactory = new SpatialContextFactory(); nonGeoContextFactory.geo = false; SpatialContext nonGeoContext = new SpatialContext(nonGeoContextFactory); // Circle in plane coordinate system Point pointLeft = new PointImpl(-179, 0, nonGeoContext); Point pointRight = new PointImpl(179, 0, nonGeoContext); Circle circleLeft = new CircleImpl(pointLeft, 10, nonGeoContext); Circle circleRight = new CircleImpl(pointRight, 10, nonGeoContext); System.out.println("cartesian circleLeft relate circleRight: " + circleLeft.relate(circleRight)); // Circle in geospatial Point geoCenterWest = new PointImpl(-179, 0, SpatialContext.GEO); Point geoCenterEast = new PointImpl(179, 0, SpatialContext.GEO); Circle geoCircleWest = new CircleImpl(geoCenterWest, 10, SpatialContext.GEO); Circle geoCircleEast = new CircleImpl(geoCenterEast, 10, SpatialContext.GEO); System.out.println("geodesic circleWest relate circleEast: " + geoCircleWest.relate(geoCircleEast)); } Output results: cartesian circleLeft relate circleRight: DISJOINT geodesic circleWest relate circleEast: INTERSECTS
IV. parsing standard data format
Spatial4j supports serialization and deserialization of standard spatial description syntax. The following are examples of WKT and geojason. Note that both the reader and writer of geojson rely on the Noggit serialization tool.
void testReadStdFormat() { JtsSpatialContextFactory jtsSpatialContextFactory = new JtsSpatialContextFactory(); jtsSpatialContextFactory.geo = false; JtsSpatialContext jtsSpatialContext = jtsSpatialContextFactory.newSpatialContext(); // Read / write WKT format ShapeReader wktReader = jtsSpatialContext.getFormats().getReader(ShapeIO.WKT); ShapeWriter wktWriter = jtsSpatialContext.getFormats().getWriter(ShapeIO.WKT); try { // Note that BUFFER is a Spatial4j WKT based extension definition Circle circle = (Circle) wktReader.read("BUFFER(POINT(0 0), 1)"); System.out.println(String.format("read WKT shape area: %.2f", circle.getArea(jtsSpatialContext))); Rectangle rectangle = new RectangleImpl(1,10,3,8, jtsSpatialContext); System.out.println("WKT format string: " + wktWriter.toString(rectangle)); } catch (Exception e) { // } // Read and write geojason format ShapeReader geoJsonReader = jtsSpatialContext.getFormats().getReader(ShapeIO.GeoJSON); ShapeWriter geoJsonWriter = jtsSpatialContext.getFormats().getWriter(ShapeIO.GeoJSON); try { // Note that parsing polygon depends on JTS Shape polygon = geoJsonReader.read("{\"type\":\"Polygon\",\"coordinates\":[[[1,1],[2,2],[3,1],[5,3],[3,5],[2,4],[1,5],[1,1]]]}"); System.out.println(String.format("read GeoJson polygon area: %.2f", polygon.getArea(jtsSpatialContext))); Circle circle = new CircleImpl(new PointImpl(0, 0, jtsSpatialContext), 10, jtsSpatialContext); System.out.println("GeoJSON format string: " + geoJsonWriter.toString(circle)); } catch (Exception e) { // } } Output results: read WKT shape area: 3.14 WKT format string: ENVELOPE (1, 10, 8, 3) read GeoJson polygon area: 10.00 GeoJSON format string: {"type":"Circle","coordinates":[0,0],"radius":10}
V. citation
1 https://github.com/locationtech/spatial4j