Opened 19 months ago

Last modified 16 months ago

#18415 new enhancement

Add shear and projective geometrical transformations

Reported by: Handmaus Owned by: stippi
Priority: normal Milestone: Unscheduled
Component: Applications/Icon-O-Matic Version: R1/beta4
Keywords: Cc:
Blocked By: Blocking:
Platform: All

Description

  • Adding shear (opposite sides) geometrical transformation

To Paths: as it is a destructive edit it will have no filesize cost because the points simply end up in new positions that you then have to optimize manually, snaping to the grid..., same as with the actual transformations. (enhancement to Icon-O-Matic)

To Shapes: I think it can have a filesize cost similar to stretching? Just a wild guess. (this possibly needs to be implemented in HVIF 2.0)

Being able to aply it to shapes it's possible to do, for example, multiple thick diagonal lines that have the correct vertical sides at the ends (caps) avoiding the incoherently tilted end that happens now when you give thickness this way to a diagonal path. All reusing a single 2 point horizontal path, aplying stroke + shear transform to as many Shapes as needed, instead of having to draw a different 4 point path for every line.


  • Adding projective (4 corners) geometrical transformation

To Paths: same as with any transform, it will have no filesize cost because the points simply end up in new positions that then you have to optimize, bla bla bla... (enhancement to Icon-O-Matic)

To Shapes: Although it will undoubtedly have a higher filesize and computational cost, I think than in various situations it will be cheaper than the sum of other individual operations that, also, still lead to a not quite right result. (for HVIF 2.0)

Extremely useful when dealing with perspective, specially for complex shapes (complex meaning anything with a Path with a very specific form, even if is as simple as a triangle, or any combination of Shapes with at least two elements that need to retain a specific spatial relationship) . For example, this will ease a lot the very common situation of having to take an already existing logo of some program, that generally are flat and frontal, and render it with the characteristic perspective of the Haiku icon style guide. Another situation will be when you need to reuse the same shape in different faces of an object. See for example the icon for PatchBay. The two sides are really well solved because the author of the icon was smart and drew it in a way that just needed to mirror and squish the same connector in the vertical axis. But the top face looks strangely distorted, because it reached the limits of what can be done without the need to redraw the whole connector. In this case I think the cost of one 4 corner transformation will be way less than having to redraw a big part of the connector again or having to rotate, squish and reposition every tiny element individually.

This way we can have the versatility of this transformation for the scenarios when it makes more sense than squish/stretch/resize+rotation, but of course maintaining the squish/stretch/resize and the rotation not only for compatibility with the previous format icons but because they are less wheighty (I think?), at least than a 4 corner transform.

Attachments (2)

Transformations in Icon-O-Matic 01.png (153.8 KB ) - added by Handmaus 19 months ago.
Diagonal lines example.iom (7.0 KB ) - added by Handmaus 19 months ago.

Download all attachments as: .zip

Change History (12)

in reply to:  description ; comment:1 by Zardshard, 19 months ago

  • Adding shear (opposite sides) geometrical transformation

To Paths: as it is a destructive edit it will have no filesize cost because the points simply end up in new positions that you then have to optimize manually, snaping to the grid..., same as with the actual transformations. (enhancement to Icon-O-Matic)

You can actually already do this to transformations. Go to Shape->Freeze Transformation and it will be applied to the path. Maybe renaming this option to Apply Transformation would make it clearer?

To Shapes: I think it can have a filesize cost similar to stretching? Just a wild guess. (this possibly needs to be implemented in HVIF 2.0)

Actually, the format models all of these effects as an affine transformation. So if you've already stretched it, the shearing is free!

Being able to aply it to shapes it's possible to do, for example, multiple thick diagonal lines that have the correct vertical sides at the ends (caps) avoiding the incoherently tilted end that happens now when you give thickness this way to a diagonal path. All reusing a single 2 point horizontal path, aplying stroke + shear transform to as many Shapes as needed, instead of having to draw a different 4 point path for every line.

I manually edited the affine transformation matrix of a line in an hvif file, and, the ends look exactly as you described it. Now it's just to add the feature to Icon-O-Matic.


  • Adding projective (4 corners) geometrical transformation

There has actually been some code written on the topic in the Icon library. I wonder what state it is in. This is also implementable using the HVIF format's existing affine transformation.

in reply to:  1 ; comment:2 by Handmaus, 19 months ago

Replying to Zardshard:

  • Adding shear (opposite sides) geometrical transformation

To Paths: as it is a destructive edit it will have no filesize cost because the points simply end up in new positions that you then have to optimize manually, snaping to the grid..., same as with the actual transformations. (enhancement to Icon-O-Matic)

You can actually already do this to transformations. Go to Shape->Freeze Transformation and it will be applied to the path. Maybe renaming this option to Apply Transformation would make it clearer?

