工作中经常需要处理一些狭长的弯曲图形,但这个“狭长”怎么定义呢,我们就想到通过计算多边形的最大外切圆直径与最小可穿过圆的直径比,如果比值在判识指标之下就认为是需要忽略掉的狭长图形。
已下面图形为例,计算它的最小可穿过圆的直径(一个比较low的方法^ _ ^)。
第一步 继续多边形的最小外切矩形 得到多边形的第一个相交线
第二步 使用上一步的相交线,将多边形进行切分,分别计算每个子多边形的相交线长度
如果第一步的相交线第二部的相交线,就不用再继续递归执行了,如果第二步的大,则需要继续递归。知道满足条件。(其实上面的图形,到这一步我们已经找到最小可穿过圆的直径了)
!!!下面就让程序去执行吧!!!
import com.vividsolutions.jts.algorithm.MinimumDiameter;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.geom.util.LineStringExtracter;
import com.vividsolutions.jts.operation.polygonize.Polygonizer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class PolygonUtils {
/**
* 计算能让多边形通过的最小外接圆的直径
* @param geometry 多边形
* @param maxLine 已经判断出来的最大直径,初始传入null
* @return 计算后的多边形最大腰围直径
*/
public static double getMaxDiameter(Geometry geometry, Double maxLine){
//1.生成最小外接矩形面
MinimumDiameter minimumDiameter = new MinimumDiameter(geometry);
//2.得到外接矩形的最小直径
LineString diameter = minimumDiameter.getDiameter();
//3.获取面与直径的相交线
Geometry line = geometry.intersection(diameter);
//4.计算相交线的长度
if(maxLine==null || line.getLength()>maxLine){
maxLine=line.getLength();
}else {
return maxLine;
}
//使用相交线对面进行拆分,得到多个拆分后的小面
Geometry geometry1 = splitPolygon((Polygon) geometry, diameter);
//遍历拆分后的每个子面,递归判断子面的最大腰围
for (int i = 0; i < geometry1.getNumGeometries(); i++) {
Geometry tempPoly=geometry1.getGeometryN(i);
if(!(tempPoly instanceof Polygon)){
continue;
}
//递归,对每个小面计算最大腰围直径
maxLine=getMaxDiameter(tempPoly,maxLine);
}
return maxLine;
}
/**
* 使用线拆分面,得到所有拆分后的面
* @param polygon 需要被拆分的面
* @param line 线
* @return 拆分后的多面集合
*/
public static Geometry splitPolygon(Polygon polygon,LineString line){
Geometry nodedLinework = polygon.getBoundary().union(line);
Geometry polys = polygonize(nodedLinework);
// Only keep polygons which are inside the input
List<Polygon> output = new ArrayList<Polygon>();
for (int i = 0; i < polys.getNumGeometries(); i++) {
Polygon candpoly = (Polygon) polys.getGeometryN(i);
// use interior point to test for inclusion in parent
if (polygon.contains(candpoly.getInteriorPoint())) {
output.add(candpoly);
}
}
return polygon.getFactory().createGeometryCollection(GeometryFactory.toGeometryArray(output));
}
/**
* 复杂线多边形化
*
* @param geometry
* @return 转化后的多边形
*/
public static Geometry polygonize(Geometry geometry) {
//多线转集合线
List lines = LineStringExtracter.getLines(geometry);
Polygonizer polygonizer = new Polygonizer();
polygonizer.add(lines);
//线转面集合
Collection polys = polygonizer.getPolygons();
Polygon[] polyArray = GeometryFactory.toPolygonArray(polys);
return geometry.getFactory().createGeometryCollection(polyArray);
}
public static void main(String[] args) {
Geometry geometry=JTSNewUtil.geometry("POLYGON ((100 160, 250 320, 270 260, 460 410, 440 250, 560 320, 810 20, 705 114, 550 20, 567 205, 500 170, 389 245, 415 333, 270 190, 100 160))");
double maxDiameter = getMaxDiameter(geometry, null);
System.out.println(maxDiameter);
}
}