变换
|
该页面正在翻译中。 |
每个情节和每个场景都包含一个 转型 持有 变换_func 并生成一个 模型 矩阵。
模型转换
该 模型 矩阵由平移、缩放和旋转组成,旋转首先起作用,平移最后起作用。 翻译由 翻译!(),按比例缩放 规模!() 和旋转通过 旋转!(). 此外,您可以更改用于缩放和旋转的原点 起源!().
</无翻译>
using GLMakie
using GLMakie
box = Rect2f(0.9, -0.1, 0.2, 0.2)
f = Figure(size = (500, 450))
a = Axis(f[1, 1], aspect = DataAspect())
xlims!(a, 0.2, 1.2); a.xticks[] = 0.1:0.2:1.1
ylims!(a, -0.2, 0.8); a.yticks[] = -0.1:0.2:0.7
# Initial plot for reference
scatterlines!(a, box, color = 1:4, markersize = 20, linewidth = 5)
# Transformed plot
p2 = scatterlines!(a, box, color = 1:4, markersize = 20, linewidth = 5)
origin!(p2, 1,0,0) # apply rotation & scaling relative to the center of the box
scale!(p2, 2, 2) # double x, y
Makie.rotate!(p2, pi/2) # 90° rotation
translate!(p2, -0.5, 0.5) # translate 0.5 left, 0.5 up
f
默认情况下,调用这些函数将复盖以前调用设置的值。 所以如果你打电话 翻译!(情节,1,0,0);翻译!(剧情,0,1,0) 翻译将是 (0,1,0). 要累积转换,您需要添加 [医]Accum 作为第一个参数,例如 翻译!(情节,情节,0,1,0).
变换函数
该 变换_func 是一个函数,它在之后应用于绘图的输入数据 convert_arguments() (类型规范化)和dim_converts(处理单位和类别值)。 它通常由轴管理。 例如,如果设置 斧头xscale[]=log,底层 斧头场景 将其转换函数设置为 (日志、身份) 它将传播到轴/场景内的绘图。
using Makie
f, a, p = scatter(1:10);
Makie.transform_func(a.scene) # (identity, identity)
Makie.transform_func(p) # (identity, identity)
a.xscale[] = log
Makie.transform_func(a.scene) # (log, identity)
Makie.transform_func(p) # (log, identity)
您可以通过更新设置绘图的变换函数 情节。转型。transform_func[]=new_func. 这也会改变每个子图的变换函数。 请注意,这通常会在plots父级转换函数更改时重置,例如,如果 斧头x尺度,x尺度 在上面的例子中设置。 您可以通过显式不继承转换函数或构造 转型 反对你自己。 见下文。
转型 属性
转换属性控制如何 转型 对象进行初始化。 它在情节建设过程中被处理一次,然后被移除。
默认情况下,属性设置为 麦琪自动的. 在这种情况下,如果两个图或场景都使用相同的坐标,则转换将从父图或场景继承 空间. 因此,如果父场景使用3D相机,并且情节使用 空间=:像素,转换不会被继承。 如果相机是像素相机,它将是。 继承转换时,父级 变换_func 被重用和父 模型 矩阵作为二次矩阵变换。 在伪代码中,我们有:
transformation.model = parent.model * local_model
transformation.transform_func = parent.transform_func
继承可以通过几个符号显式控制。 对于所有这些,父级和子级的坐标空间都被忽略。
-
:继承:继承两者模型和变换_func -
:继承_model:只继承模型 -
:继承_transform_func:只继承变换_func -
:没有:继承既不使新转型身份转换
该 转型 属性也接受输入到 变身!() 函数。 这允许您准备具有初始模型转换的绘图。 你可以通过 比例尺, 轮调 和/或 翻译 作为NamedTuple,Dict或Attributes的一部分,或旋转并将xy平面平移到另一个平面 (飞机、班次). 例如:
</无翻译>
using CairoMakie
using CairoMakie
f = Figure()
# transform 0..1 Rect to -1..1 Rect
lines(f[1, 1], Rect2f(0, 0, 1, 1),
transformation = (scale = Vec3f(2), translation = Vec3f(-1)))
a = LScene(f[1, 2])
heatmap!(a, rand(4,4), transformation = (:xy, 0.5))
heatmap!(a, rand(4,4), transformation = (:xz, 0.5))
heatmap!(a, rand(4,4), transformation = (:yz, 0.5))
f
最后还可以构造一个 转型 反对自己,并通过 转型 属性。
构造函数
正如在转换函数部分中所提到的,在某些情况下,构造一个 转型 自己可以是有用的。 例如,您可能想要申请 变换_func 在配方中运行三角测量算法之前,这样三角测量就不会失真。 或者,您可能希望将一系列图的变换连锁起来,使它们保持相对(见下文)。 有一些构造函数有助于了解这一点。
如果要将情节与其父变换完全分离,可以使用以下方法创建它 变换=变换(). 如果您只想删除 变换_func 但不是模型转换,您可以使用 transformation=Transformation(parent,transform_func=identity). 您还可以为以下对象传递不同的起始值 翻译, 比例尺 和 轮调 到这些功能。 这不会影响是否考虑父级模型转换。
using GLMakie
using GLMakie
using Makie: Vec3d
f = Figure(size = (600, 400))
a = Axis(f[2, 2], aspect = DataAspect())
ylims!(0, 3); xlims!(-3, 3)
# Cart
cart = Transformation()
scatter!(a, [-0.32, -0.15, 0.15, 0.32], fill(0.09, 4), transformation = cart,
marker = Circle, color = :transparent, strokewidth = 2, strokecolor = :black,
markerspace = :data, markersize = 0.1
)
linesegments!(a, [-0.4, 0.4], [0.2, 0.2], transformation = cart,
color = :black, linewidth = 5
)
# arms
arm1 = Transformation(cart, origin = Vec3d(0, 0.2, 0))
linesegments!(a, [0, 0], [0.2, 2], transformation = arm1,
color = :black, linewidth = 5, linecap = :round
)
arm2 = Transformation(arm1, origin = Vec3d(0, 2, 0))
linesegments!(a, [0.0, 1.5], [2, 2], transformation = arm2,
color = :black, linewidth = 5, linecap = :round
)
# rope - we want this to just extend downwards rather than inherit rotations
rope_length = Observable(1.0)
rope_points = map(arm2.model, rope_length) do model, len
# position of end of arm2 after transformations apply
rope_origin = (model * Point4(1.5, 2, 0, 1))[Vec(1,2)]
rope_end = rope_origin - Vec2(0, len)
return [rope_origin, rope_end]
end
crate_origin = map(ps -> ps[2] .+ Vec2(0, -0.12), rope_points)
linesegments!(a, rope_points,
color = :black, linewidth = 3, linestyle = :dot, linecap = :round
)
scatter!(a, crate_origin,
marker = Rect, color = :white, strokewidth = 2, strokecolor = :black,
markerspace = :data, markersize = Vec2f(0.3, 0.2)
)
# Move cart
sl1 = Slider(f[3, 2], range = range(-4, 4, length = 101))
on(v -> translate!(cart, v, 0, 0), sl1.value)
# Pivot arm 1
sl2 = Slider(f[1, 2], range = range(-pi/3, pi/3, length = 101))
on(v -> Makie.rotate!(arm1, -v), sl2.value)
# Pivot arm 2
sl3 = Slider(f[2, 1], range = range(-pi/3, pi/3, length = 101), horizontal = false)
on(v -> Makie.rotate!(arm2, -v), sl3.value)
# Extend rope
sl4 = Slider(f[2, 3], range = range(2, 0.1, length = 101), startvalue = 1.0, horizontal = false)
on(v -> rope_length[] = v, sl4.value)
# Set up some configuration
set_close_to!(sl1, -1.0) # move cart to -1
set_close_to!(sl2, -0.5) # angle arm1 to the left
set_close_to!(sl3, 0.5) # counter-angle arm2 to be horizontal
set_close_to!(sl4, 0.5) # raise crate
f