NetTopologySuite 工具类
1 using System.Threading; 2 using System.Collections.Generic; 3 using GeoAPI.Geometries; 4 using NetTopologySuite.Geometries; 5 using NetTopologySuite.Operation.Polygonize; 6 using System.Linq; 7 8 namespace Test.Workspace 9 { 10 public static class NTSExpend 11 { 12 public static IGeometry Validate(this IGeometry geometry) => NTSUtils.Instance.Validate(geometry); 13 } 14 public class NTSUtils 15 { 16 private static NTSUtils _this = null; 17 private static object lockObj = new object(); 18 19 /// <summary> 20 /// 单例创建对象 21 /// </summary> 22 /// <returns></returns> 23 public static NTSUtils Instance 24 { 25 get 26 { 27 if (_this == null) 28 { 29 lock (lockObj) 30 { 31 if (_this == null) 32 _this = new NTSUtils(); 33 return _this; 34 } 35 } 36 else 37 return _this; 38 } 39 } 40 41 /// <summary> 42 /// 处理图形自相交 43 /// </summary> 44 /// <returns></returns> 45 public IGeometry Validate(IGeometry geometry) 46 { 47 Polygonizer polygonizer = null; 48 if (geometry is Polygon) 49 { 50 if (geometry.IsValid) 51 { 52 geometry.Normalize(); 53 return geometry; 54 } 55 polygonizer = new Polygonizer(); 56 57 AddPolygon((Polygon)geometry, polygonizer); 58 } 59 else if (geometry is MultiPolygon) 60 { 61 if (geometry.IsValid) 62 { 63 geometry.Normalize(); 64 return geometry; 65 } 66 polygonizer = new Polygonizer(); 67 for (int n = geometry.NumGeometries; n-- > 0;) 68 { 69 AddPolygon((Polygon)geometry.GetGeometryN(n), polygonizer); 70 } 71 } 72 else if (geometry is GeometryCollection) 73 { 74 if (geometry.IsValid) 75 { 76 geometry.Normalize(); 77 return geometry; 78 } 79 polygonizer = new Polygonizer(); 80 for (int n = geometry.NumGeometries; n-- > 0;) 81 { 82 IGeometry temp = geometry.GetGeometryN(n); 83 if (temp is Polygon) 84 { 85 AddPolygon((Polygon)temp, polygonizer); 86 } 87 else if (temp is MultiPolygon) 88 { 89 for (int m = temp.NumGeometries; m-- > 0;) 90 { 91 AddPolygon((Polygon)temp.GetGeometryN(m), polygonizer); 92 } 93 } 94 } 95 } 96 else 97 return geometry; 98 99 return ToPolygonGeometry(polygonizer.GetPolygons(), geometry.Factory); 100 } 101 102 void AddPolygon(Polygon polygon, Polygonizer polygonizer) 103 { 104 AddLineString(polygon.ExteriorRing, polygonizer); 105 for (int n = polygon.NumInteriorRings; n-- > 0;) 106 { 107 AddLineString(polygon.GetInteriorRingN(n), polygonizer); 108 } 109 } 110 111 void AddLineString(ILineString lineString, Polygonizer polygonizer) 112 { 113 114 if (lineString is LinearRing) 115 { // LinearRings are treated differently to line strings : we need a LineString NOT a LinearRing 116 lineString = lineString.Factory.CreateLineString(lineString.CoordinateSequence); 117 } 118 119 // unioning the linestring with the point makes any self intersections explicit. 120 121 IPoint point = lineString.Factory.CreatePoint(lineString.GetCoordinateN(0)); 122 IGeometry toAdd = lineString.Union(point); 123 124 //Add result to polygonizer 125 polygonizer.Add(toAdd); 126 } 127 128 /** 129 * Get a geometry from a collection of polygons. 130 * 131 * @param polygons collection 132 * @param factory factory to generate MultiPolygon if required 133 * @return null if there were no polygons, the polygon if there was only one, or a MultiPolygon containing all polygons otherwise 134 */ 135 IGeometry ToPolygonGeometry(ICollection<IGeometry> polygons, IGeometryFactory factory)// geoSource.factory 可以创建多边形 136 { 137 switch (polygons.Count()) 138 { 139 case 0: 140 return null; // No valid polygons! 141 case 1: 142 return polygons.FirstOrDefault(); // single polygon - no need to wrap 143 default: 144 //polygons may still overlap! Need to sym difference them 145 List<IGeometry> ps = polygons.ToList(); 146 double maxArea = ps.Select(x => x.Envelope.Area).Max(); 147 IGeometry geometry = ps.FirstOrDefault(x => x.Envelope.Area == maxArea); 148 IGeometry result = geometry; 149 for (int i = 0; i < ps.Count; i++) 150 { 151 IGeometry currentGeo = ps[i]; 152 153 //string testStr = currentGeo.ToString(); 154 //string res = GdalShapeOperate.Instance.GetPoints(OSGeo.OGR.Ogr.CreateGeometryFromWkt(ref testStr, null)); 155 if (currentGeo == null || currentGeo.Equals(geometry)) 156 continue; 157 158 //1. 判断当前图形是否是多环图形 159 160 //Covers 优于 Contains 161 // symDifference 并集去掉重合部分 162 IPolygon p = result as IPolygon; 163 if (p?.NumInteriorRings > 0) 164 { 165 //多环的话 需要把内部空环依次和当前图形比对 判断是否是重叠 (重叠取diff) 166 Polygonizer polygonizer = new Polygonizer(); 167 for (int n = p.NumInteriorRings; n-- > 0;) 168 { 169 AddLineString(p.GetInteriorRingN(n), polygonizer); 170 } 171 List<IGeometry> interPolygons = polygonizer.GetPolygons().ToList(); 172 //内环存在的话 需要和当前图形比对 如果基本匹配(重合面积>90) 取差集 173 if (interPolygons.Count > 0) 174 { 175 bool isIntersect = false; 176 foreach (var item in interPolygons) 177 { 178 if (item.Intersects(currentGeo) && item.Intersection(currentGeo).Area / currentGeo.Area > 0.9) 179 { 180 isIntersect = true; 181 break; 182 } 183 } 184 if (isIntersect) 185 { 186 result = result.Difference(currentGeo); 187 continue; 188 } 189 } 190 } 191 192 //不是多环图形, 如果重叠 且重叠面积>当前图形面积的90%则 交集, 否则并集 193 if (geometry.Intersects(currentGeo) && geometry.Intersection(currentGeo).Area / currentGeo.Area > 0.9) 194 result = result.Difference(currentGeo); 195 else 196 result = result.Union(currentGeo); 197 198 } 199 return result; 200 } 201 } 202 203 /// <summary> 204 /// wkt转geometry 205 /// </summary> 206 /// <param name="wkt"></param> 207 /// <returns></returns> 208 public IGeometry WktToGeometry(string wkt) 209 { 210 NetTopologySuite.IO.WKTReader reader = new NetTopologySuite.IO.WKTReader(); 211 IGeometry geo = reader.Read(wkt); 212 return geo; 213 } 214 215 /// <summary> 216 /// rings 转 geometry 217 /// </summary> 218 /// <param name="rings"></param> 219 /// <returns></returns> 220 public IGeometry RingsToGeometry(string rings) 221 { 222 OSGeo.OGR.Geometry geometry = GdalShapeOperate.Instance.GetGeometryFromShapeJson(rings); 223 224 string wkt = string.Empty; 225 while (wkt == string.Empty) 226 { 227 wkt = GdalShapeOperate.Instance.ExportToWkt(geometry); 228 Thread.Sleep(50); 229 } 230 return WktToGeometry(wkt); 231 } 232 233 public string WktToRings(string wkt) => GdalShapeOperate.Instance.GetPoints(OSGeo.OGR.Geometry.CreateFromWkt(wkt)); 234 235 public string GeometryToRings(Geometry geo) => GdalShapeOperate.Instance.GetPoints(OSGeo.OGR.Geometry.CreateFromWkt(geo.ToString())); 236 } 237 }