I have a Java application that needs to generate mathematically-defined 3D shapes for a voxel world (Minecraft specifically, but that's not important to the discussion). These include sphere, ovoid, ellipsoid, cone, capsule, and others, and there are two distinct applications that I have for them. Currently I have a single Shape class which Sphere, Capsule, etc extend. Each shape has its own set of parameters like Centre, Radius, Height, etc.
The first way I'm using these shapes is to generate solid objects by iterating over the voxel grid and determining which voxels lie inside the shape. This gives me a boolean Contains(Vector v)
method for each unique shape, and Fill()
which is generic to all solid shapes.
The second way I'm using them is to generate a field of randomised points that do not lie on the grid, which will need a method like Vector GetRandomPoint()
for each shape, and GenerateRandomPoints()
which is generic to all point generators.
Neither of these types of shape can reuse each others' code. Solid shapes are to determine which voxels lie inside them, and point generators create floating point vectors. The random points can't be generated naively then filtered for whether they lie inside the shape (ie, using the Contains()
function) for technical reasons that would take too long to explain here.
To add yet another wrinkle, there is a noise component which both classes need as well, and this component can be generic to all shapes and applications.
The way I'm considering doing this is to have two base classes SolidShape and PointGenerator, then have interfaces for each shape. So for example the two kinds of sphere would be:
public class SolidSphere extends SolidShape implements Sphere {...}
public class SpherePointGenerator extends PointGenerator implements Sphere {...}
This way the generic methods would be reused between shapes, and the dimension parameters like Centre and Radius would be reused between the two applications.
I'm still not sure how to make the noise component generic between all of them, though, although that may be solvable by simply making a Noise class and giving each shape a Noise member.
However, when I attempt to do this, it turns out interfaces aren't used for declaring member variables, and they don't let you do this. Is there a way to do this, or should I just replicate the member variables for each shape? I really don't want to have duplicates of the same variables hanging around because that fast becomes a maintenance nightmare.
Sphere
as constructor parameter, not deriving from Sphere. If your SpherePointGenerator requires attributes like Radius and Center, just delegate the getters to the Radius and Center of the referenced Sphere.