66 const std::set<size_t> &selectedFaceIDs)
68 if(!std::isfinite(maxArea) || maxArea <= 0.0)
70 throw std::invalid_argument(
"Maximum triangle area must be finite and positive");
72 std::set<const Simplex<3, 2> *> selectedSimplices;
75 for(
const auto &face : region.second->faces())
77 if(selectedFaceIDs.count(face.second->sID))
79 selectedSimplices.insert(face.second->simplices().begin(),face.second->simplices().end());
83 std::vector<const Simplex<3, 2> *> faces(selectedSimplices.begin(),selectedSimplices.end());
84 double largestArea=0.0;
85 for(
const auto* face : faces)
87 largestArea=std::max(largestArea,face->vol0);
94 const double subdivisions = std::max(1.0, std::ceil(std::sqrt(largestArea / maxArea)));
95 if(!std::isfinite(subdivisions) || subdivisions * subdivisions * faces.size() > 500000)
97 throw std::invalid_argument(
"Surface would exceed 500000 triangles; increase mesh size");
99 const size_t n =
static_cast<size_t>(subdivisions);
101 using Key = std::vector<std::pair<size_t, size_t>>;
102 std::map<Key, size_t> pointIDs;
103 for(
const auto *face : faces)
105 const auto vertices = face->vertices();
106 std::map<std::pair<size_t, size_t>,
size_t> local;
107 for(
size_t i = 0;
i <= n; ++
i)
109 for(
size_t j = 0;
j <= n -
i; ++
j)
111 const std::array<size_t, 3>
weights{n -
i -
j,
i,
j};
113 Vector position = Vector::Zero();
114 for(
size_t k = 0;
k < 3; ++
k)
122 const auto inserted = pointIDs.emplace(
key,
result.referencePoints.size());
125 result.referencePoints.push_back(position);
128 local.emplace(std::make_pair(
i,
j), inserted.first->second);
132 auto append = [&](
size_t a,
size_t b,
size_t c)
141 result.boundaryFaces.push_back(face);
143 for(
size_t i = 0;
i < n; ++
i)
145 for(
size_t j = 0;
j < n -
i; ++
j)
147 append(local.at({i, j}), local.at({i + 1, j}), local.at({i, j + 1}));
150 append(local.at({i + 1, j}), local.at({i + 1, j + 1}), local.at({i, j + 1}));
163 if(inputTraces.empty())
170 scale = std::max(scale,
p.norm());
172 const double tolerance = scale * 1.e-10;
173 std::vector<Trace> traces;
174 for(
const auto &trace : inputTraces)
177 for(
auto &existing : traces)
179 if(existing.normal.cross(trace.normal).norm() < 1.e-10 &&
180 std::abs(existing.normal.dot(trace.point - existing.point)) < tolerance)
182 existing.faces.insert(trace.faces.begin(), trace.faces.end());
189 traces.push_back(trace);
193 using Polygon = std::vector<Vector>;
194 using EdgeKey = std::array<long long, 10>;
201 std::map<EdgeKey, Edge> seams;
206 std::vector<size_t> active;
207 for(
size_t k = 0;
k < traces.size(); ++
k)
209 if(traces[
k].faces.count(face))
214 std::vector<Polygon> polygons{
216 for(
const auto k : active)
218 const auto &trace = traces[
k];
219 std::vector<Polygon> next;
220 for(
const auto &polygon : polygons)
224 for(
const auto &
p : polygon)
226 const double d = trace.normal.dot(
p - trace.point);
227 lo = std::min(lo, d);
228 hi = std::max(hi, d);
230 if(lo >= -tolerance || hi <= tolerance)
232 next.push_back(polygon);
237 for(
size_t j = 0;
j < polygon.size(); ++
j)
240 const Vector &
b = polygon[(
j + 1) % polygon.size()];
241 double da = trace.normal.dot(
a - trace.point);
242 double db = trace.normal.dot(
b - trace.point);
243 if(std::abs(da) <= tolerance)
247 if(std::abs(db) <= tolerance)
253 positive.push_back(
a);
257 negative.push_back(
a);
261 const Vector intersection =
a + da / (da - db) * (
b -
a);
262 positive.push_back(intersection);
263 negative.push_back(intersection);
266 next.push_back(std::move(positive));
267 next.push_back(std::move(negative));
269 polygons = std::move(next);
270 if(polygons.size() +
result.triangles.size() > 500000)
272 throw std::runtime_error(
"Too many slip-trace cuts; increase surface mesh size");
275 for(
const auto &polygon : polygons)
277 Vector center = Vector::Zero();
278 for(
const auto &
p : polygon)
282 center /= polygon.size();
283 const size_t first =
result.referencePoints.size();
284 for(
const auto &
p : polygon)
286 double fraction = 0.0;
287 for(
const auto k : active)
289 if(std::abs(traces[
k].normal.dot(
p - traces[
k].point)) <= tolerance)
291 const double distance = std::abs(traces[
k].normal.dot(center -
p));
294 if(distance > tolerance)
296 fraction = std::max(fraction, std::min(0.25, 2.e-6 * scale / distance));
300 result.referencePoints.push_back(
p);
303 result.samplePoints.push_back(
Vector(
p + fraction * (center -
p)));
306 for(
size_t j = 1;
j + 1 < polygon.size(); ++
j)
309 result.boundaryFaces.push_back(face);
311 for(
size_t j = 0;
j < polygon.size(); ++
j)
313 const size_t next = (
j + 1) % polygon.size();
315 const Vector &
b = polygon[next];
316 for(
const auto k : active)
318 const auto &trace = traces[
k];
319 const double side = trace.normal.dot(center - trace.point);
320 if(std::abs(side) <= tolerance || std::abs(trace.normal.dot(
a - trace.point)) > tolerance ||
321 std::abs(trace.normal.dot(
b - trace.point)) > tolerance)
325 std::array<long long, 3> qa, qb;
326 for(
size_t d = 0; d < 3; ++d)
328 qa[d] = std::llround(
a[d] / tolerance);
329 qb[d] = std::llround(
b[d] / tolerance);
336 const EdgeKey
key{
static_cast<long long>(
k),
343 std::llround(normal[0] * 1.e8),
344 std::llround(normal[1] * 1.e8),
345 std::llround(normal[2] * 1.e8)};
346 const Edge edge{
first +
j,
first + next, side > 0.0};
347 const auto inserted = seams.emplace(
key, edge);
350 const auto other = inserted.first->second;
351 if(other.positive != edge.positive)
355 result.walls.push_back({other.b, other.a, edge.b});
356 result.walls.push_back({other.b, edge.b, edge.a});
358 seams.erase(inserted.first);
362 if(
result.triangles.size() +
result.walls.size() > 500000)
364 throw std::runtime_error(
"Surface with slip walls exceeds 500000 triangles");