然后测试代码如下:
private void ButtonBase_OnClick(object sender, RoutedEventArgs e) { var pathGeometry = PathGeometry.CreateFromGeometry(Geometry.Parse("M0,0 A18.10005249343832,16.00031496062992,60,0,0,-21.634424410598417,-21.472913522584044")); var pathFigure = pathGeometry.Figures[0]; if (pathFigure.Segments[0] is ArcSegment arcSegment) { var x1 = pathFigure.StartPoint.X; var y1 = pathFigure.StartPoint.Y; var rx = arcSegment.Size.Width; var ry = arcSegment.Size.Height; var φ = arcSegment.RotationAngle; var fA = arcSegment.IsLargeArc ? 1 : 0; var fs = arcSegment.SweepDirection is SweepDirection.Clockwise ? 1 : 0; var x2 = arcSegment.Point.X; var y2 = arcSegment.Point.Y; var (startAngle, swAngle) = GetArcStartAngAndSwAng(x1, y1, x2, y2, fA, fs, rx, ry, φ); //算出来接近startAngle为179°,swAngle为-118° StringBuilder stringPath = new StringBuilder(); stringPath.Append($"M {x1} {y1}"); var openXmlArcToArcStrNew = SvgArcToArcStr(stringPath, rx, ry, φ, startAngle, swAngle, pathFigure.StartPoint); this.NewPath.Data = Geometry.Parse(openXmlArcToArcStrNew); } }然后我们再通过求出来的开始角和摆动角求出之前的那段Arc:
/// <summary> /// OpenXml Arc 转为SVG Arc 字符串 /// </summary> /// <param>路径字符串</param> /// <param>椭圆半长轴</param> /// <param>椭圆半短轴</param> /// <param>旋转角</param> /// <param>起始角</param> /// <param>摆动角</param> /// <param>当前坐标</param> /// <returns></returns> private string SvgArcToArcStr(StringBuilder stringPath, double rx, double ry, double φ, double stAng, double swAng, Point currentPoint) { const string comma = ","; var θ1 = stAng / 180 * Math.PI; var Δθ = swAng / 180 * Math.PI; //是否是大弧 var isLargeArcFlag = Math.Abs(Δθ) > Math.PI; //是否是顺时针 var isClockwise = Δθ > 0; //修复当椭圆弧线进行360°时,起始点和终点一样,会导致弧线变成点,因此-1°才进行计算 if (System.Math.Abs(Δθ) == 2 * System.Math.PI) { Δθ = Δθ - Δθ / 360; } //获取终点坐标 var pt = GetArcArbitraryPoint(rx, ry, Δθ, θ1, φ, currentPoint); currentPoint = pt; // 格式如下 // A rx ry x-axis-rotation large-arc-flag sweep-flag x y // 这里 large-arc-flag 是 1 和 0 表示 stringPath.Append("A") .Append(rx) //rx .Append(comma) .Append(ry) //ry .Append(comma) .Append(φ) // x-axis-rotation .Append(comma) .Append(isLargeArcFlag ? "1" : "0") //large-arc-flag .Append(comma) .Append(isClockwise ? "1" : "0") // sweep-flag .Append(comma) .Append(pt.X) .Append(comma) .Append(pt.Y) .Append(' '); return stringPath.ToString(); } /// <summary> /// 获取椭圆任意一点坐标(终点) /// </summary> /// <param>椭圆半长轴</param> /// <param>椭圆半短轴</param> /// <param>摆动角度(起始角的摆动角度,也就是起始角+摆动角=结束角)</param> /// <param>起始角</param> /// <param>旋转角</param> /// <param>起点</param> /// <returns></returns> private static Point GetArcArbitraryPoint(double rx, double ry, double Δθ, double θ1, double φ, Point currentPoint) { //开始点的椭圆任意一点的二维矩阵方程式 var matrixX1Y1 = new Matrix { M11 = currentPoint.X, M21 = currentPoint.Y }; var matrix1 = new Matrix { M11 = Math.Cos(φ), M12 = -Math.Sin(φ), M21 = Math.Sin(φ), M22 = Math.Cos(φ) }; var matrix2 = new Matrix { M11 = rx * Math.Cos(θ1), M21 = ry * Math.Sin(θ1) }; var multiplyMatrix1Matrix2 = Matrix.Multiply(matrix1, matrix2); var matrixCxCy = new Matrix { M11 = matrixX1Y1.M11 - multiplyMatrix1Matrix2.M11, M21 = matrixX1Y1.M21 - multiplyMatrix1Matrix2.M21 }; //终点的椭圆任意一点的二维矩阵方程式 var matrix3 = new Matrix { M11 = rx * Math.Cos(θ1 + Δθ), M21 = ry * Math.Sin(θ1 + Δθ) }; var multiplyMatrix1Matrix3 = Matrix.Multiply(matrix1, matrix3); var matrixX2Y2 = new Matrix { M11 = multiplyMatrix1Matrix3.M11 + matrixCxCy.M11, M21 = multiplyMatrix1Matrix3.M21 + matrixCxCy.M21 }; return new Point(matrixX2Y2.M11, matrixX2Y2.M21); }效果如下: