Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【Openxml】将Openxml的椭圆弧线arcTo转为Svg的椭圆弧线

【Openxml】将Openxml的椭圆弧线arcTo转为Svg的椭圆弧线

作者头像
ryzenWzd
发布于 2021-09-01 09:20:02
发布于 2021-09-01 09:20:02
1K03
代码可运行
举报
文章被收录于专栏:WPFWPF
运行总次数:3
代码可运行

本文将介绍如何将OpenXml的actTo转为Svg的弧线(a)

OpenXml的artTo

首先下面是一段OpenXml的arcTo弧线

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<arcTo wR="152403" hR="152403" stAng="cd4" swAng="-5400000" />

假设我们当前的点是(0,0),这时候我们已知的信息如下:

  • 当前点坐标:(x1,y1)=(0,0)
  • 椭圆的半径:半长轴 rx=wR=152403,半短轴 ry=hR=152403
  • 起始角到结束角的夹角:起始角θ1=stAng=cd4,夹角Δθ=swAng,结束角θ2=θ1+Δθ
  • 是否优(大)弧:fA=|Δθ|>Π(180°)
  • 顺逆时针:fS=|Δθ|>0°

目前Svg的椭圆弧线参数字符串为以下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
a  rx  ry  x-axis-rotation  large-arc-flag  sweep-flag  x  y 

其中涉及到的参数:

参数

说明

备注

rx

椭圆半长轴

已知:rx=wR=152403

ry

椭圆半短轴

已知:ry=hR=152403

x-axis-rotation

椭圆相对于坐标系的旋转角度,角度数而非弧度数

已知:0

large-arc-flag

是否优(大)弧:0否,1是

已知:fA=|Δθ|>Π(180°)

sweep-flag

绘制方向:0逆时针,1顺时针

已知:fS=|Δθ|>0°

x

圆弧终点的x坐标

未知

y

圆弧终点的y坐标

未知

因此实际上,我们需要求出的则是圆弧终点坐标就能够完成最终换算到Svg椭圆弧线字符串了

求椭圆弧上任意一点的二维矩阵方程式

以下是我从W3C的SVG官方文档中获取到的关于椭圆任意一点的二维矩阵方程式:

因此的存在以下两个(开始点和终点)椭圆任意一点的二维矩阵方程式:

其中涉及到的参数:

参数

说明

备注

(x1,y1)

当前坐标

已知:(0,0)

(x2,y2)

终点坐标

未知

φ

椭圆相对于坐标系的旋转角度

已知:0°

θ1

起始角

已知:stAng

Δθ

起始角到结束角的夹角

已知:swAng

(cx,cy)

椭圆中心坐标点

未知

fA

是否优(大)弧

已知:fA=|Δθ|>Π(180°)

fS

绘制方向

已知:fS=Δθ>0°

因此推导公式如下:

步骤1:

因为开始点的椭圆任意一点的二维矩阵方程式为

所以能够得出两行一列矩阵CxCy为:

步骤2:

因为终点的椭圆任意一点的二维矩阵方程式为

因此将矩阵CxCy带入到终点点的椭圆任意一点的二维矩阵方程式:

代码部分

在写代码之前,我们需要安装一些所需要用到的库,Openxml单位换算为Pixel的库和矩阵运算用到的库:

通过nuget包的控制台执行以下命令:

Openxml单位换算库

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Install-Package dotnetCampus.OpenXmlUnitConverter -Version 1.5.1

矩阵运算库

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Install-Package MathNet.Numerics -Version 5.0.0-alpha02

然后正式开始我们的代码,我们通过WPF应用窗体来展示效果:

前端xaml代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<Window x:Class="OpenxmlActToSvgSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:OpenxmlActToSvgSample"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Path x:Name="Path" Stroke="Blue" HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Grid>
</Window>

