计算 WPF 或 SVG 图形的坐标点

Calculating Coordinate Points for an WPF or SVG graphic

我正在寻找一些 tips/advice 关于如何在下面的 WPF and/or SVG[ 中计算 A、B 和 C =39=]图形。这与我刚才问的 的图形有关,但我不想使用 LineJoinMiter 的笔画,而是想用 [= 创建一个 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 英寸)。计划是 ArcToAB(如果更好的话,反之亦然)。
  • 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。由于左切线(AT)必须与AD形成一个直角,我们可以确定角度a1(在DT) 如下:

a1 = acos(r / H)

H(斜边)在本例中是从 DT 的距离,在本例中是

H = |D - T|
H = sqrt(0,7² + 1,54²)
H = 1,6916...

所以 a185.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°

现在我们知道从DA的距离(r)和角度(a)和B.

dx = cos(a) * r
dy = sin(a) * r

dx = 0.1222
dy = 0.0683

你现在所要​​做的就是从中心 (D) 中加上和减去它,你就有了 AB

A = 0.0178, 1.4717
B = 0.2622, 1.6083

现在进入 C。由于我们希望ATBC平行,所以我们可以使用已经计算出的角度a来确定BC。这里 xBC 之间的 delta X,y 是 delta Y,bBC 相对于 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>