JTS 求几何质心,外包矩形
前言
在 GIS 开发中,常常会用到求几何对象的外包矩形,求中心点,求质心等等,今天我让AI写了一些求质心的方法,可以看看,当作参考,最终实际使用个人的建议是:如果只是求质心,并且要使其在内部,那么用geometry.getInteriorPoint()就可以了
接下来一起看看AI分析了哪些东西(二,三,四,六,七里的方法是AI给的):
用到的Maven依赖
<dependency><groupId>org.locationtech.jts</groupId><artifactId>jts-core</artifactId><version>1.19.0</version></dependency>一、JTS 原生质心(基准方案)
publicstaticPointjtsCentroid(Geometrygeometry){if(geometry==null||geometry.isEmpty()){returnnull;}returngeometry.getCentroid();}特点:
- ✅ 简单、稳定、性能好
- ✅ 对任意 Geometry 类型都可用
- ❌ 对 MultiPolygon / 碎面不友好
- ❌ 凹多边形可能落在外部
适合场景:单 Polygon、数据预览、快速计算
其实个人认为这个方法基本能覆盖大部分情况了,如果图省事的话其实是能直接用的,或者用我前言里说的geometry.getInteriorPoint()
二、MultiPolygon:按面积加权质心
当 MultiPolygon 中存在多个面时,更合理的做法是按面积加权平均:
Cx = ∑(Ai × xi) / ∑Ai Cy = ∑(Ai × yi) / ∑Ai
publicstaticPointweightedCentroidByArea(MultiPolygonmp){doubletotalArea=0.0,cx=0.0,cy=0.0;for(inti=0;i<mp.getNumGeometries();i++){Polygonp=(Polygon)mp.getGeometryN(i);doublearea=p.getArea();Pointc=p.getCentroid();cx+=c.getX()*area;cy+=c.getY()*area;totalArea+=area;}returngeometryFactory.createPoint(newCoordinate(cx/totalArea,cy/totalArea));}- ✅ 优点:比原生质心更符合"整体重心"直觉
- ❌ 缺点:仍会被极小碎面轻微影响
三、忽略极小面的加权质心
在很多业务数据中,MultiPolygon 常伴随大量噪声碎面(如总面积 1% 以内的微面),对质心计算引入了不必要的干扰。
publicstaticPointweightedCentroidIgnoreSmall(MultiPolygonmp,doubleminAreaRatio){doubletotalArea=mp.getArea();doubleusedArea=0.0,cx=0.0,cy=0.0;for(inti=0;i<mp.getNumGeometries();i++){Polygonp=(Polygon)mp.getGeometryN(i);doublearea=p.getArea();if(area/totalArea<minAreaRatio)continue;Pointc=p.getCentroid();cx+=c.getX()*area;cy+=c.getY()*area;usedArea+=area;}returngeometryFactory.createPoint(newCoordinate(cx/usedArea,cy/usedArea));}经验值:minAreaRatio = 0.01(忽略小于总面积 1% 的面)
工程实践中最常用、最稳健的方案
四、仅取最大面的质心(极端简化)
publicstaticPointlargestPolygonCentroid(MultiPolygonmp){Polygonlargest=null;doublemaxArea=0.0;for(inti=0;i<mp.getNumGeometries();i++){Polygonp=(Polygon)mp.getGeometryN(i);doublearea=p.getArea();if(area>maxArea){maxArea=area;largest=p;}}returnlargest==null?null:largest.getCentroid();}- ✅ 优点:极度稳定,不受碎面干扰
- ❌ 缺点:完全忽略次要面
适合场景:行政区划、地块主区域标注
五、凹多边形:质心 vs 内部点
凹多边形的质心可能落在图形外部,这在做点标注时是个严重问题。JTS 提供了另一个方法:
publicstaticPointinteriorPoint(Geometrygeometry){returngeometry.getInteriorPoint();}对比:
| 方法 | 是否一定在内 | 稳定性 |
|---|---|---|
getCentroid() | ❌ | 高 |
getInteriorPoint() | ✅ | 中 |
💡 标注点 / 名称显示优先用
interiorPoint
六、MultiLineString:按长度加权质心
线要素没有"面积",应使用长度加权:
publicstaticPointweightedCentroidByLength(MultiLineStringmls){doubletotalLen=0.0,cx=0.0,cy=0.0;for(inti=0;i<mls.getNumGeometries();i++){LineStringls=(LineString)mls.getGeometryN(i);doublelen=ls.getLength();Pointc=ls.getCentroid();cx+=c.getX()*len;cy+=c.getY()*len;totalLen+=len;}returngeometryFactory.createPoint(newCoordinate(cx/totalLen,cy/totalLen));}适合场景:道路网、管线、河流中心线
七、自定义权重质心(通用解法)
当不同几何对象本身就有业务权重(如人口、产值):
publicstaticPointcustomWeightedCentroid(Geometry[]geometries,double[]weights){doublewx=0.0,wy=0.0,totalWeight=0.0;for(inti=0;i<geometries.length;i++){Pointc=geometries[i].getCentroid();doublew=weights[i];wx+=c.getX()*w;wy+=c.getY()*w;totalWeight+=w;}returngeometryFactory.createPoint(newCoordinate(wx/totalWeight,wy/totalWeight));}这是最通用的质心抽象模型 ✅
八、外包矩形
// 外包矩形publicstaticGeometryboundingBox(Geometrygeometry){Envelopeenv=geometry.getEnvelopeInternal();returngeometryFactory.toGeometry(env);}这个没什么好说,比较常规了
总结
| 场景 | 推荐方法 |
|---|---|
| 单 Polygon | getCentroid() |
| MultiPolygon(通用) | weightedCentroidIgnoreSmall()✅ |
| 强抗噪需求 | largestPolygonCentroid() |
| 凹多边形标注 | getInteriorPoint() |
| 线要素 | weightedCentroidByLength() |
| 业务加权 | customWeightedCentroid() |
| 使结果在内部一般使用 | getInteriorPoint() |
有试了下AI给的几个方法,个人觉得都一般,不如jts的getCentroid和getInteriorPoint,实际生产使用,建议还是用这两个,除非说计算和实际业务有关联,这种情况就要自己写方法了。
