net.algart.drawing3d
Class Drawer3D

java.lang.Object
  extended by net.algart.drawing3d.Drawer3D
All Implemented Interfaces:
Pixel3DDrawer
Direct Known Subclasses:
SimpleDrawer3D

public abstract class Drawer3D
extends java.lang.Object
implements Pixel3DDrawer

Universal 3D drawer: the main drawing tool of this toolkit.

This class operates with with some sets of shaping rules, coloring rules and drawing rules, which are usually passed to a constructor or an instantiation method. Also, this class implements Pixel3DDrawer interface and supports the current coordinate system and the current zcut limit. It allows this class to provide a very common method draw(java.util.Collection) — the main method of this class, which draws a collection of absolutely random objects.

This class draws objects inside some fixed area of the real plane 0≤xscreenWidth, 0≤yscreenHeight, named the screen. This screen is generally virtual, but usually it corresponds to a part of the real user's screen, maybe, with some scaling. This virtual screen defines the system of screen coordinates, in terms of DrawingRule interface. Usually the screen sizes (screenWidth and screenHeight) are passed to a constructor or an instantiation method and cannot be changed in future. In terms of Pixel3DDrawer.drawPoint(int, int, double, double, double, double, Color) method, implemented by this class, the screen sizes are called "the sizes of the resulting image".

The final graphic result can be obtained in a form of BufferedImage object by getImage() method. The sizes of this image can differ from the sizes of the virtual screen. For example, SimpleDrawer3D implementation automatically compresses the image, built by draw(java.util.Collection) method, in SimpleDrawer3D.getAntialiasingScale() times: it allows to provide better quality of the resulting picture.

This class is abstract and does not provide a real implementation of Pixel3DDrawer interface. This package offers a simple full implementation in SimpleDrawer3D class, based on the traditional Z-buffer algorithm.

This class is not thread-safe, but is thread-compatible and can be synchronized manually if multithread access is necessary.

AlgART Laboratory 2010

Since:
JDK 1.5
Version:
1.0
Author:
Daniel Alievsky

Field Summary
Modifier and Type Field and Description
protected  int screenHeight
          The height of the (virtual) screen, specified in the constructor.
protected  int screenWidth
          The width of the (virtual) screen, specified in the constructor.
protected  double zCut
          The current zcut limit, which will be passed to DrawingRule.draw method by draw(java.util.Collection) method of this class.
 
Constructor Summary
Modifier Constructor and Description
protected Drawer3D(int screenWidth, int screenHeight, java.awt.Color backgroundColor, java.util.Collection<ShapingRule> shapingRules, java.util.Collection<ColoringRule> coloringRules, java.util.Collection<DrawingRule> drawingRules)
          Creates new instance of this class.
 
Method Summary
Modifier and Type Method and Description
abstract  void clearRect(int left, int top, int width, int height)
          Clears (reinitialize) the rectangular area leftx<left+width, topy<top+height.
 void draw(java.util.Collection<?> items)
          Draws all passed objects.
 void draw(java.lang.Object... items)
          Draws all passed objects.
abstract  void drawPoint(int x, int y, double z, double nx, double ny, double nz, java.awt.Color color)
          Draws 1 pixel (point) of the surface of some 3D figure.
 boolean estimateContainingParallelepiped(double[] result, java.util.Collection<?> items)
          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 all passed 3D objects, in the specified order.
protected  int gammaCorrection(int brightness)
          Returns (int)(256.0 * (brightness/256.0)γ) + 0.5), where γ is the current γ exponent for the gamma-correction.
 java.awt.Color getBackgroundColor()
          Returns the current background color, used by clearRect(int, int, int, int) method.
 java.awt.Color getColor(java.lang.Object item)
          Finds and returns the desired color of the given object.
 java.util.List<ColoringRule> getColoringRules()
          Returns the list of coloring rules, used by this object.
 CoordinateSystem3D getCoordinateSystem()
          Returns the current coordinate system.
 DrawingRule getDrawingRule(Shape3D shape, java.lang.Object item)
          Finds and returns the drawing rule, which should be used for drawing the given 3D figure.
 java.util.List<DrawingRule> getDrawingRules()
          Returns the list of drawing rules, used by this object.
 double getGamma()
          Returns the current γ, used for gamma-correction of the pixel brightness.
abstract  java.awt.image.BufferedImage getImage()
          Transforms the current picture, built on the virtual screen by this object, into a buffered image, and returns it.
abstract  int getImageHeight()
          Returns the height of the image, built by getImage() method.
