我正在寻找关于如何在以下 WPF 和/或 SVG 图形中计算A,B和C的一些提示/建议。这与我刚刚提出的another question图片有关,但我不想使用LineJoin
和Miter
的笔画,而是想用{{Path
创建LineTo
1}}和ArcTo
代替。 SVG和WPF中的斜接略有不同,它不会附加到坐标空间,而是放在它之外(例如,如果边界框为100x100,则斜角将出现在负空间中,圆角端将出现在100+空间。)
我在事先知道几乎没有三角学的情况下道歉。我确实试过查找cos,sin和tan,但不能大脑。我全神贯注地看着,无法找到一些直截了当的东西来处理我正在寻求帮助的东西。
有些事情:
ArcTo
从A
到B
(反之亦然,如果那样更好)。MoveTo
始终是边界矩形的顶部中心(在本例中为0.84,0)。我真的很感激任何关于此的建议。提前致谢。 (以免我被指责为“家庭作业”,知道我在1987年获得了GED ......)
答案 0 :(得分:1)
近似结果,更好地在程序中计算它以获得更高的精度。
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
形成直角,我们可以确定角度{{1}}(a1
之间1}}和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
因此我们的水平轴(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°
到r
和a
的距离(D
)和角度(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
之间的增量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>
这会产生:
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;