void Winding::Divide(const dplane_t& split, Winding** front, Winding** back) { vec_t dists[MAX_POINTS_ON_WINDING]; int sides[MAX_POINTS_ON_WINDING]; int counts[3]; vec_t dot; int i, j; int maxpts; counts[0] = counts[1] = counts[2] = 0; // determine sides for each point for (i = 0; i < m_NumPoints; i++) { dot = DotProduct(m_Points[i], split.normal); dot -= split.dist; dists[i] = dot; if (dot > ON_EPSILON) { sides[i] = SIDE_FRONT; } else if (dot < -ON_EPSILON) { sides[i] = SIDE_BACK; } else { sides[i] = SIDE_ON; } counts[sides[i]]++; } sides[i] = sides[0]; dists[i] = dists[0]; *front = *back = NULL; if (!counts[0]) { *back = this; // Makes this function non-const return; } if (!counts[1]) { *front = this; // Makes this function non-const return; } maxpts = m_NumPoints + 4; // can't use counts[0]+2 because // of fp grouping errors Winding* f = new Winding(maxpts); Winding* b = new Winding(maxpts); *front = f; *back = b; f->m_NumPoints = 0; b->m_NumPoints = 0; for (i = 0; i < m_NumPoints; i++) { vec_t* p1 = m_Points[i]; if (sides[i] == SIDE_ON) { VectorCopy(p1, f->m_Points[f->m_NumPoints]); VectorCopy(p1, b->m_Points[b->m_NumPoints]); f->m_NumPoints++; b->m_NumPoints++; continue; } else if (sides[i] == SIDE_FRONT) { VectorCopy(p1, f->m_Points[f->m_NumPoints]); f->m_NumPoints++; } else if (sides[i] == SIDE_BACK) { VectorCopy(p1, b->m_Points[b->m_NumPoints]); b->m_NumPoints++; } if (sides[i + 1] == SIDE_ON || sides[i + 1] == sides[i]) { continue; } // generate a split point vec3_t mid; unsigned int tmp = i + 1; if (tmp >= m_NumPoints) { tmp = 0; } vec_t* p2 = m_Points[tmp]; dot = dists[i] / (dists[i] - dists[i + 1]); for (j = 0; j < 3; j++) { // avoid round off error when possible if (split.normal[j] < 1.0 - NORMAL_EPSILON) { if (split.normal[j] > -1.0 + NORMAL_EPSILON) { mid[j] = p1[j] + dot * (p2[j] - p1[j]); } else { mid[j] = -split.dist; } } else { mid[j] = split.dist; } } VectorCopy(mid, f->m_Points[f->m_NumPoints]); VectorCopy(mid, b->m_Points[b->m_NumPoints]); f->m_NumPoints++; b->m_NumPoints++; } if (f->m_NumPoints > maxpts || b->m_NumPoints > maxpts) { Error("Winding::Divide : points exceeded estimate"); } f->RemoveColinearPoints(); b->RemoveColinearPoints(); }
void Winding::Clip(const vec3_t normal, const vec_t dist, Winding** front, Winding** back) { vec_t dists[MAX_POINTS_ON_WINDING + 4]; int sides[MAX_POINTS_ON_WINDING + 4]; int counts[3]; vec_t dot; unsigned int i, j; unsigned int maxpts; counts[0] = counts[1] = counts[2] = 0; // determine sides for each point for (i = 0; i < m_NumPoints; i++) { dot = DotProduct(m_Points[i], normal); dot -= dist; dists[i] = dot; if (dot > ON_EPSILON) { sides[i] = SIDE_FRONT; } else if (dot < -ON_EPSILON) { sides[i] = SIDE_BACK; } else { sides[i] = SIDE_ON; } counts[sides[i]]++; } sides[i] = sides[0]; dists[i] = dists[0]; if (!counts[0]) { *front = NULL; *back = new Winding(*this); return; } if (!counts[1]) { *front = new Winding(*this); *back = NULL; return; } maxpts = m_NumPoints + 4; // can't use counts[0]+2 because // of fp grouping errors Winding* f = new Winding(maxpts); Winding* b = new Winding(maxpts); *front = f; *back = b; f->m_NumPoints = 0; b->m_NumPoints = 0; for (i = 0; i < m_NumPoints; i++) { vec_t* p1 = m_Points[i]; if (sides[i] == SIDE_ON) { VectorCopy(p1, f->m_Points[f->m_NumPoints]); VectorCopy(p1, b->m_Points[b->m_NumPoints]); f->m_NumPoints++; b->m_NumPoints++; continue; } else if (sides[i] == SIDE_FRONT) { VectorCopy(p1, f->m_Points[f->m_NumPoints]); f->m_NumPoints++; } else if (sides[i] == SIDE_BACK) { VectorCopy(p1, b->m_Points[b->m_NumPoints]); b->m_NumPoints++; } if ((sides[i + 1] == SIDE_ON) | (sides[i + 1] == sides[i])) // | instead of || for branch optimization { continue; } // generate a split point vec3_t mid; unsigned int tmp = i + 1; if (tmp >= m_NumPoints) { tmp = 0; } vec_t* p2 = m_Points[tmp]; dot = dists[i] / (dists[i] - dists[i + 1]); #if 0 for (j = 0; j < 3; j++) { // avoid round off error when possible if (normal[j] < 1.0 - NORMAL_EPSILON) { if (normal[j] > -1.0 + NORMAL_EPSILON) { mid[j] = p1[j] + dot * (p2[j] - p1[j]); } else { mid[j] = -dist; } } else { mid[j] = dist; } } #else 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]); } #endif VectorCopy(mid, f->m_Points[f->m_NumPoints]); VectorCopy(mid, b->m_Points[b->m_NumPoints]); f->m_NumPoints++; b->m_NumPoints++; } if ((f->m_NumPoints > maxpts) | (b->m_NumPoints > maxpts)) // | instead of || for branch optimization { Error("Winding::Clip : points exceeded estimate"); } if ((f->m_NumPoints > MAX_POINTS_ON_WINDING) | (b->m_NumPoints > MAX_POINTS_ON_WINDING)) // | instead of || for branch optimization { Error("Winding::Clip : MAX_POINTS_ON_WINDING"); } f->RemoveColinearPoints(); b->RemoveColinearPoints(); }