LCOV - code coverage report
Current view: top level - EnergyPlus - SurfaceOctree.hh (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 88 106 83.0 %
Date: 2023-01-17 19:17:23 Functions: 10 15 66.7 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2023, The Board of Trustees of the University of Illinois,
       2             : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3             : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4             : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5             : // contributors. All rights reserved.
       6             : //
       7             : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8             : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9             : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10             : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11             : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12             : //
      13             : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14             : // provided that the following conditions are met:
      15             : //
      16             : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17             : //     conditions and the following disclaimer.
      18             : //
      19             : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20             : //     conditions and the following disclaimer in the documentation and/or other materials
      21             : //     provided with the distribution.
      22             : //
      23             : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24             : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25             : //     used to endorse or promote products derived from this software without specific prior
      26             : //     written permission.
      27             : //
      28             : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29             : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30             : //     reference solely to the software portion of its product, Licensee must refer to the
      31             : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32             : //     obtained under this License and may not use a different name for the software. Except as
      33             : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34             : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35             : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36             : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37             : //
      38             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39             : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40             : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41             : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42             : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43             : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45             : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46             : // POSSIBILITY OF SUCH DAMAGE.
      47             : 
      48             : #ifndef EnergyPlus_SurfaceOctree_hh_INCLUDED
      49             : #define EnergyPlus_SurfaceOctree_hh_INCLUDED
      50             : 
      51             : // EnergyPlus Headers
      52             : #include <EnergyPlus/EPVector.hh>
      53             : #include <EnergyPlus/EnergyPlus.hh>
      54             : 
      55             : // ObjexxFCL Headers
      56             : #include <ObjexxFCL/Array1.fwd.hh>
      57             : #include <ObjexxFCL/Vector3.hh>
      58             : 
      59             : // C++ Headers
      60             : #include <cassert>
      61             : #include <cstdint>
      62             : #include <vector>
      63             : 
      64             : namespace EnergyPlus {
      65             : 
      66             : // Forward
      67             : struct EnergyPlusData;
      68             : 
      69             : namespace DataSurfaces {
      70             :     struct SurfaceData;
      71             : }
      72             : 
      73             : // Package: Surface Octree System
      74             : //
      75             : // Purpose: Spatial sort of surfaces for fast, scalable identification of active surfaces for algorithms
      76             : //  making spatial queries such as solar shading, solar reflection, and daylighting obstruction
      77             : //
      78             : // Author: Stuart Mentzer (Stuart_Mentzer@objexx.com)
      79             : //
      80             : // History:
      81             : //  Sep 2015: Experimental code
      82             : //  Jan 2016: Initial release
      83             : //
      84             : // Notes: See the .cc file
      85             : 
      86           0 : class SurfaceOctreeCube
      87             : {
      88             : 
      89             : public: // Types
      90             :     using Real = Real64;
      91             :     using Surface = DataSurfaces::SurfaceData;
      92             :     using Vertex = ObjexxFCL::Vector3<Real>;
      93             :     using Surfaces = std::vector<Surface *>;
      94             :     using size_type = Surfaces::size_type;
      95             : 
      96             : public: // Creation
      97             :     // Default Constructor
      98         771 :     SurfaceOctreeCube() : d_(0u), n_(0u), l_(Vertex(0.0)), u_(Vertex(0.0)), c_(Vertex(0.0)), w_(0.0), r_(0.0)
      99             :     {
     100        6939 :         for (std::uint8_t i = 0; i < 8; ++i)
     101        6168 :             cubes_[i] = nullptr; // VC++ 2013 compatible initialization
     102         771 :     }
     103             : 
     104             :     // Surfaces Outer Cube Constructor
     105             :     SurfaceOctreeCube(EPVector<Surface> &surfaces) : d_(0u), n_(0u), l_(Vertex(0.0)), u_(Vertex(0.0)), c_(Vertex(0.0)), w_(0.0), r_(0.0)
     106             :     {
     107             :         for (std::uint8_t i = 0; i < 8; ++i)
     108             :             cubes_[i] = nullptr; // VC++ 2013 compatible initialization
     109             :         init(surfaces);
     110             :     }
     111             : 
     112             :     // Box Constructor
     113         480 :     SurfaceOctreeCube(std::uint8_t const d, Vertex const &l, Vertex const &u, Real const w)
     114         480 :         : d_(d), n_(0u), l_(l), u_(u), c_(cen(l, u)), w_(w), r_(0.75 * (w * w))
     115             :     {
     116        4320 :         for (std::uint8_t i = 0; i < 8; ++i)
     117        3840 :             cubes_[i] = nullptr; // VC++ 2013 compatible initialization
     118         480 :         assert(valid());
     119         480 :     }
     120             : 
     121             :     // Destructor
     122        1251 :     ~SurfaceOctreeCube()
     123        1251 :     {
     124        1731 :         for (std::uint8_t i = 0; i < n_; ++i)
     125         480 :             delete cubes_[i];
     126        1251 :     }
     127             : 
     128             : public: // Properties
     129             :     // Depth
     130             :     std::uint8_t d() const
     131             :     {
     132             :         return d_;
     133             :     }
     134             : 
     135             :     // Depth
     136             :     std::uint8_t depth() const
     137             :     {
     138             :         return d_;
     139             :     }
     140             : 
     141             :     // Number of Children
     142             :     std::uint8_t nChildren() const
     143             :     {
     144             :         return n_;
     145             :     }
     146             : 
     147             :     // Number of Sub-Cubes
     148             :     std::uint8_t nSubCube() const
     149             :     {
     150             :         return n_;
     151             :     }
     152             : 
     153             :     // Lower Corner
     154             :     Vertex const &l() const
     155             :     {
     156             :         return l_;
     157             :     }
     158             : 
     159             :     // Upper Corner
     160             :     Vertex const &u() const
     161             :     {
     162             :         return u_;
     163             :     }
     164             : 
     165             :     // Center Point
     166             :     Vertex const &c() const
     167             :     {
     168             :         return c_;
     169             :     }
     170             : 
     171             :     // Center Point
     172             :     Vertex const &center() const
     173             :     {
     174             :         return c_;
     175             :     }
     176             : 
     177             :     // Width
     178             :     Real w() const
     179             :     {
     180             :         return w_;
     181             :     }
     182             : 
     183             :     // Width
     184             :     Real width() const
     185             :     {
     186             :         return w_;
     187             :     }
     188             : 
     189             :     // Surfaces
     190             :     Surfaces const &surfaces() const
     191             :     {
     192             :         return surfaces_;
     193             :     }
     194             : 
     195             :     // Surfaces
     196             :     Surfaces::size_type surfaces_size() const
     197             :     {
     198             :         return surfaces_.size();
     199             :     }
     200             : 
     201             :     // Surfaces Begin Iterator
     202             :     Surfaces::const_iterator surfaces_begin() const
     203             :     {
     204             :         return surfaces_.begin();
     205             :     }
     206             : 
     207             :     // Surfaces Begin Iterator
     208             :     Surfaces::iterator surfaces_begin()
     209             :     {
     210             :         return surfaces_.begin();
     211             :     }
     212             : 
     213             :     // Surfaces End Iterator
     214             :     Surfaces::const_iterator surfaces_end() const
     215             :     {
     216             :         return surfaces_.end();
     217             :     }
     218             : 
     219             :     // Surfaces End Iterator
     220             :     Surfaces::iterator surfaces_end()
     221             :     {
     222             :         return surfaces_.end();
     223             :     }
     224             : 
     225             : public: // Methods
     226             :     // Vertex in Cube?
     227    40428024 :     bool contains(Vertex const &v) const
     228             :     {
     229    40428024 :         return (l_.x <= v.x) && (v.x <= u_.x) && (l_.y <= v.y) && (v.y <= u_.y) && (l_.z <= v.z) && (v.z <= u_.z);
     230             :     }
     231             : 
     232             :     // Surface in Cube?
     233             :     bool contains(Surface const &surface) const;
     234             : 
     235             :     // Line Segment Intersects Enclosing Sphere?
     236             :     bool segmentIntersectsSphere(Vertex const &a, Vertex const &b) const
     237             :     {
     238             :         Vertex const ab(b - a);
     239             :         Real const ab_mag_squared(ab.mag_squared());
     240             :         if (ab_mag_squared == 0.0) { // Segment is a point
     241             :             return ObjexxFCL::distance_squared(a, c_) <= r_;
     242             :         } else { // Might pay to check if a or b in sphere first in some applications
     243             :             Vertex const ac(c_ - a);
     244             :             Real const projection_fac(((ac.x * ab.x) + (ac.y * ab.y) + (ac.z * ab.z)) / ab_mag_squared);
     245             :             if ((0.0 <= projection_fac) && (projection_fac <= 1.0)) { // Projected (closest) point is on ab segment
     246             :                 return ObjexxFCL::distance_squared(ac, projection_fac * ab) <= r_;
     247             :             } else { // Projection (closest) point is outside of ab segment: Intersects iff a or b are in sphere
     248             :                 return (ObjexxFCL::distance_squared(a, c_) <= r_) || (ObjexxFCL::distance_squared(b, c_) <= r_);
     249             :             }
     250             :         }
     251             :     }
     252             : 
     253             :     // Ray Intersects Enclosing Sphere?
     254             :     bool rayIntersectsSphere(Vertex const &a, Vertex const &dir) const
     255             :     {
     256             :         assert(std::abs(dir.mag_squared() - 1.0) < 4 * std::numeric_limits<Real>::epsilon()); // Check unit vector
     257             :         // Might pay to check if a in sphere first in some applications
     258             :         Vertex const ac(c_ - a);
     259             :         Real const projection_fac((ac.x * dir.x) + (ac.y * dir.y) + (ac.z * dir.z));
     260             :         if (0.0 <= projection_fac) { // Projected (closest) point is on ray
     261             :             return ObjexxFCL::distance_squared(ac, projection_fac * dir) <= r_;
     262             :         } else { // Projection (closest) point is outside of ray: Intersects iff a is in sphere
     263             :             return ObjexxFCL::distance_squared(a, c_) <= r_;
     264             :         }
     265             :     }
     266             : 
     267             :     // Line Intersects Enclosing Sphere?
     268             :     bool lineIntersectsSphere(Vertex const &a, Vertex const &dir) const
     269             :     {
     270             :         assert(std::abs(dir.mag_squared() - 1.0) < 4 * std::numeric_limits<Real>::epsilon()); // Check unit vector
     271             :         Vertex const ac(c_ - a);
     272             :         return ac.mag_squared() - ObjexxFCL::square((ac.x * dir.x) + (ac.y * dir.y) + (ac.z * dir.z)) <= r_;
     273             :     }
     274             : 
     275             :     // Line Segment Intersects Cube?
     276     5853602 :     bool segmentIntersectsCube(Vertex const &a, Vertex const &b) const
     277             :     {
     278             :         // Check if either segment endpoint is in cube
     279     5853602 :         if (contains(a) || contains(b)) return true;
     280             : 
     281             :         // Use separating axis theorem (faster variants exist)
     282     8387896 :         Vertex const m(mid(a, b) - c_);                                 // Mid-point relative to cube center
     283     8387896 :         Vertex const mb(b - c_ - m);                                    // ab mid-point to b half segment vector
     284     8387896 :         Vertex const e(std::abs(mb.x), std::abs(mb.y), std::abs(mb.z)); // Extent of half ab segment
     285     4193948 :         Real const h(0.5 * w_);                                         // Half-width
     286             :         // Check if x,y,z axes are separating
     287     4193948 :         if (std::abs(m.x) > h + e.x) return false;
     288     2141194 :         if (std::abs(m.y) > h + e.y) return false;
     289      707352 :         if (std::abs(m.z) > h + e.z) return false;
     290             :         // Check if cross product axes are separating
     291      136029 :         if (std::abs(m.y * mb.z - m.z * mb.y) > h * (e.z + e.y)) return false;
     292      115864 :         if (std::abs(m.x * mb.z - m.z * mb.x) > h * (e.z + e.x)) return false;
     293       88814 :         if (std::abs(m.x * mb.y - m.y * mb.x) > h * (e.y + e.x)) return false;
     294       87565 :         return true;
     295             :     }
     296             : 
     297             :     // Ray Intersects Cube?
     298    30003993 :     bool rayIntersectsCube(Vertex const &a, Vertex const &dir, Vertex const &dir_inv) const
     299             :     {
     300             :         // Note: dir_inv coordinates corresponding to a zero dir coordinate are not used and can be set to zero
     301             : 
     302    30003993 :         assert(std::abs(dir.mag_squared() - 1.0) < 4 * std::numeric_limits<Real>::epsilon()); // Check unit vector
     303    30003993 :         assert((dir.x == 0.0) || (std::abs(dir_inv.x - (1.0 / dir.x)) < 2 * std::numeric_limits<Real>::epsilon() * std::abs(dir_inv.x)));
     304    30003993 :         assert((dir.y == 0.0) || (std::abs(dir_inv.y - (1.0 / dir.y)) < 2 * std::numeric_limits<Real>::epsilon() * std::abs(dir_inv.y)));
     305    30003993 :         assert((dir.z == 0.0) || (std::abs(dir_inv.z - (1.0 / dir.z)) < 2 * std::numeric_limits<Real>::epsilon() * std::abs(dir_inv.z)));
     306             : 
     307             :         // Check if ray origin is in cube
     308    30003993 :         if (contains(a)) return true;
     309             : 
     310             :         // Refined Smits' method: Largest distance to 3 visible cube face planes along ray is the candidate entry point
     311             :         Real tx, ty, tz; // Ray position parameter for intersections with box face planes
     312    23582539 :         if (dir.x > 0.0) {
     313    11038830 :             tx = (l_.x - a.x) * dir_inv.x;
     314    12543709 :         } else if (dir.x < 0.0) {
     315    12542177 :             tx = (u_.x - a.x) * dir_inv.x;
     316             :         } else { // dir.x == 0
     317        1532 :             tx = std::numeric_limits<Real>::lowest();
     318             :         }
     319    23582539 :         if (dir.y > 0.0) {
     320    11826131 :             ty = (l_.y - a.y) * dir_inv.y;
     321    11756408 :         } else if (dir.y < 0.0) {
     322    11756067 :             ty = (u_.y - a.y) * dir_inv.y;
     323             :         } else { // dir.y == 0
     324         341 :             ty = std::numeric_limits<Real>::lowest();
     325             :         }
     326    23582539 :         if (dir.z > 0.0) {
     327    18448594 :             tz = (l_.z - a.z) * dir_inv.z;
     328     5133945 :         } else if (dir.z < 0.0) {
     329     5133945 :             tz = (u_.z - a.z) * dir_inv.z;
     330             :         } else { // dir.z == 0
     331           0 :             tz = std::numeric_limits<Real>::lowest();
     332             :         }
     333             : 
     334    23582539 :         Real const tmax(ObjexxFCL::max(tx, ty, tz));
     335    23582539 :         if (tmax >= 0.0) { // Entry point is on ray: See if it is within cube extent
     336    13730413 :             if (tx == tmax) {
     337     5650489 :                 Real const y(a.y + (tmax * dir.y));
     338     5650489 :                 if ((y < l_.y) || (y > u_.y)) return false;
     339     2199248 :                 Real const z(a.z + (tmax * dir.z));
     340     2199248 :                 if ((z < l_.z) || (z > u_.z)) return false;
     341     8079924 :             } else if (ty == tmax) {
     342     4809117 :                 Real const x(a.x + (tmax * dir.x));
     343     4809117 :                 if ((x < l_.x) || (x > u_.x)) return false;
     344     1643242 :                 Real const z(a.z + (tmax * dir.z));
     345     1643242 :                 if ((z < l_.z) || (z > u_.z)) return false;
     346             :             } else { // tz == tmax
     347     3270807 :                 Real const x(a.x + (tmax * dir.x));
     348     3270807 :                 if ((x < l_.x) || (x > u_.x)) return false;
     349     1197572 :                 Real const y(a.y + (tmax * dir.y));
     350     1197572 :                 if ((y < l_.y) || (y > u_.y)) return false;
     351             :             }
     352     2663352 :             return true;
     353             :         } else { // Entry point is on backwards projection of ray
     354     9852126 :             return false;
     355             :         }
     356             :     }
     357             : 
     358             :     // Ray Intersects Cube?
     359             :     bool rayIntersectsCube(Vertex const &a, Vertex const &dir) const
     360             :     {
     361             :         return rayIntersectsCube(a, dir, safe_inverse(dir)); // Inefficient if called in loop with same dir
     362             :     }
     363             : 
     364             :     // Line Intersects Cube?
     365             :     bool lineIntersectsCube(Vertex const &a, Vertex const &dir, Vertex const &dir_inv) const
     366             :     {
     367             :         // Note: dir_inv coordinates corresponding to a zero dir coordinate are not used and can be set to zero
     368             : 
     369             :         assert(std::abs(dir.mag_squared() - 1.0) < 4 * std::numeric_limits<Real>::epsilon()); // Check unit vector
     370             :         assert((dir.x == 0.0) || (std::abs(dir_inv.x - (1.0 / dir.x)) < 2 * std::numeric_limits<Real>::epsilon() * std::abs(dir_inv.x)));
     371             :         assert((dir.y == 0.0) || (std::abs(dir_inv.y - (1.0 / dir.y)) < 2 * std::numeric_limits<Real>::epsilon() * std::abs(dir_inv.y)));
     372             :         assert((dir.z == 0.0) || (std::abs(dir_inv.z - (1.0 / dir.z)) < 2 * std::numeric_limits<Real>::epsilon() * std::abs(dir_inv.z)));
     373             : 
     374             :         // Smits' method: Largest distance to 3 visible cube faces along ray is the candidate entry point
     375             :         Real txl, txu, tyl, tyu, tzl, tzu; // Ray position parameter for intersections with box face planes
     376             :         if (dir.x > 0.0) {
     377             :             txl = (l_.x - a.x) * dir_inv.x;
     378             :             txu = (u_.x - a.x) * dir_inv.x;
     379             :         } else if (dir.x < 0.0) {
     380             :             txl = (u_.x - a.x) * dir_inv.x;
     381             :             txu = (l_.x - a.x) * dir_inv.x;
     382             :         } else { // dir.x == 0
     383             :             if ((l_.x - a.x <= 0.0) && (u_.x - a.x >= 0.0)) {
     384             :                 txl = std::numeric_limits<Real>::lowest();
     385             :                 txu = std::numeric_limits<Real>::max();
     386             :             } else {
     387             :                 return false;
     388             :             }
     389             :         }
     390             :         if (dir.y > 0.0) {
     391             :             tyl = (l_.y - a.y) * dir_inv.y;
     392             :             tyu = (u_.y - a.y) * dir_inv.y;
     393             :         } else if (dir.y < 0.0) {
     394             :             tyl = (u_.y - a.y) * dir_inv.y;
     395             :             tyu = (l_.y - a.y) * dir_inv.y;
     396             :         } else { // dir.y == 0
     397             :             if ((l_.y - a.y <= 0.0) && (u_.y - a.y >= 0.0)) {
     398             :                 tyl = std::numeric_limits<Real>::lowest();
     399             :                 tyu = std::numeric_limits<Real>::max();
     400             :             } else {
     401             :                 return false;
     402             :             }
     403             :         }
     404             :         if ((txl > tyu) || (tyl > txu)) return false;
     405             :         if (dir.z > 0.0) {
     406             :             tzl = (l_.z - a.z) * dir_inv.z;
     407             :             tzu = (u_.z - a.z) * dir_inv.z;
     408             :         } else if (dir.z < 0.0) {
     409             :             tzl = (u_.z - a.z) * dir_inv.z;
     410             :             tzu = (l_.z - a.z) * dir_inv.z;
     411             :         } else { // dir.z == 0
     412             :             if ((l_.z - a.z <= 0.0) && (u_.z - a.z >= 0.0)) {
     413             :                 tzl = std::numeric_limits<Real>::lowest();
     414             :                 tzu = std::numeric_limits<Real>::max();
     415             :             } else {
     416             :                 return false;
     417             :             }
     418             :         }
     419             :         return ((txl <= tzu) && (tzl <= txu) && (tyl <= tzu) && (tzl <= tyu));
     420             :     }
     421             : 
     422             :     // Line Intersects Cube?
     423             :     bool lineIntersectsCube(Vertex const &a, Vertex const &dir) const
     424             :     {
     425             :         return lineIntersectsCube(a, dir, safe_inverse(dir)); // Inefficient if called in loop with same dir
     426             :     }
     427             : 
     428             :     // Surfaces Outer Cube Initilization
     429             :     void init(EPVector<Surface> &surfaces);
     430             : 
     431             :     // Surfaces that Line Segment Intersects Cube's Enclosing Sphere
     432             :     void surfacesSegmentIntersectsSphere(Vertex const &a, Vertex const &b, Surfaces &surfaces) const
     433             :     {
     434             :         if (segmentIntersectsSphere(a, b)) {
     435             :             if (!surfaces_.empty()) surfaces.insert(surfaces.end(), surfaces_.begin(), surfaces_.end()); // Add this cube's surfaces
     436             :             for (std::uint8_t i = 0; i < n_; ++i) {                                                      // Recurse
     437             :                 cubes_[i]->surfacesSegmentIntersectsSphere(a, b, surfaces);
     438             :             }
     439             :         }
     440             :     }
     441             : 
     442             :     // Surfaces that Ray Intersects Cube's Enclosing Sphere
     443             :     void surfacesRayIntersectsSphere(Vertex const &a, Vertex const &dir, Surfaces &surfaces) const
     444             :     {
     445             :         if (rayIntersectsSphere(a, dir)) {
     446             :             if (!surfaces_.empty()) surfaces.insert(surfaces.end(), surfaces_.begin(), surfaces_.end()); // Add this cube's surfaces
     447             :             for (std::uint8_t i = 0; i < n_; ++i) {                                                      // Recurse
     448             :                 cubes_[i]->surfacesRayIntersectsSphere(a, dir, surfaces);
     449             :             }
     450             :         }
     451             :     }
     452             : 
     453             :     // Surfaces that Line Intersects Cube's Enclosing Sphere
     454             :     void surfacesLineIntersectsSphere(Vertex const &a, Vertex const &dir, Surfaces &surfaces) const
     455             :     {
     456             :         if (lineIntersectsSphere(a, dir)) {
     457             :             if (!surfaces_.empty()) surfaces.insert(surfaces.end(), surfaces_.begin(), surfaces_.end()); // Add this cube's surfaces
     458             :             for (std::uint8_t i = 0; i < n_; ++i) {                                                      // Recurse
     459             :                 cubes_[i]->surfacesLineIntersectsSphere(a, dir, surfaces);
     460             :             }
     461             :         }
     462             :     }
     463             : 
     464             :     // Surfaces that Line Segment Intersects Cube
     465             :     void surfacesSegmentIntersectsCube(Vertex const &a, Vertex const &b, Surfaces &surfaces) const
     466             :     {
     467             :         if (segmentIntersectsCube(a, b)) {
     468             :             if (!surfaces_.empty()) surfaces.insert(surfaces.end(), surfaces_.begin(), surfaces_.end()); // Add this cube's surfaces
     469             :             for (std::uint8_t i = 0; i < n_; ++i) {                                                      // Recurse
     470             :                 cubes_[i]->surfacesSegmentIntersectsCube(a, b, surfaces);
     471             :             }
     472             :         }
     473             :     }
     474             : 
     475             :     // Surfaces that Ray Intersects Cube
     476             :     void surfacesRayIntersectsCube(Vertex const &a, Vertex const &dir, Vertex const &dir_inv, Surfaces &surfaces) const
     477             :     {
     478             :         if (rayIntersectsCube(a, dir, dir_inv)) {
     479             :             if (!surfaces_.empty()) surfaces.insert(surfaces.end(), surfaces_.begin(), surfaces_.end()); // Add this cube's surfaces
     480             :             for (std::uint8_t i = 0; i < n_; ++i) {                                                      // Recurse
     481             :                 cubes_[i]->surfacesRayIntersectsCube(a, dir, dir_inv, surfaces);
     482             :             }
     483             :         }
     484             :     }
     485             : 
     486             :     // Surfaces that Ray Intersects Cube
     487             :     void surfacesRayIntersectsCube(Vertex const &a, Vertex const &dir, Surfaces &surfaces) const
     488             :     {
     489             :         surfacesRayIntersectsCube(a, dir, safe_inverse(dir), surfaces); // Inefficient if called in loop with same dir
     490             :     }
     491             : 
     492             :     // Surfaces that Line Intersects Cube
     493             :     void surfacesLineIntersectsCube(Vertex const &a, Vertex const &dir, Vertex const &dir_inv, Surfaces &surfaces) const
     494             :     {
     495             :         if (lineIntersectsCube(a, dir, dir_inv)) {
     496             :             if (!surfaces_.empty()) surfaces.insert(surfaces.end(), surfaces_.begin(), surfaces_.end()); // Add this cube's surfaces
     497             :             for (std::uint8_t i = 0; i < n_; ++i) {                                                      // Recurse
     498             :                 cubes_[i]->surfacesLineIntersectsCube(a, dir, dir_inv, surfaces);
     499             :             }
     500             :         }
     501             :     }
     502             : 
     503             :     // Surfaces that Line Intersects Cube
     504             :     void surfacesLineIntersectsCube(Vertex const &a, Vertex const &dir, Surfaces &surfaces) const
     505             :     {
     506             :         surfacesLineIntersectsCube(a, dir, safe_inverse(dir), surfaces); // Inefficient if called in loop with same dir
     507             :     }
     508             : 
     509             :     // Seek a Surface in Cube that Line Segment Intersects and Satisfies Predicate
     510     5853602 :     template <typename Predicate> bool hasSurfaceSegmentIntersectsCube(Vertex const &a, Vertex const &b, Predicate const &predicate) const
     511             :     {
     512     5853602 :         if (segmentIntersectsCube(a, b)) {
     513    78482239 :             for (auto const *surface_p : surfaces_) { // Try this cube's surfaces
     514    76735020 :                 if (predicate(*surface_p)) return true;
     515             :             }
     516     7090403 :             for (std::uint8_t i = 0; i < n_; ++i) { // Recurse
     517     5343184 :                 if (cubes_[i]->hasSurfaceSegmentIntersectsCube(a, b, predicate)) return true;
     518             :             }
     519             :         }
     520     5853602 :         return false;
     521             :     }
     522             : 
     523             :     // Seek a Surface in Cube that Ray Intersects and Satisfies Predicate
     524             :     template <typename Predicate>
     525           0 :     bool hasSurfaceRayIntersectsCube(Vertex const &a, Vertex const &dir, Vertex const &dir_inv, Predicate const &predicate) const
     526             :     {
     527           0 :         if (rayIntersectsCube(a, dir, dir_inv)) {
     528           0 :             for (auto const *surface_p : surfaces_) { // Try this cube's surfaces
     529           0 :                 if (predicate(*surface_p)) return true;
     530             :             }
     531           0 :             for (std::uint8_t i = 0; i < n_; ++i) { // Recurse
     532           0 :                 if (cubes_[i]->hasSurfaceRayIntersectsCube(a, dir, dir_inv, predicate)) return true;
     533             :             }
     534             :         }
     535           0 :         return false;
     536             :     }
     537             : 
     538             :     // Seek a Surface in Cube that Ray Intersects and Satisfies Predicate
     539             :     template <typename Predicate> bool hasSurfaceRayIntersectsCube(Vertex const &a, Vertex const &dir, Predicate const &predicate) const
     540             :     {
     541             :         return hasSurfaceRayIntersectsCube(a, dir, safe_inverse(dir), predicate); // Inefficient if called in loop with same dir
     542             :     }
     543             : 
     544             :     // Process Surfaces in Cube that Ray Intersects with Function
     545             :     template <typename Function>
     546           0 :     void processSurfaceRayIntersectsCube(Vertex const &a, Vertex const &dir, Vertex const &dir_inv, Function const &function) const
     547             :     {
     548           0 :         if (rayIntersectsCube(a, dir, dir_inv)) {
     549           0 :             for (auto const *surface_p : surfaces_) { // Process this cube's surfaces
     550           0 :                 function(*surface_p);
     551             :             }
     552           0 :             for (std::uint8_t i = 0; i < n_; ++i) { // Recurse
     553           0 :                 cubes_[i]->processSurfaceRayIntersectsCube(a, dir, dir_inv, function);
     554             :             }
     555             :         }
     556           0 :     }
     557             : 
     558             :     // Process Surfaces in Cube that Ray Intersects with Function
     559             :     template <typename Function> void processSurfaceRayIntersectsCube(Vertex const &a, Vertex const &dir, Function const &function) const
     560             :     {
     561             :         processSurfaceRayIntersectsCube(a, dir, safe_inverse(dir), function); // Inefficient if called in loop with same dir
     562             :     }
     563             : 
     564             :     // Process Surfaces in Cube that Ray Intersects Stopping if Predicate Satisfied
     565             :     template <typename Predicate>
     566    30003993 :     bool processSomeSurfaceRayIntersectsCube(
     567             :         EnergyPlusData &state, Vertex const &a, Vertex const &dir, Vertex const &dir_inv, Predicate const &predicate) const
     568             :     {
     569    30003993 :         if (rayIntersectsCube(a, dir, dir_inv)) {
     570   308788634 :             for (auto const *surface_p : surfaces_) {   // Process this cube's surfaces
     571   299776131 :                 if (predicate(*surface_p)) return true; // Don't need to process more surfaces
     572             :             }
     573    36854542 :             for (std::uint8_t i = 0; i < n_; ++i) { // Recurse
     574    27884295 :                 if (cubes_[i]->processSomeSurfaceRayIntersectsCube(state, a, dir, dir_inv, predicate))
     575       42256 :                     return true; // Don't need to process more surfaces
     576             :             }
     577             :         }
     578    29889434 :         return false;
     579             :     }
     580             : 
     581             :     // Process Surfaces in Cube that Ray Intersects Stopping if Predicate Satisfied
     582             :     template <typename Predicate>
     583             :     bool processSomeSurfaceRayIntersectsCube(EnergyPlusData &state, Vertex const &a, Vertex const &dir, Predicate const &predicate) const
     584             :     {
     585             :         return processSomeSurfaceRayIntersectsCube(state, a, dir, safe_inverse(dir), predicate); // Inefficient if called in loop with same dir
     586             :     }
     587             : 
     588             : public: // Static Methods
     589             :     // Octree-Safe Vector Inverse
     590     2119698 :     static Vertex safe_inverse(Vertex const &v)
     591             :     {
     592     2119698 :         return Vertex((v.x != 0.0 ? 1.0 / v.x : 0.0), (v.y != 0.0 ? 1.0 / v.y : 0.0), (v.z != 0.0 ? 1.0 / v.z : 0.0));
     593             :     }
     594             : 
     595             : private: // Methods
     596             :     // Valid?
     597             :     bool valid() const;
     598             : 
     599             :     // Add a Surface
     600        6197 :     void add(Surface &surface)
     601             :     {
     602        6197 :         surfaces_.push_back(&surface);
     603        6197 :     }
     604             : 
     605             :     // Branch to Sub-Tree
     606             :     void branch();
     607             : 
     608             :     // Surface Branch Processing
     609             :     void surfaceBranch(Surface &surface);
     610             : 
     611             : private: // Static Methods
     612             :     // Vertex in Cube Defined by Lower and Upper Corners?
     613           0 :     static bool contains(Vertex const &l, Vertex const &u, Vertex const &v)
     614             :     {
     615           0 :         return (l.x <= v.x) && (v.x <= u.x) && (l.y <= v.y) && (v.y <= u.y) && (l.z <= v.z) && (v.z <= u.z);
     616             :     }
     617             : 
     618             :     // Surface in Cube Defined by Lower and Upper Corners?
     619             :     static bool contains(Vertex const &l, Vertex const &u, Surface const &surface);
     620             : 
     621             : private:                                 // Static Data
     622             :     static std::uint8_t const maxDepth_; // Max tree depth
     623             :     static size_type const maxSurfaces_; // Max surfaces in a cube before subdividing
     624             : 
     625             : private:                          // Data
     626             :     std::uint8_t d_;              // Depth in tree
     627             :     std::uint8_t n_;              // Number of active sub-cubes ([0,8])
     628             :     Vertex l_;                    // Lower corner
     629             :     Vertex u_;                    // Upper corner
     630             :     Vertex c_;                    // Center point
     631             :     Real w_;                      // Side width
     632             :     Real r_;                      // Enclosing sphere radius
     633             :     SurfaceOctreeCube *cubes_[8]; // Sub-cubes
     634             :     Surfaces surfaces_;           // Surfaces in this cube
     635             : 
     636             : }; // SurfaceOctreeCube
     637             : 
     638             : } // namespace EnergyPlus
     639             : 
     640             : #endif

Generated by: LCOV version 1.13