abstract  int getImageWidth()
          Returns the width of the image, built by getImage() method.
 int getScreenHeight()
          Returns the height of the (virtual) screen: screenHeight.
 int getScreenWidth()
          Returns the width of the (virtual) screen: screenWidth.
 Shape3D getShape(java.lang.Object item)
          Finds and returns the 3D shape (figure) of the given object.
 java.util.List<ShapingRule> getShapingRules()
          Returns the list of shaping rules, used by this object.
 double getZCut()
          Returns the current zcut limit.
 void setBackgroundColor(java.awt.Color backgroundColor)
          Sets the new current background color, used by clearRect(int, int, int, int) method.
 void setColoringRules(java.util.Collection<ColoringRule> coloringRules)
          Sets the new set of coloring rules, used by this object.
 void setColoringRules(ColoringRule... coloringRules)
          Sets the new set of coloring rules, used by this object.
 void setCoordinateSystem(CoordinateSystem3D coordinateSystem)
          Sets the new current coordinate system.
 void setDrawingRules(java.util.Collection<DrawingRule> drawingRules)
          Sets the new set of drawing rules, used by this object.
 void setDrawingRules(DrawingRule... drawingRules)
          Sets the new set of drawing rules, used by this object.
 void setGamma(double gamma)
          Sets the current γ, used for gamma-correction of the pixel brightness.
 void setShapingRules(java.util.Collection<ShapingRule> shapingRules)
          Sets the new set of shaping rules, used by this object.
 void setShapingRules(ShapingRule... shapingRules)
          Sets the new set of shaping rules, used by this object.
 void setZCut(double zCut)
          Sets the new current zcut limit.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

screenWidth

protected final int screenWidth
The width of the (virtual) screen, specified in the constructor.


screenHeight

protected final int screenHeight
The height of the (virtual) screen, specified in the constructor.


zCut

protected double zCut
The current zcut limit, which will be passed to DrawingRule.draw method by draw(java.util.Collection) method of this class. By default, it is Double.POSITIVE_INFINITY, but it can be set to another value by setZCut(double) method.

Constructor Detail

Drawer3D

protected Drawer3D(int screenWidth,
                   int screenHeight,
                   java.awt.Color backgroundColor,
                   java.util.Collection<ShapingRule> shapingRules,
                   java.util.Collection<ColoringRule> coloringRules,
                   java.util.Collection<DrawingRule> drawingRules)
Creates new instance of this class.

The passed collections are copied into newly created lists: no references to them are maintained by the created object.

Parameters:
screenWidth - the width of the (virtual) screen: screenWidth. Cannot be changed in future.
screenHeight - the height of the (virtual) screen: screenHeight. Cannot be changed in future.
backgroundColor - the background color, which will be used by clearRect(int, int, int, int) method. After creation, all screen is filled by this color.
shapingRules - the set of shaping rules, which will be used by draw method.
coloringRules - the set of coloring rules, which will be used by draw method.
drawingRules - the set of drawing rules, which will be used by draw method.
Throws:
java.lang.NullPointerException - if some of the arguments is null, or if one of rules in the passed collections is null.
java.lang.IllegalArgumentException - if screenWidth<0 or screenHeight<0.
Method Detail

getShapingRules

public java.util.List<ShapingRule> getShapingRules()
Returns the list of shaping rules, used by this object.

The result is an immutable view (Collections.unmodifiableList) of the internal collection, stored by this object: you cannot modify the set of used shaping rules via the result of this method.

The elements of the returned list are never null.

Returns:
the list of shaping rules, used by this object.

setShapingRules

public void setShapingRules(java.util.Collection<ShapingRule> shapingRules)
Sets the new set of shaping rules, used by this object.

The passed collection is copied into a newly created list: no references to it are maintained by this object.

Parameters:
shapingRules - new shaping rules.
Throws:
java.lang.NullPointerException - if the argument or one the elements of the passed collection is null.

setShapingRules

public void setShapingRules(ShapingRule... shapingRules)
Sets the new set of shaping rules, used by this object.

The passed array is copied into a newly created list: no references to it are maintained by this object.

Parameters:
shapingRules - new shaping rules.
Throws:
java.lang.NullPointerException - if the argument or one the elements of the passed collection is null.

getColoringRules

public java.util.List<ColoringRule> getColoringRules()
Returns the list of coloring rules, used by this object.

The result is an immutable view (Collections.unmodifiableList) of the internal collection, stored by this object: you cannot modify the set of used coloring rules via the result of this method.

The elements of the returned list are never null.

