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