# Enter the third dimension

### Use a Swing component to explore three-dimensional computer graphics

Page 4
Page 4 of 4
``` ```private void clip (Graphics g, double x1, double y1, double z1, double x2,
double y2, double z2)
{
int c, c1, c2;
double t, x = 0.0, y = 0.0, z = 0.0;   c1 = code (x1, y1, z1);
c2 = code (x2, y2, z2);   while (c1 != 0 || c2 != 0)
{
if ((c1 & c2) != 0)
return;      c = c1;
if (c == 0)
c = c2;      if ((c & LEFT) != 0)
{
t = (z1 + x1) / ((x1 - x2) - (z2 - z1));
z = t * (z2 - z1) + z1;
x = -z;
y = t * (y2 - y1) + y1;
}
else
if ((c & RIGHT) != 0)
{
t = (z1 - x1) / ((x2 - x1) - (z2 - z1));
z = t * (z2 - z1) + z1;
x = z;
y = t * (y2 - y1) + y1;
}
else
if ((c & BOTTOM) != 0)
{
t = (z1 + y1) / ((y1 - y2) - (z2 - z1));
z = t * (z2 - z1) + z1;
x = t * (x2 - x1) + x1;
y = -z;
}
else
if ((c & TOP) != 0)
{
t = (z1 - y1) / ((y2 - y1) - (z2 - z1));
z = t * (z2 - z1) + z1;
x = t * (x2 - x1) + x1;
y = z;
}      if (c == c1)
{
x1 = x;
y1 = y;
z1 = z;
c1 = code (x, y, z);
}
else
{
x2 = x;
y2 = y;          z2 = z;
c2 = code (x, y, z);
}
}   showLine (g, x1, y1, z1, x2, y2, z2);
}private int code (double x, double y, double z)
{
int result = 0;   if (x < -z)
result = LEFT;   if (x > z)
result |= RIGHT;   if (y < -z)
result |= BOTTOM;   if (y > z)
result |= TOP;   return result;
}```
```
Caution
Be careful when reading my textbook's 3D-clipping algorithm—it contains a bug. This bug and a solution are revealed by You-Dong Liang and Brian A Barsky in "A New Concept and Method for Line Clipping" (ACMTransactions on Graphics, Vol. 3, No. 1, January 1984). I employ their solution in my clipping code.

#### Projection onto a 2D screen

Subsequent to the clipping algorithm calculating the endpoints of the visible portion of a line, this line can be projected onto the 2D display screen—the final step in viewing a world. Although `Panel3D`'s projection code requires clipping coordinates, it's helpful to think about projection in terms of eye coordinates. The following matrix operation converts clipping coordinates back to eye coordinates:

``` ```[xe ye ze 1] = [xc yc zc 1] [S/D  0    0    0]
[0    S/D  0    0]
[0    0    1    0]
[0    0    0    1]```
```

Projecting eye points—world points located in the eye coordinate system—onto the 2D display screen is accomplished by dividing each point's x and y values by its z value. For example, assume that the clipping algorithm has accepted eye point P, one of a line's endpoints. After dividing its x and y values by its z value, the projection of P—point P'—appears on the screen, as illustrated in Figure 12.

The screen coordinates of the projected point, P', are obtained from observing a pair of similar triangles. In Figure 13's Ye/Ze plane, these similar triangles are OQ'P' and OQP, establishing the `ys/D = ye/ze` relation. For the Xe/Ze plane, similar triangles would establish `xs/D = xe/ze`. Rewriting these relations and dividing by half the screen size yields `xs = Dxe/Sze` and `ys = Dye/Sze`.

The `xs` and `ys` values are fractions of displacement across the screen. Each value is useless until it is converted to a screen coordinate. This conversion is accomplished by multiplying the value by half the screen's size (in the appropriate direction) and adding the result to the appropriate screen center value.

In keeping with textbook conventions, I've introduced the concept of a view-port (which defaults to the entire screen) into `Panel3D` via a `private void setViewport(int x1, int y1, int x2, int y2)` method, variables `vsx` and `vsy` (which contain half the size of the view-port), and variables `vcx` and `vcy` (which contain the center of the view-port):

``` ```private void setViewport (int x1, int y1, int x2, int y2)
{
height = y2-y1+1;   double vxl = x1;
double vyb = y1;
double vxr = x2;
double vyt = y2;   vcx = (vxl+vxr)/2;
vcy = (vyb+vyt)/2;   vsx = (vxr-vxl)/2;
vsy = (vyt-vyb)/2;
}```
```

Taking these variables into consideration, `xs = (Dxe/Sze)vsx+vcx` and `ys = (Dye/Sze)vsy+vcy` return the appropriate view-port coordinates, which are basically the 3D panel's coordinates. For the equivalent clipping coordinates, these relations are expressed as `xs = (xc/zc)vsx+vcx` and `ys = (yc/zc)vsy+vcy`.

Because `Panel3D`'s `perspective()` method is called to establish the D/S ratio prior to `lineto()` calling `clip()`, the latter clipping coordinates are used by the following `private void showLine(Graphics g, double xc1, double yc1, double zc1, double xc2, double yc2, double zc2)` method to carry out the projection:

``` ```private void showLine (Graphics g, double xc1, double yc1, double zc1,
double xc2, double yc2, double zc2)
{
int xs1 = (int) ((xc1/zc1)*vsx+vcx);
int ys1 = (int) ((yc1/zc1)*vsy+vcy);   int xs2 = (int) ((xc2/zc2)*vsx+vcx);
int ys2 = (int) ((yc2/zc2)*vsy+vcy);   g.drawLine (xs1, height-ys1, xs2, height-ys2);
}```
```

The `showLine()` method subtracts each of the values in the `ys1` and `ys2` variables from the view-port's `height` variable because the values in `ys1` and `ys2` assume a screen where the (0, 0) origin locates in the lower-left corner. In contrast, a Java component places this origin in the upper-left corner.

## Conclusion

Because 3D computer graphics theory can be hard to grasp, I hope this article's `Panel3D` component, `Demo3D` applet, and component-based 3D graphics tutorial have helped to simplify this fascinating topic. In the future, I'll expand the component and the applet to illustrate additional 3D graphics concepts.

For now, however, I have some homework for you: Create additional model files and make them accessible to Demo3D via appropriate buttons. Also, implement a checkbox for hiding/showing the coordinate axes.

Jeff Friesen is a freelance software developer and educator specializing in C, C++, and Java technology.

``` ```