有没有办法在JTS中将自相交多边形转换为多面体? [英] Is there a way to convert a self intersecting polygon to a multipolygon in JTS?
问题描述
取无效多边形 POLYGON((0 100,100 100,0 0,100 0,0 100))
- 一个带有未声明交点的卵形定时器形状
许多指令都说JTS可以使用缓冲区
方法创建一个有效版本:
Geometry input = new WKTReader()。read(POLYGON((0 100,100 100,0 0,100 0,0 100)));
几何输出= geom.buffer(0);
返回输出;
然而,这会产生输出 POLYGON((0 100,100 100, 50 50,0 100))
其中部分多边形丢失:
有没有一种方法可以让JTS验证多边形,从而生成输出 MULTIPOLYGON(((0 100,100 100,50 50,0 100)),((0 0,100 0,50 50,0 0)))
输入给定?
这似乎是应该内置到API中的东西(也许这种行为是一个错误) - 我错过了什么?
< JTS似乎提供了我所需要的行为,尽管我必须在自己的工作中做一点运动码。我写的
validate
函数将一个polygon / multipolygon分解成一个非自相交的linestrings集合,然后使用 Polygonizer
类来从结果中构建多边形。我已经在以下(有限)输入集上测试了它,它似乎按照我的要求行事: POLYGON( ((0 0,0 100,100 100,100 0,0 0))
多元组(0(0 0,0 100,100 100,100 0,0 0))
多元组((0 0,50 50,100 0,100 100,100 0,0 0)),((50 50,50 150,150 150,150 50,50 50)))
POLYGON )
代码:
/ **
*获取/创建给定几何的有效版本。如果几何图形是多边形或多边形,则自相交/
*不一致性是固定的。否则,返回几何图形。
*
* @param geom
* @return几何
* /
public static几何验证(Geometry几何){
if(geom instanceof Polygon ){
if(geom.isValid()){
geom.normalize(); //验证不会以错误的顺序拾取戒指 - 这将修复
返回几何; //如果多边形是有效的,只需返回它
}
Polygonizer polygonizer = new Polygonizer();
addPolygon((Polygon)geom,polygonizer);
返回到PolygonGeometry(polygonizer.getPolygons(),geom.getFactory());
} else if(geom instanceof MultiPolygon){
if(geom.isValid()){
geom.normalize(); //验证不会以错误的顺序拾取戒指 - 这将修复
返回几何; //如果多边形是有效的,只需返回它
}
Polygonizer polygonizer = new Polygonizer();
for(int n = geom.getNumGeometries(); n--> 0;){
addPolygon((Polygon)geom.getGeometryN(n),polygonizer);
}
返回到PolygonGeometry(polygonizer.getPolygons(),geom.getFactory());
} else {
return geom; //在我的情况下,我只关心多边形/多面几何
}
}
$ b $ / **
*从给定的多边形中添加所有行字符串polygonizer给定
*
* @param多边形多边形从中提取线串
* @param polygonizer polygonizer
* /
static void addPolygon(多边形多边形,Polygonizer多边形){
addLineString(polygon.getExteriorRing(),polygonizer);
for(int n = polygon.getNumInteriorRing(); n--> 0;){
addLineString(polygon.getInteriorRingN(n),polygonizer);
$ b $ **
*添加给线框的线串
*
* @param线串线串
* @param polygonizer polygonizer
* /
static void addLineString(LineString lineString,Polygonizer polygonizer){
if(lineString instanceof LinearRing){// LinearRings的处理方式与行字符串:我们需要一个LineString而不是一个LinearRing
lineString = lineString.getFactory()。createLineString(lineString.getCoordinateSequence());
}
//将线串与点联合使得明确任何自相交。
Point point = lineString.getFactory()。createPoint(lineString.getCoordinateN(0));
Geometry toAdd = lineString.union(point);
//向polygonizer添加结果
polygonizer.add(toAdd);
}
/ **
*从多边形集合中获取几何图形。
*
* @param多边形集合
* @param工厂工厂在需要时生成MultiPolygon
*返回null如果没有多边形,多边形如果只有一个,或者包含所有多边形的MultiPolygon,否则
* /
static Geometry toPolygonGeometry(Collection< Polygon> polygons,GeometryFactory factory){
switch(polygons.size()){
case 0 :
返回null; //没有有效的多边形!
案例1:
return polygons.iterator()。next(); //单个多边形 - 不需要包装
默认值:
//多边形可能仍然重叠!需要sym区别它们
Iterator< Polygon> iter = polygons.iterator();
Geometry ret = iter.next(); (iter.hasNext()){
ret = ret.symDifference(iter.next());
}
return ret;
}
}
Take the invalid polygon POLYGON((0 100, 100 100, 0 0, 100 0, 0 100))
- an egg timer shape with an undeclared point of intersection
Many instructions say that JTS can create a valid version of this using the buffer
method:
Geometry input = new WKTReader().read("POLYGON((0 100, 100 100, 0 0, 100 0, 0 100))");
Geometry output = geom.buffer(0);
return output;
However, this produces the output POLYGON ((0 100, 100 100, 50 50, 0 100))
where part of the polygon is lost:
Is there a way to get JTS to validate polygons such that it will produce the output MULTIPOLYGON(((0 100, 100 100, 50 50, 0 100)), ((0 0, 100 0, 50 50, 0 0)))
for the input given?
This seems like something that should be built in to the API (maybe this behaviour is a bug) - have I missed something?
Thank you.
JTS seems to offer the behaviour I require, though I had to do a little legwork in my own code. The validate
function I wrote breaks down a polygon/multipolygon into a collection of non self intersecting linestrings, and then uses the Polygonizer
class to build polygons from the result. I have tested it on the following (limited) set of inputs, and it seems to behave the way I require:
POLYGON((0 100, 100 100, 0 0, 100 0, 0 100))
POLYGON((0 0, 0 100, 100 100, 100 0, 0 0))
MULTIPOLYGON(((0 0, 0 100, 100 100, 100 0, 0 0)),((50 50, 50 150, 150 150, 150 50, 50 50)))
POLYGON((0 0, 50 50, 100 0, 150 0, 200 50, 250 0, 0 0))
Code:
/**
* Get / create a valid version of the geometry given. If the geometry is a polygon or multi polygon, self intersections /
* inconsistencies are fixed. Otherwise the geometry is returned.
*
* @param geom
* @return a geometry
*/
public static Geometry validate(Geometry geom){
if(geom instanceof Polygon){
if(geom.isValid()){
geom.normalize(); // validate does not pick up rings in the wrong order - this will fix that
return geom; // If the polygon is valid just return it
}
Polygonizer polygonizer = new Polygonizer();
addPolygon((Polygon)geom, polygonizer);
return toPolygonGeometry(polygonizer.getPolygons(), geom.getFactory());
}else if(geom instanceof MultiPolygon){
if(geom.isValid()){
geom.normalize(); // validate does not pick up rings in the wrong order - this will fix that
return geom; // If the multipolygon is valid just return it
}
Polygonizer polygonizer = new Polygonizer();
for(int n = geom.getNumGeometries(); n-- > 0;){
addPolygon((Polygon)geom.getGeometryN(n), polygonizer);
}
return toPolygonGeometry(polygonizer.getPolygons(), geom.getFactory());
}else{
return geom; // In my case, I only care about polygon / multipolygon geometries
}
}
/**
* Add all line strings from the polygon given to the polygonizer given
*
* @param polygon polygon from which to extract line strings
* @param polygonizer polygonizer
*/
static void addPolygon(Polygon polygon, Polygonizer polygonizer){
addLineString(polygon.getExteriorRing(), polygonizer);
for(int n = polygon.getNumInteriorRing(); n-- > 0;){
addLineString(polygon.getInteriorRingN(n), polygonizer);
}
}
/**
* Add the linestring given to the polygonizer
*
* @param linestring line string
* @param polygonizer polygonizer
*/
static void addLineString(LineString lineString, Polygonizer polygonizer){
if(lineString instanceof LinearRing){ // LinearRings are treated differently to line strings : we need a LineString NOT a LinearRing
lineString = lineString.getFactory().createLineString(lineString.getCoordinateSequence());
}
// unioning the linestring with the point makes any self intersections explicit.
Point point = lineString.getFactory().createPoint(lineString.getCoordinateN(0));
Geometry toAdd = lineString.union(point);
//Add result to polygonizer
polygonizer.add(toAdd);
}
/**
* Get a geometry from a collection of polygons.
*
* @param polygons collection
* @param factory factory to generate MultiPolygon if required
* @return null if there were no polygons, the polygon if there was only one, or a MultiPolygon containing all polygons otherwise
*/
static Geometry toPolygonGeometry(Collection<Polygon> polygons, GeometryFactory factory){
switch(polygons.size()){
case 0:
return null; // No valid polygons!
case 1:
return polygons.iterator().next(); // single polygon - no need to wrap
default:
//polygons may still overlap! Need to sym difference them
Iterator<Polygon> iter = polygons.iterator();
Geometry ret = iter.next();
while(iter.hasNext()){
ret = ret.symDifference(iter.next());
}
return ret;
}
}
这篇关于有没有办法在JTS中将自相交多边形转换为多面体?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!