Athens question: AffineTransform, AthensCairoMatrix and Float values

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Athens question: AffineTransform, AthensCairoMatrix and Float values

Juraj Kubelka-5
CONTENTS DELETED
The author has deleted this message.
Reply | Threaded
Open this post in threaded view
|

Re: Athens question: AffineTransform, AthensCairoMatrix and Float values

Igor Stasenko



On 11 April 2014 17:41, Juraj Kubelka <[hidden email]> wrote:
Hi,

We are integrating Athens transformation to Roassal2/Trachel and I have reached an issue.

In drawing code I use something like this:
-=-=-=-
athensCanvas pathTransform
restoreAfter: [ 
athensCanvas pathTransform
multiplyBy: matrix; “an instance of AthensAffineTransform"
athensCanvas 
setPaint: color;
drawShape: self path.
-=-=-=-

I have a problem, that sometimes it crashes because it expects a float value (I understand why). I suppose I do not have to keep float values in AthensAffineTransform object. My suggestion is to ensure float values where it is expected. For example the method #loadAffineTransform could be like this:

-=-=-=-
AthensCairoMatrix>>loadAffineTransform: m
self 
initx: m x asFloat
y: m y asFloat
sx: m sx asFloat
sy: m sy asFloat
shx: m shx asFloat
shy: m shy asFloat
-=-=-=-


Which will mean 6 extra #asFloat message sends, even if they're already floats or ints but not Fractions (and in 99% of cases they are, so you will slow down everything for the sake of 1%).
I prefer that user supplies already prepared data, so it don't have to be implicitly converted since it takes extra CPU cycles, which can be spent somewhere else.
 
But yes, it needs to be ensured, but at different place:
where you building that AthensAffineTransform

AthensAffineTransform>>sx: number
    sx := number
=>>>
AthensAffineTransform>>sx: number
    sx := number asFloat
.. (and for the rest of accessors)

like that it will ensure that AthensAffineTransform always stores floats,
which i'm not really like because integers is perfectly fine too.. its all about Fractions.


Right now I have to do that transformation myself whenever I use Athens objects. I see it error prone and I do not see it obvious. 

On other hand I do not want to keep float values in my AthensAffineTransform, because if user do #scaleBy: 0.7 and then #scaleBy: (1/0.7) I want to get the same original value. Otherwise the image could change its size.


On your place i'd better forget about it. That's impossible when you dealing with floating point values.. and multiple matrix operations.
Unless you explicitly control it by yourself, but that certainly should be outside of AthensAffineTransform/Athens.
 
The same change could be for other methods in AthensCairoMatrix.

 
Again, that would mean dozens of extra message sends at every single place,
whether it needed or not..
Like:
AthensCairoMatrix>>translateX: px Y: py

needs to be replaced with:

^ self primTranslateX: px asFloat Y: py asFloat

instead of direct call, plus adding   #primTranslateX:Y: method, of course.

Do you really want to pay a price of 50% less performance (or more) in exchange of "i don't wanna think what i passing to it"?
Because apparently, you always need to think what you passing - one cannot just pass a random object to some method and expect it to work, isn't?

Because i don't. All you need is to avoid using Fractions.. because integers or floats is perfectly fine.
Fraction created only if you use division on integer.. so all you need to do is to ensure the result of division is float:

(x/y) asFloat.
 
What do you think?

I am biased towards having better performance, even at cost of inconvenience,
where at some places i have to ensure i need to pass correct value(s).

 
Juraj

--
Best regards,
Igor Stasenko.
Reply | Threaded
Open this post in threaded view
|

Re: Athens question: AffineTransform, AthensCairoMatrix and Float values

Juraj Kubelka-5
CONTENTS DELETED
The author has deleted this message.
Reply | Threaded
Open this post in threaded view
|

Re: Athens question: AffineTransform, AthensCairoMatrix and Float values

Igor Stasenko



On 11 April 2014 20:24, Juraj Kubelka <[hidden email]> wrote:
Thank you Igor,

I understand and I agree. Just can you clarify one think. Maybe I use it wrong. Right now in Roassal2/Trachel a shape has instance variable called matrix which is an AthensAffineTransform object. And if someone calls translateBy:, or scaleBy:, etc. I call the appropriate method on AthensAffineTransform. Do you say, that I should rather have instance variables position, rotation, and scale? Do I understand well? I thought it is better (faster) to keep the matrix and in #drawOn: only call #multiplyBy:.

it doesn't really matters.. and up to your convenience. sometimes it's convenient to use decomposed form (e.g. translation, scale, rotation) instead of full matrix,
sometimes not.. depends how/who/where you using it.

And another question. Right now a rectangle is drawn like this:
-=-=-=-=-
computePath
canvas ifNil: [ ^ self ].
path := self athensCanvas
createPath: [ :builder | 
builder
absolute;
moveTo: rectangle topLeft;
lineTo: rectangle topRight;
lineTo: rectangle bottomRight;
lineTo: rectangle bottomLeft;
lineTo: rectangle topLeft. ]
-=-=-=-=-

I do not see a method which draws rectangle directly. This example shows there is a direct support for rectangle drawing. Am I right we do not have that support in Athens? Is there a reason for it?


Because there's only one method which draws any kind of shapes (including rectangle). All you need to do is to draw it:

canvas drawShape: (0@0 corner: 100@100).

or

canvas setShape: (0@0 corner: 100@100).
...
canvas draw.

else there would be need to add dozens of

drawRect:
drawOval:
drawZigZag:
drawAnotherWeirdThing:

instead of simple method which covers all.


Thank you,
Juraj


El 11-04-2014, a las 13:29, Igor Stasenko <[hidden email]> escribió:




On 11 April 2014 17:41, Juraj Kubelka <[hidden email]> wrote:
Hi,

We are integrating Athens transformation to Roassal2/Trachel and I have reached an issue.

In drawing code I use something like this:
-=-=-=-
athensCanvas pathTransform
restoreAfter: [ 
athensCanvas pathTransform
multiplyBy: matrix; “an instance of AthensAffineTransform"
athensCanvas 
setPaint: color;
drawShape: self path.
-=-=-=-

I have a problem, that sometimes it crashes because it expects a float value (I understand why). I suppose I do not have to keep float values in AthensAffineTransform object. My suggestion is to ensure float values where it is expected. For example the method #loadAffineTransform could be like this:

-=-=-=-
AthensCairoMatrix>>loadAffineTransform: m
self 
initx: m x asFloat
y: m y asFloat
sx: m sx asFloat
sy: m sy asFloat
shx: m shx asFloat
shy: m shy asFloat
-=-=-=-


Which will mean 6 extra #asFloat message sends, even if they're already floats or ints but not Fractions (and in 99% of cases they are, so you will slow down everything for the sake of 1%).
I prefer that user supplies already prepared data, so it don't have to be implicitly converted since it takes extra CPU cycles, which can be spent somewhere else.
 
But yes, it needs to be ensured, but at different place:
where you building that AthensAffineTransform

AthensAffineTransform>>sx: number
    sx := number
=>>>
AthensAffineTransform>>sx: number
    sx := number asFloat
.. (and for the rest of accessors)

like that it will ensure that AthensAffineTransform always stores floats,
which i'm not really like because integers is perfectly fine too.. its all about Fractions.


Right now I have to do that transformation myself whenever I use Athens objects. I see it error prone and I do not see it obvious. 

On other hand I do not want to keep float values in my AthensAffineTransform, because if user do #scaleBy: 0.7 and then #scaleBy: (1/0.7) I want to get the same original value. Otherwise the image could change its size.


On your place i'd better forget about it. That's impossible when you dealing with floating point values.. and multiple matrix operations.
Unless you explicitly control it by yourself, but that certainly should be outside of AthensAffineTransform/Athens.
 
The same change could be for other methods in AthensCairoMatrix.

 
Again, that would mean dozens of extra message sends at every single place,
whether it needed or not..
Like:
AthensCairoMatrix>>translateX: px Y: py

needs to be replaced with:

^ self primTranslateX: px asFloat Y: py asFloat

instead of direct call, plus adding   #primTranslateX:Y: method, of course.

Do you really want to pay a price of 50% less performance (or more) in exchange of "i don't wanna think what i passing to it"?
Because apparently, you always need to think what you passing - one cannot just pass a random object to some method and expect it to work, isn't?

Because i don't. All you need is to avoid using Fractions.. because integers or floats is perfectly fine.
Fraction created only if you use division on integer.. so all you need to do is to ensure the result of division is float:

(x/y) asFloat.
 
What do you think?

I am biased towards having better performance, even at cost of inconvenience,
where at some places i have to ensure i need to pass correct value(s).

 
Juraj

--
Best regards,
Igor Stasenko.




--
Best regards,
Igor Stasenko.