|
Boost : |
From: Dave Abrahams (abrahams_at_[hidden])
Date: 2000-01-02 00:18:17
> Probably I'm too late with my thoughts about the whole Dave Abrahams' idea
> of boost Window toolkit and the topic seems to be closed by now
Nope, just dormant. I'm going to write a motivation document and manifesto
(declaration of principles and goals) one of these days...
>, but I
> still want to discuss a small part of this not-yet-existing toolkit -
> geometry classes like point, rectangle and so on.
> In fact, a long time before Dave have posted his proposal - about 3 months
> ago, at the first time I took a look at boost.org - I thought about such
> classes as an ideal candidates to the boost library. As Paul Moore said,
> they are indeed sort of classes that get reinvented over and over and I
> think it's time to try to summarize experience we have by now with them (I
> think everybody in this group have written his own version of them, right?
> ;) and to present some initial version which eventually may become a
> standard - as it happens with 'string'. So I've took a courage to make the
> first contribution. It's really a very raw version, so any constructive
> feedback is welcome. And actually there are already a few open questions I
> want to discuss here:
> 1) What about the 'problem of one pixel'? Do coordinate values have to be
> treated as coordinates of points or as coordinates of grid lines between
> points? E.g. what pair of points describes the following rectangle:
> (1,1)-(4,3) or (1,1)-(5,4)?
> _________
> |_|_|_|_|_|_|
> |_|#|#|#|#|_|
> |_|#|_|_|#|_|
> |_|#|#|#|#|_|
> |_|_|_|_|_|_|
>
> The answer to this question determines the implementation of many
> rectangle's methods, such as width() ( 'return right - left + 1' or 'return
> right - left' ?). Native coordinate systems on many platforms seem to agree
> upon the second model - coordinate values are treated as coordinates of grid
> lines between points, but definitely there are systems which use the first
> approach. We can choose one of them and delegate dealing with the problem to
> conversion operators from our classes to native geometry types, but does
> this solve the problem?
If you want to be fully general, you parametrize. The issue is one of ranges
(another simple concept that should be covered by boost) and whether they
are represented as closed or half-open.
But I don't want to be fully general. I believe that the half-open approach
(coordinates are grid lines) is the correct one for the bitmapped graphics
problem.
Furthermore, if you really intend to represent geometry and not pixel
graphics, the half-open approach is the only correct one. If you have a
rectangle<double> and its left side is at 0 and its right side is at 5, how
wide is it? There can be only one reasonable answer: 5
> 2) Do we need a separate 'size' class, or we want to use 'point' everywhere
> instead it? Necessity for 'size' may seemed non-obvious for those who always
> worked only with 'point' and 'rect', but if you only tasted the 'size' you
> may feel it is quite naturally to have yet another geometry class. For
> example, if you have no a 'size' class and you construct a rectangle from
> two points, it is not clearly how the constructor uses these points - as
> left-top and right-bottom coordinates or as left-top coordinates and sizes
> of rectangle sides.
I don't believe that size is a neccessary separate concept for pure
geometry, though there are some cases in graphics APIs where a distinction
between size and point would reduce errors (certain blitting code). The case
you're mentioning can be handled thus:
point topleft, extent;
rectangle r( topleft, topleft + extent );
BTW, the 2-point constructor for rectangle should allow you to specify any 2
diagonally opposite corners in any order.
> And what is more, you can't even write two such
> constructors - one for the first behavior and other for the second - you
> have to choose one of them. Another example is 'size()' operation of a
> rectangle class - it seems for me at least discouraging to have this method
> return 'point' instead 'class size'.
I don't know why. In mathematics no distinction is made between the vector
representing a location and a vector representing an offset (e.g. a 'size').
I like to call this function 'extent()', BTW.
> Yet other case when it feels quite
> reasonable to distinguish point and size concepts is rect::operator +=. If
> we have both 'point' and 'size', we may have two versions of this operator
> (a) rect::operator += ( const point& p ) will move a rectangle origin, but
> not change its size and (b) rect::operator += ( const size& s ) will change
> a rectangle size, but not move the rectangle origin point.
So what do you get when you subtract 2 points? A size? Can I add a size to a
point? what type is the result?
size s = r.bottomright - r.topleft;
point p(5, 5)
point q = p + s; //?
You could just use a different function for resizing a rectangle:
rectangle r2 = expand(r, point(3, 3));
>Finally my
> version of geometry classes have a 'size' class. But I still have doubts
> about this question. Your thoughts?
I'm beginning to see why you like it, but I worry about clutter a bit. I'm
not sure it's neccessary.
> 3) Do we allow a public access to members of geometry classes, or we need to
> hide them behind accessors? I've been always using access wrappers, but for
> many people it may seemed quite ugly and uncomfortable to write rect.top()
> += 10 (or rect.origin().x() += 10).
I don't think I believe in supplying write access to data members through
functions. They may as well be fully exposed. Is there a reason why not?
> And that about names of either wrappers
> or members? Must we name them 'x', 'y'
I've been using h, v.
> for point and 'left', 'top',
> 'right', 'bottom' for rectangle
I like those.
> or, say, 'col', 'row' and 'origin().col()',
> 'origin().row()', 'corner().col()', corner().row()' or something else? By
> the way, if we will use access methods, we can to present all of name
> variants. But is it acceptable?
It's kind of scattered to do that, and we can't hope to anticipate
everyone's favorite names.
> 4) Do we want to see operators like += in both point and rectangle classes
> as member template functions, or we would prefer to make them an ordinary
> functions with 'const self&' argument and to provide a template copy
> constructor for conversions like point<long> to point<double> ? E.g. what we
> would prefer:
> a) template<class T>
> template<class U>
> point<T>& point<T>::operator +=( const point<U>& offset );
> or
> b) template<class T>
> template<class U>
> point(const point<U>& offset );
> and
> template<class T>
> point<T>& point<T>::operator +=( const point<T>& offset );
> Or we would like a combination of both approaches - a template copy
> constructor and template member operators like +=? ( current implementation
> doesn't support either of these methods because my compiler - MSVC 6.0 - can
> 't deal with member templates inside template classes ).
My favorite compiler doesn't do implicit conversions through member
templates (yet), so I would prefer that we could do the combinations without
relying on that, but OTOH avoiding it would probably result in lots more
code.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk