using System; using System.Collections.Generic; using System.Linq; using System.Text; using ESRI.ArcGIS.Geometry; using ESRI.ArcGIS.Geodatabase; using OSGeo.OGR; namespace Kingo.RuleCheck.CheckHelper { /// /// 几何操作类 /// public class GeometryOperations { /// /// 判断面是否自相交 /// /// 图形 /// true 不相交,false 相交 public static bool RuleTopoSingleCheckerIPolygon(IGeometry pgeo) { ITopologicalOperator3 topoOp3 = pgeo as ITopologicalOperator3;//Must be polygon topoOp3.IsKnownSimple_2 = false; //pTopoErrors = topoOp3.GetTopologyErrors(); bool eanpBool = topoOp3.IsSimple; return eanpBool; } /// /// 合并满足指定条件查询的所有图形,返回合并后图形 /// /// 要素类 /// 查询过滤器,IQueryFilter对象 /// 返回合并后的几何图形 public static IGeometry CreateGeometryFromEnumerator(IFeatureClass featureClass, IQueryFilter filter) { IEnumGeometry pEnumGeom = new EnumFeatureGeometry(); IEnumGeometryBind pEnumGeomBind = pEnumGeom as IEnumGeometryBind; IGeometryFactory pGeomFactory = new GeometryEnvironment() as IGeometryFactory; pEnumGeomBind.BindGeometrySource(filter, featureClass); if (pEnumGeom == null) return null; IGeometry pGeo = pGeomFactory.CreateGeometryFromEnumerator(pEnumGeom); return pGeo; } /// /// 获取要素合并区域 /// /// /// /// public static IGeometry GetFeatureUnionZoom(IList listFeature) { IGeometry m_unionGeo = null; if (m_unionGeo == null && listFeature != null && listFeature.Count != 0) { if (listFeature[0].ShapeCopy == null || listFeature[0].ShapeCopy.IsEmpty) { return m_unionGeo; } IGeometry pGeo = listFeature[0].ShapeCopy; ITopologicalOperator pTopo = pGeo as ITopologicalOperator; for (int i = 1; i <= listFeature.Count - 1; i++) { pGeo = pTopo.Union(listFeature[i].ShapeCopy); pTopo = pGeo as ITopologicalOperator; } pGeo.SpatialReference = listFeature[0].Shape.SpatialReference; m_unionGeo = pGeo; } return m_unionGeo; } /// /// 获取面状要素边界缓冲区融合区域 /// /// 要素集 /// 缓冲设置 /// /// public static IGeometry GetFeatureBoundaryUnionZoom(IList listFeature, double pBuffer) { IGeometry m_unionGeo = null; if (m_unionGeo == null && listFeature != null && listFeature.Count != 0) { IGeometry pGeo = GetFeatureBoundary(listFeature[0], pBuffer); if (pGeo == null) return m_unionGeo; IGeometry pGeoCurrent = null; ITopologicalOperator pTopo = pGeo as ITopologicalOperator; for (int i = 1; i <= listFeature.Count - 1; i++) { pGeoCurrent = GetFeatureBoundary(listFeature[i], pBuffer); if (pGeoCurrent == null) return m_unionGeo; pGeo = pTopo.Union(pGeoCurrent); pTopo = pGeo as ITopologicalOperator; } pGeo.SpatialReference = listFeature[0].Shape.SpatialReference; m_unionGeo = pGeo; } return m_unionGeo; } /// /// 获取面状要素边界缓冲区域 /// /// /// /// /// public static IGeometry GetFeatureBoundary(IFeature pFeature, double pBuffer) { IGeometry pGeo = pFeature.ShapeCopy; if (pGeo == null) return null; if (pGeo.GeometryType == esriGeometryType.esriGeometryPolygon) { ITopologicalOperator pTopo = pGeo as ITopologicalOperator; return GetBuffer(pTopo.Boundary, pBuffer); } return null; } /// /// 创建面要素(单个面要素) /// /// /// /// /// public static IGeometry CreatePolygonFeatures(IPointArray pPointArray, ISpatialReference pSpatialReference = null) { IPointArray pValidPointArray = new PointArrayClass(); //判断构造面的点是否超出数据集空间域 for (int iIndex = 0; iIndex <= pPointArray.Count - 1; iIndex++) { if (pSpatialReference == null) { IPoint pTempPoint = pPointArray.Element[iIndex]; pValidPointArray.Add(pTempPoint); } else { if (ValidateXYDomain(pPointArray.Element[iIndex], pSpatialReference)) { IPoint pTempPoint = pPointArray.Element[iIndex]; pValidPointArray.Add(pTempPoint); } } } //若有超出数据集空间域的点,则不执行导入 if (pPointArray.Count != pValidPointArray.Count) { return null; } else { //由文本文件中的点构造出单个面要素并导入 //此处构造的面要素只考虑单个ring组成的polygon,还存在多个ring和岛环的情况 IPointCollection pPolygon = new PolygonClass(); for (int iIndex = 0; iIndex <= pValidPointArray.Count - 1; iIndex++) { object Missing1 = Type.Missing; object Missing2 = Type.Missing; pPolygon.AddPoint(pValidPointArray.Element[iIndex], ref Missing1, ref Missing2); } pPolygon.AddPoint(pValidPointArray.Element[0]); return pPolygon as IPolygon; } } /// /// 创建线要素(单个线要素) /// /// /// /// public static IGeometry CreatePolyLineFeatures(IPointArray pPointArray, ISpatialReference pSpatialReference = null) { IPointArray pValidPointArray = new PointArrayClass(); //判断构造线的点是否超出数据集空间域 for (int iIndex = 0; iIndex <= pPointArray.Count - 1; iIndex++) { if (pSpatialReference == null) { IPoint pTempPoint = pPointArray.Element[iIndex]; pValidPointArray.Add(pTempPoint); } else { if (ValidateXYDomain(pPointArray.Element[iIndex], pSpatialReference)) { IPoint pTempPoint = pPointArray.Element[iIndex]; pValidPointArray.Add(pTempPoint); } } } //若有超出数据集空间域的点,则不执行导入 if (pPointArray.Count != pValidPointArray.Count) { return null; } else { //由文本文件中的点构造出单个线要素并导入 IPointCollection pPolyline = new PolylineClass(); for (int iIndex = 0; iIndex <= pValidPointArray.Count - 1; iIndex++) { object Missing1 = Type.Missing; object Missing2 = Type.Missing; pPolyline.AddPoint(pValidPointArray.Element[iIndex], ref Missing1, ref Missing2); } return pPolyline as IGeometry; } } /// /// 验证几何图形坐标是否超出数据集空间域 /// /// 几何图形 /// /// private static bool ValidateXYDomain(IGeometry pGeo, ISpatialReference pSpatialReference) { double dXMin, dXMax, dYMin, dYMax; pSpatialReference.GetDomain(out dXMin, out dXMax, out dYMin, out dYMax); if (pGeo.Envelope.XMin >= dXMin && pGeo.Envelope.YMin >= dYMin && pGeo.Envelope.XMax <= dXMax && pGeo.Envelope.YMax <= dYMax) { return true; } return false; } /// /// 获取缓冲值 /// /// 缓冲要素 /// 缓冲值(可选) /// public static IGeometry GetBuffer(IGeometry curGeo, Double bufferValue) { if (bufferValue == 0) return curGeo; IBufferConstruction pBufferConstrucion = new BufferConstruction(); IGeometry pBuffer = null; for (Double dValue = bufferValue; dValue < bufferValue + 0.3; dValue = dValue + 0.01) { try { pBuffer = pBufferConstrucion.Buffer(curGeo, dValue); System.Runtime.InteropServices.Marshal.ReleaseComObject(pBufferConstrucion); return pBuffer; } catch (Exception ex) { Console.WriteLine(ex.ToString()); } } return curGeo; } /// /// 根据宽度计算角平分线上的点(三点确定一个角) /// /// 第一个点 /// 第二个点 /// 第三个点 /// 宽度 /// 角平分线上的点 public static IPoint getParallelPoint(IPoint p0, IPoint p1, IPoint p2, double distance) { var y12 = p2.Y - p1.Y; var x12 = p2.X - p1.X; var y01 = p1.Y - p0.Y; var x01 = p1.X - p0.X; double a, b; if (x12 == 0) { a = Math.PI / 2; if (y12 < 0) a = -a; } else { a = Math.Atan(y12 / x12); } if (x01 == 0) { b = Math.PI / 2; if (y01 < 0) b = -b; } else { b = Math.Atan(y01 / x01); } // 关键核心处 if (p2.X < p1.X) { a += Math.PI; } if (p1.X < p0.X) { b += Math.PI; } var k = (b - a - Math.PI) / 2; var r = a + k; var d = distance / Math.Sin(k); var sinr = Math.Sin(r); var cosr = Math.Cos(r); var d_lat = p1.Y + d * sinr; var d_lng = p1.X + d * cosr; return new PointClass() { X = d_lng, Y = d_lat }; } /// /// 已知点A,根据B点据A点的距离,和方位,求B点的坐标 /// /// 已知点A /// B点到A点的距离 /// B点相对于A点的方位角度 /// B点的坐标 public static IPoint GetPoint(IPoint A, double distance, double angle) { //int nCoordSystem = GetCoordSystem(); IPoint point = null; //if (A.X <= 180 && A.Y <= 90) //白明雅 2018-12-19 if (A.X <= distance && A.Y <= distance) { //LongLat ll1 = LongLatHelper.GetLongLat(new LongLat(A.X, A.Y), distance, angle); //point = new Vertex2D(ll1.m_Longitude, ll1.m_Latitude); } else { double dbθ = (180 - angle) * Math.PI / 180; point = new PointClass(); point.X = A.X + distance * Math.Sin(dbθ); point.Y = A.Y - distance * Math.Cos(dbθ); } return point; } /// /// 计算两点之间的角度 /// /// 点1 /// 点2 /// public static double getAngle(IPoint p1, IPoint p2) { //两点的x、y值 double x = p2.X - p1.X; double y = p2.Y - p1.Y; double hypotenuse = Math.Sqrt(Math.Pow(x, 2) + Math.Pow(y, 2)); //斜边长度 double cos = x / hypotenuse; double radian = Math.Acos(cos); //求出弧度 double angle = 180 / (Math.PI / radian); //用弧度算出角度 if (y < 0) { angle = -angle; } else if ((y == 0) && (x < 0)) { angle = 180; } return angle; } /// /// 计算平行线上的点集合 /// /// 参考线上的点集合 /// 距离 /// 平行线上的点集合 public static void PointsFromParalleLine(IPointCollection points, double pDistance, ref IPointCollection pOutPoints) { if (pOutPoints == null) return; for (int i = 0; i < points.PointCount; i++) { double angle = 0; IPoint lp = points.get_Point(i); if (i == points.PointCount - 1) { angle = GeometryOperations.getAngle(points.Point[i - 1], points.Point[i]); } else { angle = GeometryOperations.getAngle(points.Point[i], points.Point[i + 1]); } lp = GeometryOperations.GetPoint(points.Point[i], pDistance, -angle); if (i > 1) { lp = GeometryOperations.getParallelPoint(points.get_Point(i - 2), points.get_Point(i - 1), points.get_Point(i), pDistance); pOutPoints.UpdatePoint(i - 1, lp); } if (i == points.PointCount - 1 || i <= 1) { lp = GeometryOperations.GetPoint(points.Point[i], pDistance, -angle); pOutPoints.UpdatePoint(i, lp); } } } /// /// 获取最小夹角 /// /// /// public static double GetMinAngle2(ESRI.ArcGIS.Geometry.IGeometry geometry) { ESRI.ArcGIS.Geometry.IGeometryFactory3 factory = new ESRI.ArcGIS.Geometry.GeometryEnvironment() as ESRI.ArcGIS.Geometry.IGeometryFactory3; byte[] b = factory.CreateWkbVariantFromGeometry(geometry) as byte[]; Geometry gdalGeometry = Geometry.CreateFromWkb(b); return GetAngle(gdalGeometry); } public static double GetAngle(Geometry geometry) { string wkt = ""; geometry.ExportToWkt(out wkt); double rstAngle = -1; double sumAngle = 0; if (wkt.StartsWith("POLYGON")) { //StringBuilder sb = new StringBuilder("POLYGON ("); string wktN = wkt.Replace("POLYGON ((", "").Replace("))", ""); string[] strs = wktN.Replace("),(", "@").Split('@'); for (int i = 0; i < strs.Length; i++) { string[] strsP = strs[i].Split(','); for (int j = 0; j < strsP.Length; j++) { string[] strF = strsP[j].ToString().Split(' '); string[] strC = null; string[] strS = null; if (j == strsP.Length - 2) { strC = strsP[j + 1].ToString().Split(' '); strS = strsP[0].ToString().Split(' '); if (strC[0] == strS[0] && strC[1] == strS[1]) { strS = strsP[1].ToString().Split(' '); } } else if (j == strsP.Length - 1) { strC = strsP[0].ToString().Split(' '); strS = strsP[1].ToString().Split(' '); continue; } else { strC = strsP[j + 1].ToString().Split(' '); strS = strsP[j + 2].ToString().Split(' '); } double angle = GetAngle(Convert.ToDouble(strC[0]), Convert.ToDouble(strC[1]), Convert.ToDouble(strF[0]), Convert.ToDouble(strF[1]), Convert.ToDouble(strS[0]), Convert.ToDouble(strS[1])); sumAngle += angle; if (rstAngle == -1) { rstAngle = angle; } else { if (angle < rstAngle) { rstAngle = angle; } } } } return rstAngle; } return 0; } public static double GetAngle(double cenX, double cenY, double firstX, double firstY, double secondX, double secondY) { double ma_x = firstX - cenX; double ma_y = firstY - cenY; double mb_x = secondX - cenX; double mb_y = secondY - cenY; double v1 = (ma_x * mb_x) + (ma_y * mb_y); double ma_val = Math.Sqrt(ma_x * ma_x + ma_y * ma_y); double mb_val = Math.Sqrt(mb_x * mb_x + mb_y * mb_y); double cosM = v1 / (ma_val * mb_val); double angleAMB = Math.Acos(cosM) * 180 / Math.PI; return angleAMB; } public static double GetAngle(IPoint cenPoint, IPoint firstPoint, IPoint secondPoint) { double ma_x = firstPoint.X - cenPoint.X; double ma_y = firstPoint.Y - cenPoint.Y; double mb_x = secondPoint.X - cenPoint.X; double mb_y = secondPoint.Y - cenPoint.Y; double v1 = (ma_x * mb_x) + (ma_y * mb_y); double ma_val = Math.Sqrt(ma_x * ma_x + ma_y * ma_y); double mb_val = Math.Sqrt(mb_x * mb_x + mb_y * mb_y); if (ma_val * mb_val == 0) { return -1; } double cosM = v1 / (ma_val * mb_val); double angleAMB = Math.Acos(cosM) * 180 / Math.PI; return angleAMB; } public static double GetMinAngle(IGeometry pGeo) { double rstAngle = -1; try { if (pGeo == null || pGeo.IsEmpty) return rstAngle; IPolygon4 poly4 = pGeo as IPolygon4; ITopologicalOperator topo = poly4 as ITopologicalOperator; if (topo != null) { topo.Simplify(); } GeometryBag geoBag = poly4.ExteriorRingBag as GeometryBag; if (geoBag == null) return rstAngle; IGeometryCollection geoCollection = geoBag as IGeometryCollection; List rings = new List(); for (int j = 0; j < geoCollection.GeometryCount; j++) { IGeometry geo = geoCollection.get_Geometry(j); rings.Add(geo); //内环图形 IGeometryBag InteriorBag = (pGeo as ESRI.ArcGIS.Geometry.IPolygon4).get_InteriorRingBag(geo as IRing); if (InteriorBag != null) { IGeometryCollection InteriorRingGeometryCollection = InteriorBag as IGeometryCollection; for (int IR = 0; IR < InteriorRingGeometryCollection.GeometryCount; IR++) { rings.Add(InteriorRingGeometryCollection.get_Geometry(IR)); } } } foreach (IGeometry ring in rings) { if (ring.IsEmpty) continue; IPointCollection points = ring as IPointCollection; int num = points.PointCount - 1; for (int i = 0; i < num; i++) { IPoint p1 = null; IPoint p2 = points.get_Point(i); IPoint p3 = null; if (i == 0) { p1 = points.get_Point(num - 1); p3 = points.get_Point(i + 1); } else if (i == num - 1) { p1 = points.get_Point(i - 1); p3 = points.get_Point(0); } else { p1 = points.get_Point(i - 1); p3 = points.get_Point(i + 1); } double angle = GetAngle(p2, p1, p3); if (rstAngle == -1) { rstAngle = angle; } else { if (rstAngle > angle) { rstAngle = angle; } } } } } catch (Exception ex) { throw ex; } return rstAngle; } } }