net.algart.drawing3d
Interface DrawingRule

All Known Implementing Classes:
ConvexPlanePolygon3DDrawingRule, Sphere3DDrawingRule

public interface DrawingRule

Drawing rule: the tool for 3D drawing some kind of 3D figure (Shape3D) on the base of drawing one 3D pixel.

This interface allows to solve the task of drawing 3D figure via more simple subtask of drawing 1 pixel. Namely, the basic method draw(Shape3D, Pixel3DDrawer, CoordinateSystem3D, Rectangle2D, double, Color) of this interface performs drawing of the given figure by a series of calls Pixel3DDrawer.drawPoint(int x, int y, double z, double nx, double ny, double nz, Color color) method of its argument pixelDrawer, which draws one point of the surface of this 3D object.

If you want to "teach" this toolkit to draw a new type of 3D figures, you just need to provide necessary implementation of this interface, which "knows" how to draw such figures. If you want to draw any 3D objects, maybe, not implementing Shape3D interface, you also need to provide necessary set of implementations of ShapingRule, which will convert any objects into 3D figures.

This interface works with 2 coordinate system.

The 1st coordinate system is called the coordinate system of the model. All coordinates, sizes and other geometric characteristics of the figure, specified in an Shape3D instance — for example, the center's coordinates and radius of a sphere, the coefficients of the plane equation ax+by+cz=d of a plane polygon — are specified in this coordinate system.

The 2nd coordinate system is the coordinates of the screen. We consider, as usual, that the x-axis is directed to the right (in the screen plane), the y-axis is directed downwards (in the screen plane) and the z-axis is directed from the screen to the user. The screen image is formed by simple parallel projection along z-axis. The top left corner of the built screen image has coordinates x=0, y=0, z=+∞ (+∞ means that the drawn objects are always placed "behind" the screen), and the sizes of a pixel are 1x1.

The relation between these two coordinate systems is described by CoordinateSystem3D object, passed to the methods of this interface. Namely, this object specifies the coordinate system of the model in terms of coordinates of the screen — for example, the origin of the coordinate system of the model corresponds to the point getOriginX(), getOriginY(), getOriginZ() in the screen coordinate system. So, the methods transformX, transformY, transformZ of that object transforms coordinates from the coordinate system of the model to the screen coordinates.

The classes, implementing this interface, are usually immutable and always thread-safe: they can be used simultaneously in several threads.

AlgART Laboratory 2010

Since:
JDK 1.5
Version:
1.0
Author:
Daniel Alievsky

Method Summary
Modifier and Type Method and Description
 void draw(Shape3D shape, Pixel3DDrawer pixelDrawer, CoordinateSystem3D coordinateSystemOfModel, java.awt.geom.Rectangle2D screenArea, double zCut, java.awt.Color color)
          Draws the specified 3D figure (shape), i.e. calls pixelDrawer.drawPoint method for every screen pixel and all corresponding points of the surface ot this figure.
 void estimateContainingParallelepiped(double[] result, Shape3D shape, CoordinateSystem3D coordinateSystemOfModel)
          Returns, in first 6 elements of result argument, the minimal and maximal x-coordinate, the minimal and maximal y-coordinate, the minimal and maximal z-coordinate of all drawable points of the specified 3D figure (shape), in the specified order.
 boolean isApplicable(Shape3D shape, java.lang.Object item)
          Checks whether this drawing rule is applicable to the given figure (shape), i.e. this drawing rule "knows" how to draw it.
 

Method Detail

isApplicable

boolean isApplicable(Shape3D shape,
                     java.lang.Object item)
Checks whether this drawing rule is applicable to the given figure (shape), i.e. this drawing rule "knows" how to draw it. If this method returns false, you should not call other methods of this interface for this shape: they can throw an exception. If this method returns true, you can freely use other methods with the same shape.

This method is used by Drawer3D.draw(java.util.Collection) for choosing the algorithm for drawing every object.

The item argument contains the reference to the source object (item), which was transformed to Shape3D by some shaping rule for drawing by this algorithm. It can be used to restrict the set of objects, to which this drawing algorithm should be applied: this method can return false for some kind of items, so the draw method of this instance will not be called for them. The implementations of this interface, provided by this package, ignore this argument.

Both arguments of this method can be null. If shape argument is null, this method returns false.

Parameters:
shape - the 3D figure which you want to draw; can be null, then this method returns false.
item - the source object which you want to draw as the given figure; can be null.
Returns:
true if this drawing rule can be used for this object.

draw

void draw(Shape3D shape,
          Pixel3DDrawer pixelDrawer,
          CoordinateSystem3D coordinateSystemOfModel,
          java.awt.geom.Rectangle2D screenArea,
          double zCut,
          java.awt.Color color)
Draws the specified 3D figure (shape), i.e. calls pixelDrawer.drawPoint method for every screen pixel and all corresponding points of the surface ot this figure. All coordinates, describing the real surface of the figure, are supposed to be given in the specified coordinateSystemOfModel: see comments to the interface.

