AABB Triangle::getClippedAABB(const Point *positions, const AABB &aabb) const { /* Reserve room for some additional vertices */ Point3d vertices1[MAX_VERTS], vertices2[MAX_VERTS]; int nVertices = 3; /* The kd-tree code will frequently call this function with almost-collapsed AABBs. It's extremely important not to introduce errors in such cases, otherwise the resulting tree will incorrectly remove triangles from the associated nodes. Hence, do the following computation in double precision! */ for (int i=0; i<3; ++i) vertices1[i] = Point3d(positions[idx[i]]); for (int axis=0; axis<3; ++axis) { nVertices = sutherlandHodgman(vertices1, nVertices, vertices2, axis, aabb.min[axis], true); nVertices = sutherlandHodgman(vertices2, nVertices, vertices1, axis, aabb.max[axis], false); } AABB result; for (int i=0; i<nVertices; ++i) { #if defined(SINGLE_PRECISION) for (int j=0; j<3; ++j) { /* Now this is really paranoid! */ double pos_d = vertices1[i][j]; float pos_f = (float) pos_d; float pos_roundedDown, pos_roundedUp; if (pos_f < pos_d) { /* Float value is too small */ pos_roundedDown = pos_f; pos_roundedUp = nextafterf(pos_f, std::numeric_limits<float>::infinity()); } else if (pos_f > pos_d) { /* Float value is too large */ pos_roundedUp = pos_f; pos_roundedDown = nextafterf(pos_f, -std::numeric_limits<float>::infinity()); } else { /* Double value is exactly representable */ pos_roundedDown = pos_roundedUp = pos_f; } result.min[j] = std::min(result.min[j], pos_roundedDown); result.max[j] = std::max(result.max[j], pos_roundedUp); } #else result.expandBy(vertices1[i]); #endif } result.clip(aabb); return result; }
void AABBTree::findBestPlane(const vector<Triangle>& T, const AABB& V, SplittingPlane& p_est, float& C_est, PlaneSide& pside_est) { C_est = numeric_limits<float>::max(); for(int axis=0; axis<3; axis++) { vector<SplitEvent> events; events.reserve(T.size()*2); for(int i=0; i<T.size(); ++i) { auto ti = T[i]; AABB tibb = V.clip(ti); if(tibb.isPlanar()) { events.push_back(SplitEvent(ti, axis, tibb.minPos(axis), SplitEvent::LyingOnPlane)); } else { events.push_back(SplitEvent(ti, axis, tibb.minPos(axis), SplitEvent::StartingOnPlane)); events.push_back(SplitEvent(ti, axis, tibb.maxPos(axis), SplitEvent::EndingOnPlane)); } } // sort the events sort(events.begin(), events.end()); // test every candidate plane int NL = 0, NP = 0, NR = T.size(); for(int i=0; i<events.size(); ++i) { auto p = events[i].p; int tLyingOnPlane = 0, tEndingOnPlane=0, tStartingOnPlane=0; while( i<events.size() && events[i].p.pe == p.pe && events[i].type == SplitEvent::EndingOnPlane ) { ++tEndingOnPlane; i++; } while( i<events.size() && events[i].p.pe == p.pe && events[i].type == SplitEvent::LyingOnPlane ) { ++tLyingOnPlane; i++; } while( i<events.size() && events[i].p.pe == p.pe && events[i].type == SplitEvent::StartingOnPlane ) { ++tStartingOnPlane; i++; } NP = tLyingOnPlane; NR -= tLyingOnPlane; NR -= tEndingOnPlane; float C; PlaneSide ps; SAH(p, V, NL, NR, NP, C, ps); if(C < C_est) { C_est = C; p_est = p; pside_est = ps; } NL += tStartingOnPlane; NL += tLyingOnPlane; NP = 0; } } }
AABB Shape::getClippedAABB(const AABB &box) const { AABB result = getAABB(); result.clip(box); return result; }