Open tapyu opened 1 month ago
From the manual
Elements after the group are not affected by the changes inside the group.
Well, maybe I misunderstood, but group()
should also prevent changes from being applied in elements before the group, no? Otherwise, how could I use test
within group()
if I want to rotate it?
In fact, I can retrieve test
by using resolve()
and them using the resolved coordinates
draw.get-ctx(ctx => {
let (ctx, a) = coordinate.resolve(ctx, test)
draw.content(test, [#a], frame: "rect", stroke: none, fill: white)
draw.rotate(45deg, origin: a)
draw.circle(a, radius: (0.7, 0.2), anchor: "center")
})
However, I still don't know if this is the expected behavior. Please, let me know if this is indeed a bug or not
I don't really get what you mean, it looks correct to me. What are you expecting?
I was expecting that
#import "@preview/cetz:0.2.2": canvas, plot, draw, coordinate, vector
#set page(width: auto, height: auto, margin: .5cm)
#canvas({
draw.rect((0,0), (1,1), name: "rect")
let test = (rel: (0deg, 2), to: "rect.north-east")
draw.group({
draw.rotate(45deg, origin: test)
draw.circle(test, radius: (0.7, 0.2), anchor: "center")
draw.get-ctx(ctx => {
let (ctx, a) = coordinate.resolve(ctx, test)
draw.content(test, [#a], frame: "rect", stroke: none, fill: white)
})
})
})
produces
but it produced
The whole point is that rotate()
is affecting the value of test
, and I wasn't expecting that since test
is defined outside group()
.
It is def. broken.
Oh, I am confused. I think it is correct.
The problem here is, that test
gets resolve with the rotation active.
You've got two solutions:
group({
anchor("tmp", test) // Force resolve coordinate first
rotate(45deg)
circle(...)
})
Or use set-origin
first:
group({
set-origin(test)
rotate(45deg)
circle((0,0), ...) // At (0,0)
})
Tikz has \begin{scope}[rotate around]
, so it can handle this case. Maybe we want something similar for our transformations?
The problem here is, that test gets resolve with the rotation active.
This behavior is counterintuitive. test
is set before any rotation is performed. How/why does test
gets resolved with the rotation active?
Tikz has \begin{scope}[rotate around], so it can handle this case. Maybe we want something similar for our transformations?
If we agree that it is sensible that test
should not be affected by rotate()
, we don't need to do anything as draw.rotate(45deg, origin: test)
would work as expected. I believe the is the least confusing and simplest behavior one wants to achieve. After all, if we want that test
to be affect by the rotation, we can simply define it after rotating the axis:
draw.rotate(45deg, origin: (rel: (0deg, 2), to: "rect.north-east")) // rotation
let test = (rel: (0deg, 2), to: "rect.north-east") // defining `test` on the rotated axis
It is set before any rotation, but test
is just an array which represents a cetz coordinate. Because of how Typst/cetz work, it is not possible to resolve it without calling to cetz. If you create an anchor, that anchor gets resolved where it is declared.
It would work if you call let (_, test) = coordinate.resolve(...)
.
For cetz to be able to resolve and return coordinates, Typst would need to allow to set some sort of writable global context, which it does not.
:(
I think the best thing to do is allowing anchors at the root scope (without a group). That would allow defining coordinates with the current transformation taken into account.
I am not sure how your idea would work. I just tried to help Cetz saying that it is reasonable test
isn't changed by transformations made after its definition. If it is not possible due to Typst's internal behavior, I don't know how would be the solution.
However, I assure that creating anchors like anchor("tmp", test)
to get arrays resolved where it declared is more a workaround than a good solution. Beginners will have a hard time to figure it out.
Hi there! A potentially interesting aspect about this issue:
#import "@preview/cetz:0.2.2": canvas, draw, coordinate
#import draw: *
#set page(width: auto, height: auto, margin: .5cm)
#canvas({
rect((0,0), (1,1), name: "rect")
let test = "rect.north-east"
group({
rotate(45deg)
circle(test, radius: (0.7, 0.2), anchor: "center")
get-ctx(ctx => {
let (ctx, a) = coordinate.resolve(ctx, test)
content(test, [#a], frame: "rect", stroke: none, fill: white)
})
})
})
To my surprise, removing the relative shift in test
leads to the expected position. So AFAIU the issue isn't that the array or the anchor itself. Rather, it is due to the fact that the context used inside (where we rotate) and outside (where we don't want that the rotation happens) group()
is the same.
Please, let me try to propose a solution for this: isn't possible to work with two contexts? One to apply any transformation inside and the other for anything outside group()
. In this way, test
(or anything outside group()
) would be resolved by CeTZ with the nonrotated context where it was defined.
Consider the following MWE:
This produces
The command
draw.rotate(45deg, origin: test)
shouldn't affecttest
since the rotation is scoped withingroup()
androtate()
is being applied aftertest
is defined. Therefore, uncommentingrotate()
should lead to a rotation incircle()
around its center.However, by uncommenting it, we somehow obtain
This new (and wrong) position is the because
rotate()
is changing the x-y axis used to determinetest
, which shouldn't happen.