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);}

这个没什么好说,比较常规了

总结

场景推荐方法
单 PolygongetCentroid()
MultiPolygon(通用)weightedCentroidIgnoreSmall()
强抗噪需求largestPolygonCentroid()
凹多边形标注getInteriorPoint()
线要素weightedCentroidByLength()
业务加权customWeightedCentroid()
使结果在内部一般使用getInteriorPoint()

有试了下AI给的几个方法,个人觉得都一般,不如jts的getCentroid和getInteriorPoint,实际生产使用,建议还是用这两个,除非说计算和实际业务有关联,这种情况就要自己写方法了。