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