Comment #13 on issue 842 by google....(a)ben.coman.com.au: ROTranslatingShape
mouse hotspot mis-alignment
http://code.google.com/p/moose-technology/issues/detail?id=842
Alexandre,
This turned into a bit an essay, but it brings together a number of
ideas I've developed in response to trialling ROTranslateShape.
I know Mondrian seemed to have had lots of caches which made the
architecture convoluted, however it may be reasonable for a distinction
to be made between caching shape data and caching element layout data.
(Would I be correct in saying that Mondrian had a lot less concept of
shapes?) Elements are greatly affected by nesting and layouts,
particularly dynamic layouts - whereas shapes should be at the end of
the line, with no sub elements, and within the element-local-coordinates
should not change much. Indeed stretching the concept, for "element
shapes" (as opposed to "edge shapes") perhaps the drawing can be split
into something like a #calculateShape and a #drawShape - where the
"convention" is that #calculateShape is only called on
"model-changed"
and stores ALL PARAMETERS required to draw the shape in instance
variables, while #drawShape is called in a tight rendering loop and the
"convention" is that it should use NO temporary variables, but only can
use only the exact parameters previously stored by #calculateShape.
Further, #calculateShape would statically fix the bounds of each shape
until the next "model changed" and cache that value into an ROElement
ivar perhaps called "localBounds" - so that #containsPoint on needs one
check per Element until a hit is found. This would avoid having to
process every shape every cycle, which I think is a major part of the
slowdown. Only after a hit within an anElement bounds would the shape
bounds be double-checked to avoid an invalid hit - like the part where
two offset squares don't overlap.
I think the concept of translating shapes is important, but I am
actually not sure if I like ROTranslateShape. Apart from the
performance aspect, having trialled ROTranslatingShape I think it
introduces more complexity than necessary. It also is more awkward and
constraining than I would like - for instance if I want to offset four
circles N,E,W,S from center, then I need to contend with reversing the
cumulation of chained ROTranslatingShapes, rather than just dealing with
four absolute offsets from center. With ROTranslatingShape I need to
consider how the chained cumulative offset interacts with imposed
layering of which shapes get drawn on top.
With the proviso that I haven't much experience in the trenches with
graphics programming, I can't help feeling that it would be simpler for
each and every element shape to have its own offset. Then I could more
easily add offset shapes to an element in the order convenient to the
shape layering. I speculate that using such an offset variable would
not be much more CPU load than the only other alternative of defining a
new shape class for every general combination of offset shapes.
In addition, I've been musing over whether this 'offset' ivar might be a
point or a block, or might contain a class something like NullOffset
which always returns 0@0; or StaticOffset which always returns a value
stored in an instance variable; or StaticOffsetFromBottomOfElement,
DynamicOffset which executes a block.stored in an instance variable.
DynamicOffset might somehow be tuned into
I have also been musing on whether ChildrenShape should REALLY be the
central consideration. Using labels as an example, all the cases I can
think of for positioning a label, they are dependent of the size of the
ChildrenShape - eg placed under the children shape relies on
ChildShape>>height; and placed to the right of the element relies on the
ChildrenShape>>width and possibly >>height for central vertically
alignment. Following on from this, I think ChildrenShape should always
be calculated first, even if it is drawn in a middle layer. ROElement
would always hold ROChildrenShape as its first shape, while
ROChildrenShape would have two 'next' ivars - one for those shapes above
it and one for those shapes below it.
The position ROChildrenShape would be "defined" to be _always_ at 0@0
and tied directly to whatever is thought of as the "element" position,
with all other shapes offset against it, including in the negative
direction for labels appearing above the ChildrenShape.
However if shapes can have a negative offset, then in line with my ideas
about caching only the sum of shape bounds in the element, I speculate
that the cleanest implementation would be for ROElement>>localBounds to
also allow a negative origin, so that it could be the simple union of
its ROShape>>bounds.
Some ideas end in dead-ends. A possible path forward is to first revert
the changes associated with ROTranslateShape. Then depending on how you
view the ideas I presented above, prior to adding any shape translation,
get ROElement negative bounds and negative translation working as per
Issue 831. Then work individual offsets for shapes, which I believe may
be dependent on Issue 831. Anyway, that is just how it appears to me
without knowing what other architectural constraints you are working with.
phew! (and whoops, that is a lot for you to digest.)
hope some of that is helpful.
cheers -ben