scaleFactor strangeness

Mark Waddingham mark at livecode.com
Fri Oct 16 04:20:23 EDT 2015


On 2015-10-15 19:42, hh wrote:
> Not really, if you mean affine transform. Translation destroys the 
> wonderful
> commutativity you have with my proposal: If you interchange objects in 
> the
> owner path/message path before a target then this has no effect on the 
> total
> scalefactor of this target. And you know the "inverse" operation as a 
> function!
> Beside the usual rounding effects I can see no problem with that at the 
> moment.

I'm not sure I follow - commutativity makes no difference in this 
instance - you only need invertibility and associativity. Affine 
transforms can be represented as matrices and matrix multiplication is 
associative, and non-degenerate matrices have inverses - thus you can 
replace any scale operation in your proposal with an arbitrary 
(invertible) matrix representing an affine transform.

Indeed, in that light, what you propose is precisely the same as the 
idea of every object being able to have a transform property (if not set 
it is the identity) - the total transform of a nested object is the 
multiplication of all the ancestor transforms. This is how most UI 
toolkits (which allow arbitrary affine transforms) work and from a 
rendering point of view poses no problem.

> The stack (and it's view) is the global object and handles with the OS 
> and
> the hardware (you have a lot of pretty things already realized for us).
> Everything in the stack is in local coords.

Yes - this is how it is at the moment - you can translate between local 
(card-relative) and global (screen-relative) using localLoc and 
globalLoc functions.

> The mouseLoc etc. is scaled by TSF(mouse) = 
> SF(stack)*SF(card)*SF(mouse).
> We don't have to care about such things, you do in the engine.
> And it is scripter's problem to ask for the total scalefactor ('TSF')
> of objects.

Okay - so you suggest that any co-ordinates coming from the engine 
remain in card-space - where card-space is the top-level transform.

This does mean that script will have to explicitly deal with all 
co-ordinate transforms. So let's say you have a mouseMove handler in a 
graphic which uses the location of the mouse within itself to change its 
color:

on mouseMove pX, pY
   if pX < item 1 of the loc of me then
     if pY < item 2 of the loc of me then
       set the backColor of me to red
     else
       set the backColor of me to green
     end if
   else
     if pY < item 2 of the loc of me then
       set the backColor of me to blue
     else
       set the backColor of me to orange
     end if
   end if
end mouseMove

In an ideal world, this handler would still function regardless of the 
transform of the graphic containing it. Indeed, if co-ordinates are 
delivered to it in the target object's local co-ordinate system - then 
it does.

However, for arbitrary transforms where the pX, pY is kept in the card 
co-ordinate system it cannot - the reason for this is that under an 
arbitrary affine transform a rectangle which is parallel on both sides 
to the pixel grid may cease to be parallel to the pixel grid which means 
that geometry changes (when doing things extrinsically from the target 
object, at least).

Now, it is clear that if you restrict the transform to scale (and 
translation) then because such things preserve rectangles in both 
orientation and alignment relative to the pixel grid any non-size 
related geometry conditions you code remain correct - so the above 
handler would work fine.

However, here is a handler which would not work fine in this instance:

on mouseMove pX, pY
   if pY < the top of me + 20 then
     set the backColor of me to red
   else if pY > the bottom of me - 20 then
     set the backColor of me to green
   else
     set the backColor of me to blue
   end if
end mouseMove

Under a 'keep everything at the card-space' model - this code breaks as 
the scale of the target object changes. This is because the handler is 
dependent on a size (20) which is relative to the object's innate size 
rather than its scaled size. So, for this handler to work (even in a 
restricted, scale/translate only transform model) the script would need 
to be amended:

on mouseMove pX, pY
   if pY < the top of me + 20 * the effective yScale of me then
     set the backColor of me to red
   else if pY > the bottom of me - 20 * the effective xScale of me then
     set the backColor of me to green
   else
     set the backColor of me to blue
   end if
end mouseMove

Thus, in reality, keeping things in 'card-level' co-ordinate system and 
only allowing scale/translation makes no difference to the requirements 
on code. For general scripts which manipulate co-ordinates in anything 
other than very simple ways, you still have to explicitly take into 
account the potential effects of transformation thus, at the end of the 
day, you might as well allow arbitrary affine transforms since the code 
burden is identical. For example, the above modified code works if only 
scaling is allowing, however the code for the case of arbitrary 
transforms would be something like:

on mouseMove pX, pY
   local tY
   put item 2 of objectLoc(pX, pY) into tY
   if tY <  20 then
     set the backColor of me to red
   else if tY > the relative height of me - 20 then
     set the backColor of me to green
   else
     set the backColor of me to blue
   end if
end mouseMove

Here, I'm assuming a function 'objectLoc' which transforms a point from 
card-space to object-space (object-space being defined by the 
concatenation of transforms from itself up to the card). I'm also 
assuming that 'loc', 'left', 'top', 'right', 'bottom', 'width' and 
'height' have 'relative' adjectives which return them in object-space, 
rather than card-space.

Perhaps an 'objectLoc' idea and arbitrary affine transforms are not 
something to be concerned about. If you use transforms you might have to 
do some co-ordinate juggling, if you are writing controls which you want 
to be used generally - again, you might have to do some co-ordinate 
juggling. The rule is just that if passing co-ordinates between objects 
(unless there is a prior agreement), you need to keep things in 
card-space and let the code in the target objects do the appropriate 
transform.

Of course there is a gulf between having an idea that might work and 
implementing it in the engine - the lack of floating point co-ordinates 
is going to be a huge issue here I think... The 'visibleRect' of a stack 
is at least feasible in the near term - which at least gives zoom and 
panning at the card-level if not at the individual object level.

Plenty to think about!

Warmest Regards,

Mark.

-- 
Mark Waddingham ~ mark at livecode.com ~ http://www.livecode.com/
LiveCode: Everyone can create apps




More information about the use-livecode mailing list