我正在尝试制作一个需要4个参数的bezier函数:
> import Diagrams.Backend.SVG.CmdLine
> import Diagrams.Prelude
> import Control.Applicative
> bezier4 x1 c1 c2 x2 = bezier3 (c1 ^-^ x1) (c2 ^-^ x1) (x2 ^-^ x1) # translate x1
> lineBtwPoints p1 p2 = fromOffsets [p2 ^-^ p1] # translate p1
> illustrateBézier x1 c1 c2 x2
> = endpt # translate x1
> <> endpt # translate x2
> <> ctrlpt # translate c1
> <> ctrlpt # translate c2
> <> l1
> <> l2
> <> fromSegments [bezier4 x1 c1 c2 x2]
> where
> dashed = dashingN [0.03,0.03] 0
> endpt = circle 0.05 # fc red # lw none
> ctrlpt = circle 0.05 # fc blue # lw none
> l1 = lineBtwPoints x1 c1 # dashed
> l2 = lineBtwPoints x2 c2 # dashed
>
> x1 = r2 (0.3, 0.5) :: R2
> x2 = r2 (3,-1) :: R2 -- endpoint
> [c1,c2] = map r2 [(1,2), (3,0)] -- control points
> example = illustrateBézier x1 c1 c2 x2
但结果似乎不是我想要的:
答案 0 :(得分:4)
首先让我们说出这个名字。通常bezier4
将是给出四次贝塞尔曲线段的函数的名称。一个更好的名称是fixedBezier3
,更好的形式是采用Points
而不是参数的向量。实际上,此函数以FCubic
数据类型中的FixedSegment
存在。
如果我们查看bezier4
的类型,我们可以看到出错的地方:
bezier4 x1 c1 c2 x2 = bezier3 (c1 ^-^ x1) (c2 ^-^ x1) (x2 ^-^ x1) # translate x1
ghci> :t bezier4
bezier4'
:: (Data.Basis.HasBasis v,
Data.MemoTrie.HasTrie (Data.Basis.Basis v)) =>
v -> v -> v -> v -> Segment Closed v
重要的是,结果是Segment Closed v
。阅读Segment
的{{3}}:
细分是翻译不变的,也就是说,它们没有特别之处 &#34;位置&#34;并且不受翻译的影响。然而,它们受到影响 其他转换,如旋转和缩放。
bezier4
末尾的翻译不会产生任何影响,因为Segment
类型无法表达具有位置的值,它只表示&#34;形状&#34;和流离失所。我们可以在GHCi中看到这一点:
ghci> bezier4 x1 c1 c2 x2
Cubic (0.7 ^& 1.5) (2.7 ^& (-0.5)) (OffsetClosed (2.7 ^& (-1.5)))
ghci> bezier4' x1 c1 c2 x2 # translate (r2 (1000,1000))
Cubic (0.7 ^& 1.5) (2.7 ^& (-0.5)) (OffsetClosed (2.7 ^& (-1.5)))
一种解决方法是将bezier4
的类型设为Located (Segment Closed v)
。有了这种类型,我们至少可以表达所需的曲线:
bezier4' x1 c1 c2 x2 = bezier3 (c1 ^-^ x1) (c2 ^-^ x1) (x2 ^-^ x1) `at` (0 .+^ x1)
ghci> bezier4' x1 c1 c2 x2
Loc { loc = P (0.3 ^& 0.5)
, unLoc = Cubic (0.7 ^& 1.5) (2.7 ^& (-0.5)) (OffsetClosed (2.7 ^& (-1.5)))
}
请注意,我们获得与之前相同的细分,但现在我们有了一个位置。
ghci> bezier4' x1 c1 c2 x2 # translate (r2 (1000,1000))
Loc { loc = P (1000.3 ^& 1000.5)
, unLoc = Cubic (0.7 ^& 1.5) (2.7 ^& (-0.5)) (OffsetClosed (2.7 ^& (-1.5)))
}
虽然我们在这一点上有点卡住了。定位段不是特别有趣,因为我们通常希望将多个段串联为Trail
。找到的列段会让我们在那里,我们可以使用fromLocSegments
:
fromLocSegments :: TrailLike t => Located [Segment Closed (V t)] -> t
现在我们有一些可行的方法(在bezier4
的使用网站上进行了额外的更改):
bezier4 x1 c1 c2 x2 = fromSegments [bezier3 (c1 ^-^ x1) (c2 ^-^ x1) (x2 ^-^ x1)]
# translate x1
请注意,我们不能将此函数的输出与其他段串联在一起以构成更长的路径。图表选择使用包含Segment
,Trail
,Located
和Path
的强类型,只允许与输出中表达的值精确匹配的值(&#34;含义&# 34)。例如,说我们想写
fromFixedSegments
:
fromFixedSegments :: TrailLike t => [FizedSegment (V t)] -> t
每个立方体片段将有四个点,但结果将是具有“#34;无间隙”的含义的轨迹。为此,我们必须丢弃相邻段的第一个或最后一个点的信息。这里没有好的选择!