I know, I use this a lot.

But it has the limitation that can only be used when the path is paired to only one shape, the moment a path is used by more than one shape it (understandably) doesn't let you do it.

Regarding the renaming, for me there's no need to, once you know what it does. If doing it for clarity I will be just slightly more descriptive and call it Apply Transformation To Path.

But a better solution for me is to keep menu action names short and memorable, to not clutter the interface, and have a general setting in the (still unimplemented, there are plans for it, ask around for info) App menu, called Tooltips, that enables slightly verbose tooltips describing the action, enabled by default. Tooltips are irritating, ...but only when you know your way around ;)

.

To Shapes: I think it can have a filesize cost similar to stretching? Just a wild guess. (this possibly needs to be implemented in HVIF 2.0)

Actually, the format models all of these effects as an affine transformation. So if you've already stretched it, the shearing is free!

Wait... WHAT?

.

Being able to aply it to shapes it's possible to do, for example, multiple thick diagonal lines that have the correct vertical sides at the ends (caps) avoiding the incoherently tilted end that happens now when you give thickness this way to a diagonal path. All reusing a single 2 point horizontal path, aplying stroke + shear transform to as many Shapes as needed, instead of having to draw a different 4 point path for every line.

I manually edited the affine transformation matrix of a line in an hvif file, and, the ends look exactly as you described it. Now it's just to add the feature to Icon-O-Matic.

So it was there all the time and it was just a matter of implementing in the UI a way to apply it?

Stiiiipiiiiiiii !!!

Aaaaaaargh !!!

(just joking ;)

.


  • Adding projective (4 corners) geometrical transformation

There has actually been some code written on the topic in the Icon library. I wonder what state it is in. This is also implementable using the HVIF format's existing affine transformation.

Looking around the internet I jumped to the conclusion that it needed a different transformation matrix, but if it's possible and you end up doing it, I'll drew you an icon of a pedestal to put your avatar on top :D

by Handmaus, 19 months ago

Attachment: Diagonal lines example.iom added

comment:3 by Handmaus, 19 months ago

Just to illustrate what I mean, to avoid confusions

in reply to:  2 ; comment:4 by Zardshard, 19 months ago

But a better solution for me is to keep menu action names short and memorable, to not clutter the interface, and have a general setting in the (still unimplemented, there are plans for it, ask around for info) App menu, called Tooltips, that enables slightly verbose tooltips describing the action, enabled by default. Tooltips are irritating, ...but only when you know your way around ;)

No luck finding this. Got any leads?

There has actually been some code written on the topic in the Icon library. I wonder what state it is in. This is also implementable using the HVIF format's existing affine transformation.

Looking around the internet I jumped to the conclusion that it needed a different transformation matrix, but if it's possible and you end up doing it, I'll drew you an icon of a pedestal to put your avatar on top :D

Turns out it's not possible with an affine matrix. Looks like something for HVIF 2.0! But wait, Stippi had foresight. The HVIF format supports a couple of "transformers": affine, contour, stroke, and, luckily, perspective.

Just to illustrate what I mean, to avoid confusions

*Picture of rotation, shearing, and perspective transformations*

Yes, shearing does work as shown in the picture, keeping the sides parallel.

BTW, Icon-O-Matic works surprisingly well with lines with an arbitrary affine transformation. No crashes. It can still rotate them without messing up the existing transformation.

in reply to:  4 comment:5 by Handmaus, 18 months ago

Replying to Zardshard:

... the (still unimplemented, there are plans for it, ask around for info) App menu ...

No luck finding this. Got any leads?

Sorry, I mentioned it from the top of my head, and have been searching for it this last days, but havn't found anything also, how embarrassing :<

I remember a conversation, in the forums or somewhere else, about implementing a default menubar pre-populated with at least a few standard menus:

  • App (sometimes labeled with the app name) with some standard entries for the app itself
    • Settings
    • Help
    • About
    • Quit

And then others like File, Edit, etc, but there was dissent about this others because this could lead to what happens in MacOS, with simpler apps that have no need for most of the entries having a skeleton of a menubar that is basically empty.

As far as I can see, HaikuDepot, Terminal, MediaPlayer, ArtPaint, FFmpegGUI, Clipdinger, Vision... already have some variation of this App menu, though I think it has nothing to do with this default menubar, so please forget it, i'm just digressing and distracting you and anyone who happens to be reading this.

.

... But wait, Stippi had foresight. The HVIF format supports a couple of "transformers": affine, contour, stroke, and, luckily, perspective.

Perspective!

If shear falls under the affine transformations, I hope that perspective must be the one that corresponds to projection.

comment:6 by Zardshard, 18 months ago

