LCOV - code coverage report
Current view: top level - src/csg - CSGRegion.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #31730 (e8b711) with base e0c998 Lines: 86 92 93.5 %
Date: 2025-10-29 16:49:47 Functions: 15 15 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://www.mooseframework.org
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #include "CSGRegion.h"
      11             : 
      12             : namespace CSG
      13             : {
      14             : 
      15         175 : CSGRegion::CSGRegion()
      16             : {
      17          35 :   _region_str = "";
      18          35 :   _region_type = "EMPTY";
      19          35 : }
      20             : 
      21             : // halfspace constructor
      22        1410 : CSGRegion::CSGRegion(const CSGSurface & surf, const CSGSurface::Halfspace halfspace)
      23             : {
      24         282 :   _region_type = "HALFSPACE";
      25         282 :   _region_str = ((halfspace == CSGSurface::Halfspace::POSITIVE) ? "+" : "-") + surf.getName();
      26         282 :   _surfaces.push_back(surf);
      27         282 : }
      28             : 
      29             : // intersection and union constructor
      30         145 : CSGRegion::CSGRegion(const CSGRegion & region_a,
      31             :                      const CSGRegion & region_b,
      32         725 :                      const std::string & region_type)
      33             : {
      34         145 :   _region_type = region_type;
      35         145 :   if (getRegionType() != RegionType::INTERSECTION && getRegionType() != RegionType::UNION)
      36          24 :     mooseError("Region type " + getRegionTypeString() + " is not supported for two regions.");
      37         276 :   if (region_a.getRegionType() == RegionType::EMPTY ||
      38         137 :       region_b.getRegionType() == RegionType::EMPTY)
      39          16 :     mooseError("Region operation " + getRegionTypeString() +
      40             :                " cannot be performed on an empty region.");
      41             : 
      42         135 :   std::string op = (getRegionType() == RegionType::UNION) ? " | " : " & ";
      43         135 :   auto a_string = stripRegionString(region_a.toString(), op);
      44         135 :   auto b_string = stripRegionString(region_b.toString(), op);
      45             : 
      46         135 :   _region_str = "(" + a_string + op + b_string + ")";
      47         135 :   const auto & a_surfs = region_a.getSurfaces();
      48         135 :   const auto & b_surfs = region_b.getSurfaces();
      49         135 :   _surfaces.insert(_surfaces.end(), a_surfs.begin(), a_surfs.end());
      50         135 :   _surfaces.insert(_surfaces.end(), b_surfs.begin(), b_surfs.end());
      51         165 : }
      52             : 
      53             : // complement or explicitly empty constructor
      54          40 : CSGRegion::CSGRegion(const CSGRegion & region, const std::string & region_type)
      55             : {
      56           8 :   _region_type = region_type;
      57           8 :   if (getRegionType() != RegionType::COMPLEMENT && getRegionType() != RegionType::EMPTY)
      58          24 :     mooseError("Region type " + getRegionTypeString() + " is not supported for a single region.");
      59             : 
      60           2 :   if (getRegionType() == RegionType::COMPLEMENT)
      61             :   {
      62             :     // no change to surfaces, but update string
      63           2 :     _region_str = "~" + region.toString();
      64           2 :     _surfaces = region.getSurfaces();
      65             :   }
      66           0 :   else if (getRegionType() == RegionType::EMPTY)
      67             :   {
      68             :     // reset the region and make it empty
      69           0 :     _region_str = "";
      70           0 :     _surfaces.clear();
      71             :   }
      72          20 : }
      73             : 
      74             : CSGRegion &
      75         113 : CSGRegion::operator&=(const CSGRegion & other_region)
      76             : {
      77         113 :   if (this != &other_region)
      78         226 :     *this = CSGRegion(*this, other_region, "INTERSECTION");
      79         113 :   return *this;
      80             : }
      81             : 
      82             : CSGRegion &
      83           2 : CSGRegion::operator|=(const CSGRegion & other_region)
      84             : {
      85           2 :   if (this != &other_region)
      86           4 :     *this = CSGRegion(*this, other_region, "UNION");
      87           2 :   return *this;
      88             : }
      89             : 
      90             : const std::string
      91         280 : stripRegionString(std::string region_str, std::string op)
      92             : {
      93             :   // add expected spacing around operator if not provided
      94         280 :   if (op == "|")
      95           2 :     op = " | ";
      96         280 :   if (op == "&")
      97           2 :     op = " & ";
      98             : 
      99         560 :   std::vector<std::string> ops_list = {" | ", " & ", "~"};
     100         280 :   if (op.compare(" | ") && op.compare(" & "))
     101             :   { // compare() returns non zero if strings are not equal
     102           0 :     mooseError(
     103             :         "Region string can only be simplified based on intersection (&) and union (|) operations.");
     104             :   }
     105             : 
     106             :   // find if there are any operators in string already that are not the op of interest
     107             :   // if not, then remove parentheses:
     108         280 :   bool remove_par = true; // assume parentheses can be removed unless otherwise
     109        1114 :   for (auto opi : ops_list)
     110         836 :     if (opi != op)
     111             :       // only look for strings that are not of the current op type
     112         558 :       if (region_str.find(opi) != std::string::npos)
     113             :       {
     114           2 :         remove_par = false;
     115           2 :         break;
     116         836 :       }
     117             : 
     118         280 :   if (remove_par)
     119         278 :     region_str.erase(std::remove_if(region_str.begin(),
     120             :                                     region_str.end(),
     121        9949 :                                     [](char c) { return c == '(' || c == ')'; }),
     122         556 :                      region_str.end());
     123         560 :   return region_str;
     124         280 : }
     125             : 
     126             : // Operators for region construction
     127             : 
     128             : // positive halfspace
     129             : const CSGRegion
     130         153 : operator+(const CSGSurface & surf)
     131             : {
     132         153 :   return CSGRegion(surf, CSGSurface::Halfspace::POSITIVE);
     133             : }
     134             : 
     135             : // negative halfspace
     136             : const CSGRegion
     137         129 : operator-(const CSGSurface & surf)
     138             : {
     139         129 :   return CSGRegion(surf, CSGSurface::Halfspace::NEGATIVE);
     140             : }
     141             : 
     142             : // intersection
     143             : const CSGRegion
     144           4 : operator&(const CSGRegion & region_a, const CSGRegion & region_b)
     145             : {
     146           8 :   return CSGRegion(region_a, region_b, "INTERSECTION");
     147             : }
     148             : 
     149             : // union
     150             : const CSGRegion
     151          20 : operator|(const CSGRegion & region_a, const CSGRegion & region_b)
     152             : {
     153          40 :   return CSGRegion(region_a, region_b, "UNION");
     154             : }
     155             : 
     156             : // complement
     157             : const CSGRegion
     158           2 : operator~(const CSGRegion & region)
     159             : {
     160           4 :   return CSGRegion(region, "COMPLEMENT");
     161             : }
     162             : 
     163             : bool
     164         136 : CSGRegion::operator==(const CSGRegion & other) const
     165             : {
     166         136 :   const bool region_type_eq = this->getRegionType() == other.getRegionType();
     167         136 :   const bool region_str_eq = this->toString() == other.toString();
     168         136 :   if (region_type_eq && region_str_eq)
     169             :   {
     170          84 :     const auto & all_surfs = getSurfaces();
     171          84 :     const auto & other_surfs = other.getSurfaces();
     172          84 :     const bool num_cells_eq = all_surfs.size() == other_surfs.size();
     173          84 :     if (num_cells_eq)
     174             :     {
     175         168 :       for (const auto i : index_range(all_surfs))
     176          84 :         if (all_surfs[i].get() != other_surfs[i].get())
     177           0 :           return false;
     178          84 :       return true;
     179             :     }
     180             :     else
     181           0 :       return false;
     182             :   }
     183             :   else
     184          52 :     return false;
     185             : }
     186             : 
     187             : bool
     188           4 : CSGRegion::operator!=(const CSGRegion & other) const
     189             : {
     190           4 :   return !(*this == other);
     191             : }
     192             : 
     193             : } // namespace CSG

Generated by: LCOV version 1.14