1,总是会得到一些奇奇怪怪的要求,求一个面对象的外接最小面积的矩形,和ArcToolBox中的Mininum Bounding Geometry功能下的RECTANGLE_BY_AREA想似。具体看下图:
区别如上图所示:IEnvelope 得到的是下图所示,需要的是第一种
(只是记录一下,可以解决问题,但不是最优方法,代码冗余量大,待解决)
基本思路:获取所有边,以其中的某一条边入手,遍历所有点到这条边的距离,取最大距离的点(pointA),以此点为准画一条平行于第一条线的线,作为第二条边,再以此点(pointA)画一条垂直于第一条边的线作为辅助线,再次遍历所有点到此辅助线的距离,得到最大距离的点(pointB),以pointB画一条垂直第一条边的线作为第三条边,再次遍历所有点到第三条边的距离,取得最大距离的点pointC,以pointC画一条垂直第一条边的线,作为第四条边。然后相邻两条线求交点,得到四个点,用四个点构造矩形。计算面积,以此,将所有的矩形都得到然后,比较面积求最小的就好了,好鸡儿啰嗦我。
不喜就喷!接受反驳!
实现方法如下:
1 private void Mininum() 2 { 3 IFeatureClass pFClass = (this.axMapControl1.get_Layer(0) as IFeatureLayer).FeatureClass; 4 IFeatureCursor pFCursor = pFClass.Search(null, false); 5 IFeature pFeature = pFCursor.NextFeature(); 6 while (pFeature != null) 7 { 8 //求凸包 9 IGeometry pGeometry = pFeature.Shape; 10 ITopologicalOperator pTOperator = pGeometry as ITopologicalOperator; 11 IGeometry pNEWGeometry = pTOperator.ConvexHull(); 12 //每个凸包边的集合 13 ISegmentCollection pSCollection = pNEWGeometry as ISegmentCollection; 14 //每个凸包点的集合 15 IPointCollection pPCollection = pNEWGeometry as IPointCollection; 16 //用来筛选最小的面积的一个界值,只要足够大,多少都可以 17 double area = 99999999999999; 18 //存储当前遍历的要素(feature)的最小面积矩形对象。 19 IGeometry pGeoMetry = null; 20 for (int i = 0; i < pSCollection.SegmentCount; i++) 21 { 22 double DIS = 0; 23 double DIS3 = 0; 24 double DIS4 = 0; 25 26 IPoint RESUPoint=new PointClass(); 27 IPoint Resu3point = new PointClass(); 28 IPoint Resu4point = new PointClass(); 29 ISegment pPolyline_Segment = pSCollection.get_Segment(i); 30 IPoint FromPoint = pPolyline_Segment.FromPoint; 31 IPoint ToPoint = pPolyline_Segment.ToPoint; 32 //y=kx+b下边两行为第一条边的表达式的参数值 33 double k = (FromPoint.Y - ToPoint.Y) / (FromPoint.X - ToPoint.X); 34 double b = FromPoint.Y - FromPoint.X * k; 35 for (int j = 0; j < pPCollection.PointCount; j++) 36 { 37 IPoint eachPoint = pPCollection.get_Point(j); 38 double distanse = dis(eachPoint, k, b); 39 if (distanse > DIS) 40 { 41 DIS = distanse; 42 RESUPoint = eachPoint; 43 } 44 } 45 //第二条边的参数值 46 double k1 = k; 47 double b1 = RESUPoint.Y - k1 * RESUPoint.X; 48 //求第二个点到第一条边的投影点及所在直线的参数(辅助线) 49 double k2 = -1 / k; 50 double b2 = RESUPoint.Y - k2 * RESUPoint.X; 51 //遍历第三条边所在的位置 52 for (int m = 0; m < pPCollection.PointCount; m++) 53 { 54 IPoint pPoint = pPCollection.get_Point(m); 55 double distance = dis(pPoint, k2, b2); 56 if (distance > DIS3) 57 { 58 DIS3 = distance; 59 Resu3point = pPoint; 60 } 61 } 62 //第三条的参数值 63 double k3 = k2; 64 double b3 = Resu3point.Y - k3 * Resu3point.X; 65 //------------开始求第四条边 66 for (int n = 0; n < pPCollection.PointCount; n++) 67 { 68 IPoint pPoint=pPCollection.get_Point(n); 69 double distance = dis(pPoint,k3,b3); 70 if(distance>DIS4) 71 { 72 DIS4=distance; 73 Resu4point = pPoint; 74 } 75 } 76 //第四条边的参数值; 77 double k4 = k3; 78 double b4 = Resu4point.Y-k4*Resu4point.X; 79 80 //------------四个交点的值 81 //pointA 82 double x_a=(b4-b)/(k-k4); 83 double y_a = k * x_a + b; 84 //pointB 85 double x_b = (b4 - b1) / (k1 - k4); 86 double y_b = k1 * x_b + b1; 87 //pointC 88 double x_c = (b3 - b1) / (k1 - k3); 89 double y_c = k1 * x_c + b1; 90 //pointD 91 double x_d = (b3 - b) / (k - k3); 92 double y_d = k * x_d + b; 93 //构造矩形 94 IPoint pointa = new PointClass(); 95 pointa.PutCoords(x_a, y_a); 96 IPoint pointb = new PointClass(); 97 pointb.PutCoords(x_b, y_b); 98 IPoint pointc = new PointClass(); 99 pointc.PutCoords(x_c, y_c); 100 IPoint pointd = new PointClass(); 101 pointd.PutCoords(x_d, y_d); 102 IPoint pointa1 = new PointClass(); 103 pointa1.PutCoords(x_a, y_a); 104 IPointCollection RECTANG = new PolygonClass(); 105 RECTANG.AddPoint(pointa); 106 RECTANG.AddPoint(pointb); 107 RECTANG.AddPoint(pointc); 108 RECTANG.AddPoint(pointd); 109 RECTANG.AddPoint(pointa1); 110 IPolygon pPolygon = RECTANG as IPolygon; 111 IGeometry PPPPPPPPGeo = pPolygon as IGeometry; 112 //************************* 113 //axMapControl1.FlashShape(PPPPPPPPGeo); 114 //注意此处!因构造矩形的时候,顺时针逆时针不能确定,因此从ArcGIS来说这个面积有可能为负值,并不是取绝对值就可以,外环与内环的区别,因此用数学方法。 115 double a1=Math.Sqrt((pointb.Y-pointa.Y)*(pointb.Y-pointa.Y)+(pointb.X-pointa.X)*(pointb.X-pointa.X)); 116 double c1=Math.Sqrt((pointc.Y-pointb.Y)*(pointc.Y-pointb.Y)+(pointc.X-pointb.X)*(pointc.X-pointb.X)); 117 double pArea = a1 * c1; 118 if (Math.Abs(pArea) < area) 119 { 120 area = Math.Abs(pArea); 121 pGeoMetry = PPPPPPPPGeo; 122 } 123 } 124 axMapControl1.FlashShape(pGeoMetry); 125 pFeature = pFCursor.NextFeature(); 126 } 127 System.Runtime.InteropServices.Marshal.ReleaseComObject(pFCursor); 128 }
1 public double dis(IPoint pPoint, double k, double b) 2 { 3 double numerator = System.Math.Abs(k * pPoint.X - pPoint.Y + b); 4 double Denominator = System.Math.Sqrt(k * k + 1); 5 double dis=numerator/Denominator; 6 return Math.Abs(dis); 7 }
弱弱的再啰嗦一句:这个功能在arcpy中很好实现
arcpy.MinimumBoundingGeometry_management("parks.shp", "c:/output/output.gdb/parks_mbg", "RECTANGLE_BY_AREA", "NONE")
就一句就可以了,只是这个东西速度慢的要死,再次使用最小得到的矩形的又得选择。
OK!BBBBBBBBBBBBBBBBBBBBBBBBBBB完了,