在haskell中接受4个参数的bezier函数
我正在尝试制作一个需要4个参数的贝塞尔函数:在haskell中接受4个参数的bezier函数,haskell,graphics,haskell-diagrams,Haskell,Graphics,Haskell Diagrams,我正在尝试制作一个需要4个参数的贝塞尔函数: > 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
> 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
>导入Diagrams.Backend.SVG.CmdLine
>导入图表。序曲
>导入控制
>bezier4 x1 c1 c2 x2=bezier3(c1^-^x1)(c2^-^x1)(x2^-^x1)#翻译x1
>lineBtwPoints p1 p2=从偏移量[p2^-^p1]#转换p1
>illustrateBézier x1 c1 c2 x2
>=endpt#平移x1
>endpt#翻译为x2
>ctrlpt#翻译c1
>ctrlpt#翻译c2
>l1
>l2
>fromSegments[bezier4 x1 c1 c2 x2]
>在哪里
>虚线=虚线[0.03,0.03]0
>endpt=圆圈0.05#fc红色#lw无
>ctrlpt=圆圈0.05#fc蓝色#lw无
>l1=线B点x1 c1#虚线
>l2=线B点x2 c2#虚线
>
>x1=r2(0.3,0.5)::r2
>x2=r2(3,-1)::r2--端点
>[c1,c2]=地图r2[(1,2)、(3,0)]--控制点
>示例=illustrateBézier x1 c1 c2 x2
但结果似乎不是我想要的:
首先让我们对名称进行寻址。通常,
bezier4
将是给出四次bezier曲线段的函数的名称。更好的名称是fixedBezier3
,更好的形式是为参数取点而不是向量。实际上,该函数在fixedsecgment
数据类型中以FCubic
的形式存在
如果我们看一下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
重要的一点是,结果是段闭合v
。读取段
:
分段是平移不变的,也就是说,它们没有特定的属性
“位置”和不受翻译的影响。然而,它们受到了以下因素的影响:
其他变换,例如旋转和缩放
bezier4
末尾的平移不会产生任何效果,因为类型段
无法表示具有位置的值,它只表示“形状”和位移。我们可以在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
类型产生定位(段闭合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)))
}
不过,我们在这一点上有点卡住了。定位的段并不特别有趣,因为我们通常希望将多个段串在一起作为轨迹
。一个定位的段列表将我们带到那里,我们可以使用LocSegments的fromLocSegments
:
fromLocSegments :: TrailLike t => Located [Segment Closed (V t)] -> t
fromFixedSegments :: TrailLike t => [FizedSegment (V t)] -> t
现在我们有了一些可以使用的东西(在bezier4
的使用站点上进行了额外的更改):
请注意,我们不能将此函数的输出与其他段串在一起以形成更长的轨迹。图表选择使用具有段
、轨迹
、定位
、和路径
的强类型,仅允许精确匹配输出中表达的值(“含义”)。例如,假设我们想写作
来自FixedSegments的:
fromLocSegments :: TrailLike t => Located [Segment Closed (V t)] -> t
fromFixedSegments :: TrailLike t => [FizedSegment (V t)] -> t
每个立方段将有四个点,但结果将是一条具有“无间隙”含义的轨迹。要做到这一点,我们必须扔掉相邻线段的第一个或最后一个点的信息。这里没有好的选择 但就我所知,bezier4
曲线并不是一条经过翻译的bezier3
曲线……哦,这不是一个好名字。bezier3函数总是从原点开始,我只是想做一个可以从任意点开始的函数。这是一个好名字:正如你在上所看到的,你可以为任意数量的点定义一条Bezier曲线。bezier3中的3不是参数的数量,而是曲线的阶数(它是一个立方)因此,函数中的4表示贝塞尔曲线是四次曲线(需要5个点或4个向量)。请注意,bezier3并不“总是从原点开始”,它只是一个段,因此没有位置(这有点像一个向量)。线段在列表中非常有用,可以创建复杂曲线,然后使用在其起点进行定位。然后,您可以使用fromLocSegments
获取图表。