Project URL: https://github.com/locationtech/jts
Maven Central:
org.locationtech.jts:jts-coreLicense: Eclipse Public License 2.0 / Eclipse Distribution License 1.0 (BSD-style)
Overview
JTS Topology Suite (JTS for short) is an open-source Java 2D vector geometry library under the LocationTech project group, and is the geometry computation core of numerous open-source GIS projects such as GeoTools and GeoServer. It provides:
- Geometric object model:Point、LineString、Polygon、MultiPoint、MultiLineString、MultiPolygon、GeometryCollection
- Spatial relationship determination:equals、contains、within、intersects、touches、crosses、overlaps、disjoint、relate(DE-9IM)
- Set operations:intersection、union、difference、symDifference、buffer
- Geometric analysis:convexHull、centroid、area、length、distance、isValid、simplify
- Linear referencing: distance-based positioning along a line, interpolation on a line
- Spatial indexing: STRtree, Quadtree, accelerating bulk spatial queries
- Format read/write:WKT、WKB、GeoJSON
Environment requirements: JDK 8+
Quick integration
Maven
<properties>
<jts.version>1.20.0</jts.version>
</properties>
<dependency>
<groupId>org.locationtech.jts</groupId>
<artifactId>jts-core</artifactId>
<version>${jts.version}</version>
</dependency>
If I/O support such as GeoJSON is needed:
<dependency>
<groupId>org.locationtech.jts.io</groupId>
<artifactId>jts-io-common</artifactId>
<version>${jts.version}</version>
</dependency>
Gradle
implementation 'org.locationtech.jts:jts-core:1.20.0'
implementation 'org.locationtech.jts.io:jts-io-common:1.20.0'
Project module overview
| Module | artifactId | Purpose |
|---|---|---|
| jts-core | jts-core |
★ Core — geometric model, algorithms, spatial operations, indexing |
| jts-io-common | jts-io-common |
General I/O: WKT, WKB, GeoJSON read/write |
| jts-io-ora | jts-io-ora |
Oracle Spatial SDO_GEOMETRY read/write |
| jts-io-sde | jts-io-sde |
ArcSDE geometry read/write |
Core class overview
| Class | Package | Purpose |
|---|---|---|
GeometryFactory |
org.locationtech.jts.geom |
★ Recommended entry point— factory for creating all geometric objects |
Geometry |
org.locationtech.jts.geom |
Abstract geometry base class, providing spatial operation and relationship determination methods |
Point |
org.locationtech.jts.geom |
Point (0-dimensional) |
LineString |
org.locationtech.jts.geom |
LineString (1-dimensional) |
LinearRing |
org.locationtech.jts.geom |
Closed LinearRing (used to construct Polygon) |
Polygon |
org.locationtech.jts.geom |
Polygon (2-dimensional, with an exterior ring and optional interior rings) |
MultiPoint |
org.locationtech.jts.geom |
MultiPoint collection |
MultiLineString |
org.locationtech.jts.geom |
MultiLineString collection |
MultiPolygon |
org.locationtech.jts.geom |
MultiPolygon collection |
GeometryCollection |
org.locationtech.jts.geom |
Arbitrary GeometryCollection |
Coordinate |
org.locationtech.jts.geom |
Coordinate values (x, y, z) |
Envelope |
org.locationtech.jts.geom |
Envelope (MBR) |
PrecisionModel |
org.locationtech.jts.geom |
Coordinate precision model |
WKTReader |
org.locationtech.jts.io |
WKT format parsing |
WKTWriter |
org.locationtech.jts.io |
WKT format output |
WKBReader |
org.locationtech.jts.io |
WKB format parsing |
WKBWriter |
org.locationtech.jts.io |
WKB format output |
GeoJsonReader |
org.locationtech.jts.io.geojson |
GeoJSON parsing |
GeoJsonWriter |
org.locationtech.jts.io.geojson |
GeoJSON output |
STRtree |
org.locationtech.jts.index.strtree |
R-tree spatial index (bulk-loaded, efficient queries) |
Quadtree |
org.locationtech.jts.index.quadtree |
Quadtree spatial index (supports dynamic insertion and deletion) |
PreparedGeometry |
org.locationtech.jts.geom.prep |
Prepared geometry, accelerating repeated spatial relationship determination |
PreparedGeometryFactory |
org.locationtech.jts.geom.prep |
Factory for creating PreparedGeometry |
BufferOp |
org.locationtech.jts.operation.buffer |
Buffer operation (fine-grained control over end cap and join styles) |
OverlayNGRobust |
org.locationtech.jts.operation.overlayng |
Robust overlay operation (recommended next-generation overlay engine) |
TopologyPreservingSimplifier |
org.locationtech.jts.simplify |
Topology-preserving geometry simplification |
DouglasPeuckerSimplifier |
org.locationtech.jts.simplify |
Douglas-Peucker geometry simplification |
IsValidOp |
org.locationtech.jts.operation.valid |
Geometry validity checking |
LengthIndexedLine |
org.locationtech.jts.linearref |
Linear referencing by length |
LocationIndexedLine |
org.locationtech.jts.linearref |
Linear referencing by position |
Geometry object creation
import org.locationtech.jts.geom.*;
GeometryFactory gf = new GeometryFactory();
// 点
Point point = gf.createPoint(new Coordinate(116.4, 39.9));
// 带 Z 值的点
Point point3d = gf.createPoint(new Coordinate(116.4, 39.9, 50.0));
// 线串
LineString line = gf.createLineString(new Coordinate[]{
new Coordinate(0, 0),
new Coordinate(10, 10),
new Coordinate(20, 0)
});
// 线环(必须闭合)
LinearRing ring = gf.createLinearRing(new Coordinate[]{
new Coordinate(0, 0), new Coordinate(10, 0),
new Coordinate(10, 10), new Coordinate(0, 10),
new Coordinate(0, 0) // 首尾相同
});
// 面(无洞)
Polygon polygon = gf.createPolygon(new Coordinate[]{
new Coordinate(0, 0), new Coordinate(10, 0),
new Coordinate(10, 10), new Coordinate(0, 10),
new Coordinate(0, 0)
});
// 面(带洞)
LinearRing shell = gf.createLinearRing(new Coordinate[]{
new Coordinate(0, 0), new Coordinate(20, 0),
new Coordinate(20, 20), new Coordinate(0, 20),
new Coordinate(0, 0)
});
LinearRing hole = gf.createLinearRing(new Coordinate[]{
new Coordinate(5, 5), new Coordinate(15, 5),
new Coordinate(15, 15), new Coordinate(5, 15),
new Coordinate(5, 5)
});
Polygon polygonWithHole = gf.createPolygon(shell, new LinearRing[]{hole});
// 多点
MultiPoint multiPoint = gf.createMultiPointFromCoords(new Coordinate[]{
new Coordinate(1, 2), new Coordinate(3, 4)
});
// 多线
MultiLineString multiLine = gf.createMultiLineString(new LineString[]{line});
// 多面
MultiPolygon multiPolygon = gf.createMultiPolygon(new Polygon[]{polygon});
// 几何集合
GeometryCollection gc = gf.createGeometryCollection(new Geometry[]{point, line, polygon});
Spatial relationship determination
// 八大空间谓词
boolean eq = geomA.equals(geomB); // 几何相等
boolean dj = geomA.disjoint(geomB); // 相离
boolean ix = geomA.intersects(geomB); // 相交
boolean tc = geomA.touches(geomB); // 接触
boolean cr = geomA.crosses(geomB); // 穿越
boolean wn = geomA.within(geomB); // A 在 B 内
boolean ct = geomA.contains(geomB); // A 包含 B
boolean ol = geomA.overlaps(geomB); // 重叠
// DE-9IM 关系矩阵
boolean rel = geomA.relate(geomB, "T*F**FFF*");
String matrix = geomA.relate(geomB).toString(); // 返回 "212101212" 等
// 距离判断
boolean near = geomA.isWithinDistance(geomB, 100.0);
Set operations
// 交集
Geometry intersection = geomA.intersection(geomB);
// 合并
Geometry union = geomA.union(geomB);
// 差集
Geometry difference = geomA.difference(geomB);
// 对称差
Geometry symDiff = geomA.symDifference(geomB);
// 缓冲区
Geometry buffer = geometry.buffer(10.0); // 默认圆弧端头
Geometry bufferFlat = geometry.buffer(10.0, 8, BufferOp.CAP_FLAT); // 平头端
// 多几何合并(高性能)
import org.locationtech.jts.operation.union.UnaryUnionOp;
Geometry merged = UnaryUnionOp.union(geometryCollection);
// 鲁棒叠加运算(推荐)
import org.locationtech.jts.operation.overlayng.OverlayNGRobust;
Geometry robustIntersection = OverlayNGRobust.overlay(geomA, geomB, OverlayNG.INTERSECTION);
Geometry robustUnion = OverlayNGRobust.overlay(geomA, geomB, OverlayNG.UNION);
Geometric analysis
// 面积与长度
double area = polygon.getArea();
double length = line.getLength();
// 距离
double dist = geomA.distance(geomB);
// 质心
Point centroid = geometry.getCentroid();
// 内部点(保证在几何内部)
Point interiorPoint = geometry.getInteriorPoint();
// 凸包
Geometry hull = geometry.convexHull();
// 外接矩形
Envelope env = geometry.getEnvelopeInternal();
// 有效性检测
boolean valid = geometry.isValid();
// 详细有效性诊断
import org.locationtech.jts.operation.valid.IsValidOp;
IsValidOp validator = new IsValidOp(geometry);
if (!validator.isValid()) {
System.out.println(validator.getValidationError());
}
// 几何修复
import org.locationtech.jts.geom.util.GeometryFixer;
Geometry fixed = GeometryFixer.fix(geometry);
Geometry simplification
import org.locationtech.jts.simplify.TopologyPreservingSimplifier;
import org.locationtech.jts.simplify.DouglasPeuckerSimplifier;
// 保持拓扑的简化(推荐)
Geometry simplified = TopologyPreservingSimplifier.simplify(geometry, 0.001);
// Douglas-Peucker 简化(更快,但可能产生自相交)
Geometry dpSimplified = DouglasPeuckerSimplifier.simplify(geometry, 0.001);
Precision model
// 浮点精度(默认)
PrecisionModel pmFloat = new PrecisionModel();
// 固定精度(如保留 6 位小数 → scale = 1000000)
PrecisionModel pmFixed = new PrecisionModel(1000000);
// 使用精度模型创建工厂
GeometryFactory gf = new GeometryFactory(pmFixed);
// 带 SRID 的工厂
GeometryFactory gfSrid = new GeometryFactory(pmFloat, 4326);
Format read/write
WKT(Well-Known Text)
import org.locationtech.jts.io.WKTReader;
import org.locationtech.jts.io.WKTWriter;
WKTReader reader = new WKTReader();
// 读取
Geometry point = reader.read("POINT (116.4 39.9)");
Geometry line = reader.read("LINESTRING (0 0, 10 10, 20 0)");
Geometry poly = reader.read("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))");
// 写入
WKTWriter writer = new WKTWriter();
String wkt = writer.write(point); // "POINT (116.4 39.9)"
// 3D WKT
WKTWriter writer3d = new WKTWriter(3);
String wkt3d = writer3d.write(gf.createPoint(new Coordinate(1, 2, 3)));
WKB(Well-Known Binary)
import org.locationtech.jts.io.WKBReader;
import org.locationtech.jts.io.WKBWriter;
// 写入
WKBWriter wkbWriter = new WKBWriter();
byte[] wkb = wkbWriter.write(geometry);
// 读取
WKBReader wkbReader = new WKBReader();
Geometry geom = wkbReader.read(wkb);
// 输出 Hex 字符串(常用于数据库交互)
String hex = WKBWriter.toHex(wkb);
byte[] fromHex = WKBReader.hexToBytes(hex);
GeoJSON
import org.locationtech.jts.io.geojson.GeoJsonReader;
import org.locationtech.jts.io.geojson.GeoJsonWriter;
// 读取
GeoJsonReader gjReader = new GeoJsonReader();
Geometry geom = gjReader.read("{\"type\":\"Point\",\"coordinates\":[116.4,39.9]}");
// 写入
GeoJsonWriter gjWriter = new GeoJsonWriter();
String json = gjWriter.write(geom);
Spatial indexing
STRtree (R-tree, recommended for bulk queries)
import org.locationtech.jts.index.strtree.STRtree;
STRtree index = new STRtree();
// 批量插入(插入后首次查询时自动构建索引)
for (Geometry geom : geometries) {
index.insert(geom.getEnvelopeInternal(), geom);
}
// 矩形范围查询
Envelope searchEnv = new Envelope(10, 20, 10, 20);
List<?> candidates = index.query(searchEnv);
// 最近邻查询
import org.locationtech.jts.index.strtree.ItemDistance;
Object nearest = index.nearestNeighbour(
point.getEnvelopeInternal(), point,
(ItemDistance) (itemBoundable1, itemBoundable2) -> {
Geometry g1 = (Geometry) itemBoundable1.getItem();
Geometry g2 = (Geometry) itemBoundable2.getItem();
return g1.distance(g2);
}
);
Quadtree (quadtree, supports dynamic insertion and deletion)
import org.locationtech.jts.index.quadtree.Quadtree;
Quadtree qtree = new Quadtree();
qtree.insert(geom.getEnvelopeInternal(), geom);
List<?> results = qtree.query(searchEnv);
qtree.remove(geom.getEnvelopeInternal(), geom);
PreparedGeometry (accelerates repeated tests)
When the same geometry needs to be repeatedly tested for spatial relationships (such as determining whether a large number of points are inside a polygon), use PreparedGeometry to significantly improve performance:
import org.locationtech.jts.geom.prep.PreparedGeometry;
import org.locationtech.jts.geom.prep.PreparedGeometryFactory;
PreparedGeometry prepared = PreparedGeometryFactory.prepare(polygon);
for (Point pt : points) {
if (prepared.contains(pt)) {
// 命中
}
}
Linear referencing
import org.locationtech.jts.linearref.LengthIndexedLine;
import org.locationtech.jts.linearref.LocationIndexedLine;
LengthIndexedLine lil = new LengthIndexedLine(line);
// 按长度获取坐标
Coordinate midPoint = lil.extractPoint(line.getLength() / 2);
// 截取子线
Geometry subLine = lil.extractLine(10.0, 50.0);
// 计算某点在线上的投影位置(距起点长度)
double index = lil.indexOf(new Coordinate(5, 5));
// 按位置引用
LocationIndexedLine locLine = new LocationIndexedLine(line);
Affine transformation
import org.locationtech.jts.geom.util.AffineTransformation;
// 平移
AffineTransformation translate = AffineTransformation.translationInstance(10, 20);
Geometry moved = translate.transform(geometry);
// 旋转(弧度,绕原点)
AffineTransformation rotate = AffineTransformation.rotationInstance(Math.PI / 4);
Geometry rotated = rotate.transform(geometry);
// 缩放
AffineTransformation scale = AffineTransformation.scaleInstance(2.0, 2.0);
Geometry scaled = scale.transform(geometry);
// 组合变换
AffineTransformation combo = new AffineTransformation();
combo.translate(10, 0);
combo.rotate(Math.PI / 6);
Geometry result = combo.transform(geometry);
Typical application scenarios
| Scenario | Key classes / methods |
|---|---|
| Create geometry objects | GeometryFactory.createPoint() / createLineString() / createPolygon() |
| Geofencing / point-in-polygon determination | Geometry.contains() / within(), for high-frequency scenarios use PreparedGeometry |
| Calculate the distance between two geometries | Geometry.distance() |
| Buffer analysis | Geometry.buffer() or BufferOp |
| Polygon overlay analysis (intersection, union, difference) | Geometry.intersection() / union() / difference() |
| Robust overlay operations | OverlayNGRobust.overlay() |
| Geometry format conversion | WKTReader / WKTWriter / WKBReader / WKBWriter / GeoJsonReader / GeoJsonWriter |
| Batch spatial query acceleration | STRtree / Quadtree |
| Nearest neighbor search | STRtree.nearestNeighbour() |
| Geometry simplification (thinning) | TopologyPreservingSimplifier / DouglasPeuckerSimplifier |
| Geometry validity checking and repair | IsValidOp / GeometryFixer |
| Linear referencing / locating along a line | LengthIndexedLine / LocationIndexedLine |
| Convex hull computation | Geometry.convexHull() |
| Geometry affine transformation | AffineTransformation |
| Database WKB interaction | WKBReader.hexToBytes() / WKBWriter.toHex() |
Common considerations
- Use GeometryFactory to create geometries: do not directly
new Point(), always create geometry objects throughGeometryFactory's factory methods. - Polygons must be closed: the first and last coordinates of the exterior ring and interior ring coordinate arrays of a Polygon must be the same.
- Coordinate order: JTS uses
(x, y), i.e.(经度, 纬度)order; be careful to distinguish it from the(纬度, 经度)of some GIS systems. - Geometry validity: externally imported geometry data should use
geometry.isValid()to check validity; invalid geometries can be repaired withGeometryFixer.fix(). - SRID does not participate in computation: JTS's SRID is only used as a metadata tag and does not affect spatial operations; all JTS computations are performed on the Cartesian plane and do not handle projections.
- Performance optimization: for batch spatial queries use
STRtree; for repeated spatial relationship determinations usePreparedGeometry; for merging large numbers of geometries useUnaryUnionOp。 - Thread safety:
GeometryFactoryis thread-safe;Geometryobjects themselves are immutable and can be shared safely; however, Reader/Writer instances are not thread-safe, and a separate instance must be created for each thread. - Package name migration: in JTS 1.15+ the package name migrated from
com.vividsolutions.jtstoorg.locationtech.jts; be careful when upgrading old code. - OverlayNG: for overlay operations (intersection / union / difference), it is recommended to use
OverlayNGRobust, which is more robust than the traditional overlay engine and can handle more edge cases.
Reference links
- GitHub repository: https://github.com/locationtech/jts
- Javadoc: https://locationtech.github.io/jts/javadoc
- User guide: https://github.com/locationtech/jts/blob/master/USING.md
- FAQ: https://locationtech.github.io/jts/jts-faq.html
- Maven Central: https://mvnrepository.com/artifact/org.locationtech.jts
- LocationTech homepage: https://locationtech.org/projects/technology.jts
- Version history: https://github.com/locationtech/jts/blob/master/doc/JTS_Version_History.md
- Derived project — GEOS (C++ port): https://trac.osgeo.org/geos
- Derived project — NetTopologySuite (.NET port): https://github.com/NetTopologySuite/NetTopologySuite
- Derived project — JSTS (JavaScript port): https://github.com/bjornharrtell/jsts