While calling drawPoint(int x, int y, double z, double nx, double ny, double nz, Color color) method, this method passes to it the coordinates x, y, z of each surface point in the screen coordinate system. More precisely, let's consider some screen pixel with integer coordinates X, Y and an infinite prism X−½<x<X, Y−½<y<Y, −∞<z<+∞. The intersection of this prism and the surface of the drawn figure (shape) consists of 0 or more connected "pieces" — little surfaces σ1, σ2, ..., σm. There is a guarantee that this method calls drawPoint at least 1 time (but maybe several times) for each such "piece" σk with arguments x=Math.round(x)=X, y=Math.round(y)=Y, z=z, where (x, y, z)∈σk is some point of that "piece". If the central straight line x=X, y=Y of the prism does not intersects the figure, drawPoint method can be not called for the given (X, Y) pair at all, even if the prism little intersects the figure.

The nx, ny, nz arguments of drawPoint are equal to the components of the unit normal vector n=(nx,ny,nz) of the drawn surface at the corresponding point (x, y, z)∈σk, for which it is called. The color argument of drawPoint is equal to the color argument of this method.

The described algorithm is the simplest way of drawing 3D surface. A concrete way, how the surface will be drawn, for example, how the light falls to the surface, depends on Pixel3DDrawer implementation. For example, the standard Z-buffer algorithm, offered by SimpleDrawer3D.getSimpleDrawer3D method, draws only the "top" part of the surface (nearest to the observer), i.e. from all points with given integer X, Y only the one with maximal z-coordinate is really drawn, and it is supposed that the light falls along z axis from the side of the user — the color is multiplied by Math.abs(nz).

The drawn area is restricted by screenArea rectangle: only pixels, lying inside the area screenArea.getMinX()xscreenArea.getMaxX(), screenArea.getMinY()yscreenArea.getMaxY(), should be drawn. But it is not a strict requirement: this method may draw pixels outside this area, if the drawn figure does not fully lie inside it. This argument should be used for optimization needs: for example, it allows quickly returning if the figure lies fully outside the required area.

This method must draw only the part of the 3D figure, lying (in terms of the screen coordinate system) "behind" the plane z=zcut (i.e. in area zzcut), specified by zCut argument. In other words, this argument allows to "dissect" drawn object by some plane and to see only parts "behind" this plane, and to hide (not to draw at all) the objects which are fully "in front of" this plane (z>zcut). Usually, this feature is used by GUI to allow seeing a cut set of a complex 3D configuration. You can specify zCut=Double.POSITIVE_INFINITY, if you don't want to use this feature.

The pixels of the "dissected" figure can be drawn with maximal brightness (1.0 value of the brightness argument of drawPoint method) — it corresponds to showing a plane section of a solid 3D body. But also the drawing rule can show the internal surface of the figure "behind" this place — if corresponds to dissection of a hollow 3D body. The first variant ("solid body") is used by Sphere3DDrawingRule, the second one (drawing surface only) is used by ConvexPlanePolygon3DDrawingRule.

This method works normally, only if this object "knows", how to draw this kind of 3D figures. You can be sure that it is true, if isApplicable(Shape3D, Object) method returns true for this shape and some 2nd argument. In this case, this method does not throw any exceptions, excepting NullPointerException (when one of the arguments is null). But if this object does not "know", how to draw this kind of 3D figures, this method can throw ClassCastException or other unexpected runtime exceptions.

Parameters:
shape - the drawn 3D figure.
pixelDrawer - the object which will be used for drawing each pixel.
coordinateSystemOfModel - the coordinate system of the model, in which the passed 3D figure is represented.
screenArea - the screen area, inside which the figure should be drawn (for optimization needs only).
zCut - z-coordinates of the section plane: only points with zzCut should be drawn.
color - the color of the drawn figure.
Throws:
java.lang.NullPointerException - if one of the arguments is null.
See Also:
Drawer3D.draw(java.util.Collection)

estimateContainingParallelepiped

void estimateContainingParallelepiped(double[] result,
                                      Shape3D shape,
                                      CoordinateSystem3D coordinateSystemOfModel)
Returns, in first 6 elements of result argument, the minimal and maximal x-coordinate, the minimal and maximal y-coordinate, the minimal and maximal z-coordinate of all drawable points of the specified 3D figure (shape), in the specified order. In other words, this method estimates a circumscribed parallelepiped of this figure. The resulting coordinates are returned in the screen coordinate system, and coordinateSystemOfModel argument is used for conversion of coordinates from the model coordinate system, as described in the comments to the interface.

There is no guarantee that the returned coordinate limits will be precise: they can be just an estimation. But, in any case, the returned parallelepiped fully contains the specified figure. Usually, this method helps GUI modules to determine a suitable range of possible zCut arguments for draw method.

This method works normally, only if this object "knows", how to draw this kind of 3D figures. You can be sure that it is true, if isApplicable(Shape3D, Object) method returns true for this shape and some 2nd argument. But if this object does not "know", how to draw this kind of 3D figures, this method can throw ClassCastException or other unexpected runtime exceptions.

Parameters:
result - Java-array for storing results.
shape - the 3D figure (that should be probably drawn by draw method).
coordinateSystemOfModel - the coordinate system in which the figure should be drawn.
Throws:
java.lang.NullPointerException - if one of the arguments is null.
java.lang.IndexOutOfBoundsException - if result.length<6; it is not checked at the very beginning, so, in a case of this exception, some elements of result array can be still filled (the method is non-atomic regarding this failure).
See Also:
Drawer3D.estimateContainingParallelepiped(double[], java.util.Collection)