LCOV - code coverage report
Current view: top level - EnergyPlus - SurfaceOctree.hh (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 39.8 % 259 103
Test Date: 2025-06-02 07:23:51 Functions: 21.7 % 46 10

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, 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              : 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          801 :     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         7209 :         for (std::uint8_t i = 0; i < 8; ++i) {
     101         6408 :             cubes_[i] = nullptr; // VC++ 2013 compatible initialization
     102              :         }
     103          801 :     }
     104              : 
     105              :     // Surfaces Outer Cube Constructor
     106            0 :     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)
     107              :     {
     108            0 :         for (std::uint8_t i = 0; i < 8; ++i) {
     109            0 :             cubes_[i] = nullptr; // VC++ 2013 compatible initialization
     110              :         }
     111            0 :         init(surfaces);
     112            0 :     }
     113              : 
     114              :     // Box Constructor
     115          557 :     SurfaceOctreeCube(std::uint8_t const d, Vertex const &l, Vertex const &u, Real const w)
     116          557 :         : d_(d), n_(0u), l_(l), u_(u), c_(cen(l, u)), w_(w), r_(0.75 * (w * w))
     117              :     {
     118         5013 :         for (std::uint8_t i = 0; i < 8; ++i) {
     119         4456 :             cubes_[i] = nullptr; // VC++ 2013 compatible initialization
     120              :         }
     121          557 :         assert(valid());
     122          557 :     }
     123              : 
     124              :     // Destructor
     125         1358 :     ~SurfaceOctreeCube()
     126              :     {
     127         1915 :         for (std::uint8_t i = 0; i < n_; ++i) {
     128          557 :             delete cubes_[i];
     129              :         }
     130         1358 :     }
     131              : 
     132              : public: // Properties
     133              :     // Depth
     134              :     std::uint8_t d() const
     135              :     {
     136              :         return d_;
     137              :     }
     138              : 
     139              :     // Depth
     140              :     std::uint8_t depth() const
     141              :     {
     142              :         return d_;
     143              :     }
     144              : 
     145              :     // Number of Children
     146              :     std::uint8_t nChildren() const
     147              :     {
     148              :         return n_;
     149              :     }
     150              : 
     151              :     // Number of Sub-Cubes
     152              :     std::uint8_t nSubCube() const
     153              :     {
     154              :         return n_;
     155              :     }
     156              : 
     157              :     // Lower Corner
     158            0 :     Vertex const &l() const
     159              :     {
     160            0 :         return l_;
     161              :     }
     162              : 
     163              :     // Upper Corner
     164            0 :     Vertex const &u() const
     165              :     {
     166            0 :         return u_;
     167              :     }
     168              : 
     169              :     // Center Point
     170            0 :     Vertex const &c() const
     171              :     {
     172            0 :         return c_;
     173              :     }
     174              : 
     175              :     // Center Point
     176              :     Vertex const &center() const
     177              :     {
     178              :         return c_;
     179              :     }
     180              : 
     181              :     // Width
     182            0 :     Real w() const
     183              :     {
     184            0 :         return w_;
     185              :     }
     186              : 
     187              :     // Width
     188              :     Real width() const
     189              :     {
     190              :         return w_;
     191              :     }
     192              : 
     193              :     // Surfaces
     194              :     Surfaces const &surfaces() const
     195              :     {
     196              :         return surfaces_;
     197              :     }
     198              : 
     199              :     // Surfaces
     200              :     Surfaces::size_type surfaces_size() const
     201              :     {
     202              :         return surfaces_.size();
     203              :     }
     204              : 
     205              :     // Surfaces Begin Iterator
     206              :     Surfaces::const_iterator surfaces_begin() const
     207              :     {
     208              :         return surfaces_.begin();
     209              :     }
     210              : 
     211              :     // Surfaces Begin Iterator
     212              :     Surfaces::iterator surfaces_begin()
     213              :     {
     214              :         return surfaces_.begin();
     215              :     }
     216              : 
     217              :     // Surfaces End Iterator
     218              :     Surfaces::const_iterator surfaces_end() const
     219              :     {
     220              :         return surfaces_.end();
     221              :     }
     222              : 
     223              :     // Surfaces End Iterator
     224              :     Surfaces::iterator surfaces_end()
     225              :     {
     226              :         return surfaces_.end();
     227              :     }
     228              : 
     229              : public: // Methods
     230              :     // Vertex in Cube?
     231     42856471 :     bool contains(Vertex const &v) const
     232              :     {
     233     42856471 :         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);
     234              :     }
     235              : 
     236              :     // Surface in Cube?
     237              :     bool contains(Surface const &surface) const;
     238              : 
     239              :     // Line Segment Intersects Enclosing Sphere?
     240            0 :     bool segmentIntersectsSphere(Vertex const &a, Vertex const &b) const
     241              :     {
     242            0 :         Vertex const ab(b - a);
     243            0 :         Real const ab_mag_squared(ab.mag_squared());
     244            0 :         if (ab_mag_squared == 0.0) { // Segment is a point
     245            0 :             return ObjexxFCL::distance_squared(a, c_) <= r_;
     246              :         } else { // Might pay to check if a or b in sphere first in some applications
     247            0 :             Vertex const ac(c_ - a);
     248            0 :             Real const projection_fac(((ac.x * ab.x) + (ac.y * ab.y) + (ac.z * ab.z)) / ab_mag_squared);
     249            0 :             if ((0.0 <= projection_fac) && (projection_fac <= 1.0)) { // Projected (closest) point is on ab segment
     250            0 :                 return ObjexxFCL::distance_squared(ac, projection_fac * ab) <= r_;
     251              :             } else { // Projection (closest) point is outside of ab segment: Intersects iff a or b are in sphere
     252            0 :                 return (ObjexxFCL::distance_squared(a, c_) <= r_) || (ObjexxFCL::distance_squared(b, c_) <= r_);
     253              :             }
     254            0 :         }
     255            0 :     }
     256              : 
     257              :     // Ray Intersects Enclosing Sphere?
     258            0 :     bool rayIntersectsSphere(Vertex const &a, Vertex const &dir) const
     259              :     {
     260            0 :         assert(std::abs(dir.mag_squared() - 1.0) < 4 * std::numeric_limits<Real>::epsilon()); // Check unit vector
     261              :         // Might pay to check if a in sphere first in some applications
     262            0 :         Vertex const ac(c_ - a);
     263            0 :         Real const projection_fac((ac.x * dir.x) + (ac.y * dir.y) + (ac.z * dir.z));
     264            0 :         if (0.0 <= projection_fac) { // Projected (closest) point is on ray
     265            0 :             return ObjexxFCL::distance_squared(ac, projection_fac * dir) <= r_;
     266              :         } else { // Projection (closest) point is outside of ray: Intersects iff a is in sphere
     267            0 :             return ObjexxFCL::distance_squared(a, c_) <= r_;
     268              :         }
     269            0 :     }
     270              : 
     271              :     // Line Intersects Enclosing Sphere?
     272            0 :     bool lineIntersectsSphere(Vertex const &a, Vertex const &dir) const
     273              :     {
     274            0 :         assert(std::abs(dir.mag_squared() - 1.0) < 4 * std::numeric_limits<Real>::epsilon()); // Check unit vector
     275            0 :         Vertex const ac(c_ - a);
     276            0 :         return ac.mag_squared() - ObjexxFCL::square((ac.x * dir.x) + (ac.y * dir.y) + (ac.z * dir.z)) <= r_;
     277            0 :     }
     278              : 
     279              :     // Line Segment Intersects Cube?
     280      6281823 :     bool segmentIntersectsCube(Vertex const &a, Vertex const &b) const
     281              :     {
     282              :         // Check if either segment endpoint is in cube
     283      6281823 :         if (contains(a) || contains(b)) {
     284      1797866 :             return true;
     285              :         }
     286              : 
     287              :         // Use separating axis theorem (faster variants exist)
     288      4483957 :         Vertex const m(mid(a, b) - c_);                                 // Mid-point relative to cube center
     289      4483957 :         Vertex const mb(b - c_ - m);                                    // ab mid-point to b half segment vector
     290      4483957 :         Vertex const e(std::abs(mb.x), std::abs(mb.y), std::abs(mb.z)); // Extent of half ab segment
     291      4483957 :         Real const h(0.5 * w_);                                         // Half-width
     292              :         // Check if x,y,z axes are separating
     293      4483957 :         if (std::abs(m.x) > h + e.x) {
     294      2227916 :             return false;
     295              :         }
     296      2256041 :         if (std::abs(m.y) > h + e.y) {
     297      1517279 :             return false;
     298              :         }
     299       738762 :         if (std::abs(m.z) > h + e.z) {
     300       601122 :             return false;
     301              :         }
     302              :         // Check if cross product axes are separating
     303       137640 :         if (std::abs(m.y * mb.z - m.z * mb.y) > h * (e.z + e.y)) {
     304        20165 :             return false;
     305              :         }
     306       117475 :         if (std::abs(m.x * mb.z - m.z * mb.x) > h * (e.z + e.x)) {
     307        27050 :             return false;
     308              :         }
     309        90425 :         if (std::abs(m.x * mb.y - m.y * mb.x) > h * (e.y + e.x)) {
     310         1790 :             return false;
     311              :         }
     312        88635 :         return true;
     313      4483957 :     }
     314              : 
     315              :     // Ray Intersects Cube?
     316     31691428 :     bool rayIntersectsCube(Vertex const &a, Vertex const &dir, Vertex const &dir_inv) const
     317              :     {
     318              :         // Note: dir_inv coordinates corresponding to a zero dir coordinate are not used and can be set to zero
     319              : 
     320     31691428 :         assert(std::abs(dir.mag_squared() - 1.0) < 4 * std::numeric_limits<Real>::epsilon()); // Check unit vector
     321     31691428 :         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)));
     322     31691428 :         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)));
     323     31691428 :         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)));
     324              : 
     325              :         // Check if ray origin is in cube
     326     31691428 :         if (contains(a)) {
     327      6910290 :             return true;
     328              :         }
     329              : 
     330              :         // Refined Smits' method: Largest distance to 3 visible cube face planes along ray is the candidate entry point
     331              :         Real tx, ty, tz; // Ray position parameter for intersections with box face planes
     332     24781138 :         if (dir.x > 0.0) {
     333     11609518 :             tx = (l_.x - a.x) * dir_inv.x;
     334     13171620 :         } else if (dir.x < 0.0) {
     335     13169919 :             tx = (u_.x - a.x) * dir_inv.x;
     336              :         } else { // dir.x == 0
     337         1701 :             tx = std::numeric_limits<Real>::lowest();
     338              :         }
     339     24781138 :         if (dir.y > 0.0) {
     340     12406152 :             ty = (l_.y - a.y) * dir_inv.y;
     341     12374986 :         } else if (dir.y < 0.0) {
     342     12373774 :             ty = (u_.y - a.y) * dir_inv.y;
     343              :         } else { // dir.y == 0
     344         1212 :             ty = std::numeric_limits<Real>::lowest();
     345              :         }
     346     24781138 :         if (dir.z > 0.0) {
     347     19203853 :             tz = (l_.z - a.z) * dir_inv.z;
     348      5577285 :         } else if (dir.z < 0.0) {
     349      5577285 :             tz = (u_.z - a.z) * dir_inv.z;
     350              :         } else { // dir.z == 0
     351            0 :             tz = std::numeric_limits<Real>::lowest();
     352              :         }
     353              : 
     354     24781138 :         Real const tmax(ObjexxFCL::max(tx, ty, tz));
     355     24781138 :         if (tmax >= 0.0) { // Entry point is on ray: See if it is within cube extent
     356     14439455 :             if (tx == tmax) {
     357      5942153 :                 Real const y(a.y + (tmax * dir.y));
     358      5942153 :                 if ((y < l_.y) || (y > u_.y)) {
     359      3637679 :                     return false;
     360              :                 }
     361      2304474 :                 Real const z(a.z + (tmax * dir.z));
     362      2304474 :                 if ((z < l_.z) || (z > u_.z)) {
     363      1094616 :                     return false;
     364              :                 }
     365      8497302 :             } else if (ty == tmax) {
     366      5050752 :                 Real const x(a.x + (tmax * dir.x));
     367      5050752 :                 if ((x < l_.x) || (x > u_.x)) {
     368      3335165 :                     return false;
     369              :                 }
     370      1715587 :                 Real const z(a.z + (tmax * dir.z));
     371      1715587 :                 if ((z < l_.z) || (z > u_.z)) {
     372       823436 :                     return false;
     373              :                 }
     374              :             } else { // tz == tmax
     375      3446550 :                 Real const x(a.x + (tmax * dir.x));
     376      3446550 :                 if ((x < l_.x) || (x > u_.x)) {
     377      2166424 :                     return false;
     378              :                 }
     379      1280126 :                 Real const y(a.y + (tmax * dir.y));
     380      1280126 :                 if ((y < l_.y) || (y > u_.y)) {
     381       574442 :                     return false;
     382              :                 }
     383              :             }
     384      2807693 :             return true;
     385              :         } else { // Entry point is on backwards projection of ray
     386     10341683 :             return false;
     387              :         }
     388              :     }
     389              : 
     390              :     // Ray Intersects Cube?
     391            0 :     bool rayIntersectsCube(Vertex const &a, Vertex const &dir) const
     392              :     {
     393            0 :         return rayIntersectsCube(a, dir, safe_inverse(dir)); // Inefficient if called in loop with same dir
     394              :     }
     395              : 
     396              :     // Line Intersects Cube?
     397            0 :     bool lineIntersectsCube(Vertex const &a, Vertex const &dir, Vertex const &dir_inv) const
     398              :     {
     399              :         // Note: dir_inv coordinates corresponding to a zero dir coordinate are not used and can be set to zero
     400              : 
     401            0 :         assert(std::abs(dir.mag_squared() - 1.0) < 4 * std::numeric_limits<Real>::epsilon()); // Check unit vector
     402            0 :         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)));
     403            0 :         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)));
     404            0 :         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)));
     405              : 
     406              :         // Smits' method: Largest distance to 3 visible cube faces along ray is the candidate entry point
     407              :         Real txl, txu, tyl, tyu, tzl, tzu; // Ray position parameter for intersections with box face planes
     408            0 :         if (dir.x > 0.0) {
     409            0 :             txl = (l_.x - a.x) * dir_inv.x;
     410            0 :             txu = (u_.x - a.x) * dir_inv.x;
     411            0 :         } else if (dir.x < 0.0) {
     412            0 :             txl = (u_.x - a.x) * dir_inv.x;
     413            0 :             txu = (l_.x - a.x) * dir_inv.x;
     414              :         } else { // dir.x == 0
     415            0 :             if ((l_.x - a.x <= 0.0) && (u_.x - a.x >= 0.0)) {
     416            0 :                 txl = std::numeric_limits<Real>::lowest();
     417            0 :                 txu = std::numeric_limits<Real>::max();
     418              :             } else {
     419            0 :                 return false;
     420              :             }
     421              :         }
     422            0 :         if (dir.y > 0.0) {
     423            0 :             tyl = (l_.y - a.y) * dir_inv.y;
     424            0 :             tyu = (u_.y - a.y) * dir_inv.y;
     425            0 :         } else if (dir.y < 0.0) {
     426            0 :             tyl = (u_.y - a.y) * dir_inv.y;
     427            0 :             tyu = (l_.y - a.y) * dir_inv.y;
     428              :         } else { // dir.y == 0
     429            0 :             if ((l_.y - a.y <= 0.0) && (u_.y - a.y >= 0.0)) {
     430            0 :                 tyl = std::numeric_limits<Real>::lowest();
     431            0 :                 tyu = std::numeric_limits<Real>::max();
     432              :             } else {
     433            0 :                 return false;
     434              :             }
     435              :         }
     436            0 :         if ((txl > tyu) || (tyl > txu)) {
     437            0 :             return false;
     438              :         }
     439            0 :         if (dir.z > 0.0) {
     440            0 :             tzl = (l_.z - a.z) * dir_inv.z;
     441            0 :             tzu = (u_.z - a.z) * dir_inv.z;
     442            0 :         } else if (dir.z < 0.0) {
     443            0 :             tzl = (u_.z - a.z) * dir_inv.z;
     444            0 :             tzu = (l_.z - a.z) * dir_inv.z;
     445              :         } else { // dir.z == 0
     446            0 :             if ((l_.z - a.z <= 0.0) && (u_.z - a.z >= 0.0)) {
     447            0 :                 tzl = std::numeric_limits<Real>::lowest();
     448            0 :                 tzu = std::numeric_limits<Real>::max();
     449              :             } else {
     450            0 :                 return false;
     451              :             }
     452              :         }
     453            0 :         return ((txl <= tzu) && (tzl <= txu) && (tyl <= tzu) && (tzl <= tyu));
     454              :     }
     455              : 
     456              :     // Line Intersects Cube?
     457            0 :     bool lineIntersectsCube(Vertex const &a, Vertex const &dir) const
     458              :     {
     459            0 :         return lineIntersectsCube(a, dir, safe_inverse(dir)); // Inefficient if called in loop with same dir
     460              :     }
     461              : 
     462              :     // Surfaces Outer Cube Initilization
     463              :     void init(EPVector<Surface> &surfaces);
     464              : 
     465              :     // Surfaces that Line Segment Intersects Cube's Enclosing Sphere
     466            0 :     void surfacesSegmentIntersectsSphere(Vertex const &a, Vertex const &b, Surfaces &surfaces) const
     467              :     {
     468            0 :         if (segmentIntersectsSphere(a, b)) {
     469            0 :             if (!surfaces_.empty()) {
     470            0 :                 surfaces.insert(surfaces.end(), surfaces_.begin(), surfaces_.end()); // Add this cube's surfaces
     471              :             }
     472            0 :             for (std::uint8_t i = 0; i < n_; ++i) { // Recurse
     473            0 :                 cubes_[i]->surfacesSegmentIntersectsSphere(a, b, surfaces);
     474              :             }
     475              :         }
     476            0 :     }
     477              : 
     478              :     // Surfaces that Ray Intersects Cube's Enclosing Sphere
     479            0 :     void surfacesRayIntersectsSphere(Vertex const &a, Vertex const &dir, Surfaces &surfaces) const
     480              :     {
     481            0 :         if (rayIntersectsSphere(a, dir)) {
     482            0 :             if (!surfaces_.empty()) {
     483            0 :                 surfaces.insert(surfaces.end(), surfaces_.begin(), surfaces_.end()); // Add this cube's surfaces
     484              :             }
     485            0 :             for (std::uint8_t i = 0; i < n_; ++i) { // Recurse
     486            0 :                 cubes_[i]->surfacesRayIntersectsSphere(a, dir, surfaces);
     487              :             }
     488              :         }
     489            0 :     }
     490              : 
     491              :     // Surfaces that Line Intersects Cube's Enclosing Sphere
     492            0 :     void surfacesLineIntersectsSphere(Vertex const &a, Vertex const &dir, Surfaces &surfaces) const
     493              :     {
     494            0 :         if (lineIntersectsSphere(a, dir)) {
     495            0 :             if (!surfaces_.empty()) {
     496            0 :                 surfaces.insert(surfaces.end(), surfaces_.begin(), surfaces_.end()); // Add this cube's surfaces
     497              :             }
     498            0 :             for (std::uint8_t i = 0; i < n_; ++i) { // Recurse
     499            0 :                 cubes_[i]->surfacesLineIntersectsSphere(a, dir, surfaces);
     500              :             }
     501              :         }
     502            0 :     }
     503              : 
     504              :     // Surfaces that Line Segment Intersects Cube
     505            0 :     void surfacesSegmentIntersectsCube(Vertex const &a, Vertex const &b, Surfaces &surfaces) const
     506              :     {
     507            0 :         if (segmentIntersectsCube(a, b)) {
     508            0 :             if (!surfaces_.empty()) {
     509            0 :                 surfaces.insert(surfaces.end(), surfaces_.begin(), surfaces_.end()); // Add this cube's surfaces
     510              :             }
     511            0 :             for (std::uint8_t i = 0; i < n_; ++i) { // Recurse
     512            0 :                 cubes_[i]->surfacesSegmentIntersectsCube(a, b, surfaces);
     513              :             }
     514              :         }
     515            0 :     }
     516              : 
     517              :     // Surfaces that Ray Intersects Cube
     518            0 :     void surfacesRayIntersectsCube(Vertex const &a, Vertex const &dir, Vertex const &dir_inv, Surfaces &surfaces) const
     519              :     {
     520            0 :         if (rayIntersectsCube(a, dir, dir_inv)) {
     521            0 :             if (!surfaces_.empty()) {
     522            0 :                 surfaces.insert(surfaces.end(), surfaces_.begin(), surfaces_.end()); // Add this cube's surfaces
     523              :             }
     524            0 :             for (std::uint8_t i = 0; i < n_; ++i) { // Recurse
     525            0 :                 cubes_[i]->surfacesRayIntersectsCube(a, dir, dir_inv, surfaces);
     526              :             }
     527              :         }
     528            0 :     }
     529              : 
     530              :     // Surfaces that Ray Intersects Cube
     531            0 :     void surfacesRayIntersectsCube(Vertex const &a, Vertex const &dir, Surfaces &surfaces) const
     532              :     {
     533            0 :         surfacesRayIntersectsCube(a, dir, safe_inverse(dir), surfaces); // Inefficient if called in loop with same dir
     534            0 :     }
     535              : 
     536              :     // Surfaces that Line Intersects Cube
     537            0 :     void surfacesLineIntersectsCube(Vertex const &a, Vertex const &dir, Vertex const &dir_inv, Surfaces &surfaces) const
     538              :     {
     539            0 :         if (lineIntersectsCube(a, dir, dir_inv)) {
     540            0 :             if (!surfaces_.empty()) {
     541            0 :                 surfaces.insert(surfaces.end(), surfaces_.begin(), surfaces_.end()); // Add this cube's surfaces
     542              :             }
     543            0 :             for (std::uint8_t i = 0; i < n_; ++i) { // Recurse
     544            0 :                 cubes_[i]->surfacesLineIntersectsCube(a, dir, dir_inv, surfaces);
     545              :             }
     546              :         }
     547            0 :     }
     548              : 
     549              :     // Surfaces that Line Intersects Cube
     550            0 :     void surfacesLineIntersectsCube(Vertex const &a, Vertex const &dir, Surfaces &surfaces) const
     551              :     {
     552            0 :         surfacesLineIntersectsCube(a, dir, safe_inverse(dir), surfaces); // Inefficient if called in loop with same dir
     553            0 :     }
     554              : 
     555              :     // Seek a Surface in Cube that Line Segment Intersects and Satisfies Predicate
     556      6281823 :     template <typename Predicate> bool hasSurfaceSegmentIntersectsCube(Vertex const &a, Vertex const &b, Predicate const &predicate) const
     557              :     {
     558      6281823 :         if (segmentIntersectsCube(a, b)) {
     559     87286908 :             for (auto const *surface_p : surfaces_) { // Try this cube's surfaces
     560     85400407 :                 if (predicate(*surface_p)) {
     561            0 :                     return true;
     562              :                 }
     563              :             }
     564      7626399 :             for (std::uint8_t i = 0; i < n_; ++i) { // Recurse
     565      5739898 :                 if (cubes_[i]->hasSurfaceSegmentIntersectsCube(a, b, predicate)) {
     566            0 :                     return true;
     567              :                 }
     568              :             }
     569              :         }
     570      6281823 :         return false;
     571              :     }
     572              : 
     573              :     // Seek a Surface in Cube that Ray Intersects and Satisfies Predicate
     574              :     template <typename Predicate>
     575            0 :     bool hasSurfaceRayIntersectsCube(Vertex const &a, Vertex const &dir, Vertex const &dir_inv, Predicate const &predicate) const
     576              :     {
     577            0 :         if (rayIntersectsCube(a, dir, dir_inv)) {
     578            0 :             for (auto const *surface_p : surfaces_) { // Try this cube's surfaces
     579            0 :                 if (predicate(*surface_p)) {
     580            0 :                     return true;
     581              :                 }
     582              :             }
     583            0 :             for (std::uint8_t i = 0; i < n_; ++i) { // Recurse
     584            0 :                 if (cubes_[i]->hasSurfaceRayIntersectsCube(a, dir, dir_inv, predicate)) {
     585            0 :                     return true;
     586              :                 }
     587              :             }
     588              :         }
     589            0 :         return false;
     590              :     }
     591              : 
     592              :     // Seek a Surface in Cube that Ray Intersects and Satisfies Predicate
     593            0 :     template <typename Predicate> bool hasSurfaceRayIntersectsCube(Vertex const &a, Vertex const &dir, Predicate const &predicate) const
     594              :     {
     595            0 :         return hasSurfaceRayIntersectsCube(a, dir, safe_inverse(dir), predicate); // Inefficient if called in loop with same dir
     596              :     }
     597              : 
     598              :     // Process Surfaces in Cube that Ray Intersects with Function
     599              :     template <typename Function>
     600            0 :     void processSurfaceRayIntersectsCube(Vertex const &a, Vertex const &dir, Vertex const &dir_inv, Function const &function) const
     601              :     {
     602            0 :         if (rayIntersectsCube(a, dir, dir_inv)) {
     603            0 :             for (auto const *surface_p : surfaces_) { // Process this cube's surfaces
     604            0 :                 function(*surface_p);
     605              :             }
     606            0 :             for (std::uint8_t i = 0; i < n_; ++i) { // Recurse
     607            0 :                 cubes_[i]->processSurfaceRayIntersectsCube(a, dir, dir_inv, function);
     608              :             }
     609              :         }
     610            0 :     }
     611              : 
     612              :     // Process Surfaces in Cube that Ray Intersects with Function
     613            0 :     template <typename Function> void processSurfaceRayIntersectsCube(Vertex const &a, Vertex const &dir, Function const &function) const
     614              :     {
     615            0 :         processSurfaceRayIntersectsCube(a, dir, safe_inverse(dir), function); // Inefficient if called in loop with same dir
     616            0 :     }
     617              : 
     618              :     // Process Surfaces in Cube that Ray Intersects Stopping if Predicate Satisfied
     619              :     template <typename Predicate>
     620     31691428 :     bool processSomeSurfaceRayIntersectsCube(
     621              :         EnergyPlusData &state, Vertex const &a, Vertex const &dir, Vertex const &dir_inv, Predicate const &predicate) const
     622              :     {
     623     31691428 :         if (rayIntersectsCube(a, dir, dir_inv)) {
     624    346368486 :             for (auto const *surface_p : surfaces_) { // Process this cube's surfaces
     625    336544556 :                 if (predicate(*surface_p)) {
     626       105947 :                     return true; // Don't need to process more surfaces
     627              :                 }
     628              :             }
     629     38964035 :             for (std::uint8_t i = 0; i < n_; ++i) { // Recurse
     630     29436223 :                 if (cubes_[i]->processSomeSurfaceRayIntersectsCube(state, a, dir, dir_inv, predicate)) {
     631        84224 :                     return true; // Don't need to process more surfaces
     632              :                 }
     633              :             }
     634              :         }
     635     31501257 :         return false;
     636              :     }
     637              : 
     638              :     // Process Surfaces in Cube that Ray Intersects Stopping if Predicate Satisfied
     639              :     template <typename Predicate>
     640            0 :     bool processSomeSurfaceRayIntersectsCube(EnergyPlusData &state, Vertex const &a, Vertex const &dir, Predicate const &predicate) const
     641              :     {
     642            0 :         return processSomeSurfaceRayIntersectsCube(state, a, dir, safe_inverse(dir), predicate); // Inefficient if called in loop with same dir
     643              :     }
     644              : 
     645              : public: // Static Methods
     646              :     // Octree-Safe Vector Inverse
     647      2255205 :     static Vertex safe_inverse(Vertex const &v)
     648              :     {
     649      2255205 :         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));
     650              :     }
     651              : 
     652              : private: // Methods
     653              :     // Valid?
     654              :     bool valid() const;
     655              : 
     656              :     // Add a Surface
     657         7908 :     void add(Surface &surface)
     658              :     {
     659         7908 :         surfaces_.push_back(&surface);
     660         7908 :     }
     661              : 
     662              :     // Branch to Sub-Tree
     663              :     void branch();
     664              : 
     665              :     // Surface Branch Processing
     666              :     void surfaceBranch(Surface &surface);
     667              : 
     668              : private: // Static Methods
     669              :     // Vertex in Cube Defined by Lower and Upper Corners?
     670            0 :     static bool contains(Vertex const &l, Vertex const &u, Vertex const &v)
     671              :     {
     672            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);
     673              :     }
     674              : 
     675              :     // Surface in Cube Defined by Lower and Upper Corners?
     676              :     static bool contains(Vertex const &l, Vertex const &u, Surface const &surface);
     677              : 
     678              : private:                                 // Static Data
     679              :     static std::uint8_t const maxDepth_; // Max tree depth
     680              :     static size_type const maxSurfaces_; // Max surfaces in a cube before subdividing
     681              : 
     682              : private:                          // Data
     683              :     std::uint8_t d_;              // Depth in tree
     684              :     std::uint8_t n_;              // Number of active sub-cubes ([0,8])
     685              :     Vertex l_;                    // Lower corner
     686              :     Vertex u_;                    // Upper corner
     687              :     Vertex c_;                    // Center point
     688              :     Real w_;                      // Side width
     689              :     Real r_;                      // Enclosing sphere radius
     690              :     SurfaceOctreeCube *cubes_[8]; // Sub-cubes
     691              :     Surfaces surfaces_;           // Surfaces in this cube
     692              : 
     693              : }; // SurfaceOctreeCube
     694              : 
     695              : } // namespace EnergyPlus
     696              : 
     697              : #endif
        

Generated by: LCOV version 2.0-1