I am having trouble designing the part of my application that deals with geometry. In particular, I would like to have a hierarchy of classes and separate methods for intersections.
The problem
The hierarchy would be something like this:
- Geometry
- Mesh
- Parametric
- Box
- Sphere
And the intersection methods something like:
namespace intersections
{
bool intersection( const Box &, const Box &);
bool intersection( const Box &, const Sphere &);
}
This is quite simple. The problem arises now, when I want to store all geometries together in a single structure, say for example a std::vector
(or a KD-Tree, or whatever).
To do that, I need to use a std::vector<Geometry*>
. However, reading from this vector would get me Geometry*
objects and thus I have no way of calling the appropriate intersection function.
Example of the problem:
std::vector<Geometry*> arrGeometry;
// add the elements
arrGeometry.push( new Box() );
arrGeometry.push( new Sphere() );
// ... some more code
// try to intersect them?
Geometry* g1 = arrGeometry[0];
Geometry* g2 = arrGeometry[1];
bool intersecting = intersections::intersection( g1, g2 ); //< As expected, this does
// not work
If I implemented the algorithms inside the geometry objects the problem could be solved by a visitor and some pretty weird function call bouncing.
However, I would like to keep the intersection algorithms outside the Geometry classes. the reasons are:
to avoid deciding which should have the ownership (eg. where do you implement the intersection between box and sphere, in
Box
or inSphere
?)to avoid cluttering the geometry objects will all that can be done to geometry, which is quite a lot (just to name a few: voxelize it, compute intersections, applying constructive geometry operators...). Thus, separating logic from data is quite desirable here.
On the other hand, I need to have a hierarchy instead of templates because for some things the specific geometry can be abstracted away... (eg. for storing it in a std::vector
, or a KD-Tree, or... ).
How would you solve this? Is there any design pattern appropriate for this? I tried looking at some libraries but I ended up more confused that I already was...
The easiest way (which is sometimes used) is to use RTTI (or to fake it) and downcastings, but that is not exactly maintainable... (adding a new geometry implies change a lot of switch statement though all the code).
Any thoughts?
Thanks you very much in advance.