Returns:
the list of coloring rules, used by this object.

setColoringRules

public void setColoringRules(java.util.Collection<ColoringRule> coloringRules)
Sets the new set of coloring rules, used by this object.

The passed collection is copied into a newly created list: no references to it are maintained by this object.

Parameters:
coloringRules - new coloring rules.
Throws:
java.lang.NullPointerException - if the argument or one the elements of the passed collection is null.

setColoringRules

public void setColoringRules(ColoringRule... coloringRules)
Sets the new set of coloring rules, used by this object.

The passed array is copied into a newly created list: no references to it are maintained by this object.

Parameters:
coloringRules - new coloring rules.
Throws:
java.lang.NullPointerException - if the argument or one the elements of the passed collection is null.

getDrawingRules

public java.util.List<DrawingRule> getDrawingRules()
Returns the list of drawing rules, used by this object.

The result is an immutable view (Collections.unmodifiableList) of the internal collection, stored by this object: you cannot modify the set of used drawing rules via the result of this method.

The elements of the returned list are never null.

Returns:
the list of drawing rules, used by this object.

setDrawingRules

public void setDrawingRules(java.util.Collection<DrawingRule> drawingRules)
Sets the new set of drawing rules, used by this object.

The passed collection is copied into a newly created list: no references to it are maintained by this object.

Parameters:
drawingRules - new drawing rules.
Throws:
java.lang.NullPointerException - if the argument or one the elements of the passed collection is null.

setDrawingRules

public void setDrawingRules(DrawingRule... drawingRules)
Sets the new set of drawing rules, used by this object.

The passed array is copied into a newly created list: no references to it are maintained by this object.

Parameters:
drawingRules - new drawing rules.
Throws:
java.lang.NullPointerException - if the argument or one the elements of the passed collection is null.

getBackgroundColor

public java.awt.Color getBackgroundColor()
Returns the current background color, used by clearRect(int, int, int, int) method.

Returns:
the current background color.

setBackgroundColor

public void setBackgroundColor(java.awt.Color backgroundColor)
Sets the new current background color, used by clearRect(int, int, int, int) method.

Parameters:
backgroundColor - new current background color
Throws:
java.lang.NullPointerException - if the argument is null.

getCoordinateSystem

public CoordinateSystem3D getCoordinateSystem()
Returns the current coordinate system. After creating this object, the coordinate system is trivial: new CoordinateSystem3D(0.0, 0.0, 0.0, 1.0, Orientation3D.DEFAULT);.

The result is a clone (CoordinateSystem3D.clone()) of the internal field of this object: you cannot modify the coordinate system via the result of this method.

Returns:
the current coordinate system.

setCoordinateSystem

public void setCoordinateSystem(CoordinateSystem3D coordinateSystem)
Sets the new current coordinate system.

The passed object is cloned (CoordinateSystem3D.clone()): no references to it are maintained by this object.

Parameters:
coordinateSystem - new current coordinate system.
Throws:
java.lang.NullPointerException - if the argument is null.

getZCut

public double getZCut()
Returns the current zcut limit.

Returns:
the current zcut limit. After creating this object, it is Double.POSITIVE_INFINITY.

setZCut

public void setZCut(double zCut)
Sets the new current zcut limit.

Parameters:
zCut - new current zcut limit.

getGamma

public double getGamma()
Returns the current γ, used for gamma-correction of the pixel brightness. See setGamma(double) for more details. After creating this object, γ=1.0 (no correction).

Returns:
the current γ, used for gamma-correction of the pixel brightness.
See Also:
gammaCorrection(int)

setGamma

public void setGamma(double gamma)
Sets the current γ, used for gamma-correction of the pixel brightness. This correction means, that the brightness L (light intensity), 0≤L≤1, of any surface point (calculated on the base of the normal vector unit n, passed to drawPoint) is automatically replaces with Lγ by drawPoint method. In many situation, it can improve visual quality of the resulting image.

This method corrects an internal table, used by gammaCorrection(int) method.

Parameters:
gamma - the new current γ, used for gamma-correction of the pixel brightness.
Throws:
java.lang.IllegalArgumentException - if the passed gamma<=0.0.

getScreenWidth

public final int getScreenWidth()
Returns the width of the (virtual) screen: screenWidth.

Returns:
the width of the (virtual) screen.

getScreenHeight

public final int getScreenHeight()
Returns the height of the (virtual) screen: screenHeight.

Returns:
the height of the (virtual) screen.

getImageWidth

public abstract int getImageWidth()
Returns the width of the image, built by getImage() method.

Returns:
the width of the image, built by getImage() method.

getImageHeight

public abstract int getImageHeight()
Returns the height of the image, built by getImage() method.

Returns:
the height of the image, built by getImage() method.

clearRect

public abstract void clearRect(int left,
                               int top,
                               int width,
                               int height)
Description copied from interface: Pixel3DDrawer
Clears (reinitialize) the rectangular area leftx<left+width, topy<top+height. After this call, this object will be in the same state, as when drawPoint was never called for integer pairs (x,y) in this area, and this area is filled by some default background color.

The implementation, provided by SimpleDrawer3D.getSimpleDrawer3D method, initializes Z-buffer for this area by default −∞ values.

If the specified area is out of ranges of the screen (i.e. some coordinates are <0 or ≥width/height of the image, which should be built as a result), the extra pixels are ignored. In particular, you can specify left=top=0, width=height=MAX_VALUE to reinitialize all drawable area. If width≤0 or height≤0, this method does nothing.

Specified by:
clearRect in interface Pixel3DDrawer
Parameters:
left - the minimal x-coordinate of the cleared area.
top - the minimal y-coordinate of the cleared area.
width - the width of the cleared area.
height - the height of the cleared area.

drawPoint

public abstract void drawPoint(int x,
                               int y,
                               double z,
                               double nx,
                               double ny,
                               double nz,
                               java.awt.Color color)
Description copied from interface: Pixel3DDrawer
Draws 1 pixel (point) of the surface of some 3D figure. It is the basic primitive, on the base of which DrawingRule.draw method is implemented.

The coordinates of the pixel are specified in the coordinate system of the computer screen: 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 top left corner of the screen image, which should be built as a result, has coordinates x=0, y=0, z=+∞.

x and y coordinates, passed to this method, specify the pixel of the resulting image, which should be built (from 0 to the image width−1 or height−1). The resulting color of the pixel (x,y) of that image depends on the full series of calls of this method, in which these x, y coordinates were passed.

z-coordinate, passed to this method, is compared with z-coordinates of other points, which were probably drawn by this method at the same (x,y) coordinates. The simplest implementation can just overwrite the color of this pixel, if the passed z is greater than z-coordinates of all previous calls with same (x,y), or preserve the previous color if not — it is the known "Z-buffer" algorithm. But other implementations are also possible: for example, the new color can be combined with the previous color at (x,y) position, to provide an effect of translucency. The implementation, provided by SimpleDrawer3D.getSimpleDrawer3D method, uses the described simple Z-buffer algorithm.

The color argument specifies the color of the drawn point of the 3D surface. But this color is used directly only in a case, when the surface is perpendicular to the rays of the light. In other case, the color should be made darker. To provide this behavior, this method has additional arguments nx, ny, nz, equal to the components of the unit normal vector n=(nx,ny,nz) of the drawn surface. An implementation can use this information to reduce the brightness according to some lighting model. The implementation, provided by SimpleDrawer3D.getSimpleDrawer3D method, multiplies all R, G, B components of the color by Math.abs(nz) — it corresponds to the light rays, falling along z axis from the side of the user (observer). Note: the normal vector is supposed to be unit, i.e. nx²+ny²+nz²=1.0.

The alpha component of the passed color affects the transparency. It is guaranteed, that if color.getAlpha()==0, then this pixel is not drawn (the method does nothing), and if color.getAlpha()==0, then it means normal drawing. Other values 1–254 can affect the transparency, but it is not guaranteed. The implementation, provided by SimpleDrawer3D.getSimpleDrawer3D method, uses 1–254 values for mixing the passed color with previously drawn color, which partially emulates translucency. But note that this feature does not really provide correct translucency, because that implementation is based on a simple Z-buffer algorithm and does nothing if z argument is less than z-coordinates of the previously drawn pixel.

If x or y arguments are out of ranges of the screen (i.e. <0 or ≥width/height of the image), this method does nothing. Besides this, the object can support some zcut limit and ignore calls with z>zcut: it allows creating "cut sets" of a complex 3D configuration (this limit is really supported by Drawer3D class).

Specified by:
drawPoint in interface Pixel3DDrawer
Parameters:
x - x-coordinate of the point.
y - y-coordinate of the point.
z - z-coordinate of the point.
nx - x-component of the unit normal vector of the drawn surface at this point.
ny - y-component of the unit normal vector of the drawn surface at this point.
nz - z-component of the unit normal vector of the drawn surface at this point.
color - the color of drawn surface point.

getImage

public abstract java.awt.image.BufferedImage getImage()
Transforms the current picture, built on the virtual screen by this object, into a buffered image, and returns it. Usually the pixels of the returned buffered image precisely corresponds to the picture, built by clearRect and drawPoint methods of this object, but some little transformation, like scaling, is possible: for example, SimpleDrawer3D implementation automatically compresses the image in SimpleDrawer3D.getAntialiasingScale() times.

Further drawing in this object will not affect the returned image, but the further calls of this method can change it. (For example, SimpleDrawer3D implementation uses for building a buffered image the separate memory, allocated only once, and does not reallocate it in this method.)

Returns:
the buffered image with the picture, built in this object.
See Also:
getImageWidth(), getImageHeight()

getShape

public Shape3D getShape(java.lang.Object item)
Finds and returns the 3D shape (figure) of the given object. To do this, this method sequentially calls shapingRule.isApplicable(item) for all shaping rules, used by this object, and if this method returns true for some rule, this method immediately return shapingRule.getShape(item). If isApplicable(item) returns false for all shaping rules, but item implements Shape3D interface itself, this method returns (Shape3D)item. In other cases, and also if item==null, this method returns null.

Parameters:
item - some 3D object; can be null, then this method returns null
Returns:
the shape of this object, according the current set of shaping rules.

getColor

public java.awt.Color getColor(java.lang.Object item)
Finds and returns the desired color of the given object. To do this, this method sequentially calls coloringRule.isApplicable(item) for all coloring rules, used by this object, and if this method returns true for some rule, this method immediately return coloringRule.getColor(item). If isApplicable(item) returns false for all coloring rules, and also if item==null, this method returns null.

Parameters:
item - some 3D object; can be null, then this method returns null
Returns:
the color of this object, according the current set of coloring rules.

getDrawingRule

public DrawingRule getDrawingRule(Shape3D shape,
                                  java.lang.Object item)
Finds and returns the drawing rule, which should be used for drawing the given 3D figure. To do this, this method sequentially calls drawingRule.isApplicable(shape, item) for all drawing rules, used by this object, and if this method returns true for some rule, this method immediately return that drawingRule. If isApplicable(shape, item) returns false for all drawing rules, and also if shape==null, this method returns null.

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:
the drawing rule, which should be used for drawing the given object.

draw

public void draw(java.lang.Object... items)
Draws all passed objects. Equivalent to draw(Arrays.asList(items)).

Parameters:
items - objects that should be drawn.
Throws:
java.lang.NullPointerException - if items array is null.

draw

public void draw(java.util.Collection<?> items)
Draws all passed objects.

More precisely, this method performs the following operations for each element item of the passed collection:

Note: this method allows to draw absolutely any objects, if there are necessary shaping rules, which allows to transform them to 3D figures, coloring rules, which allows to select their colors, and drawing rules, which allows to draw the found 3D figures with the found colors. But if the argument of this method is a collection of 3D figures (implementing Shape3D interface), you can go without shaping rules.

Parameters:
items - objects that should be drawn.
Throws:
java.lang.NullPointerException - if the argument is null.

estimateContainingParallelepiped

public boolean estimateContainingParallelepiped(double[] result,
                                                java.util.Collection<?> items)
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 all passed 3D objects, in the specified order.

More precisely, this method performs the following operations for each element item of the passed collection:

The result argument will contains the union of all found parallelepipeds, i.e. an estimation of the parallelepiped, circumscribed about all passed items configuration. Usually, this method helps GUI modules to determine a suitable range for changing current zcut limit.

The result of this method is true if at least one parallelepiped was really found, i.e. both shape and drawing rule was not null at least for one item. In other case, this method returns false and does not modify the passed result array.

Parameters:
result - Java-array for storing results.
items - objects that should be drawn.
Returns:
Java array with the estimated containing parallelepiped.
Throws:
java.lang.NullPointerException - if one of the arguments is null.
java.lang.IndexOutOfBoundsException - if result.length<6.

gammaCorrection

protected int gammaCorrection(int brightness)
Returns (int)(256.0 * (brightness/256.0)γ) + 0.5), where γ is the current γ exponent for the gamma-correction. This method works very quickly: it just returns the corresponding element of an internal table, stored in this object and rebuilt by any setGamma(double) call. The argument must be in 0<=brightness<=256 range.

Parameters:
brightness - some brightness which should be corrected, in 0..256 range.
Returns:
the brightness after gamma correction.
Throws:
java.lang.IndexOutOfBoundsException - if brightness<0 or brightness≥257.