NEMoSys  0.63.0
A modular, extensible resource with robust automated mesh generation, mesh quality analysis, adaptive mesh refinement, and data transfer between arbitrary meshes.
CirclesAndPolys.C
Go to the documentation of this file.
1 /*******************************************************************************
2 * Promesh *
3 * Copyright (C) 2022, IllinoisRocstar LLC. All rights reserved. *
4 * *
5 * Promesh is the property of IllinoisRocstar LLC. *
6 * *
7 * IllinoisRocstar LLC *
8 * Champaign, IL *
9 * www.illinoisrocstar.com *
10 * promesh@illinoisrocstar.com *
11 *******************************************************************************/
12 /*******************************************************************************
13 * This file is part of Promesh *
14 * *
15 * This version of Promesh is free software: you can redistribute it and/or *
16 * modify it under the terms of the GNU Lesser General Public License as *
17 * published by the Free Software Foundation, either version 3 of the License, *
18 * or (at your option) any later version. *
19 * *
20 * Promesh is distributed in the hope that it will be useful, but WITHOUT ANY *
21 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS *
22 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more *
23 * details. *
24 * *
25 * You should have received a copy of the GNU Lesser General Public License *
26 * along with this program. If not, see <https://www.gnu.org/licenses/>. *
27 * *
28 *******************************************************************************/
30 
31 #include <cassert>
32 
33 #include <BRepBuilderAPI_MakeEdge.hxx>
34 #include <BRepBuilderAPI_MakeFace.hxx>
35 #include <BRepBuilderAPI_MakeVertex.hxx>
36 #include <BRepBuilderAPI_MakeWire.hxx>
37 #include <TopoDS_Edge.hxx>
38 #include <TopoDS_Face.hxx>
39 #include <TopoDS_Vertex.hxx>
40 #include <TopoDS_Wire.hxx>
41 #include <gce_MakeCirc.hxx>
42 #include <gce_MakePln.hxx>
43 #include <gp_Circ.hxx>
44 #include <gp_Pnt.hxx>
45 
46 #include "Geometry/GeoManager.H"
48 
49 namespace NEM {
50 namespace NUCMESH {
51 
52 namespace {
53 
54 constexpr double increment(int numSides) { return 360. / numSides; }
55 
56 constexpr double baseRotation(int numSides) {
57  return -1. * (180 - increment(numSides)) / 2.;
58 }
59 
60 std::array<double, 3> getRingPoint(const std::array<double, 3> &center,
61  int numSides, double radius, double rotation,
62  int pointIdx) {
64  center, {radius, (pointIdx * increment(numSides) + rotation +
65  baseRotation(numSides))});
66 }
67 
68 double modRotation(int numSides, double rotation) {
69  return std::fmod(rotation, increment(numSides));
70 }
71 
72 gp_Pnt coords2Point(const std::array<double, 3> &points) {
73  return {points[0], points[1], points[2]};
74 }
75 
76 std::pair<std::vector<TopoDS_Vertex>, std::vector<TopoDS_Edge>>
77 getRingVerticesAndCircEdges(
78  const std::array<double, 3> &center, const int numSides,
79  const double radius, double rotation,
81  std::vector<TopoDS_Vertex> verts;
82  std::vector<TopoDS_Edge> edges;
83  assert(verts.empty() && edges.empty());
84  verts.reserve(numSides);
85  rotation = modRotation(numSides, rotation);
86  for (int i = 0; i < numSides; ++i) {
87  auto coords = getRingPoint(center, numSides, radius, rotation, i);
88  verts.emplace_back(BRepBuilderAPI_MakeVertex{coords2Point(coords)});
89  }
91  gp_Pnt centerPt{center[0], center[1], center[2]};
92  auto circlePoint1 = getRingPoint(center, 2, radius, 0, 0);
93  auto circlePoint2 = getRingPoint(center, 2, radius, 90., 0);
94  gp_Circ circle{
95  gce_MakeCirc{centerPt,
96  gce_MakePln{coords2Point(circlePoint1),
97  coords2Point(circlePoint2), centerPt}
98  .Value(),
99  radius}};
100  for (int i = 0; i < numSides; ++i) {
101  edges.emplace_back(BRepBuilderAPI_MakeEdge{
102  circle, verts[i], verts[i == numSides - 1 ? 0 : i + 1]});
103  }
104  } else {
106  for (int i = 0; i < numSides; ++i) {
107  edges.emplace_back(BRepBuilderAPI_MakeEdge{
108  verts[i], verts[i == numSides - 1 ? 0 : i + 1]});
109  }
110  }
111  return {std::move(verts), std::move(edges)};
112 }
113 
114 std::vector<TopoDS_Edge> getRadialEdges(
115  const std::vector<TopoDS_Vertex> &innerVerts,
116  const std::vector<TopoDS_Vertex> &outerVerts) {
117  assert(innerVerts.size() == outerVerts.size());
118  std::vector<TopoDS_Edge> radialEdges;
119  radialEdges.reserve(innerVerts.size());
120  for (std::size_t i = 0; i < innerVerts.size(); ++i) {
121  radialEdges.emplace_back(
122  BRepBuilderAPI_MakeEdge{innerVerts[i], outerVerts[i]});
123  }
124  return radialEdges;
125 }
126 
127 std::vector<TopoDS_Face> getFaces(const std::vector<TopoDS_Edge> &innerEdges,
128  const std::vector<TopoDS_Edge> &outerEdges,
129  const std::vector<TopoDS_Edge> &radialEdges) {
130  assert(innerEdges.size() == outerEdges.size() &&
131  innerEdges.size() == radialEdges.size());
132  std::vector<TopoDS_Face> faces;
133  faces.reserve(innerEdges.size());
134  for (std::size_t i = 0; i < innerEdges.size(); ++i) {
135  // Does BRepBuilderAPI_MakeWire care about orientation?
136  faces.emplace_back(BRepBuilderAPI_MakeFace{BRepBuilderAPI_MakeWire{
137  outerEdges[i], radialEdges[i == innerEdges.size() - 1 ? 0 : i + 1],
138  innerEdges[i], radialEdges[i]}});
139  }
140  return faces;
141 }
142 
143 } // namespace
144 
145 RingMeshOption::RingMeshOption(const std::array<int, 2> &numElems)
146  : meshingType(MeshingType::STRUCT), numSegments(numElems) {}
147 
149  : meshingType(type), numSegments() {}
150 
151 CirclesAndPolys::CirclesAndPolys(int numSides, std::vector<PolyRing> rings,
152  const std::array<double, 3> &center)
153  : ShapeBase(center), numSides_(numSides), rings_(std::move(rings)) {}
154 
156 
157 void CirclesAndPolys::setNumSides(int numSides) { this->numSides_ = numSides; }
158 
159 const std::vector<PolyRing> &CirclesAndPolys::getRings() const {
160  return rings_;
161 }
162 
163 void CirclesAndPolys::setRings(std::vector<PolyRing> rings) {
164  this->rings_ = std::move(rings);
165 }
166 
168  this->rings_.emplace_back(ring);
169 }
170 
171 template <typename RingT, typename FVertCirc>
172 NEM::GEO::GeoManager drawNested(int numSides, const std::vector<RingT> &rings,
173  const std::array<double, 3> &center,
174  FVertCirc funcVertsCircEdges) {
175  NEM::GEO::GeoManager output{2};
176  if (rings.empty()) { return output; }
177 
178  TopoDS_Vertex centerVert{BRepBuilderAPI_MakeVertex{coords2Point(center)}};
179 
180  std::vector<std::vector<TopoDS_Vertex>> vertices{}; // along the rings
181  vertices.reserve(rings.size());
182  std::vector<std::vector<TopoDS_Edge>> circumferentialEdges{};
183  circumferentialEdges.reserve(rings.size());
184  for (const auto &ring : rings) {
185  auto vertsAndEdges = funcVertsCircEdges(ring);
186  vertices.emplace_back(std::move(vertsAndEdges.first));
187  circumferentialEdges.emplace_back(std::move(vertsAndEdges.second));
188  }
189 
190  std::vector<std::vector<TopoDS_Edge>> radialEdges{};
191  radialEdges.reserve(rings.size());
192  std::vector<std::vector<TopoDS_Face>> faces{};
193  faces.reserve(rings.size());
194  {
195  auto prevVerts = vertices.begin();
196  auto iterVerts = rings.size() >= 2 ? prevVerts + 1 : vertices.end();
197  auto prevCircEdges = circumferentialEdges.begin();
198  auto iterCircEdges =
199  rings.size() >= 2 ? prevCircEdges + 1 : circumferentialEdges.end();
200  {
201  radialEdges.emplace_back();
202  faces.emplace_back();
203  auto &innerEdges = circumferentialEdges[0];
204  BRepBuilderAPI_MakeWire wireBuilder{};
205  for (const auto &edge : innerEdges) { wireBuilder.Add(edge); }
206  faces.back().emplace_back(BRepBuilderAPI_MakeFace{wireBuilder});
207  }
208  for (; iterVerts != vertices.end();
209  ++prevVerts, ++iterVerts, ++prevCircEdges, ++iterCircEdges) {
210  radialEdges.emplace_back(getRadialEdges(*prevVerts, *iterVerts));
211  faces.emplace_back(
212  getFaces(*prevCircEdges, *iterCircEdges, radialEdges.back()));
213  }
214  }
215 
216  {
217  { // innermost ring
218  switch (rings[0].meshType.meshingType) {
221  output.insertConstruct<QuadMeshSurface>(faces[0][0],
222  rings[0].material);
223  break;
225  default:
226  output.insertConstruct<TriMeshSurface>(faces[0][0],
227  rings[0].material);
228  break;
229  }
230  if (!rings[0].sideset.empty()) {
231  auto &ssetName = rings[0].sideset;
232  for (int i = 0; i < numSides; ++i) {
233  output.insertConstruct<SideSetEdge>(circumferentialEdges[0][i],
234  ssetName);
235  }
236  }
237  }
238  auto prevCircEdges = circumferentialEdges.begin();
239  auto iterCircEdges =
240  rings.size() >= 2 ? prevCircEdges + 1 : circumferentialEdges.end();
241  auto iterRadialEdges = radialEdges.begin() + 1;
242  auto iterFaces = faces.begin() + 1;
243  auto prevRing = rings.begin();
244  auto iterRing = rings.size() >= 2 ? prevRing + 1 : rings.end();
245  for (; iterRing != rings.end(); prevCircEdges = iterCircEdges,
246  ++iterCircEdges, ++iterRadialEdges,
247  ++iterFaces, ++iterRing, ++prevRing) {
248  auto &meshingParams = iterRing->meshType;
249  auto meshingType = meshingParams.meshingType;
250  auto &prevMeshingParams = prevRing->meshType;
251  for (int i = 0; i < numSides; ++i) {
252  switch (meshingType) {
255  output.insertConstruct<QuadMeshSurface>(iterFaces->at(i),
256  iterRing->material);
257  break;
259  default:
260  output.insertConstruct<TriMeshSurface>(iterFaces->at(i),
261  iterRing->material);
262  }
263  }
264  if (meshingType == RingMeshOption::MeshingType::STRUCT) {
265  if (prevMeshingParams.meshingType ==
267  prevMeshingParams.numSegments[1] != meshingParams.numSegments[1]) {
268  std::cerr << "Different number of nodes in circumferential direction "
269  "in adjacent rings may cause mesh errors.\n";
270  }
271  for (int i = 0; i < numSides; ++i) {
272  // If previous ring is NOT struct mesh, ensure
273  if (prevMeshingParams.meshingType !=
275  // In case added to map previously, override it
276  output.getMap()[prevCircEdges->at(i)].reset(new EdgeSegments{
277  prevRing->sideset, meshingParams.numSegments[1]});
278  }
279  output.insertConstruct<EdgeSegments>(iterCircEdges->at(i),
280  iterRing->sideset,
281  meshingParams.numSegments[1]);
282  output.insertConstruct<EdgeSegments>(iterRadialEdges->at(i), "",
283  meshingParams.numSegments[0]);
284  }
285  } else {
286  if (!iterRing->sideset.empty()) {
287  auto &ssetName = iterRing->sideset;
288  for (int i = 0; i < numSides; ++i) {
289  output.insertConstruct<SideSetEdge>(iterCircEdges->at(i), ssetName);
290  }
291  }
292  }
293  }
294  }
295  return output;
296 }
297 
299  return drawNested(
300  numSides_, rings_, this->getCenter(), [this](const PolyRing &ring) {
301  return getRingVerticesAndCircEdges(this->getCenter(), this->numSides_,
302  ring.radius, ring.rotation,
303  ring.shapeType);
304  });
305 }
306 
307 Circles::Circles(std::vector<Ring> rings, const std::array<double, 3> &center)
308  : ShapeBase(center), rings_(std::move(rings)) {}
309 
310 const std::vector<Ring> &Circles::getRings() const { return rings_; }
311 
312 void Circles::setRings(std::vector<Ring> rings) {
313  this->rings_ = std::move(rings);
314 }
315 
316 void Circles::addRing(const Ring &ring) { this->rings_.emplace_back(ring); }
317 
319  return drawNested(2, rings_, this->getCenter(), [this](const Ring &ring) {
320  return getRingVerticesAndCircEdges(this->getCenter(), 2, ring.radius, 0);
321  });
322 }
323 
324 } // namespace NUCMESH
325 } // namespace NEM
Class to manage TopoDS_Shapes along with metadata.
Definition: GeoManager.H:61
void addRing(const Ring &ring)
RingMeshOption(MeshingType type)
Class to describe meshing an edge by StdMeshers_NumberOfSegments.
std::vector< Ring > rings_
NEM::GEO::GeoManager createGeo() const override
Construct a NEM::GEO::GeoManager.
NEM::GEO::GeoManager drawNested(int numSides, const std::vector< RingT > &rings, const std::array< double, 3 > &center, FVertCirc funcVertsCircEdges)
void setRings(std::vector< Ring > rings)
STL namespace.
void addRing(const PolyRing &ring)
static constexpr auto shapeType
Definition: NucMeshJson.H:81
void setNumSides(int numSides)
static std::array< double, 3 > getRotatedPoint(const std::array< double, 3 > &center, const std::array< double, 2 > &rotation)
Definition: ShapeBase.C:58
CirclesAndPolys(int numSides, std::vector< PolyRing > rings, const std::array< double, 3 > &center={0, 0, 0})
Container to describe a set of concentric circles/polygons.
std::array< int, 2 > numSegments
const std::array< double, 3 > & getCenter() const
Definition: ShapeBase.C:50
std::vector< PolyRing > rings_
Abstract base class for types that create NEM::GEO::GeoManager.
Definition: ShapeBase.H:52
NEM::GEO::GeoManager createGeo() const override
Construct a NEM::GEO::GeoManager.
std::vector< vtkIdType > points
points given by id in .inp file
Definition: inpGeoMesh.C:133
Apply a tri mesh to a face.
Structured quad mesh (assuming edges meshed appropriately) or quad-dominant mesh. ...
Circles(std::vector< Ring > rings, const std::array< double, 3 > &center={0, 0, 0})
Container to describe a set of concentric circles (note circles treated as two 180 degree arcs) ...
void setRings(std::vector< PolyRing > rings)
const std::vector< Ring > & getRings() const
const std::vector< PolyRing > & getRings() const