It turns out that, with enough work, Icon-O-Matic can shear shapes. Whenever you deselect and reselect a shape, such as a square, its bounding box resets to an unrotated box. This is annoying when working with a rotated shape, such as a square rotated 45°. After deselecting it and reselecting it, it is no longer possible to change the width and the height of the square. It is only possible to squash/stretch the shape vertically or horizontally. Stretching it, for example, would yield a shape that looks like a diamond. But this nuisance actually can be used to shear. Take the diamond, and rotate it so that it lays on its side. You now have a sheared rectangle!

Needless to say, we need to make a better way to shear than this.

comment:7 by Handmaus, 17 months ago

Replying to Zardshard:

...this nuisance actually can be used to shear

Yes I discovered it not long ago, but only have used it once or twice. Its imprecise and not very intuitive to do. 'Needless to say, we need to make a better way to shear than this.' Indeed. Apart from the greater precision, an important aspect of this is that it will let you do, with the cost of a single operation, what otherwise would cost at least three cumulative operations.

Zardshard:

Whenever you deselect and reselect a shape, (...), its bounding box resets to an unrotated box.'

That means, that when I do lots of tiny corrections they keep piling up as a different transformation every time the bounding box resets, is that correct?

That makes me wonder...

As the result of the accumulation of simpler transformations can equally be achieved with a single projective transform, maybe it will be possible to implement a mechanism that detects when the cost of the sum of various consecutive simpler transforms is higher than the cost of a projective one and starts saving the final state of the added transformations with a single, comparatively less expensive, projective transformation.

(As a starting caveat, some assumptions I do, that may be incorrect:

  • that moving, resizing in any dimension, shearing and rotating can each one be replicated individually with a projective transform
  • that the combined result of, for example, moving, plus resizing in any dimension, plus shearing, plus rotating can be replicated with a single projective transform
  • that any time the boundary box resets, the next transformation is saved as a new one, steadily adding up to the filesize
  • that the boundary box itself has any importance in the way the transformations are calculated or stored, other than serving as a way to visualize and interact )

I don't know how every transformation gets calculated and/or saved to the file. Can it be that it registers the dimensions and position of the new boundary box at every change? If this is so, given that the original bounding box got lost after a few changes, one way I imagine to determine what projective transformation needs to be done to substitute a bunch of previous simpler ones will be to take the starting bounding box, treat it as if it was a sort of rectangular path, and apply to it all this previous resizings, movings, rotations, shearings, etc..., so you can have the resulting distorted "bounding box" that the corners of the new projective transform bounding box needs to match. Or maybe a less complicated way will be to redo every step with the equivalent projective transform, but saving only the final state in the series.

A requisite for that to work will be that the distorted projective bounding box remains for as long as possible, so that any subsequent transforms have no added cost, because if it gets reset just by deselecting and reselecting, as it happens now, it will get expensive very fast.

So, possibly, this constant resetting is something that needs to be reconsidered? Now that we're going to have shear and projection I don't see any benefit in having them constantly resetting and slowly piling up in filesize everytime one does any tiny correction to something (in the case that this is what happens). I think that now will be better that the default will be to not reset, but leaving the option to voluntarily 'Reset boundary box' as an entry in the shapes menu?

A limitation I initially imagine is that this mechanism can only be applied to sets of successive transformations to a single shape, or group of shapes, as long as no other kind of boundary-altering change (contour, stroke, selecting or deselecting additional shapes) is done in-between?

Lastly, a similar mechanism could be added in the opposite direction, one that detects when some transform is unnecessarily done as projective when it could be solved with a less expensive one, and automatically saves it in the cheaper way.

Quite possibly this mechanisms are something that could be added later, after this transformations are already implemented, even dealing with it in a separate ticket (except maybe the reset/not reset part). But I prefer to mention it here first, in case some of this things could affect somehow the way all this needs to be implemented.

Sorry if this is all a bit rambling, I have been rethinking, revisiting and rewording it for a couple of days, but it still is a bit of a hodgepodge of ideas. I hope you're able to make sense of it.

In the end, the important part to keep in mind is to maintain the HVIF format as lean and efficient as it is, if not even more.

Version 0, edited 17 months ago by Handmaus (next)

comment:8 by Zardshard, 17 months ago

Whenever you deselect and reselect a shape, (...), its bounding box resets to an unrotated box.'

That means, that when I do lots of tiny corrections they keep piling up as a different transformation every time the bounding box resets, is that correct?

No. There goes a large part of your essay :)

Stippi used affine transformations to represent translations, rotations, and scales. Any number of these operations can be represented as a single affine transformation. The bounding box resets every time you deselect and reselect simply because Icon-O-Matic never bothers to store the bounding box anywhere.

On a tangent, everything you can achieve using only translations, rotations, and scales in Icon-O-Matic is everything an affine transformations can do. No more, no less.

  • that the combined result of, for example, moving, plus resizing in any dimension, plus shearing, plus rotating can be replicated with a single projective transform

Indeed, projective transformations can do this. In fact, I believe they can do anything an affine transformation can do and more. At the cost of a couple more bytes storage, of course.

Sorry if this is all a bit rambling, I have been rethinking, revisiting and rewording it for a couple of days, but it still is a bit of a hodgepodge of ideas. I hope you're able to make sense of it.

Nice, I like it and understood it quite well. Thanks for taking the time to write it :)

A comment of my own: A shape with both an affine transformation and a perspective transformation will have duplicate data. Both transformations can rotate, move, and scale a shape. A shape with a perspective transformation could be represented without any affine transformation. I took a quick look, and, it appears Icon-O-Matic currently stores both at the same time. That's 18 wasted bytes for each shape that uses a perspective transformation.

comment:9 by Handmaus, 16 months ago

(From the forum https://discuss.haiku-os.org/t/gsoc-2023-progress-on-perspective-transformation-haiku-project/13594 , discussing about simple transformation, transformation applied to a layer or transformation as a new shared item):

"[quote="Zardshard, post:16, topic:13594"] Currently, you will have to recreate the perspective transformation for each shape that you want transformed [end quote]"

"[quote="Zardshard, post:16, topic:13594"] There are two solutions that I can think of:

  1. Add support for layers. Then, you can add a single perspective transformation to the layer and let it affect every shape in the layer. This would require updating the HVIF format.
  2. Add support for the same perspective transformation to be applied to multiple shapes. This would make transformations similar to shapes and styles, in that they can be reused in multiple shapes. This would also require updating the HVIF format.

[end quote]"

Even if internally they work the same, each of the three serves a slightly different purpose.

This last weeks I have been musing about @Null 's idea for perspective planes, and I have to retract myself and concede that it was indeed a good idea.

"[quote="Null, post:4, topic:13594"] An even more advanced idea I had is to add support for automatic perspective on planes to the hvif icon format. In the Patchbay icon example it would mean you would only have to draw the din-sockets once in 2D and have them applied to the three planes with the correct perspective. [end quote]"

Even started to write a lengthy response discussing the possibilities, but the draft got lost after some server problem with Discuss and was too lazy to write it again. Apart from that I didn't wanted to stress you out after losing part of the progress, messing with exotic ideas, but now that you mention them yourself... :D

Apart from the basic perspective transformation that can be applied to any path or shape at any moment, Layers was one of the possibilities and a new item called Planes was the other.

BTW, layers are a worthy addition by themselves just by the fact that they let you select a bunch of shapes in one go instead of having to select them manually every time, they're invaluable to organize elements that go together, even if nothing else could be done with them. Also, they can exist inside the Shapes list, so no need to take extra room for them in the UI:

Layer:

-Shape

-Shape

Layer:

-Shape

-Shape

-Shape

So I'll say, keep 'em coming either way!

But lets consider them in the actual context of a transformation applied to a layer.

Pros:

  • transforming a bunch of shapes maintaining the geometrical relationship between them
  • possibility of adding new shapes after (or even before) the initial transformation
  • each shape can get fine-tuned individually

Cons:

  • for repeated elements the shapes need to be duplicated, increasing the filesize cost

The other one, Planes, is how I imagined Null's idea could be implemented without needing to implement 3d features for it. As it will be a new item alongside Paths, Shapes and styles, with its own list, a bit of room will need to be made in the UI.

Pros:

  • the same Plane be applied to more than one shape or layer
  • (here comes the special part from Null's idea) each shape or layer could have more than one Plane applied, in doing so, it appears in each of the planes with the corresponding projection
  • less filesize cost in having a shape or layer appearing more than one time without duplicating them

Cons:

  • it doesn't let each 'virtual copy' of the original shapes to be fine-tuned as they are not duplicates

comment:10 by Zardshard, 16 months ago

Nice ideas. No idea if I will be able to implement them all, but, while we're dreaming...

There is the possibility of completely redesigning the UI around layers. The shape, style, and transformer menus would disappear leaving just the layers menu. It would look like

  • Layer 1
    • Shape 1
      • Path 1
      • Path 2
      • Style 1 (shared)
      • Transformation 1
      • Transformation 2
    • Shape 2
      • Path 3
      • Style 1 (shared)

Here, you can see that Style 1 is shared across two shapes.

This also lets you implement the idea of planes without taking up more space in the UI.

  • Layer 1 (shared) (hidden)
    • *Shapes to make one face of patchbay's icon*
  • Layer 2
    • Layer 1 (shared)
    • Perspective transformation 1
  • Layer 3
    • Layer 1 (shared)
    • Perspective transformation 2
  • Layer 4
    • Layer 1 (shared)
    • Perspective transformation 3

That rearrangement would leave so much free space in the UI, I wouldn't know what to do with it all :D

Note: See TracTickets for help on using tickets.