Skip to content

Commit a6eeabb

Browse files
committed
Adds compress lines
1 parent a8a2c92 commit a6eeabb

6 files changed

Lines changed: 337 additions & 10 deletions

File tree

src/app/launcher.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,12 +123,27 @@ bool readStaircaseMesherCompressOption(const std::string &fn)
123123
}
124124
return false;
125125
}
126+
127+
bool readStaircaseMesherCompressLinesOption(const std::string &fn)
128+
{
129+
nlohmann::json j;
130+
{
131+
std::ifstream i(fn);
132+
i >> j;
133+
}
134+
if (j["mesher"].contains("options") &&
135+
j["mesher"]["options"].contains("compressLines")) {
136+
return j["mesher"]["options"]["compressLines"];
137+
}
138+
return false;
139+
}
126140
std::unique_ptr<meshlib::meshers::MesherBase> buildMesher(const Mesh &in, const std::string &fn)
127141
{
128142
auto mesherType = readMesherType(fn);
129143
if (mesherType == meshlib::app::staircase_mesher) {
130144
bool compress = readStaircaseMesherCompressOption(fn);
131-
return std::make_unique<meshlib::meshers::StaircaseMesher>(meshlib::meshers::StaircaseMesher{in, 4, compress});
145+
bool compressLines = readStaircaseMesherCompressLinesOption(fn);
146+
return std::make_unique<meshlib::meshers::StaircaseMesher>(meshlib::meshers::StaircaseMesher{in, 4, compress, compressLines});
132147
} else if (mesherType == meshlib::app::conformal_mesher) {
133148
return std::make_unique<meshlib::meshers::ConformalMesher>(meshlib::meshers::ConformalMesher{in, readConformalMesherOptions(fn)});
134149
} else {

src/core/Splitter.cpp

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,153 @@ std::size_t Splitter::splitSurfaces(Mesh& mesh) {
4444
return totalNewQuads;
4545
}
4646

47+
std::size_t Splitter::splitLines(Mesh& mesh) {
48+
std::size_t totalNewLines = 0;
49+
50+
for (GroupId g = 0; g < mesh.groups.size(); g++) {
51+
std::vector<Element> newElements;
52+
53+
for (ElementId e = 0; e < mesh.groups[g].elements.size(); e++) {
54+
const Element& elem = mesh.groups[g].elements[e];
55+
if (elem.type == Element::Type::Line) {
56+
// Split this line into unit grid lines
57+
std::map<Coordinate, CoordinateId> coordMap;
58+
59+
// Build initial coord map from existing coordinates
60+
for (CoordinateId i = 0; i < static_cast<CoordinateId>(mesh.coordinates.size()); ++i) {
61+
coordMap[mesh.coordinates[i]] = i;
62+
}
63+
64+
std::vector<Element> splitLines = splitLine_(
65+
elem, mesh.coordinates, mesh.grid, coordMap);
66+
67+
// Add new coordinates from coordMap
68+
for (const auto& [coord, id] : coordMap) {
69+
if (id >= mesh.coordinates.size()) {
70+
mesh.coordinates.push_back(coord);
71+
}
72+
}
73+
74+
newElements.insert(newElements.end(), splitLines.begin(), splitLines.end());
75+
totalNewLines += splitLines.size();
76+
} else {
77+
newElements.push_back(elem);
78+
}
79+
}
80+
81+
mesh.groups[g].elements = std::move(newElements);
82+
}
83+
84+
return totalNewLines;
85+
}
86+
87+
std::vector<Element> Splitter::splitLine_(
88+
const Element& line,
89+
const std::vector<Coordinate>& coords,
90+
const Grid& grid,
91+
std::map<Coordinate, CoordinateId>& coordMap) {
92+
std::vector<Element> unitLines;
93+
94+
// Get the axis direction of the line
95+
Axis lineAxis = getLineAxis_(line, coords);
96+
97+
// Get the grid cell bounds
98+
auto [minCell, maxCell] = getLineBounds_(line, coords);
99+
100+
// Determine the fixed coordinate axes (the two axes perpendicular to lineAxis)
101+
Axis axis1 = (lineAxis + 1) % 3;
102+
Axis axis2 = (lineAxis + 2) % 3;
103+
104+
// Get the fixed coordinate values from minCell
105+
CellDir fixedCoord1 = minCell(axis1);
106+
CellDir fixedCoord2 = minCell(axis2);
107+
108+
// Generate unit lines for each cell along the line axis
109+
for (CellDir i = minCell(lineAxis); i < maxCell(lineAxis); i++) {
110+
Element unitLine = createUnitLine_(
111+
fixedCoord1, fixedCoord2, lineAxis, i, grid, coordMap);
112+
unitLines.push_back(unitLine);
113+
}
114+
115+
return unitLines;
116+
}
117+
118+
std::pair<Cell, Cell> Splitter::getLineBounds_(
119+
const Element& line,
120+
const std::vector<Coordinate>& coords) {
121+
Cell minCell = utils::GridTools::toCell(coords[line.vertices[0]]);
122+
Cell maxCell = utils::GridTools::toCell(coords[line.vertices[1]]);
123+
124+
// Ensure minCell <= maxCell for all axes
125+
for (Axis d = 0; d < 3; d++) {
126+
if (minCell(d) > maxCell(d)) {
127+
std::swap(minCell(d), maxCell(d));
128+
}
129+
}
130+
131+
return {minCell, maxCell};
132+
}
133+
134+
Axis Splitter::getLineAxis_(
135+
const Element& line,
136+
const std::vector<Coordinate>& coords) {
137+
// Find which axis has different coordinate values (the line direction)
138+
Cell cell0 = utils::GridTools::toCell(coords[line.vertices[0]]);
139+
Cell cell1 = utils::GridTools::toCell(coords[line.vertices[1]]);
140+
141+
for (Axis d = 0; d < 3; d++) {
142+
if (cell0(d) != cell1(d)) {
143+
return d;
144+
}
145+
}
146+
147+
// Fallback (should not happen for valid lines)
148+
return 0;
149+
}
150+
151+
Element Splitter::createUnitLine_(
152+
CellDir fixedCoord1,
153+
CellDir fixedCoord2,
154+
Axis lineAxis,
155+
CellDir cell,
156+
const Grid& grid,
157+
std::map<Coordinate, CoordinateId>& coordMap) {
158+
Axis axis1 = (lineAxis + 1) % 3;
159+
Axis axis2 = (lineAxis + 2) % 3;
160+
161+
// Create 2 coordinates for the unit line
162+
std::array<Coordinate, 2> endpoints;
163+
endpoints[0] = Coordinate({0, 0, 0});
164+
endpoints[1] = Coordinate({0, 0, 0});
165+
166+
// Set coordinates for each endpoint
167+
endpoints[0](lineAxis) = grid[lineAxis][cell];
168+
endpoints[0](axis1) = grid[axis1][fixedCoord1];
169+
endpoints[0](axis2) = grid[axis2][fixedCoord2];
170+
171+
endpoints[1](lineAxis) = grid[lineAxis][cell + 1];
172+
endpoints[1](axis1) = grid[axis1][fixedCoord1];
173+
endpoints[1](axis2) = grid[axis2][fixedCoord2];
174+
175+
// Get or create coordinate IDs
176+
std::array<CoordinateId, 2> vids;
177+
for (int i = 0; i < 2; i++) {
178+
auto it = coordMap.find(endpoints[i]);
179+
if (it != coordMap.end()) {
180+
vids[i] = it->second;
181+
} else {
182+
coordMap[endpoints[i]] = static_cast<CoordinateId>(coordMap.size());
183+
vids[i] = coordMap[endpoints[i]];
184+
}
185+
}
186+
187+
Element unitLine;
188+
unitLine.type = Element::Type::Line;
189+
unitLine.vertices = {vids[0], vids[1]};
190+
191+
return unitLine;
192+
}
193+
47194
std::vector<Element> Splitter::splitSurface_(
48195
const Element& surface,
49196
const std::vector<Coordinate>& coords,

src/meshers/StaircaseMesher.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@ using namespace utils;
1818
using namespace core;
1919
using namespace meshTools;
2020

21-
StaircaseMesher::StaircaseMesher(const Mesh& inputMesh, int decimalPlacesInCollapser, bool compress) :
21+
StaircaseMesher::StaircaseMesher(const Mesh& inputMesh, int decimalPlacesInCollapser, bool compress, bool compressLines) :
2222
MesherBase(inputMesh),
2323
decimalPlacesInCollapser_(decimalPlacesInCollapser),
24-
compress_(compress)
24+
compress_(compress),
25+
compressLines_(compressLines)
2526
{
2627
log("Preparing surfaces.");
2728
surfaceMesh_ = buildMeshFilteringElements(inputMesh, isNotTetrahedron);
@@ -84,6 +85,16 @@ void StaircaseMesher::process(Mesh& mesh) const
8485
" quads (merged " + std::to_string(merged) + " surfaces)", 1);
8586
}
8687

88+
if (compressLines_) {
89+
log("Compressing lines.", 1);
90+
std::size_t beforeLines = countMeshElementsIf(mesh, isLine);
91+
std::size_t merged = Compressor::compressLines(mesh);
92+
std::size_t afterLines = countMeshElementsIf(mesh, isLine);
93+
log("Compressed " + std::to_string(beforeLines) +
94+
" -> " + std::to_string(afterLines) +
95+
" lines (merged " + std::to_string(merged) + " segments)", 1);
96+
}
97+
8798
log("Recovering original grid size.", 1);
8899
reduceGrid(mesh, originalGrid_);
89100

src/meshers/StaircaseMesher.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@ namespace meshlib::meshers {
77

88
class StaircaseMesher : public MesherBase {
99
public:
10-
StaircaseMesher(const Mesh& in, int decimalPlacesInCollapser = 4, bool compress = false);
10+
StaircaseMesher(const Mesh& in, int decimalPlacesInCollapser = 4, bool compress = false, bool compressLines = false);
1111
virtual ~StaircaseMesher() = default;
1212
Mesh mesh() const;
1313

1414
private:
1515
int decimalPlacesInCollapser_;
1616
bool compress_;
17+
bool compressLines_;
1718

1819
Mesh surfaceMesh_;
1920

test/MeshFixtures.h

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1273,12 +1273,10 @@ static Mesh buildProblematicTriMesh2()
12731273
// Helper to add a quad (as a surface with four vertices) to a mesh
12741274
static void addQuad(Mesh& mesh, const std::array<int, 3>& v0, const std::array<int, 3>& v1,
12751275
const std::array<int, 3>& v2, const std::array<int, 3>& v3) {
1276-
// Ensure at least one group exists
12771276
if (mesh.groups.empty()) {
12781277
mesh.groups.emplace_back();
12791278
}
12801279

1281-
// Find or create coordinates
12821280
auto findOrAddCoord = [&](const std::array<int, 3>& gridIdx) {
12831281
double pos[3];
12841282
pos[0] = mesh.grid[0][gridIdx[0]];
@@ -1301,8 +1299,36 @@ static void addQuad(Mesh& mesh, const std::array<int, 3>& v0, const std::array<i
13011299
CoordinateId c2 = findOrAddCoord(v2);
13021300
CoordinateId c3 = findOrAddCoord(v3);
13031301

1304-
// Add quad as a surface with four vertices
13051302
mesh.groups[0].elements.push_back(Element({c0, c1, c2, c3}, Element::Type::Surface));
13061303
}
13071304

1305+
// Helper to add a line (as a line with two vertices) to a mesh
1306+
static void addLine(Mesh& mesh, const std::array<int, 3>& v0, const std::array<int, 3>& v1) {
1307+
if (mesh.groups.empty()) {
1308+
mesh.groups.emplace_back();
1309+
}
1310+
1311+
auto findOrAddCoord = [&](const std::array<int, 3>& gridIdx) {
1312+
double pos[3];
1313+
pos[0] = mesh.grid[0][gridIdx[0]];
1314+
pos[1] = mesh.grid[1][gridIdx[1]];
1315+
pos[2] = mesh.grid[2][gridIdx[2]];
1316+
1317+
for (CoordinateId i = 0; i < static_cast<CoordinateId>(mesh.coordinates.size()); ++i) {
1318+
if (mesh.coordinates[i](0) == pos[0] &&
1319+
mesh.coordinates[i](1) == pos[1] &&
1320+
mesh.coordinates[i](2) == pos[2]) {
1321+
return i;
1322+
}
1323+
}
1324+
mesh.coordinates.push_back(Coordinate({pos[0], pos[1], pos[2]}));
1325+
return static_cast<CoordinateId>(mesh.coordinates.size() - 1);
1326+
};
1327+
1328+
CoordinateId c0 = findOrAddCoord(v0);
1329+
CoordinateId c1 = findOrAddCoord(v1);
1330+
1331+
mesh.groups[0].elements.push_back(Element({c0, c1}, Element::Type::Line));
1332+
}
1333+
13081334
}

0 commit comments

Comments
 (0)