cetz icon indicating copy to clipboard operation
cetz copied to clipboard

Anchor on `rect` needs doc clarification

Open uben0 opened this issue 1 year ago • 4 comments

I'm just beginning to use CeTZ (awesome job BTW 🤩) and I could not find how to center rectangles. Maybe it's just a skill issue 😶‍🌫️

#rect((3, 0), (0.8, 0.8), name: "b", anchor: "center")

Setting the anchor to center doesn't change the a position in the rectangle, it remains what seems to be south-west. Which makes sens as this is what the documentation says:

a: Coordinate of the bottom left corner of the rectangle.

I wrote a wrapper to bypass this limitation:

#let rectc(center, dim, ..param) = {
    let x = center.at(0) - dim.at(0) / 2
    let y = center.at(1) - dim.at(1) / 2
    rect((x, y), (rel: dim), ..param)
}

But this scratched my head. How could such a trivial problem could remain unnoticed for so long? It has to be a problem with my comprehension. So I experimented with different anchors and I was very surprised by the behavior, that looked, at first glance, chaotic and nonsensical. But at the end, I got it:

  • a is bottom left
  • b is top right
  • the anchor applies a shift (or drag) to have the anchor point on the center (a + b) / 2

It makes sens after all. It is coherent. Knowing that, a rectangle can be centered by putting its anchor to north-east.

Request

I suggest to add a clarification in the documentation about this.

Or even maybe add an optional center: false parameter to change the meaning of a as the center instead of the bottom left corner. (Which is not equivalent to setting anchor to north-east)

uben0 avatar Jan 31 '24 16:01 uben0

Note: the second argument of rect is an absolute position! If you want to pass a size, use (rel: (width, height)). Using relative coordinates is the correct way to add multiple coordinates in cetz.

You can get centered rects if you use relative coordinates:

rect((rel: (-1,-1), to: (...center...)), (rel: (2,2)), name: "b")

johannes-wolf avatar Jan 31 '24 16:01 johannes-wolf

Proposal: Change rect’s default anchor to its first parameter (a). This would allow the expected transformation to happen (anchor: "center"). The intersection code of line must be changed to use the center anchor instead of the default anchor.

johannes-wolf avatar Jan 31 '24 20:01 johannes-wolf

Proposal: Change rect’s default anchor to its first parameter (a). This would allow the expected transformation to happen (anchor: "center"). The intersection code of line must be changed to use the center anchor instead of the default anchor.

I just ran into the same problem and this solution sound like it would make sense.

Currently rects anchor to south-west, but think that they would anchor to center. Changing the anchor to anything else leads to even more unexpected behavior. Changing it to south for example leads to a rect that's not even in touch with its anchor.

Are there any plans to implement this?

freundTech avatar Aug 10 '24 15:08 freundTech

I'd like to point out another problem with the current behaviour. Suppose we want to draw two rectangles side by side. We can do that as follows, using north-east as the anchor for the second rectangle:

rect((0,0), (rel: (2,1)), name: "a")
rect((rel: (2,0), to: "a"), (rel: (2,1)), anchor: "north-east")

It works fine: out-1

But if we want the second rectangle to have rounded corners, the output is not as expected:

rect((0,0), (rel: (2,1)), name: "a")
rect((rel: (2,0), to: "a"), (rel: (2,1)), anchor: "north-east", radius: .3)

out-2

This is because if the rectangle has rounded corners the distance of the corner anchors from the center changes, and so does the shift that is applied to the rectangle.

The following workaround works:

rect((0,0), (rel: (2,1)), name: "a")
rect((rel: (2,0), to: "a.west"), (rel: (2,1)), anchor: "north", radius: .5)

out-3 but it's not really intuitive in my opinion.

lvgrr avatar Jan 09 '25 14:01 lvgrr