计算 WPF 或 SVG 图形的坐标点
Calculating Coordinate Points for an WPF or SVG graphic
我正在寻找一些 tips/advice 关于如何在下面的 WPF and/or SVG[ 中计算 A、B 和 C =39=]图形。这与我刚才问的 的图形有关,但我不想使用 LineJoin
和 Miter
的笔画,而是想用 [= 创建一个 Path
13=] 和 ArcTo
代替。 SVG 和 WPF 中的斜接略有不同,它不会附加到坐标 space,而是位于坐标之外(例如,如果边界框为 100x100,斜接将出现在负 space 圆角的末端会出现在 100+ space).
我想弄清楚的图形是:
对于三角学几乎一无所知,我提前道歉。我确实尝试查找 cos、sin 和 tan,但想不通。我找遍了 SO,找不到足够直接的东西来处理我正在寻求帮助的东西。
一些事情:
- 我使用英寸作为以下值。
- 我将永远知道边界矩形(在本例中为 1.68 英寸 x 1.68 英寸)
- 我永远都知道"stroke thickness"(箭头的两个斜面)。在这种情况下,0.28 英寸。
- 两个圆圈(实际上是半个圆圈)总是与左下角和右下角齐平。它们将始终具有已知尺寸(在本例中,直径为 0.28 英寸)。计划是
ArcTo
从 A
到 B
(如果更好的话,反之亦然)。
MoveTo
始终是边界矩形的顶部中心(在本例中为 0.84,0)。
我非常感谢任何关于此的建议。提前致谢。 (以免我被可怕地指责 "homework",要知道我在 1987 年获得了 GED...)
大概的结果,最好在你的程序中计算得到更高的精度。
A = 0.0178, 1.4717
B = 0.2622, 1.6083
C = 0.84, 0.5739
左下圆圈粗略特写
此计算可能包含一些不必要的步骤,但这里是您可以使用基本三角函数计算 A 和 B 的方法。由于箭头是对称的我只计算了左半部分,假设原点(0,0)在左上角。
r = 0.14 (0.28/2)
w,h = 1.64
圆心 (D
) 位于 r, h-r
。箭头 (T
) 的尖端是 w/2,0
。由于左切线(A
到T
)必须与A
到D
形成一个直角,我们可以确定角度a1
(在D
和 T
) 如下:
a1 = acos(r / H)
H
(斜边)在本例中是从 D
到 T
的距离,在本例中是
H = |D - T|
H = sqrt(0,7² + 1,54²)
H = 1,6916...
所以 a1
是 85.25273°
。加上从水平方向到DT
的角度(a2
):
a2 = atan(DTy / DTx)
a2 = atan((1.54 - 0.0) / (0.84 - 0.14))
a2 = atan(1.54 / 0.7)
a2 = 65.56°
所以我们的水平轴 (X) 和 DA
之间的总角度是
a = a1+a2
a = 150.81273°
现在我们知道从D
到A
的距离(r
)和角度(a
)和B
.
dx = cos(a) * r
dy = sin(a) * r
dx = 0.1222
dy = 0.0683
你现在所要做的就是从中心 (D
) 中加上和减去它,你就有了 A
和 B
A = 0.0178, 1.4717
B = 0.2622, 1.6083
现在进入 C
。由于我们希望AT
和BC
平行,所以我们可以使用已经计算出的角度a
来确定BC
。这里 x
是 B
和 C
之间的 delta X,y
是 delta Y,b
是 BC
相对于 x-轴.
b = a - 90°
b = 60.81273°
我们已经知道 C
(Cx
) 的 x 位置,因为我们希望它位于中心。
Cx = w/2
Cx = 0.84
x = Cx - Bx
x = 0.84 - 0.2622
x = 0.5778
现在我们有了另一个直角三角形,我们可以确定y
。
tan(b) = y/x
y = tan(b) * x
y = 1.79022 * 0.5778
y = 1.0344
Cy = By - y
Cy = 1.6083 - 1.0344
Cy = 0.5739
把所有这些放在一起,你就得到了
C = 0.84, 0.5739
左半部分的完整路径如下所示(准确得多):
<SVG Width="84px" height="168px">
<g transform="scale(100)">
<Path d="M 0,0 L 0.84,0 L 0.84,1.68 L 0,1.68 Z" fill="#f6be98"/>
<Path d="M 0.84,0 L 0.0178 1.4717 A 0.14,0.14 0 0 0 0.2622 1.6083 L 0.84 0.5739 Z" fill="#4472c4" />
</g>
</SVG>
下面的编辑是 Todd Main,原创 poster。以下是 Manfred Radlwimmer 精彩代码的实现。它在 VB.NET 中并使用 XML 文字。它没有任何分号。如果 SO 在这个时代允许在 VB 中评论代码,它就会有评论。它在原始 post 中创建图片,并附加到此答案以供其他人根据需要查看和使用。
Private Sub Main()
Dim diameter = 20
Dim bb As New Size(120, 120)
Dim pathData = RenderedArrowheadPath(diameter, bb)
Dim svg As String = RenderedSVG(bb, pathData).ToString
Console.WriteLine(svg)
Console.ReadLine()
End Sub
Private Function RenderedSVG(bb As Size, pathData As String) As XElement
Return <SVG width=<%= bb.Width.ToString & "px" %> height=<%= bb.Height.ToString & "px" %>>
<g>
<Path d=<%= $"M0,0 L{bb.Width},0 L{bb.Width},{bb.Height} L0,{bb.Height} Z" %> fill="#f6be98"/>
<Path d=<%= pathData %> fill="#4472c4"/>
</g>
</SVG>
End Function
Private Function RenderedArrowheadPath(diameter As Double, bb As Size) As String
Dim radius = diameter / 2
Dim Distance = New Point(radius, bb.Height - radius)
Dim Tip = bb.Width / 2
Dim DT = New Point(bb.Height - radius, (bb.Width / 2) - radius)
Dim Hypotenuse = Math.Sqrt(DT.X ^ 2 + DT.Y ^ 2)
Dim angle1 = Math.Acos(radius / Hypotenuse)
Dim angle2 = Math.Atan(DT.X / DT.Y)
Dim angle = angle1 + angle2
Dim dx = Math.Cos(angle) * radius
Dim dy = Math.Sin(angle) * radius
Dim PointA = New Point(Distance.X + dx, Distance.Y - dy)
Dim PointB = New Point(Distance.X - dx, Distance.Y + dy)
Dim b = angle - (90 / (180 / Math.PI))
Dim Cx = bb.Width / 2
Dim Bx = PointB.X
Dim X = Cx - Bx
Dim Y = Math.Tan(b) * X
Dim Cy = PointB.Y - Y
Dim PointC = New Point(Cx, Cy)
Dim PointBInv = New Point(bb.Width - (Distance.X - dx), Distance.Y + dy)
Dim PointAInv = New Point(bb.Width - (Distance.X + dx), Distance.Y - dy)
Return $"M{Tip},0 L{PointA.X},{PointA.Y} A{radius},{radius} 0 0 0 {PointB.X},{PointB.Y} L{PointC.X},{PointC.Y} L{PointBInv.X},{PointBInv.Y} A{radius},{radius} 0 0 0 {PointAInv.X},{PointAInv.Y} Z"
End Function
这会产生:
<SVG width="120px" height="120px">
<g>
<Path d="M0,0 L120,0 L120,120 L0,120 Z" fill="#f6be98" />
<Path d="M60,0 L1.27003148173183,105.122741582605 A10,10 0 0 0 18.7299685182682,114.877258417395 L60,41.0066440783012 L101.270031481732,114.877258417395 A10,10 0 0 0 118.729968518268,105.122741582605 Z" fill="#4472c4" />
</g>
</SVG>
我正在寻找一些 tips/advice 关于如何在下面的 WPF and/or SVG[ 中计算 A、B 和 C =39=]图形。这与我刚才问的 LineJoin
和 Miter
的笔画,而是想用 [= 创建一个 Path
13=] 和 ArcTo
代替。 SVG 和 WPF 中的斜接略有不同,它不会附加到坐标 space,而是位于坐标之外(例如,如果边界框为 100x100,斜接将出现在负 space 圆角的末端会出现在 100+ space).
我想弄清楚的图形是:
对于三角学几乎一无所知,我提前道歉。我确实尝试查找 cos、sin 和 tan,但想不通。我找遍了 SO,找不到足够直接的东西来处理我正在寻求帮助的东西。
一些事情:
- 我使用英寸作为以下值。
- 我将永远知道边界矩形(在本例中为 1.68 英寸 x 1.68 英寸)
- 我永远都知道"stroke thickness"(箭头的两个斜面)。在这种情况下,0.28 英寸。
- 两个圆圈(实际上是半个圆圈)总是与左下角和右下角齐平。它们将始终具有已知尺寸(在本例中,直径为 0.28 英寸)。计划是
ArcTo
从A
到B
(如果更好的话,反之亦然)。 MoveTo
始终是边界矩形的顶部中心(在本例中为 0.84,0)。
我非常感谢任何关于此的建议。提前致谢。 (以免我被可怕地指责 "homework",要知道我在 1987 年获得了 GED...)
大概的结果,最好在你的程序中计算得到更高的精度。
A = 0.0178, 1.4717
B = 0.2622, 1.6083
C = 0.84, 0.5739
左下圆圈粗略特写
此计算可能包含一些不必要的步骤,但这里是您可以使用基本三角函数计算 A 和 B 的方法。由于箭头是对称的我只计算了左半部分,假设原点(0,0)在左上角。
r = 0.14 (0.28/2)
w,h = 1.64
圆心 (D
) 位于 r, h-r
。箭头 (T
) 的尖端是 w/2,0
。由于左切线(A
到T
)必须与A
到D
形成一个直角,我们可以确定角度a1
(在D
和 T
) 如下:
a1 = acos(r / H)
H
(斜边)在本例中是从 D
到 T
的距离,在本例中是
H = |D - T|
H = sqrt(0,7² + 1,54²)
H = 1,6916...
所以 a1
是 85.25273°
。加上从水平方向到DT
的角度(a2
):
a2 = atan(DTy / DTx)
a2 = atan((1.54 - 0.0) / (0.84 - 0.14))
a2 = atan(1.54 / 0.7)
a2 = 65.56°
所以我们的水平轴 (X) 和 DA
之间的总角度是
a = a1+a2
a = 150.81273°
现在我们知道从D
到A
的距离(r
)和角度(a
)和B
.
dx = cos(a) * r
dy = sin(a) * r
dx = 0.1222
dy = 0.0683
你现在所要做的就是从中心 (D
) 中加上和减去它,你就有了 A
和 B
A = 0.0178, 1.4717
B = 0.2622, 1.6083
现在进入 C
。由于我们希望AT
和BC
平行,所以我们可以使用已经计算出的角度a
来确定BC
。这里 x
是 B
和 C
之间的 delta X,y
是 delta Y,b
是 BC
相对于 x-轴.
b = a - 90°
b = 60.81273°
我们已经知道 C
(Cx
) 的 x 位置,因为我们希望它位于中心。
Cx = w/2
Cx = 0.84
x = Cx - Bx
x = 0.84 - 0.2622
x = 0.5778
现在我们有了另一个直角三角形,我们可以确定y
。
tan(b) = y/x
y = tan(b) * x
y = 1.79022 * 0.5778
y = 1.0344
Cy = By - y
Cy = 1.6083 - 1.0344
Cy = 0.5739
把所有这些放在一起,你就得到了
C = 0.84, 0.5739
左半部分的完整路径如下所示(准确得多):
<SVG Width="84px" height="168px">
<g transform="scale(100)">
<Path d="M 0,0 L 0.84,0 L 0.84,1.68 L 0,1.68 Z" fill="#f6be98"/>
<Path d="M 0.84,0 L 0.0178 1.4717 A 0.14,0.14 0 0 0 0.2622 1.6083 L 0.84 0.5739 Z" fill="#4472c4" />
</g>
</SVG>
下面的编辑是 Todd Main,原创 poster。以下是 Manfred Radlwimmer 精彩代码的实现。它在 VB.NET 中并使用 XML 文字。它没有任何分号。如果 SO 在这个时代允许在 VB 中评论代码,它就会有评论。它在原始 post 中创建图片,并附加到此答案以供其他人根据需要查看和使用。
Private Sub Main()
Dim diameter = 20
Dim bb As New Size(120, 120)
Dim pathData = RenderedArrowheadPath(diameter, bb)
Dim svg As String = RenderedSVG(bb, pathData).ToString
Console.WriteLine(svg)
Console.ReadLine()
End Sub
Private Function RenderedSVG(bb As Size, pathData As String) As XElement
Return <SVG width=<%= bb.Width.ToString & "px" %> height=<%= bb.Height.ToString & "px" %>>
<g>
<Path d=<%= $"M0,0 L{bb.Width},0 L{bb.Width},{bb.Height} L0,{bb.Height} Z" %> fill="#f6be98"/>
<Path d=<%= pathData %> fill="#4472c4"/>
</g>
</SVG>
End Function
Private Function RenderedArrowheadPath(diameter As Double, bb As Size) As String
Dim radius = diameter / 2
Dim Distance = New Point(radius, bb.Height - radius)
Dim Tip = bb.Width / 2
Dim DT = New Point(bb.Height - radius, (bb.Width / 2) - radius)
Dim Hypotenuse = Math.Sqrt(DT.X ^ 2 + DT.Y ^ 2)
Dim angle1 = Math.Acos(radius / Hypotenuse)
Dim angle2 = Math.Atan(DT.X / DT.Y)
Dim angle = angle1 + angle2
Dim dx = Math.Cos(angle) * radius
Dim dy = Math.Sin(angle) * radius
Dim PointA = New Point(Distance.X + dx, Distance.Y - dy)
Dim PointB = New Point(Distance.X - dx, Distance.Y + dy)
Dim b = angle - (90 / (180 / Math.PI))
Dim Cx = bb.Width / 2
Dim Bx = PointB.X
Dim X = Cx - Bx
Dim Y = Math.Tan(b) * X
Dim Cy = PointB.Y - Y
Dim PointC = New Point(Cx, Cy)
Dim PointBInv = New Point(bb.Width - (Distance.X - dx), Distance.Y + dy)
Dim PointAInv = New Point(bb.Width - (Distance.X + dx), Distance.Y - dy)
Return $"M{Tip},0 L{PointA.X},{PointA.Y} A{radius},{radius} 0 0 0 {PointB.X},{PointB.Y} L{PointC.X},{PointC.Y} L{PointBInv.X},{PointBInv.Y} A{radius},{radius} 0 0 0 {PointAInv.X},{PointAInv.Y} Z"
End Function
这会产生:
<SVG width="120px" height="120px">
<g>
<Path d="M0,0 L120,0 L120,120 L0,120 Z" fill="#f6be98" />
<Path d="M60,0 L1.27003148173183,105.122741582605 A10,10 0 0 0 18.7299685182682,114.877258417395 L60,41.0066440783012 L101.270031481732,114.877258417395 A10,10 0 0 0 118.729968518268,105.122741582605 Z" fill="#4472c4" />
</g>
</SVG>