/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a license // agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// #ifndef OD_SR_CAMERA_CLIPPING_H #define OD_SR_CAMERA_CLIPPING_H #include #include "utils/SrGeometryHelpers.h" #include "utils/SrGeometryHelpers.inl" // Z-clipper class class OdSrZClipper { public: enum ZClipLineResult { kFullyOutside = 0, kFullyInside = 1, kPartial = 2 }; struct ZClipPlanes { double frontDistance; bool frontClippingEnabled = false; double backDistance; bool backClippingEnabled = false; ZClipPlanes() : frontDistance(1.0), backDistance(0.0) {} }; struct ClipVertex { OdGePoint3d pos; double u, v; ClipVertex() {} ClipVertex(const OdGePoint3d& p, double _u, double _v) : pos(p), u(_u), v(_v) {} }; public: static int clipTriangleZ(const ClipVertex inputVerts[3], ClipVertex outputVerts[6], const ZClipPlanes& planes) { if (!planes.frontClippingEnabled && !planes.backClippingEnabled) { outputVerts[0] = inputVerts[0]; outputVerts[1] = inputVerts[1]; outputVerts[2] = inputVerts[2]; return 3; } bool allOutsideFront = true, allOutsideBack = true; for (int i = 0; i < 3; i++) { if (!planes.frontClippingEnabled || inputVerts[i].pos.z <= planes.frontDistance) allOutsideFront = false; if (!planes.backClippingEnabled || inputVerts[i].pos.z >= planes.backDistance) allOutsideBack = false; } if (allOutsideFront || allOutsideBack) return 0; ClipVertex tempVerts[6]; int vertCount = 3; for (int i = 0; i < 3; i++) tempVerts[i] = inputVerts[i]; if (planes.frontClippingEnabled) { vertCount = clipAgainstPlane(tempVerts, vertCount, planes.frontDistance, true); if (vertCount == 0) return 0; } if (planes.backClippingEnabled) { vertCount = clipAgainstPlane(tempVerts, vertCount, planes.backDistance, false); if (vertCount == 0) return 0; } for (int i = 0; i < vertCount; i++) outputVerts[i] = tempVerts[i]; return vertCount; } static int clipAgainstPlane(ClipVertex* verts, int vertCount, double planeZ, bool isFrontPlane) { ClipVertex output[6]; int outCount = 0; for (int i = 0; i < vertCount; i++) { const ClipVertex& v1 = verts[i]; const ClipVertex& v2 = verts[(i + 1) % vertCount]; bool v1Inside = isFrontPlane ? (v1.pos.z <= planeZ) : (v1.pos.z >= planeZ); bool v2Inside = isFrontPlane ? (v2.pos.z <= planeZ) : (v2.pos.z >= planeZ); if (v1Inside && v2Inside) output[outCount++] = v2; else if (v1Inside && !v2Inside) output[outCount++] = interpolateVertex(v1, v2, (planeZ - v1.pos.z) / (v2.pos.z - v1.pos.z)); else if (!v1Inside && v2Inside) { double t = (planeZ - v1.pos.z) / (v2.pos.z - v1.pos.z); output[outCount++] = interpolateVertex(v1, v2, t); output[outCount++] = v2; } } for (int i = 0; i < outCount; i++) verts[i] = output[i]; return outCount; } static ClipVertex interpolateVertex(const ClipVertex& v1, const ClipVertex& v2, double t) { ClipVertex result; result.pos = v1.pos + (v2.pos - v1.pos) * t; result.u = v1.u + (v2.u - v1.u) * t; result.v = v1.v + (v2.v - v1.v) * t; return result; } static inline bool clipPointZ(const OdGePoint3d& point, const ZClipPlanes& planes) { //it's expected that this early check has been already done /*if (!planes.frontClippingEnabled && !planes.backClippingEnabled) return true;*/ double z = point.z; if (planes.frontClippingEnabled && z > planes.frontDistance) return false; if (planes.backClippingEnabled && z < planes.backDistance) return false; return true; } static inline ZClipLineResult clipLineZEye(OdGePoint3d& p1, OdGePoint3d& p2, const ZClipPlanes& planes) { if (!planes.frontClippingEnabled && !planes.backClippingEnabled) return kFullyInside; double z1 = p1.z, z2 = p2.z; double x1 = p1.x, x2 = p2.x; double y1 = p1.y, y2 = p2.y; bool p1_clipped = false, p2_clipped = false; if (planes.frontClippingEnabled && planes.backClippingEnabled && ((z1 > planes.frontDistance && z2 > planes.frontDistance) || (z1 < planes.backDistance && z2 < planes.backDistance))) return kFullyOutside; if (planes.frontClippingEnabled && !planes.backClippingEnabled && z1 > planes.frontDistance && z2 > planes.frontDistance) return kFullyOutside; if (!planes.frontClippingEnabled && planes.backClippingEnabled && z1 < planes.backDistance && z2 < planes.backDistance) return kFullyOutside; if (planes.frontClippingEnabled && z1 > planes.frontDistance && z2 <= planes.frontDistance) { // p1 is outside near, p2 is inside - clip p1 to near plane if (!linterp_add(x1, x2, z1, z2, planes.frontDistance)) return kFullyOutside; if (!linterp_add(y1, y2, z1, z2, planes.frontDistance)) return kFullyOutside; z1 = planes.frontDistance; p1_clipped = true; } if (planes.frontClippingEnabled && z2 > planes.frontDistance && z1 <= planes.frontDistance) { // p2 is outside near, p1 is inside - clip p2 to near plane if (!linterp_add(x2, x1, z2, z1, planes.frontDistance)) return kFullyOutside; if (!linterp_add(y2, y1, z2, z1, planes.frontDistance)) return kFullyOutside; z2 = planes.frontDistance; p2_clipped = true; } if (planes.backClippingEnabled && z1 < planes.backDistance && z2 >= planes.backDistance) { // p1 is outside far, p2 is inside - clip p1 to far plane if (!linterp_add(x1, x2, z1, z2, planes.backDistance)) return kFullyOutside; if (!linterp_add(y1, y2, z1, z2, planes.backDistance)) return kFullyOutside; z1 = planes.backDistance; p1_clipped = true; } if (planes.backClippingEnabled && z2 < planes.backDistance && z1 >= planes.backDistance) { // p2 is outside far, p1 is inside - clip p2 to far plane if (!linterp_add(x2, x1, z2, z1, planes.backDistance)) return kFullyOutside; if (!linterp_add(y2, y1, z2, z1, planes.backDistance)) return kFullyOutside; z2 = planes.backDistance; p2_clipped = true; } p1.set(x1, y1, z1); p2.set(x2, y2, z2); return (p1_clipped || p2_clipped) ? kPartial : kFullyInside; } }; #endif // OD_SR_CAMERA_CLIPPING_H