后端cs代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        public MainWindow()
        {
            InitializeComponent();

            //Openxml的360° circle
            const double c = 21600000d;
            //circle divide 4
            var cd4 = c / 4;

            //<arcTo wR="152403" hR="152403" stAng="cd4" swAng="-5400000" />
            var wR = 152403;
            var hR = 152403;
            var stAng = cd4;
            var swAng = -5400000d;

            StringBuilder stringPath=new StringBuilder();
            var currentPoint=new Point(0, 0);
            stringPath.Append($"M {currentPoint.X} {currentPoint.Y}");

            ParseOpenxmlArcTo(stringPath, wR, hR, stAng, swAng, currentPoint);
            this.Path.Data=Geometry.Parse(stringPath.ToString());
        }


         private Point  ParseOpenxmlArcTo(StringBuilder stringPath, double wR, double hR, double stAng, double swAng, Point currentPoint)
        {
            const string comma = ",";

            //将Openxml的角度转为真实的角度
            var θ1 = new Angle((int)stAng).ToRadiansValue();
            var Δθ = new Angle((int)swAng).ToRadiansValue();
            //旋转角
            var φ = 0d;
            //是否是大弧
            var isLargeArcFlag = Math.Abs(Δθ) > Math.PI;
            //是否是顺时针
            var isClockwise = Δθ > 0;

            var rx = new Emu(wR).ToPixel().Value;
            var ry = new Emu(hR).ToPixel().Value;

            //获取终点坐标
            var pt = GetArBitraryPoint(rx, ry, swAng, stAng, φ, 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 currentPoint;

        }

         /// <summary>
        /// 获取椭圆任意一点坐标
        /// </summary>
        /// <returns></returns>
        private static Point GetArBitraryPoint(double rx, double ry, double Δθ, double θ1, double φ, Point currentPoint)
        {
            //开始点的椭圆任意一点的二维矩阵方程式
            var matrixX1Y1 = DenseMatrix.OfArray(new double[2, 1]
            {
                { currentPoint.X},
                { currentPoint.Y}
            });

            var matrix1 = DenseMatrix.OfArray(new double[2, 2]
            {
            { Math.Cos(φ),-Math.Sin(φ)},
            { Math.Sin(φ),Math.Cos(φ)}
            });
            var matrix2 = DenseMatrix.OfArray(new double[2, 1]
            {
                { rx*Math.Cos(θ1)},
                { ry*Math.Sin(θ1)}
            });
            var matrixCxCy = matrixX1Y1 - (matrix1 * matrix2);

            //终点的椭圆任意一点的二维矩阵方程式
            var matrix3 = DenseMatrix.OfArray(new double[2, 1]
            {
                { rx*Math.Cos(θ1+Δθ)},
                { ry*Math.Sin(θ1+Δθ)}
            });

            var matrixX2Y2 = matrix1 * matrix3 + matrixCxCy;

            return new Point(matrixX2Y2.Values[0], matrixX2Y2.Values[1]);

        }

效果如下:

可以看到,我们成功的绘制出我们的一条椭圆弧线,虽然很简单,但是其实这条弧线是我取ppt形状缺角矩形当中的一条弧线,在绘制其形状时候,上述方法会自动根据arcTo的数据来自动判断弧线的大小弧、顺逆时针等情况的绘制

源码

BlogCodeSample/OpenxmlActToSvgSample at main · ZhengDaoWang/BlogCodeSample

参考

Implementation Notes — SVG 2

【OpenXml】Pptx的形状转为WPF的Geometry - RyzenAdorer - 博客园

dotnet OpenXML SDK 形状几何 Geometry 的计算公式含义

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-08-26 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
根据SVG Arc求出其开始角、摆动角和椭圆圆心
这时候我们通过矩阵运算得到了矩阵x1y1和矩阵cxcy,然后还有以下公式求开始角和摆动角:
ryzenWzd
2022/05/07
5850
根据SVG Arc求出其开始角、摆动角和椭圆圆心
dotnet OpenXML 让 PathLst 自定义形状转 SVG 路径格式的 Geometry 内容
在 Office 文档里面,可以使用自己定制的自绘制形状,自己绘制的内容将会存放为 pathLst 也就是 List of Shape Paths 内容到文档里面。本文将告诉大家如何将 PathLst 自定义形状转换为标准的 SVG 路径,以支持在 WPF 或 UWP 中的 Path 元素作为 Geometry 显示
林德熙
2021/02/04
1.9K1
基础 | 在物理引擎中画圆弧
作者|zzbozheng 原文|http://imweb.io/topic/5959aee62536e43f14da1a68 因为需求的需要,要使用在物理引擎中使用四分之一圆弧,我们来看看怎么实现在物理引擎中画出四分之一的圆弧, 在物理引擎中绘制圆弧 一般来说,物理引擎都是提供一般的画图方法,比如:circle(圆)、polygon(不规则多边形)、rectangle(矩形) 等图形,但如果需要画出比较灵活又不规则的图形的话,那么就需要使用 svg 提供支持了。下面来探讨一下如何实现四分之一圆弧: 我们来看
用户1097444
2022/06/29
1.5K0
基础 | 在物理引擎中画圆弧
在物理引擎中画圆弧
本文作者:IMWeb zzbozheng 原文出处:IMWeb社区 未经同意,禁止转载 因为需求的需要,要使用在物理引擎中使用四分之一圆弧,我们来看看怎么实现在物理引擎中画出四分之一的圆弧,
IMWeb前端团队
2018/01/08
2.5K0
在物理引擎中画圆弧
svg上实现图形移动
前两个参数分别是x轴半径和y轴半径,x-axis-rotation是绕x轴旋转角度,large-arc-flag(角度大小) 和sweep-flag(弧线方向),large-arc-flag决定弧线是大于还是小于180度,0表示小角度弧,1表示大角度弧。sweep-flag表示弧线的方向,0表示从起点到终点沿逆时针画弧,1表示从起点到终点沿顺时针画弧。
Enterprise_
2020/07/09
1K0
svg上实现图形移动
SVG 快速入门
本文作者:ivweb villainthr SVG 全称是 Scalable Vector Graphics,即,矢量图。在 Web 中使用 SVG 可以解决位图放大失真的问题。首先,不要把 SVG
腾讯IVWEB团队
2017/07/11
3.1K5
SVG 快速入门
SVG基础知识速查笔记
svg是指可缩放矢量图形,是用于描述二维矢量图形的一种图形格式。svg使用XML格式来定义图形,除ie8之前版本外,绝不部分浏览器均支持svg,可将svg文本直接嵌入HTML中显示。
前端_AWhile
2019/09/06
2K0
【OpenXml】Pptx的多路径形状转为WPF的Path
本文是将演示如何解析pptx文件的多路径的形状转换到WPF,绘制多个Shape的Path
ryzenWzd
2021/07/14
4490
【HarmonyOS之旅】基于ArkTS开发(三) -> 兼容JS的类Web开发(五) -> Svg
通过设置width、height、x、y和viewBox属性为Svg设置宽度、高度、x轴坐标、y轴坐标和Svg视口。
枫叶丹
2025/02/24
840
【HarmonyOS之旅】基于ArkTS开发(三) -> 兼容JS的类Web开发(五) -> Svg
SVG绘制饼状图
SVG绘制饼状图 昨天学习了基本的SVG,下面是使用SVG绘制饼状图 创建SVG空间 创建SVG 需要一个document.createElementNS()方法 一个一个setAttribute()方法 编写如下js,将会创建一个svg空间 // 创建一个XML命名空间 var svgns = "http://www.w3.org/2000/svg"; // 创建一个SVG元素指定大小和坐标 var chart = document.createElementNS(svgns, "svg:sv
mySoul
2018/10/15
2.7K0
SVG
HTML体系中,最常用的绘制矢量图的技术是SVG和HTML5新增加的canvas元素。这两种技术都支持绘制矢量图和光栅图。不过canvas更偏重于动画的制作。所以,绘制矢量图的大任落到了SVG身上。
踏浪
2019/07/31
5.8K0
SVG
VectorDrawable与AnimatedVectorDrawable
VectorDrawable  Android L开始提供了新的API VectorDrawable 可以使用SVG类型的资源,也就是矢量图。先来一个例子吧。 <?xml version="1.0
xiangzhihong
2018/02/05
9800
VectorDrawable与AnimatedVectorDrawable
用SVG实现一个优雅的提示框
Tooltips常被称为提示框(或信息提示框),提示框能够以较强的交互性、自由度为用户提供相应的提示信息。今天我们要聊的不是如何实现强大的交互行为,而是来看看如何以最好的方式来还原他们的视觉效果,并且能适用于不同的场景。
ConardLi
2020/06/10
2.5K0
用SVG实现一个优雅的提示框
HarmonyOS:ArkTS Path 组件自学指南
在日常的鸿蒙应用开发工作中,我常常会遇到需要绘制各种图形和路径的场景。无论是简单的直线、折线,还是复杂的曲线、椭圆弧,传统的布局方式很难满足多样化的图形绘制需求。直到我接触到了 ArkTS 中的 Path 组件,它就像一把神奇的画笔,为我打开了创意绘图的大门。通过灵活运用 Path 组件,我能够轻松地在应用中绘制出各种精美的图形,为用户带来更加丰富和生动的视觉体验。为了帮助更多开发者快速掌握这个强大的组件,我决定将自己的学习经验整理成这篇自学指南。
李游Leo
2025/03/30
890
HarmonyOS:ArkTS Path 组件自学指南
【Flutter 绘制番外】svg 终篇 - 路径指令
上两篇我们通过对 svg 路径 M/H/V/L/C/Q/Z 几个指令的解析。把 掘金 logo 的 svg ,转化为 Flutter 的原生路径绘制,并且附加了一些绘制效果。
张风捷特烈
2022/04/15
1.5K0
【Flutter 绘制番外】svg 终篇 - 路径指令
Threejs进阶之十七:Threejs中的Path、Shape和ShapeGeometry类
在实际的应用中,有时候需要我们根据一个二维图形拉伸为三维图形的情况,这就需要我们对Threejs中提供的二维图形相关的类有一个深入的了解,这一节我们就深入的聊一聊Threejs中的Path、Shape和ShapeGeometry类
九仞山
2023/10/14
2K0
Threejs进阶之十七:Threejs中的Path、Shape和ShapeGeometry类
Graphics2D 绘制图形-圆角矩形,矩形,椭圆、圆弧等
Java语言在Graphics类提供绘制各种基本的几何图形的基础上,扩展Graphics类提供一个Graphics2D类,它拥用更强大的二维图形处理能力,提供、坐标转换、颜色管理以及文字布局等更精确的控制。
botkenni
2023/03/16
2.9K0
svg.js教程及使用手册详解(二)
上篇简要介绍了svg.js的基本信息和基本用法,这篇开始详细讲解svg.js的用法。
王金龙
2018/08/24
6.5K1
【Web技术】1139- 手把手教你实现手绘风格图形
https://juejin.cn/post/6942262577460314143
pingan8787
2021/11/17
8660
带你玩转自定义view系列
View是Android所有控件的基类,接下来借鉴网上的一张图片让大家一目了然(图片出自:http://blog.51cto.com/wangzhaoli/1292313)
Android技术干货分享
2019/03/26
1.6K0
带你玩转自定义view系列
相关推荐
根据SVG Arc求出其开始角、摆动角和椭圆圆心
更多 >
领券
💥开发者 MCP广场重磅上线!
精选全网热门MCP server,让你的AI更好用 🚀
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验