if (dotProduct(N,P(t)-Q) > 0) P(t) OUTSIDE since A < 90 degrees else if (dotProduct(N,P(t)-Q) < 0) P(t) INSIDE since A > 90 degrees else P(t) SHOULD BE ON EDGE E this is because N would be perpendicular to both E and P(t)-QSince we want the intersection of L and E, this last case is the one that we want (dotProduct (N,P(t)-Q) = 0). Unsing the above parametric vector equation for a line --- substituting in P0 + t(P1 - P0) (for the point on L) for P(t). Then we solve for t by using various vector and scalar/vector and dot product rules we get that
A value of 0 for the denominator is bad because we cannot divide by 0, so we consider the possible ways in which the denominator could be 0
if (dotProduct(N,P1-P0) > 0) EXITING - since angle A < 90 degrees else if (dotProduct (N,P1-P0) < 0) ENTERING - since angle A > 90 degreesIf we repeat this for each edge in the polygon -
for each (edge E in polygon)
{ generate t value
test for range 0 to 1
if (in range)
classify as entering or exiting
}
We logically would generate two lists of t's - entering t's and exiting
t's. Note that we have required that the polygon be convex, here is where it is
used again. Since the polygon is CONVEX only two of these values are "real". One
entering and one exiting t will generate the clipped line segment. The
values of t that we want are
t1 = MAX {t | t entering}
t2 = MIN {t | t exiting}
Finding the MAX and the MIN is easy - just keep "current MAX" and "current
MIN" in the above for loop. Thus we only need to have two t values at any
time in the above for loop. If we end with tentering > texiting
then the line L misses the polygon completely.
// Cyrus-Beck 2-D Line Clipping algorithm
// for ease of coding we will treat a 2D point and a 2D vector
// as the same
struct Point2D
{ float x,y;
}
// for simplicity we set an upper bound on the number of
// points allowed to define a polygon - by moving to a class
// with a constructor we could make the array any size we wanted
const int MAXP = 100;
struct Polygon
{ int nPoints;
Point2D v[MAXP];
}
const int MAXN = 100;
typedef Point2D Normal[MAXN];
// compute the outer normals.
// note that this requires that the polygon be convex
// to always work
void CalcNormals (Polygon p, Normal & n)
{ int i,j,k;
point2D v;
for (i = 0; i < p.nPoints; i++)
{ j = (i+1)%p.nPoints;
k = (i+2)%p.nPoints;
// make vector be -1/mI + 1J
n[i].x = -(p.v[j].y - p.v[i].y)/(p.v[j].x - p.v[i].x);
n[i].y = 1.0;
v.x = p.v[k].x - p.v[i].x;
v.y = p.v[k].y - p.v[i].y;
if (DotProduct (n[i],v) > 0) // inner normal
{ n[i].x *= -1;
n[i].y = -1;
}
}
}
float DotProduct (Point2D v1, Point2D v2)
{
return v1.x*v2.x + v1.y*v2*y;
}
void CBClip (Point2D p1, Point2D p2, Normal n, Polygon p, Boolean & visible,
Point2D & rp, Point2D & q)
{ float t1,t2,t,num,den;
Point2D dirV,F; // vectors
int I;
// start largest at smallest legal value and smallest
// at largest legal value
t1 = 0.0;
t2 = 1.0;
// compute the direction vector
dirV.x = p2.x - p1.x;
dirV.y = p2.y - p1.y;
visible = TRUE;
i = 0;
while ( (i < p.nPoints) && visible)
{ F.x = p1.x - p.v[i].x;
F.y = p1.y - p.v[i].y;
num = DotProduct (n[i],F);
den = DotProduct (n[i],dirV);
if (den == 0.0) // Parallel or Point
{ // parallel - if outside then forget the line; if inside then there are no
// intersections with this side
// but there may be with other edges, so in this case just keep going
if (num > 0.0)
visible = FALSE; // Parallel and outside or point (p1 == p2) and outside
}
else
{ t = -(num/den);
if (den < 0.0) // entering
{ if (t <= 1.0)
if (t > t1)
t1 = t;
}
else if ( t >= 0.0) //exiting
if (t < t2)
t2 = t;
}
i++;
}
if ( t1 <= t2)
{ rp.x = p1.x + t1*dirV.x;
rp.y = p1.y + t1*dirV.y;
q.x = p1.x + t2.dirV.x
q.y = p1.y + t2*dirV.y
}
else
visible = FALSE;
}
void LBLineClipping (float &x0, float &y0, float &x1, float &y1, bool &visible)
{ float dx = x1 - x0;
float dy = y1 - y0;
float tE = 0.0, tL = 1.0;
visible = FALSE;
if ( dx == 0 && dy == 0 && ClipPoint(x0,y0))
visible = TRUE;
else
{ if (CLIP (dx,xmin-x0,tE,tL)) // Inside relative to left side
if (CLIP (-dx,x0-xmax,tE,tL)) // Inside relative to right side
if (CLIP (dy,y0-ymax,tE,tL)) // Inside relative to bottom
if (CLIP(-dy,y0-ymin,tE,tL)) // Inside relative to top
{ visible = TRUE;
if (tL < 1.0)
{ x1 = x0 + tL*dx;
y1 = y0 + tL*dy;
}
if (tE > 0.0)
{ x0 += tE*dx;
y0 += tE*dy;
}
}
}
}
bool ClipPoint (float x, float y)
{ // True if the point is inside the clip area ….
// you write this one - xmin <= x <= xmax and
// ymin <= y <= ymax
}
bool CLIP (float denom, float numer, float &tE, float &tL)
{ float t;
if (denom > 0)
{ t = numer/denom;
if (t > tL)
return FALSE;
else if (t > tE)
tE = t;
}
else if (denom < 0)
{ t = numer / denom;
if ( t < tE)
return FALSE;
else
rL = t;
}
else if ( numer > 0)
return FALSE;
return TRUE;
}