[feature request] `translate()` in polar coordinates
Currently, draw.translate() function receives as input "a single vector or any combination of the named arguments x, y and z to translate by." (vide manual). However, this is quite restrictive once we cannot pass, for example, polar coordinates.
Consider the following MWE:
#import "@preview/cetz:0.2.2": canvas, plot, draw, coordinate, vector
#set page(width: auto, height: auto, margin: .5cm)
#let draw-me(radius, angle) = {
draw.group({
draw.translate(angle: angle, radius: radius)
draw.line(
(-0.2,+0.2),
(rel: (+0.2,-0.2)),
(rel: (+0.2,+0.2)),
)
})
}
#canvas({
draw.circle((0,0), radius: 0.1)
draw-me(2, 30deg)
})
This produces
translate() doesn't work when polar coordinates is passed.
By changing
draw.translate(angle: angle, radius: radius)
by
draw.translate((radius*calc.cos(angle), radius*calc.sin(angle)))
We can achieve the desired result
It would be interesting to overload translate() so that polar coordinates can also be handled by this function.
PS: I am not sure whether relative coordinates can be handled.
You can use set-origin(<coordinate>), which allows passing any coordinate, including polar:
set-origin((angle, radius)) or set-origin((angle: angle, radius: radius))
But I think adding said functionality to translate is a good idea.
You can use set-origin(
), which allows passing any coordinate, including polar
Yeah, that might be a workaround.
But I think adding said functionality to translate is a good idea.
Agreed.
Didn't we previously allow passing coordinates to translate but changed it in favour of set-origin?
@tapyu what are the cases where being able to translate with polar coordinates are useful? Examples etc.
@tapyu what are the cases where being able to translate with polar coordinates are useful? Examples etc.
Okay, I can give a very illustrative example:
#import "@preview/cetz:0.2.2": canvas, plot, draw, coordinate, decorations
#set page(width: auto, height: auto, margin: .5cm)
#let draw-satelite(height, angle, name) = {
// draw.move-to("ground-station.tip")
draw.group(
name: name, {
draw.set-origin("ground-station.tip")
draw.translate(x: height*calc.cos(90deg-angle), y: height*calc.sin(90deg-angle))
draw.rotate(-angle)
draw.anchor("tip", (0,0))
draw.line(
(-0.2,+0.2),
(rel: (+0.2,-0.2)),
(rel: (+0.2,+0.2)),
)
draw.circle((rel: (-0.2, 0.07)), radius: (0.5,0.2), name: "antenna-base")
draw.rect((rel: (0,0.1)), (rel: (1, 1)), name: "body", anchor: "east")
draw.rect("body.east", (rel: (0.5, 0.5)), anchor: "north")
draw.rect("body.west", (rel: (-0.5, 0.5)), anchor: "north")
}
)
}
#let draw-ground-station() = {
draw.group(name: "ground-station", {
draw.line(name:"base", "earth.80deg", (rel: (0,1), to:"earth.90deg"), "earth.100deg")
draw.move-to("base.50%")
draw.move-to((rel: (y: 1)))
draw.move-to((rel: (angle: 320deg, radius: 1)))
draw.arc((), start: 320deg, stop: 220deg, mode: "CLOSE", name: "antenna-arc")
draw.anchor("tip", (rel: (0, 0.4), to: "antenna-arc.chord-center"))
draw.line("tip", (rel:(0.2,0), to: "antenna-arc.chord-center"))
draw.line("tip", (rel:(-0.2,0), to: "antenna-arc.chord-center"))
})
}
#canvas({
draw.arc((0,0), start: 45deg, stop: 135deg, radius: 5, name: "earth")
// the layer
draw.move-to("earth.chord-center")
draw.move-to((rel: (angle: 70.1, radius: 8)))
draw.merge-path(
fill: gray, {
draw.arc((), start: 70deg, stop: 110deg, radius: 12, name: "upper-layer")
draw.line((), (rel: (0, -2)))
draw.arc((), start: 110deg, stop: 70deg, radius: 12, name: "lower-layer")
draw.line((), (rel: (0, 2)))
}
)
draw-ground-station()
draw-satelite(5, 30deg, "satelite1")
draw-satelite(5, -30deg, "satelite2")
// scintillation-induced signal
decorations.wave(draw.line("satelite1.tip", ("satelite1.tip", 20%, "ground-station.tip")), amplitude: .25, start: 0%, stop: 100%, stroke: red, name: "wave1")
for (i, (perc, amp)) in (40%,60%,80%,100%).zip((.125,0.25,0.55,.18)).enumerate() {
decorations.wave(draw.line("wave"+str(i + 1)+".end", ("satelite1.tip", perc, "ground-station.tip")), amplitude: amp, start: 0%, stop: 100%, stroke: red, name: "wave"+str(i + 2))
}
decorations.wave(draw.line("satelite2.tip", "ground-station.tip"),
// to scintillation
amplitude: .25, start: 0%, stop: 100%, stroke: blue)
})
In this not-so-minimal working example, a satellite is a set of elements (line(), rect(), circle(), ...) that is grouped and is drawn with the function draw-satelite(height, angle, name), which translates the satellite antenna's tip in polar coordinates and with respect to the ground station antenna's tip.
Here, using polar coordinates to translate/shift it makes total sense as we always think about satellite positioning in terms of radial distance from the ground station and the zenith angle (or, equivalently, the elevation angle):
Of course we can came up with workarounds that work (you see that, in my case, I used trigonometry to obtain the same result). But again, translating in polar coordinates is the most intuitive way to go.
Didn't we previously allow passing coordinates to translate but changed it in favour of set-origin?
Well, I don't know, but in my POV it is an error. Being able to set the origin in polar coordinates doesn't free us to want to translate an object in polar coordinates with respect to that origin.
This is clear in my previous example, where we set the origin to the ground station antenna's tip, but we want to translate the satellites in polar coordinates with respect to that new origin.
So, can we finally agree that it is useful to translate in polar coordinates? :eyes: