计算WPF或SVG图形的坐标点

时间:2017-09-26 07:20:32

标签: c# vb.net math trigonometry

我正在寻找关于如何在以下 WPF 和/或 SVG 图形中计算A,B和C的一些提示/建议。这与我刚刚提出的another question图片有关,但我不想使用LineJoinMiter的笔画,而是想用{{Path创建LineTo 1}}和ArcTo代替。 SVG和WPF中的斜接略有不同,它不会附加到坐标空间,而是放在它之外(例如,如果边界框为100x100,则斜角将出现在负空间中,圆角端将出现在100+空间。)

我想弄清楚的图形是: arrow

我在事先知道几乎没有三角学的情况下道歉。我确实试过查找cos,sin和tan,但不能大脑。我全神贯注地看着,无法找到一些直截了当的东西来处理我正在寻求帮助的东西。

有些事情:

  • 我使用英寸作为下面的值。
  • 我将永远知道边界矩形(在这种情况下,1.68英寸x 1.68英寸)
  • 我将永远知道“笔划厚度”(箭头的两个斜率)。在这种情况下,0.28英寸。
  • 两个圆圈(实际上是半圆圈)将始终与左下角和右下角齐平。它们将始终具有已知尺寸(在这种情况下,直径为0.28英寸)。该计划是ArcToAB(反之亦然,如果那样更好)。
  • MoveTo始终是边界矩形的顶部中心(在本例中为0.84,0)。

我真的很感激任何关于此的建议。提前致谢。 (以免我被指责为“家庭作业”,知道我在1987年获得了GED ......)

1 个答案:

答案 0 :(得分:1)

近似结果,更好地在程序中计算它以获得更高的精度。

A = 0.0178, 1.4717
B = 0.2622, 1.6083
C = 0.84,   0.5739

Close up of Circle

左下角的粗略特写

此计算可能包含一些不必要的步骤,但这里是如何使用基本三角函数计算A和B.由于箭头是对称的,我只计算左半部分,假设原点(0,0)在左上角。

r = 0.14 (0.28/2)
w,h = 1.64

圆圈的中心(D)位于r, h-r。箭头的尖端(T)是w/2,0。由于左切线(AT)必须与AD形成直角,我们可以确定角度{​​{1}}(a1之间1}}和D)以下方式:

T
在这种情况下,

a1 = acos(r / H) (斜边)是从HD的距离,在这种情况下

T

所以H = |D - T| H = sqrt(0,7² + 1,54²) H = 1,6916... a1。连同从水平到85.25273°DT)的角度:

a2

因此我们的水平轴(X)和a2 = atan(DTy / DTx) a2 = atan((1.54 - 0.0) / (0.84 - 0.14)) a2 = atan(1.54 / 0.7) a2 = 65.56° 之间的总角度是

DA

现在我们知道从a = a1+a2 a = 150.81273° ra的距离(D)和角度(A)。

B

您现在要做的就是从中心添加和减去(dx = cos(a) * r dy = sin(a) * r dx = 0.1222 dy = 0.0683 ),然后DA

B

Determining C

现在开始A = 0.0178, 1.4717 B = 0.2622, 1.6083 。由于我们希望CAT平行,因此我们可以使用已计算的角度BC来确定a。此处BCxB之间的增量X,C增量Y,y角度b相对于x-轴。

BC

我们已经知道b = a - 90° b = 60.81273° C)的x位置,因为我们希望它位于中心位置。

Cx

现在我们有了另一个直角三角形,我们可以确定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




以下编辑由Todd Main撰写,原创海报。以下是Manfred Radlwimmer奇妙代码的实现。它在VB.NET中并使用XML Literals。它没有任何分号。如果SO允许在这个日子和年龄的VB中注释代码,它就会有评论。它会在原始帖子中创建图片,并附加到此答案中,供其他人根据需要查看和使用。

<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>

这会产生:

&#13;
&#13;
    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
&#13;
&#13;
&#13;