/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2016, 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 Teigha(R) software pursuant to a license // agreement with Open Design Alliance. // Teigha(R) Copyright (C) 2002-2016 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// // Volumetric spatial index query shape. For perspective mode projections. #ifndef _SpVolume_h_Included_ #define _SpVolume_h_Included_ #include "TD_PackPush.h" #include "Si/SiSpatialIndex.h" #include "Ge/GePlane.h" namespace OdSi { class Volume : public OdSiShape { protected: // Subset of OdGePlane functionality. Optimized allocation, transforms and accessibility. class PlaneImpl { OdGePoint3d m_origin; OdGeVector3d m_normal; double m_dist; public: PlaneImpl() : m_dist(0.0) { } PlaneImpl(const PlaneImpl &pl2) : m_origin(pl2.m_origin), m_normal(pl2.m_normal), m_dist(pl2.m_dist) { } PlaneImpl &operator =(const PlaneImpl &pl2) { m_origin = pl2.m_origin; m_normal = pl2.m_normal; m_dist = pl2.m_dist; return *this; } void set(const OdGePoint3d &origin, const OdGeVector3d &normal) { m_origin = origin; m_normal = normal; m_dist = -m_normal.dotProduct(m_origin.asVector()); } void transformBy(const OdGeMatrix3d &xfm) { m_origin.transformBy(xfm); m_normal.transformBy(xfm); m_normal.normalize(); m_dist = -m_normal.dotProduct(m_origin.asVector()); } void getCoefficients(double& a, double& b, double& c, double& d) const { a = m_normal.x; b = m_normal.y; c = m_normal.z; d = m_dist; } }; OdUInt32 m_nPlanes; //OdGePlane m_plane[6]; PlaneImpl m_plane[6]; bool m_planeValid[6]; public: Volume() : m_nPlanes(0) {} Volume( const Volume& source ) : m_nPlanes(source.m_nPlanes) { for (OdUInt32 npl = 0; npl < m_nPlanes; npl++) { if (source.m_planeValid[npl]) m_plane[npl] = source.m_plane[npl]; m_planeValid[npl] = source.m_planeValid[npl]; } } Volume( const OdGePoint3d& origin, const OdGeVector3d& zAxis, const OdGeVector3d& yAxis, const OdGeVector3d& xAxis, double xFov, double yFov, bool xFovAsAspect = false, bool yFovAsAspect = false, bool bNearPlane = false, double fNearPlane = 0.01, bool bFarPlane = false, double fFarPlane = 1.0 ); // Si interface virtual bool contains( const OdGeExtents3d& extents, bool planar = false, const OdGeTol& tol = OdGeContext::gTol ) const; virtual bool intersects( const OdGeExtents3d& extents, bool planar = false, const OdGeTol& tol = OdGeContext::gTol ) const; virtual OdSiShape* clone() const { return new Volume(*this); } virtual void transform(const OdGeMatrix3d& mtx) { for (OdUInt32 npl = 0; npl < m_nPlanes; npl++) { if (m_planeValid[npl]) m_plane[npl].transformBy(mtx); } } // misc static double fovToPlane(double fov, double len) { return 2.0 * (len * tan(fov * 0.5)); } static double fovFromPlane(double plane, double len) { return atan(plane / len * .5) * 2.0; } protected: static bool planeFromTri(const OdGePoint3d &A, const OdGePoint3d &B, const OdGePoint3d &C, /*OdGePlane*/ PlaneImpl &pl) { OdGeVector3d u = B - A; OdGeVector3d v = C - A; if (!u.isZeroLength(1e-100) && !v.isZeroLength(1e-100)) { u.normalize(1e-100); v.normalize(1e-100); } else { return false; } pl.set(A, u.crossProduct(v).normal()); return true; } static bool aabbInsidePlane(const OdGePoint3d &min, const OdGePoint3d &max, const /*OdGePlane*/ PlaneImpl &plane, const OdGeTol &tol) { double pt[3]; double pl[4]; plane.getCoefficients(pl[0], pl[1], pl[2], pl[3]); pt[0] = (pl[0] > 0.0) ? max.x : min.x; pt[1] = (pl[1] > 0.0) ? max.y : min.y; pt[2] = (pl[2] > 0.0) ? max.z : min.z; return pl[0] * pt[0] + pl[1] * pt[1] + pl[2] * pt[2] + pl[3] >= /*0.0*/ -tol.equalVector(); } }; inline Volume::Volume( const OdGePoint3d& origin, const OdGeVector3d& zAxis, const OdGeVector3d& yAxis, const OdGeVector3d& xAxis, double xFov, double yFov, bool xFovAsAspect, bool yFovAsAspect, bool bNearPlane, double fNearPlane, bool bFarPlane, double fFarPlane ) { // Aspect is width/height, so x is y*aspect, y is x/aspect ODA_ASSERT(!(xFovAsAspect && yFovAsAspect)); double nearPlane_ = odmax(fNearPlane, 1.0); // near plane is required for plane calculation double planeWidth = 1., planeHeight = 1.; if (!xFovAsAspect) planeWidth = fovToPlane(xFov, nearPlane_); if (!yFovAsAspect) planeHeight = fovToPlane(yFov, nearPlane_); if (xFovAsAspect) planeWidth = xFov * planeHeight; if (yFovAsAspect) planeHeight = planeWidth / yFov; OdGeVector3d basisX(xAxis.normal()), basisY(yAxis.normal()), basisZ(zAxis.normal()); //basisX = basisZ.crossProduct(basisY).normal(); // from input, for support isotropy OdGeVector3d deltaX = basisX * (planeWidth * 0.5); OdGeVector3d deltaY = basisY * (planeHeight * 0.5); OdGePoint3d nearPlane = origin + basisZ * nearPlane_; OdGePoint3d planeQuad[4] = { nearPlane - deltaX - deltaY, nearPlane + deltaX - deltaY, nearPlane + deltaX + deltaY, nearPlane - deltaX + deltaY }; m_planeValid[0] = planeFromTri(planeQuad[0], origin, planeQuad[1], m_plane[0]); m_planeValid[1] = planeFromTri(planeQuad[1], origin, planeQuad[2], m_plane[1]); m_planeValid[2] = planeFromTri(planeQuad[2], origin, planeQuad[3], m_plane[2]); m_planeValid[3] = planeFromTri(planeQuad[3], origin, planeQuad[0], m_plane[3]); if (bNearPlane || bFarPlane) { m_planeValid[4] = bNearPlane; if (bNearPlane) m_plane[4].set(origin + basisZ * fNearPlane, basisZ); if (bFarPlane) { m_planeValid[5] = true; m_plane[5].set(origin + basisZ * fFarPlane, -basisZ); m_nPlanes = 6; } else m_nPlanes = 5; } else m_nPlanes = 4; } inline bool Volume::contains( const OdGeExtents3d& extents, bool planar, const OdGeTol& tol ) const { ODA_ASSERT( planar == false ); OdUInt32 i; for (i = 0; i < m_nPlanes; i++) { if (!m_planeValid[i]) continue; if (!aabbInsidePlane(extents.minPoint(), extents.maxPoint(), m_plane[i], tol)) return false; // entirely outside } for (i = 0; i < m_nPlanes; i++) { if (!m_planeValid[i]) continue; if (!aabbInsidePlane(extents.maxPoint(), extents.minPoint(), m_plane[i], tol)) return false; // intersects } return true; // entirely inside } inline bool Volume::intersects( const OdGeExtents3d& extents, bool planar, const OdGeTol& tol ) const { ODA_ASSERT( planar == false ); for (OdUInt32 i = 0; i < m_nPlanes; i++) { if (!m_planeValid[i]) continue; if (!aabbInsidePlane(extents.minPoint(), extents.maxPoint(), m_plane[i], tol)) return false; } return true; } } // OdSi #include "TD_PackPop.h" #endif // _SpVolume_h_Included_