public void ToX(XElement xe) { var closed = Closed; if (GeoUtils.Equals(ControlPoints[0], ControlPoints[ControlPoints.Count - 1])) { closed = true; } xe.Add(new XAttribute("Closed", closed)); xe.Add(new XAttribute("Degree", Degree)); var controlPoints = new XElement("ControlPoints"); xe.Add(controlPoints); foreach (var pt in ControlPoints) { controlPoints.Add(pt.ToX("Point")); } xe.Add(Knots.ToX()); }
public Curve2D GetSegmentAt(int index) { if (index < 0 || index >= SegmentCount) { return(null); } var pt1 = Vertexs[index]; var pt2 = index == Vertexs.Count - 1 ? Vertexs[0] : Vertexs[index + 1]; if (GeoUtils.Equals(pt1.Bulge, 0)) { return(new LineSegment2D(pt1.Position, pt2.Position)); } else { return(new CircleArc2D(pt1.Position, pt2.Position, pt1.Bulge)); } }
public CircleArc2D(Point2D pt1, Point2D pt2, Point2D pt3, bool isWholeCircle) { if (isWholeCircle) { var xy1 = Math.Pow(pt1.X, 2) + Math.Pow(pt1.Y, 2); var xy2 = xy1 - Math.Pow(pt3.X, 2) - Math.Pow(pt3.Y, 2); var xy3 = xy1 - Math.Pow(pt2.X, 2) - Math.Pow(pt2.Y, 2); xy1 = (pt1.X - pt2.X) * (pt1.Y - pt3.Y) - (pt1.X - pt3.X) * (pt1.Y - pt2.Y); if (GeoUtils.Equals(xy1, 0)) { throw new Exception("无法创建圆!"); } Center = new Point2D( (xy3 * (pt1.Y - pt3.Y) - xy2 * (pt1.Y - pt2.Y)) / (2 * xy1), (xy2 * (pt1.X - pt2.X) - xy3 * (pt1.X - pt3.X)) / (2 * xy1)); Radius = (pt1 - Center).Length; if (GeoUtils.Equals(Radius, 0)) { throw new Exception("半径为零!"); } StartAngle = Angle.Zero; EndAngle = Angle.Degree360; } else { CircleArc2D cir = new CircleArc2D(pt1, pt2, pt3, true); Center = cir.Center; Radius = cir.Radius; IsClockWise = Vector2D.IsClockWise( pt1 - cir.Center, pt2 - cir.Center, pt3 - cir.Center); } }
/// <summary> /// 按向量的镜像矩阵 /// </summary> /// <param name="start"></param> /// <param name="end"></param> /// <returns></returns> public static Matrix2D Mirror(Vector2D vec) { bool ex = GeoUtils.Equals(vec.X, 0); bool ey = GeoUtils.Equals(vec.Y, 0); if (ex && ey) { return(Rotation(new Angle(Math.PI))); } else if (ex) { return(new Matrix2D(-1, 0, 0, 1, 0, 0)); } else if (ey) { return(new Matrix2D(1, 0, 0, -1, 0, 0)); } double angle = vec.Angle * 2; double s2 = Math.Sin(angle); double c2 = Math.Cos(angle); return(new Matrix2D(c2, s2, s2, -c2, 0, 0)); }
public void ToX(XElement xe) { xe.Add(new XAttribute("X", GeoUtils.Round(X))); xe.Add(new XAttribute("Y", GeoUtils.Round(Y))); }
public bool IsPerpendicularTo(Vector2D vec) { return(GeoUtils.Equals(DotProduct(vec), 0)); }
public bool IsParallelTo(Vector2D vec) { return(GeoUtils.Equals(CrossProduct(vec), 0)); }
public static bool operator ==(Vector2D v1, Vector2D v2) { return (GeoUtils.Equals(v1.X, v2.X, GeoUtils.EqualsPoint) && GeoUtils.Equals(v1.Y, v2.Y, GeoUtils.EqualsPoint)); }
public bool Equals(Angle x, Angle y) { return(GeoUtils.Equals(x._radian, y._radian)); }
public bool IsWholeCircle() { return(GeoUtils.Equals(_radian, PI2)); }
public bool IsZero() { return(GeoUtils.Equals(_radian, 0)); }
/// <summary> /// 交换矩阵元素 /// </summary> /// <param name="x1"></param> /// <param name="y1"></param> /// <param name="x2"></param> /// <param name="y2"></param> public void Swap(int x1, int y1, int x2, int y2) { GeoUtils.Swap(ref _elements, x1, y1, x1, y1); }
public override string ToString() { return(string.Format("{0},{1}", GeoUtils.Round(X), GeoUtils.Round(Y)));; }
public static bool operator ==(Point2D p1, Point2D p2) { return (GeoUtils.Equals(p1.X, p2.X, GeoUtils.EqualsPoint) && GeoUtils.Equals(p1.Y, p2.Y, GeoUtils.EqualsPoint)); }
/// <summary> /// 插值点反求控制点 /// </summary> /// <param name="closed"></param> /// <param name="fitPoints"></param> public Spline2D(bool closed, IEnumerable <Point2D> fitPoints) { Periodic = false; HasFitPoints = true; FitPoints = new List <Point2D>(fitPoints); //参数区间数 int n = FitPoints.Count - 1; //参数化 List <double> knots = new List <double>(); knots.Add(0); double totalLength = 0; for (int i = 0; i < n; i++) { totalLength += (FitPoints[i + 1] - FitPoints[i]).Length; knots.Add(totalLength); } if (closed) { totalLength += (FitPoints[0] - FitPoints[FitPoints.Count - 1]).Length; knots.Add(totalLength); } NurbsData = new NurbsData(knots, 3, closed); if (closed) { //构建矩阵方程组 double[,] mat = new double[n + 1, n + 1]; for (int i = 0; i < n + 1; i++) { var par = NurbsData.Knots[i + Degree]; int span = NurbsData.Knots.FindSpan(par); var nn = NurbsData.Knots.BasicFuns(span, par); for (int j = 0; j < Degree; j++) { mat[i, (span - Degree + j) % (n + 1)] = nn[j]; } } var fpts = new List <Point2D>(FitPoints); //求解 GeoUtils.Inverse(ref mat, n + 1); for (int i = 0; i < n + 1; i++) { NurbsData.AddControlPoint(new Point2D()); for (int j = 0; j < n + 1; j++) { NurbsData.ControlPoints[i] += fpts[j] * mat[i, j]; } } } else { //构建矩阵方程组 double[,] mat = new double[n + 3, n + 3]; //计算插值点的非零幂基函数值 for (int i = 1; i < n; i++) { var par = NurbsData.Knots[i + Degree]; int span = NurbsData.Knots.FindSpan(par); var nn = NurbsData.Knots.BasicFuns(span, par); for (int j = 0; j < Degree; j++) { mat[i + 1, span - Degree + j] = nn[j]; } } mat[1, 0] = mat[n + 1, n + 2] = 1; //使用自由边界条件,即端点处二阶导数为0 var t1 = totalLength / NurbsData.Knots[Degree + 1]; var t2 = totalLength / NurbsData.Knots[Degree + 2]; mat[0, 0] = t1; mat[0, 1] = -t1 - t2; mat[0, 2] = t2; t1 = totalLength / (totalLength - NurbsData.Knots[n + Degree - 2]); t2 = totalLength / (totalLength - NurbsData.Knots[n + Degree - 1]); mat[n + 2, n] = t1; mat[n + 2, n + 1] = -t1 - t2; mat[n + 2, n + 2] = t2; var fpts = new List <Point2D>(); fpts.Add(Point2D.Origin); fpts.AddRange(FitPoints); fpts.Add(Point2D.Origin); //求解 GeoUtils.Inverse(ref mat, n + 3); for (int i = 0; i < n + 3; i++) { NurbsData.AddControlPoint(new Point2D()); for (int j = 0; j < n + 3; j++) { NurbsData.ControlPoints[i] += fpts[j] * mat[i, j]; } } } }