SWMMVis  6.0.0-alpha.4
Qt6/C++ GIS-based graphical user interface for the SWMMVis engine (6.0.0-alpha.4)
Loading...
Searching...
No Matches
trirefinehook.h File Reference
#include <QtGlobal>
#include <functional>
Include dependency graph for trirefinehook.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  mesh::RefineHook
 Callbacks consulted by Triangle's -u user test. More...
 
class  mesh::RefineHookGuard
 Installs hook as the active refinement hook for the current thread. More...
 

Namespaces

namespace  mesh
 

Functions

bool mesh::refineHookWasCancelled () noexcept
 True if the hook active on this thread observed cancellation.
 
qint64 mesh::refineHookTestCount () noexcept
 Number of triunsuitable() invocations since the active guard was constructed. Useful for logging refinement cost.
 

Detailed Description

Author
Caleb Buahin caleb.nosp@m..bua.nosp@m.hin@g.nosp@m.mail.nosp@m..com
Date
2026
License\n GPL-3.0-or-later

Triangle refinement hook — cancellation, progress, and graded element sizing without modifying vendor/triangle/.

Shewchuk's Triangle exposes exactly one extension point during quality refinement: the triunsuitable() callback, invoked from testtriangle() for every candidate triangle when the -u switch is present. Upstream sanctions supplying it externally by defining EXTERNAL_TEST (see the comment block at triangle.c:1363-1384), which is how it is wired here — triangle.c itself is untouched.

Three things ride on this one hook:

  1. CANCELLATION. Triangle's refinement loop is otherwise uninterruptible: a long -q/-a run cannot be stopped, so the GUI's Stop button is dead for its whole duration. The hook polls a caller-supplied predicate and, once cancelled, reports every triangle as suitable. The bad-triangle queue then drains and Triangle returns through its normal exit path.

    This is deliberately NOT a longjmp out of triangulate(). Triangle's memory pools are freed by triangledeinit() at the very end of triangulate(); jumping out past it leaks them, and they are the dominant allocation in the whole pipeline (~200 bytes per output vertex). Draining is slightly slower to respond but leaks nothing.

  2. PROGRESS. The hook fires often enough during refinement to drive a progress indicator, which Triangle otherwise provides no way to observe.
  3. GRADED SIZING. A single global -a<area> cap forces the SAME element size everywhere, which is the primary driver of output vertex count on large domains. A size function lets the caller ask for fine elements only where they matter and coarse ones elsewhere. This is the largest available lever on final mesh size.

NOTE: triunsuitable() takes no user-data pointer, so the active hook has to be reachable from a free function. It is stored thread-locally rather than globally so that triangulating several domains (or, later, several tiles) concurrently stays correct.