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