📄 l_poly.c
字号:
{
winding_t *in;
vec_t dists[MAX_POINTS_ON_WINDING+4];
int sides[MAX_POINTS_ON_WINDING+4];
int counts[3];
//MrElusive: DOH can't use statics when unsing multithreading!!!
vec_t dot; // VC 4.2 optimizer bug if not static
int i, j;
vec_t *p1, *p2;
vec3_t mid;
winding_t *f;
int maxpts;
in = *inout;
counts[0] = counts[1] = counts[2] = 0;
// determine sides for each point
for (i=0 ; i<in->numpoints ; i++)
{
dot = DotProduct (in->p[i], normal);
dot -= dist;
dists[i] = dot;
if (dot > epsilon)
sides[i] = SIDE_FRONT;
else if (dot < -epsilon)
sides[i] = SIDE_BACK;
else
{
sides[i] = SIDE_ON;
}
counts[sides[i]]++;
}
sides[i] = sides[0];
dists[i] = dists[0];
if (!counts[0])
{
FreeWinding (in);
*inout = NULL;
return;
}
if (!counts[1])
return; // inout stays the same
maxpts = in->numpoints+4; // cant use counts[0]+2 because
// of fp grouping errors
f = AllocWinding (maxpts);
for (i=0 ; i<in->numpoints ; i++)
{
p1 = in->p[i];
if (sides[i] == SIDE_ON)
{
VectorCopy (p1, f->p[f->numpoints]);
f->numpoints++;
continue;
}
if (sides[i] == SIDE_FRONT)
{
VectorCopy (p1, f->p[f->numpoints]);
f->numpoints++;
}
if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
continue;
// generate a split point
p2 = in->p[(i+1)%in->numpoints];
dot = dists[i] / (dists[i]-dists[i+1]);
for (j=0 ; j<3 ; j++)
{ // avoid round off error when possible
if (normal[j] == 1)
mid[j] = dist;
else if (normal[j] == -1)
mid[j] = -dist;
else
mid[j] = p1[j] + dot*(p2[j]-p1[j]);
}
VectorCopy (mid, f->p[f->numpoints]);
f->numpoints++;
}
if (f->numpoints > maxpts)
Error ("ClipWinding: points exceeded estimate");
if (f->numpoints > MAX_POINTS_ON_WINDING)
Error ("ClipWinding: MAX_POINTS_ON_WINDING");
FreeWinding (in);
*inout = f;
}
/*
=================
ChopWinding
Returns the fragment of in that is on the front side
of the cliping plane. The original is freed.
=================
*/
winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist)
{
winding_t *f, *b;
ClipWindingEpsilon (in, normal, dist, ON_EPSILON, &f, &b);
FreeWinding (in);
if (b)
FreeWinding (b);
return f;
}
/*
=================
CheckWinding
=================
*/
void CheckWinding (winding_t *w)
{
int i, j;
vec_t *p1, *p2;
vec_t d, edgedist;
vec3_t dir, edgenormal, facenormal;
vec_t area;
vec_t facedist;
if (w->numpoints < 3)
Error ("CheckWinding: %i points",w->numpoints);
area = WindingArea(w);
if (area < 1)
Error ("CheckWinding: %f area", area);
WindingPlane (w, facenormal, &facedist);
for (i=0 ; i<w->numpoints ; i++)
{
p1 = w->p[i];
for (j=0 ; j<3 ; j++)
if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE)
Error ("CheckWinding: BUGUS_RANGE: %f",p1[j]);
j = i+1 == w->numpoints ? 0 : i+1;
// check the point is on the face plane
d = DotProduct (p1, facenormal) - facedist;
if (d < -ON_EPSILON || d > ON_EPSILON)
Error ("CheckWinding: point off plane");
// check the edge isnt degenerate
p2 = w->p[j];
VectorSubtract (p2, p1, dir);
if (VectorLength (dir) < ON_EPSILON)
Error ("CheckWinding: degenerate edge");
CrossProduct (facenormal, dir, edgenormal);
VectorNormalize (edgenormal);
edgedist = DotProduct (p1, edgenormal);
edgedist += ON_EPSILON;
// all other points must be on front side
for (j=0 ; j<w->numpoints ; j++)
{
if (j == i)
continue;
d = DotProduct (w->p[j], edgenormal);
if (d > edgedist)
Error ("CheckWinding: non-convex");
}
}
}
/*
============
WindingOnPlaneSide
============
*/
int WindingOnPlaneSide (winding_t *w, vec3_t normal, vec_t dist)
{
qboolean front, back;
int i;
vec_t d;
front = false;
back = false;
for (i=0 ; i<w->numpoints ; i++)
{
d = DotProduct (w->p[i], normal) - dist;
if (d < -ON_EPSILON)
{
if (front)
return SIDE_CROSS;
back = true;
continue;
}
if (d > ON_EPSILON)
{
if (back)
return SIDE_CROSS;
front = true;
continue;
}
}
if (back)
return SIDE_BACK;
if (front)
return SIDE_FRONT;
return SIDE_ON;
}
//#ifdef ME
#define CONTINUOUS_EPSILON 0.005
//#else
// #define CONTINUOUS_EPSILON 0.001
//#endif
/*
=============
TryMergeWinding
If two polygons share a common edge and the edges that meet at the
common points are both inside the other polygons, merge them
Returns NULL if the faces couldn't be merged, or the new face.
The originals will NOT be freed.
=============
*/
winding_t *TryMergeWinding (winding_t *f1, winding_t *f2, vec3_t planenormal)
{
vec_t *p1, *p2, *p3, *p4, *back;
winding_t *newf;
int i, j, k, l;
vec3_t normal, delta;
vec_t dot;
qboolean keep1, keep2;
//
// find a common edge
//
p1 = p2 = NULL; // stop compiler warning
j = 0; //
for (i = 0; i < f1->numpoints; i++)
{
p1 = f1->p[i];
p2 = f1->p[(i+1) % f1->numpoints];
for (j = 0; j < f2->numpoints; j++)
{
p3 = f2->p[j];
p4 = f2->p[(j+1) % f2->numpoints];
for (k = 0; k < 3; k++)
{
if (fabs(p1[k] - p4[k]) > 0.1)//EQUAL_EPSILON) //ME
break;
if (fabs(p2[k] - p3[k]) > 0.1)//EQUAL_EPSILON) //ME
break;
} //end for
if (k==3)
break;
} //end for
if (j < f2->numpoints)
break;
} //end for
if (i == f1->numpoints)
return NULL; // no matching edges
//
// check slope of connected lines
// if the slopes are colinear, the point can be removed
//
back = f1->p[(i+f1->numpoints-1)%f1->numpoints];
VectorSubtract (p1, back, delta);
CrossProduct (planenormal, delta, normal);
VectorNormalize (normal);
back = f2->p[(j+2)%f2->numpoints];
VectorSubtract (back, p1, delta);
dot = DotProduct (delta, normal);
if (dot > CONTINUOUS_EPSILON)
return NULL; // not a convex polygon
keep1 = (qboolean)(dot < -CONTINUOUS_EPSILON);
back = f1->p[(i+2)%f1->numpoints];
VectorSubtract (back, p2, delta);
CrossProduct (planenormal, delta, normal);
VectorNormalize (normal);
back = f2->p[(j+f2->numpoints-1)%f2->numpoints];
VectorSubtract (back, p2, delta);
dot = DotProduct (delta, normal);
if (dot > CONTINUOUS_EPSILON)
return NULL; // not a convex polygon
keep2 = (qboolean)(dot < -CONTINUOUS_EPSILON);
//
// build the new polygon
//
newf = AllocWinding (f1->numpoints + f2->numpoints);
// copy first polygon
for (k=(i+1)%f1->numpoints ; k != i ; k=(k+1)%f1->numpoints)
{
if (k==(i+1)%f1->numpoints && !keep2)
continue;
VectorCopy (f1->p[k], newf->p[newf->numpoints]);
newf->numpoints++;
}
// copy second polygon
for (l= (j+1)%f2->numpoints ; l != j ; l=(l+1)%f2->numpoints)
{
if (l==(j+1)%f2->numpoints && !keep1)
continue;
VectorCopy (f2->p[l], newf->p[newf->numpoints]);
newf->numpoints++;
}
return newf;
}
//#ifdef ME
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
winding_t *MergeWindings(winding_t *w1, winding_t *w2, vec3_t planenormal)
{
winding_t *neww;
float dist;
int i, j, n, found, insertafter;
int sides[MAX_POINTS_ON_WINDING+4];
vec3_t newp[MAX_POINTS_ON_WINDING+4];
int numpoints;
vec3_t edgevec, sepnormal, v;
RemoveEqualPoints(w1, 0.2);
numpoints = w1->numpoints;
memcpy(newp, w1->p, w1->numpoints * sizeof(vec3_t));
//
for (i = 0; i < w2->numpoints; i++)
{
VectorCopy(w2->p[i], v);
for (j = 0; j < numpoints; j++)
{
VectorSubtract(newp[(j+1)%numpoints],
newp[(j)%numpoints], edgevec);
CrossProduct(edgevec, planenormal, sepnormal);
VectorNormalize(sepnormal);
if (VectorLength(sepnormal) < 0.9)
{
//remove the point from the new winding
for (n = j; n < numpoints-1; n++)
{
VectorCopy(newp[n+1], newp[n]);
sides[n] = sides[n+1];
} //end for
numpoints--;
j--;
Log_Print("MergeWindings: degenerate edge on winding %f %f %f\n", sepnormal[0],
sepnormal[1],
sepnormal[2]);
continue;
} //end if
dist = DotProduct(newp[(j)%numpoints], sepnormal);
if (DotProduct(v, sepnormal) - dist < -0.1) sides[j] = SIDE_BACK;
else sides[j] = SIDE_FRONT;
} //end for
//remove all unnecesary points
for (j = 0; j < numpoints;)
{
if (sides[j] == SIDE_BACK
&& sides[(j+1)%numpoints] == SIDE_BACK)
{
//remove the point from the new winding
for (n = (j+1)%numpoints; n < numpoints-1; n++)
{
VectorCopy(newp[n+1], newp[n]);
sides[n] = sides[n+1];
} //end for
numpoints--;
} //end if
else
{
j++;
} //end else
} //end for
//
found = false;
for (j = 0; j < numpoints; j++)
{
if (sides[j] == SIDE_FRONT
&& sides[(j+1)%numpoints] == SIDE_BACK)
{
if (found) Log_Print("Warning: MergeWindings: front to back found twice\n");
found = true;
} //end if
} //end for
//
for (j = 0; j < numpoints; j++)
{
if (sides[j] == SIDE_FRONT
&& sides[(j+1)%numpoints] == SIDE_BACK)
{
insertafter = (j+1)%numpoints;
//insert the new point after j+1
for (n = numpoints-1; n > insertafter; n--)
{
VectorCopy(newp[n], newp[n+1]);
} //end for
numpoints++;
VectorCopy(v, newp[(insertafter+1)%numpoints]);
break;
} //end if
} //end for
} //end for
neww = AllocWinding(numpoints);
neww->numpoints = numpoints;
memcpy(neww->p, newp, numpoints * sizeof(vec3_t));
RemoveColinearPoints(neww);
return neww;
} //end of the function MergeWindings
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
char *WindingErrorString(void)
{
return windingerror;
} //end of the function WindingErrorString
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int WindingError(winding_t *w)
{
int i, j;
vec_t *p1, *p2;
vec_t d, edgedist;
vec3_t dir, edgenormal, facenormal;
vec_t area;
vec_t facedist;
if (w->numpoints < 3)
{
sprintf(windingerror, "winding %i points", w->numpoints);
return WE_NOTENOUGHPOINTS;
} //end if
area = WindingArea(w);
if (area < 1)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -