
Andy Little <andy <at> servocomm.freeserve.co.uk> writes:
template<typename ValueType> struct rectangle{ xy_pair<ValueType> position; xy_pair<ValueType> size; };
Nice ! I like the idea of a meaningful neagative size.
I generally only have a very few low level conversion functions where my user types are converted to the platform dependent types for output. I would guess that the system call to the graphics device is much more expensive than the single conversion so the cost is small,( but I havent tested this theory)
Ok ! Consider this: We are writing a 2D Game using SDL. Each time we move something on the screen we must remember its last and new position (two rectangles) so that we can redraw that area and update the screen (we call this, a dirty rectangle mechanisim) So at each frame we construct the region of the screen that has to be redrawen before calling SDL_UpdateRects to update the screen. The region is constructed 60 times per second (this the refresh rate of most screens), do you think that the game writer will want to convert a vector<rectangle> (whose size may vary between 0 and 100) into the corresponding vector<SDL_Rect> 60 times per second ? And remember there is far more stuff to be done in this 1/60 of a second.
I prefer using my own graphics primitives for various reasons. For example using Windows GDI output range is limited to a 16 bit integral value. I perform to work using (underlying) doubles, convert to the device coordinate system and finally clip the resulting value to the device viewport and only then cast to an integer to perform the raw output using the implementation defined call. In practise I never use the graphics platform defined types directly.
Fair enough ! But what if you're actually satisfied with 16 bit integrals ? Do you still want to do conversions ?
Yes , I see the point of the wrapper , but OTOH
point_polar p1 = point_xy(); point_xy p 2 = p1;
should also work.
I beg to differ. Implementation types were never ment to be used as such, they were designed to be wrapped. Indeed, for sometime I resisted the following idea : template<class T> struct point_xy { friend class point_traits< point_xy<T> >; point(); point(T x, T y); private: T x, y; }; That is only the traits class specilization need to know about members of point_xy. I really can't see why you'd want to use (the simple, featureless) point_xy when you have (the powerfull, general) point<point_xy>. For example if you use point_xy for your project and after 2 months you realize that polar points are more suitable, lots of stuff will need to be changed for point_xy provides direct access to its x and Y (only), while polar_point provides RHO and THETA (only) , but point<point_xy> *and* point<polar_point> do provide X, Y, Z, RHO, THETA, and PHI !!!
Sure ...Assuming the above two types
point_polar.x(); point_xy.x();
point_xy. phase_angle(); point_polar.phase_angle();
IOW each has the same interface.
Ok, but you seem to be only considering implementation types provided by Boost.Geom. Of course we could do that, but this is only because we have complete control over point_xy and point_polar. Now what about std::complex<> ? Do you think you can arrange to be able to write: typedef std::complex<float> point; point pt; pt.x()=10; pt.phase_angle()+=3.141592654; What about POINT, QPOint, XPoint, XYZ_Point_XYZ ? So no, giving a bunch of types the same interface is quite not the same as using traits. For one good reason: You don't have control over all the types you'd like to give the same interface. Using traits you can effectively call x() on an std::complex<> ; geom::point< std::complex<double> > pt; pt.x()+=0.3; // Et Voila ! So, in order to keep consistency we don't provide complicated members in implementation types, we put them in wrapper classes.
Note that : - You take benefit of the notaional convinience of geom::box - geom::box is a zero cost wrapper, using it does not create additional overhead as such. - You don't have to convert between geom::box<TG_RECT> and TG_RECT, or more precisely, the conversion is zero cost. And that is not specific to trendy_graph, if you also work with FastGraph you'll be able to wrap FG_Rectangle in a geom::box and enjoy the same interface as with geom::box<TG_RECT>, while still be able to turn a geom::box<FG_Rectangle> into a FG_Rectangle at no cost ! You learn one interface (that of geom::box) and you keep using it regardless of the underlying graph API, while not having to pay in efficiency, Isn't wrapping other libraries wonderful ?
Well its certainly a trick that this library plays but the wrapping is very limited (because the underlying tyopes are exposed in the template parameter),
What ? I don't see in what it is limited. If you don't want to expose the templete parameter, use typedefs !! typedef geom::point< geom::point_xy<float> > point; // Now forget about Boost.Geom and use point ! POINT convert_to_POINT(const point& pt);
but how useful is it in practise? How often do you need to convert?
60 times per second converting 100 rectangles is overkill.
I prefer to hide the platform dependent points behind a 'standard' type which works at a level above the output device towards which these other types seem to be geared. However I dont think that your library rules this out.
It doesn't. If you want close integration use point<GG_Point_2D> if you want platform independent types use point< point_xy<double> > !
You could even specialise it for eg double parameter..
The point I'm trying to make is that its much easier to do this if the
And could you tell me about the possible benefits we'd reaping of this ? platforms
own types are not exposed at all.
Don't get why...:(
OK.. take a look at the angles in pqs. Using them you can use both degrees and radians interchangeably. degrees is more human friendly IMO , while radians is better for math of course. :-)
This certainly is a good idea. Now if only your library gets accepted in Boost ...
U={(x,y,z) in IRxIRxIR such that z=0}; [...] Not too good on the math theory . IOW I dont understand this :-(
Unless you provide ready made output facilities, no one will use the library IMO. I disagree. People already have/know output facilities optimized for thier
Don't be afraid by technical math terms like ``automorphism'' ! (they're merely good enough for impressing girls .. ;-) ) It only means that there is a bijection between U and IRxIR , i.e to every element of U corresponds one and only one element of IRxIR, and to every element of IRxIR corresponds one and only one element of U. So IRxIR and U are (mathematically) the same. [...] platform and they can easily use them to draw geom::boxes.
It also gives a chance to prove how cross-platform the library really is.
It is already cross platform. You can plug almost anything in a geom::point<>
template < typename GX
void redraw(GX & gx) { pt p0,p1,p2,p3; // some points line L1(p0,p2); /
polyline poly0; poly0 += p0, p1,p2,p3; // assign values
polygon poly1; poly1 += p0, p1,p2,p3;
bezier bez( L1, line(p1,p3)); // gx is some graphics output device
gx << L1 << poly0 << poly1 << bez; }
Wow !!! You got far away my friend !! We aren't writing a graphical library, we are writing a "Geometric Primitives Library". If you already have some graphical library feel free to use it to draw geom::points, geom::bezier ... But I doubt it is the purpose of Boost.Geom to provide things like GraphContext or Window::handle_event(const MouseEvent&)! Of course if someone wants to do this (think of it ! a Boost-Quality cross platform GUI/Graph library) Boost.Geom could serve as a "base", but it shouldn't itself be the graph API. Let's divide the problem into small pieces and deal with each spearatly.
Hopefully some day sooner or later I plan to redo it suitable for boost and of course will announce the fact too :-)
Ok I'll wait :). -- Anis Benyelloul