<Clip>=
public void clip(Hpoint p, String action) {
<Calculate boundary coordinates for p>
<Set outcode using boundary coordinates>
if (action.compareTo("move") {
<Do move stuff>
}
else {
<Do draw stuff>
}
<Copy p>
<Copy boundary conditions>
<Copy outcodes>
}
Here we just compute the boundary coordinates using the definitions given earlier.
<Calculate boundary coordinates for p>= double[] boundaryCoord = new double[6]; boundaryCoord[0] = p.x; boundaryCoord[1] = p.w - p.x; boundaryCoord[2] = p.y; boundaryCoord[3] = p.w - p.y; boundaryCoord[4] = p.z; boundaryCoord[5] = p.w - p.y;
The signs of the boundary coordinates determine the bit codes. Although not real efficient, will store them in a \texttt{boolean} array.
<Set outcode using boundary coordinates>= boolean[] outCode = new boolean[6]; if (boundaryCoord[0] < 0) outCode[0] = true; if (boundaryCoord[1] < 0) outCode[1] = true; if (boundaryCoord[2] < 0) outCode[2] = true; if (boundaryCoord[3] < 0) outCode[3] = true; if (boundaryCoord[4] < 0) outCode[4] = true; if (boundaryCoord[5] < 0) outCode[5] = true;
We won't fill out this chunk of code, basically if the point is visible we just pass it through the pipe.
<Do move stuff>=
if <outCode is all zeros (false)> { // point is visible
<Pass point p down the pipeline as a move to point>
}
The drawing stuff is more interesting. If we can't trivially reject the segment, we'll see if we can trivially accept it, and if not we'll do the non-trivial stuff. Of course, if we can trivially reject we do not need to do anything!
<Do draw stuff>=
if <Not trivial reject> {
if <Trivial accept> {
<Draw line from previous point passed down the pipeline to p>
}
else {
<Do non-trivial stuff>
}
}
We're cheating here (when haven't I lied to you) by writing pseudo-code.
We want to compute the bit-wise AND of the two outcodes.
If the result is all false then we can not trivially reject the segment.
Also, we've not seen it yet but firstOutcode was saved from the
outCode of the first call.
<Not trivial reject>= firstOutCode & outCode;
Still cheating, the trivial accept test the bit-wise OR of two outcodes. If the result is all false then both points are in the clipping volume.
<Trivial accept>= firstOutCode | outCode;
clipCode will tell us which boundary coordinates have opposite signs
(true and false), and hence which boundaries are straddled.
We'll still act as if we can just take bit-wise operations on arrays
of booleans.
What we want to do is compute the last (largest) entering parameter
value and the first (smallest) leaving parameter value.
We'll clip against some number of clip planes so if you don't
want to clip against the near and far plane set the terminating variable
in the \texttt{for} loop to $4$.
<Do non-trivial stuff>=
boolean[] clipCode = firstOutCode | outCode;
double uEnter = 0.0;
double uLeave = 1.0;
for (int i = 0; i < numberOfClipPlanes; i++) {
<Does segment straddle boundary? update parameters if so>
}
if (firstOutcode != false) { // first point was outside
Hpoint q = firstP + u*(p - firstP);
<Pass point q down the pipeline as a move to point>
}
if (outCode != false) { // second point was outside
Hpoint q = firstP + u*(p - firstP);
<Draw line from previous point passed down the pipeline to q>
}
else { // second point was inside
<Draw line from previous point passed down the pipeline to p>
}
Now if a clipCode element is set the corresponding boundary is
straddled. So we'll compute the parameter value u
and update the entering and leaving parameters, if appropriate.
If the first point was outside the boundary we must be entering,
so if we have a larger u than the current entering parameter
save this larger value.
On the other hand, if the first point was inside, the second must
be outside (after all the boundary is straddled). Thus the intersection
must be a leaving one, so we'll update the leaving value if we've
computed a smaller one.
If at any time we discover we've left the clipping volume before
we've entered it we'll simple return.
<Does segment straddle boundary? update parameters if so>=
if (clipCode[i]) {
u = firstBoundryCoord[i]/(firstBoundaryCoord[i] - boundaryCoord[i]);
if ((firstOutcode[i] == true) { // first point outside this boundary
uEnter = max (uEnter, u);
}
else { // first point inside, so second point outside
uLeave = min (uLeave, u);
}
if (uLeave < uEnter) { // segment is invisible
return;
}
Here we just save the values of the point, boundary coordinates, and outcodes between calls to the clipper.
<Copy p>= static Hpoint firstP; firstP = p;
<Copy boundary conditions>= static double[] firstBoundaryCoord; firstBoundaryCoord = boundaryCoord;
<Copy outcodes>= static boolean[] firstOutcode; firstOutcode = outCode;