/// <summary> /// 计算多边形的中心点 /// </summary> /// <param name="polygonPoints">多边形顶点集合(封闭,最后一个点和起始点相同)</param> /// <returns></returns> private PlanePoint getCenterPoint(List <PlanePoint> polygonPoints) { // 多边形的点必须大于等于3,最后一个点和起点相同,所以长度需要大于等于4 if (polygonPoints.Count < 4) { return(null); } double centerX = 0; double centerY = 0; // 循环多边形的顶点(因最后一个点与第一个点相同,故排除在外) for (int i = 0; i < polygonPoints.Count - 1; i++) { PlanePoint p1 = polygonPoints[i]; PlanePoint p2 = polygonPoints[i + 1]; centerX += (p1.x + p2.x) * (p1.x * p2.y - p2.x * p1.y); centerY += (p1.y + p2.y) * (p1.x * p2.y - p2.x * p1.y); } double polygonArea = this.getArea(polygonPoints); centerX /= (6 * polygonArea); centerY /= (6 * polygonArea); PlanePoint centerPoint = new PlanePoint(); centerPoint.x = centerX; centerPoint.y = centerY; return(centerPoint); }
/// <summary> /// 计算点到线段的最近点坐标 /// </summary> /// <param name="targetPoint">目标点</param> /// <param name="lineStartPoint">线段起点</param> /// <param name="lineEndPoint">线段终点</param> /// <returns></returns> private PlanePoint pointToLineSegmentNearstPoint(PlanePoint targetPoint, PlanePoint lineStartPoint, PlanePoint lineEndPoint) { double deltaX = lineEndPoint.x - lineStartPoint.x; double deltaY = lineEndPoint.y - lineStartPoint.y; double som = deltaX * deltaX + deltaY * deltaY; double u = ((targetPoint.x - lineStartPoint.x) * deltaX + (targetPoint.y - lineStartPoint.y) * deltaY) / som; if (u > 1) { u = 1; } else if (u < 0) { u = 0; } double resultX = lineStartPoint.x + u * deltaX; double resultY = lineStartPoint.y + u * deltaY; PlanePoint result = new PlanePoint(); result.x = resultX; result.y = resultY; return(result); }
private static IEnumerable GetNDimensionPoints() { PlanePoint[] points = new PlanePoint[] { new PlanePoint(new double[] { 1, 1, 0 }), new PlanePoint(new double[] { 5, 1, 0 }), new PlanePoint(new double[] { 1, 5, 0 }), new PlanePoint(new double[] { 5, 5, 0 }), new PlanePoint(new double[] { 1, 1, 5 }), new PlanePoint(new double[] { 5, 1, 5 }), new PlanePoint(new double[] { 1, 5, 5 }), new PlanePoint(new double[] { 5, 5, 5 }), new PlanePoint(new double[] { 3, 3, 3 }), }; Vector v1 = new Vector(new double[] { 0, 0, -1 }); Vector v2 = new Vector(new double[] { 0, -1, 0 }); Vector v3 = new Vector(new double[] { -1, 0, 0 }); Hyperplane[] expect = new Hyperplane[] { new Hyperplane(points[0], v1), new Hyperplane(points[0], v2), new Hyperplane(points[0], v3), }; yield return(new TestCaseData(points).SetName("{m}_3dPoints")); }
/// <summary> /// 判断点相对于线的方位 /// </summary> /// <param name="targetPoint">目标点</param> /// <param name="lineStartPoint">线的起点</param> /// <param name="lineEndPoint">线的终点</param> /// <returns>1:左边,0:线上,-1:右边</returns> private int pointLeftPolyline(PlanePoint targetPoint, PlanePoint lineStartPoint, PlanePoint lineEndPoint) { double x0 = targetPoint.x; double y0 = targetPoint.y; double x1 = lineStartPoint.x; double y1 = lineStartPoint.y; double x2 = lineEndPoint.x; double y2 = lineEndPoint.y; double temp = (x2 - x1) * (y0 - y1) - (y2 - y1) * (x0 - x1); int result = 0; if (temp > 0) // 点在线左边 { result = 1; } else if (temp == 0) // 点在线上 { result = 0; } else // 点在线右边 { result = -1; } return(result); }
public void FindConvexHull2D_Points2d_ReturnConvexHull2D() { PlanePoint[] points = new PlanePoint[] { new PlanePoint(new double[] { 4, 0 }), new PlanePoint(new double[] { 0, 4 }), new PlanePoint(new double[] { 4, 4 }), new PlanePoint(new double[] { 0, 0 }), new PlanePoint(new double[] { 0.5, 0.5 }), new PlanePoint(new double[] { 1, 1 }), }; List <PlanePoint> expectPoint = new List <PlanePoint> { new PlanePoint(new double[] { 0, 0 }), new PlanePoint(new double[] { 4, 0 }), new PlanePoint(new double[] { 0, 4 }), new PlanePoint(new double[] { 4, 4 }), }; ConvexHull2d expect = expectPoint.ToConvexHull2d(); GiftWrappingAlgorithm giftWrapping = new GiftWrappingAlgorithm(points, Tools.Eps); GrahamScan2d per = new GrahamScan2d(); ConvexHull2d actual = (ConvexHull2d)giftWrapping.Create(); actual.Should().Be(expect); }
private static IEnumerable <TestCaseData> GetDataForConvertPoint() { PlanePoint mainPoint = new PlanePoint(new double[] { 1, 1, 2 }); Vector normal = new Vector(new double[] { 1, 0, 0 }); Vector[] basis = new[] { new Vector(new double[] { 1, 0, 0 }), new Vector(new double[] { 0, 1, 0 }), }; Hyperplane hyperplane = new Hyperplane(mainPoint, normal); hyperplane.Basis = basis; Point point = new Point(new double[] { 2, 2, 2 }); Point expect = new Point(new double[] { 1, 1 }); yield return(new TestCaseData(hyperplane, point).Returns(expect)); mainPoint = new PlanePoint(new double[] { 2, 2, 4 }); normal = new Vector(new double[] { 2, 0, 2 }); basis = new[] { new Vector(new double[] { -2, 0, 2 }), new Vector(new double[] { 0, 1, 0 }), }; hyperplane = new Hyperplane(mainPoint, normal); hyperplane.Basis = basis; point = new Point(new double[] { 2, 5, 4 }); expect = new Point(new double[] { 0, 3 }); yield return(new TestCaseData(hyperplane, point).Returns(expect)); }
/// <summary> /// 目标坐标转源坐标(批量) /// </summary> /// <param name="targetCoordiantes">目标坐标集合</param> /// <returns>源坐标集合</returns> public List <ICoordinate> TargetToSourceBatch(IEnumerable <ICoordinate> targetCoordiantes) { if (targetCoordiantes == null || targetCoordiantes.Count() == 0) { return(null); } List <ICoordinate> result = new List <ICoordinate>(); // 两个中间变量 SpherePoint spTemp = null; PlanePoint ppTemp = null; // 高斯转换 GaussKrugerTransform gauss_source = new GaussKrugerTransform(sourceCS); GaussKrugerTransform gauss_target = new GaussKrugerTransform(targetCS); // 大地坐标转换 GeodeticTransform geo_source = new GeodeticTransform(sourceCS, sourceMeridian); GeodeticTransform geo_target = new GeodeticTransform(targetCS, targetMeridian); // 七参数模型,对空间直角坐标进行转换,转换后同样是空间直角坐标 BursaWolfTransform bursa_target = new BursaWolfTransform(sevenParams.Reverse()); foreach (ICoordinate targetCoordinate in targetCoordiantes) { // 如果目标是平面坐标 // 1.平面坐标转高斯坐标;2.高斯反算,转为球面坐标 if (targetCT == CoordinateType.Plane) { ppTemp = gauss_target.PlaneToGauss((PlanePoint)targetCoordinate); spTemp = gauss_target.GaussKrugerReverse(ppTemp, targetMeridian); } else { spTemp = (SpherePoint)targetCoordinate.Clone(); } // 大地坐标转空间直角坐标 ppTemp = geo_target.GeodeticToThreeDimensions(spTemp); // 七参数模型,对空间直角坐标进行转换,转换后同样是空间直角坐标 ppTemp = (PlanePoint)bursa_target.Transform(ppTemp); // 空间直角坐标转大地坐标 spTemp = geo_source.ThreeDimensionsToGeodetic(ppTemp); // 如果源是平面坐标 // 1.高斯正算,转为高斯坐标;2.高斯坐标转平面坐标 if (sourceCT == CoordinateType.Plane) { ppTemp = gauss_source.GaussKrugerForward(spTemp, sourceMeridian); ppTemp = gauss_source.GaussToPlane(ppTemp); result.Add(ppTemp.Clone()); } else { result.Add(spTemp.Clone()); } } return(result); }
public void Initialization_WhenSamePoints_ThrowsException() { PlanePoint p1 = new PlanePoint(new double[] { 1, 1, 1, 0 }); PlanePoint p2 = new PlanePoint(new double[] { 1, 1, 1, 0 }); Assert.Throws <ArgumentException>((() => new Edge(p1, p2))); }
public void Initialization_WhenDifferentPoints_CreatesEdge2d() { PlanePoint p1 = new PlanePoint(new double[] { 1, 1, 1, 0 }); PlanePoint p2 = new PlanePoint(new double[] { 0, 0, 0, 0 }); Assert.DoesNotThrow((() => new Edge(p1, p2))); }
public IConvexHull FindConvexHull(IList <PlanePoint> points) { List <PlanePoint> sortPoints = points.ToList().MergeSort <PlanePoint>(); List <PlanePoint> up = new List <PlanePoint>(), down = new List <PlanePoint>(); PlanePoint minPoint = sortPoints[0]; PlanePoint maxPoint = sortPoints[^ 1];
/// <summary> /// 源坐标转目标坐标 /// </summary> /// <param name="sourceCoordinate">源坐标</param> /// <returns>目标坐标</returns> public ICoordinate SourceToTarget(ICoordinate sourceCoordinate) { if (sourceCoordinate == null) { return(null); } // 两个中间变量 SpherePoint spTemp = null; PlanePoint ppTemp = null; // 如果源是平面坐标 // 1.平面坐标转高斯坐标;2.高斯反算,转为球面坐标 if (sourceCT == CoordinateType.Plane) { GaussKrugerTransform gauss_source = new GaussKrugerTransform(sourceCS); ppTemp = gauss_source.PlaneToGauss((PlanePoint)sourceCoordinate); spTemp = gauss_source.GaussKrugerReverse(ppTemp, sourceMeridian); } else { spTemp = (SpherePoint)sourceCoordinate.Clone(); } // 大地坐标转空间直角坐标 GeodeticTransform geo_source = new GeodeticTransform(sourceCS, sourceMeridian); ppTemp = geo_source.GeodeticToThreeDimensions(spTemp); // 七参数模型,对空间直角坐标进行转换,转换后同样是空间直角坐标 BursaWolfTransform bursa_source = new BursaWolfTransform(sevenParams); ppTemp = (PlanePoint)bursa_source.Transform(ppTemp); // 空间直角坐标转大地坐标 GeodeticTransform geo_target = new GeodeticTransform(targetCS, targetMeridian); spTemp = geo_target.ThreeDimensionsToGeodetic(ppTemp); ICoordinate result = null; // 如果目标是平面坐标 // 1.高斯正算,转为高斯坐标;2.高斯坐标转平面坐标 if (targetCT == CoordinateType.Plane) { GaussKrugerTransform gauss_target = new GaussKrugerTransform(targetCS); ppTemp = gauss_target.GaussKrugerForward(spTemp, targetMeridian); ppTemp = gauss_target.GaussToPlane(ppTemp); result = ppTemp.Clone(); } else { result = spTemp.Clone(); } return(result); }
/// <summary> /// 判断点是否在多边形内(适用于任意多边形) /// </summary> /// <param name="targetPoint">目标点</param> /// <param name="targetPolygon">多边形点集合(按照顺时针或逆时针顺序存储多边形的点)</param> /// <returns>true or false</returns> private bool IsPointInPolygon(PlanePoint targetPoint, List <PlanePoint> targetPolygon) { // 多边形的点必须大于等于3,最后一个点和起点相同,所以长度需要大于等于4 if (targetPolygon.Count < 4) { return(false); } // 点在第一条线段的左边(1),右边(-1),线上(0) int first = 0; // 点在其他线段的左边(1),右边(-1),线上(0) int other = 0; // 角度合计 double angleSummation = 0; // 循环多边形的点 for (int i = 0, j = i + 1; i < targetPolygon.Count - 1; i++, j++) { PlanePoint lineStartPoint = targetPolygon[i]; // 线段起点 PlanePoint lineEndPoint = targetPolygon[j]; // 线段终点 // 首先判断点是否在线段上,如果是则直接返回true if (this.pointAtSegment(targetPoint, lineStartPoint, lineEndPoint)) { return(true); } // 角度 double angle = this.getTriangleTopAngle(targetPoint, lineStartPoint, lineEndPoint); // 位置 int position = this.pointLeftPolyline(targetPoint, lineStartPoint, lineEndPoint); if (first == 0) // 如果点在第一条线上,则将点相对于下一条线的位置作为标记 { first = position; } else // 点相对于当前线的位置 { other = position; } if (first == position) // 如果点相对于第一条线的位置和当前线的位置一致,则角度相加。 { angleSummation += angle; } else // 如果点相对于第一条线的位置和当前线的位置不一致,则角度相减。(处理凹多边形的情况) { angleSummation -= angle; } } // 如果角度之和等于360度,表示点在多边形内 if (Math.Round(angleSummation, 5) == 360) { return(true); } else { return(false); } }
/// <summary> /// 获取三角形顶点所在的角度值 /// </summary> /// <param name="topPoint">三角形顶点坐标</param> /// <param name="point1">三角形另一点</param> /// <param name="point2">三角形另一点</param> /// <returns>角度值</returns> private double getTriangleTopAngle(PlanePoint topPoint, PlanePoint point1, PlanePoint point2) { // 计算顶点角的余弦值 double cosValue = this.getAngleCos(topPoint, point1, point2); // 计算角度值 double angle = Math.Acos(cosValue) * 180 / Math.PI; return(angle); }
/// <summary> /// 获取两点之间的长度 /// </summary> /// <param name="point1">起点</param> /// <param name="point2">终点</param> /// <returns>长度值</returns> private double getLength(PlanePoint point1, PlanePoint point2) { double deltaX = point2.x - point1.x; double deltaY = point2.y - point1.y; // 两点之间的距离公式:( (x2-x1)^2 + (y2-y1)^2 )^(1/2) double length = Math.Sqrt(Math.Pow(deltaX, 2) + Math.Pow(deltaY, 2)); return(length); }
/// <summary> /// 高斯坐标转平面坐标(y+500Km;x,y交换) /// </summary> /// <param name="gaussianPoint"></param> /// <returns></returns> public PlanePoint GaussToPlane(PlanePoint gaussianPoint) { PlanePoint result = new PlanePoint(); result.x = gaussianPoint.y + 500000; result.y = gaussianPoint.x; result.z = gaussianPoint.z; return(result); }
public void Equals_EqualObjects_ReturnTrue() { PlanePoint p1 = new PlanePoint(new double[] { 4, 4, 0, 0 }); PlanePoint p2 = new PlanePoint(new double[] { 4, 4, 0, 0 }); PlanePoint pp1 = new PlanePoint(new double[] { 1, 1, 1 }, p1); Point pp2 = new PlanePoint(new double[] { 2, 2, 2 }, p2); Assert.AreEqual(pp1, pp2); }
/// <summary> /// 平面坐标转高斯坐标(x,y交换;y-500Km) /// </summary> /// <param name="planePoint"></param> /// <returns></returns> public PlanePoint PlaneToGauss(PlanePoint planePoint) { PlanePoint result = new PlanePoint(); result.x = planePoint.y; result.y = planePoint.x - 500000; result.z = planePoint.z; return(result); }
public void GetPoints_ContainsInsertedPoint() { PlanePoint p1 = new PlanePoint(new double[] { 1, 1, 1, 0 }); PlanePoint p2 = new PlanePoint(new double[] { 0, 0, 0, 0 }); Point[] points = new[] { p1, p2 }; Edge edge = new Edge(p1, p2); edge.GetPoints().Should().Equal(points); }
public void Angle_SamePlane_ReturnAngle() { PlanePoint p1 = new PlanePoint(3); Vector n1 = new Vector(new double[] { 1, 0, 0 }); Hyperplane h1 = new Hyperplane(p1, n1); const double expect = 0; double result = h1.Angle(h1); Assert.AreEqual(expect, result, Tools.Eps); }
public void Side_PointOfPlane_ReturnPosition() { PlanePoint p1 = new PlanePoint(3); Vector n1 = new Vector(new double[] { 1, 0, 0 }); Hyperplane h1 = new Hyperplane(p1, n1); Point p2 = new Point(new double[] { 0, 4, 4 }); const int expect = 0; int result = h1.Side(p2); Assert.AreEqual(expect, result); }
public void ReorientNormal_WhenCall_ChangeOrientationNormal() { PlanePoint p1 = new PlanePoint(3); Vector n1 = new Vector(new double[] { 1, 1, 1 }); Hyperplane h1 = new Hyperplane(p1, n1); Vector n2 = new Vector(new double[] { -1, -1, -1 }); Hyperplane h2 = new Hyperplane(p1, n2); h1.ReorientNormal(); Assert.AreEqual(h2.Normal, h1.Normal); }
/// <summary> /// 高斯-克吕格 投影反算(平面坐标转换为球面坐标) /// </summary> /// <param name="coordinate">平面坐标</param> /// <param name="centerMeridian">中央经线</param> /// <returns>球面坐标</returns> public SpherePoint GaussKrugerReverse(PlanePoint coordinate, double centerMeridian) { double x = coordinate.x; double y = coordinate.y; double lng = 0; double lat = 0; this.xytoBL(x, y, centerMeridian, out lng, out lat); SpherePoint result = new SpherePoint(lng, lat); return(result); }
/// <summary> /// 高斯-克吕格 投影正算(球面坐标转换为平面坐标) /// </summary> /// <param name="coordinate">球面坐标</param> /// <param name="centerMeridian">中央经线</param> /// <returns>平面坐标</returns> public PlanePoint GaussKrugerForward(SpherePoint coordinate, double centerMeridian) { double lng = coordinate.lng; double lat = coordinate.lat; double x = 0; double y = 0; this.BLtoxy(lng, lat, centerMeridian, out x, out y); PlanePoint result = new PlanePoint(x, y); return(result); }
/// <summary> /// 经纬度坐标转Web墨卡托坐标 /// </summary> /// <param name="lnglat"></param> /// <returns></returns> public PlanePoint LngLat_To_WebMercator(SpherePoint lnglat) { double lng = lnglat.lng; double lat = lnglat.lat; double x = 0; double y = 0; this.lnglat_to_webmercator(lng, lat, out x, out y); PlanePoint xy = new PlanePoint(x, y); return(xy); }
/// <summary> /// Web墨卡托坐标转经纬度坐标 /// </summary> /// <param name="xy"></param> /// <returns></returns> public SpherePoint WebMercator_To_LngLat(PlanePoint xy) { double x = xy.x; double y = xy.y; double lng = 0; double lat = 0; this.webmercator_to_lnglat(x, y, out lng, out lat); SpherePoint lnglat = new SpherePoint(lng, lat); return(lnglat); }
public void Equals_UnequalPlane_ReturnFalse() { PlanePoint p1 = new PlanePoint(new double[] { 1, 7, 0 }); Vector n1 = new Vector(new double[] { 1, -1, 0 }); Hyperplane h1 = new Hyperplane(p1, n1); PlanePoint p2 = new PlanePoint(new double[] { -1, 3, 0 }); Vector n2 = new Vector(new double[] { -4, 2, 0 }); Hyperplane h2 = new Hyperplane(p2, n2); bool result = h1.Equals(h2); Assert.AreEqual(false, result); }
public void Angle_WhenCall_ReturnAngle() { PlanePoint p1 = new PlanePoint(3); Vector n1 = new Vector(new double[] { 1, 0, 0 }); Vector n2 = new Vector(new double[] { 0, 1, 0 }); Hyperplane h1 = new Hyperplane(p1, n1); Hyperplane h2 = new Hyperplane(p1, n2); const double expect = Math.PI / 2; double result = h1.Angle(h2); Assert.AreEqual(expect, result, Tools.Eps); }
/// <summary> /// 获取角度的余弦值 /// </summary> /// <param name="topPoint">顶点</param> /// <param name="point1">起点</param> /// <param name="point2">终点</param> /// <returns>余弦值</returns> private double getAngleCos(PlanePoint topPoint, PlanePoint point1, PlanePoint point2) { // 顶点对应的边的长度 double topPoint_Side_Length = this.getLength(point1, point2); // point1对应的边的长度 double point1_Side_Length = this.getLength(topPoint, point2); // point2对应的边的长度 double point2_Side_Length = this.getLength(topPoint, point1); // 顶点余弦公式:cosA=(b^2+c^2-a^2)/(2*b*c) double cosValue = (Math.Pow(point1_Side_Length, 2) + Math.Pow(point2_Side_Length, 2) - Math.Pow(topPoint_Side_Length, 2)) / (2 * point1_Side_Length * point2_Side_Length); return(cosValue); }
public void Create_2dPoints_ReturnHyperplane() { PlanePoint[] points = new PlanePoint[] { new PlanePoint(new double[] { 0, 0 }), new PlanePoint(new double[] { 0, 4 }) }; Vector normal = new Vector(new double[] { -1, 0 }); Hyperplane h2 = new Hyperplane(points[0], normal); Hyperplane h = Hyperplane.Create(points); Assert.AreEqual(h2, h); }
/// <summary> /// 空间直角坐标转大地坐标 /// </summary> /// <param name="coordinate">空间直角坐标</param> /// <returns></returns> public SpherePoint ThreeDimensionsToGeodetic(PlanePoint coordinate) { double X = coordinate.x; double Y = coordinate.y; double Z = coordinate.z; double B = 0; double L = 0; double H = 0; this.XYZtoBLH(X, Y, Z, out B, out L, out H); SpherePoint result = new SpherePoint(B, L); return(result); }