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
mesh Namespace Reference

Namespaces

namespace  pslg
 

Classes

struct  AutoCoupleResult
 Result of findCoincidentNodes. More...
 
struct  CellAreaStats
 Min / max / mean / median of triangle areas (project CRS units²). More...
 
struct  CellCoupling
 A 1D node coupled to a mesh cell (centroid coupling). More...
 
struct  CellGeom
 Per-cell derived geometry shared by every consumer. More...
 
struct  CellParamSpec
 Describes one editable per-cell parameter: how to label it, how to configure a numeric editor for it, and whether it is live yet. More...
 
struct  CflStats
 The 2D marcher's CFL characteristic length, per cell and summarised. More...
 
struct  CleanupPolicy
 
struct  CleanupReport
 
struct  ConstraintSegment
 A polyline that must appear as constrained edges in the mesh. More...
 
struct  CouplingMap
 1D↔2D coupling map produced by the meshing dialog. More...
 
class  CrossField
 
class  DTMSampler
 
class  DTMThinner
 Terrain-adaptive Steiner point selector from a DTM raster. More...
 
struct  DTMThinnerLimits
 Test-injectable resource limits for generatePoints(). More...
 
struct  DTMThinnerOptions
 Parameters for the normal-deviation terrain thinning. More...
 
struct  GenerationOptions
 Quality knobs surfaced to the user dialog. More...
 
struct  InfilDefaultRow
 One [2D_INFILTRATION_DEFAULTS] row. tag == "*" is the mesh-wide fallback and may appear anywhere in the section. More...
 
struct  InfilLookupEntry
 One row of a classified lookup: a key (or key pair, for the Curve-Number landuse×HSG case) mapping to a full InfilRow. More...
 
struct  InfilLookupTable
 An editable, reusable classified lookup table. Saved/loaded as CSV so an agency's standard table travels between projects. More...
 
struct  InfilOptions
 [2D_INFILTRATION_OPTIONS]. More...
 
struct  InfilRow
 One infiltration specification: method + positional parameters + destination. More...
 
class  InpMeshReader
 
struct  InpMeshReadResult
 Outcome of InpMeshReader::read. More...
 
class  InpMeshWriter
 
class  MeshBCTypes
 
class  MeshBoundaryGraph
 Undirected graph whose nodes are mesh vertices and whose arcs are boundary edge slots (mesh::edgeSlot(cell, edgeLocal)). More...
 
struct  MeshEdge
 A boundary edge with its source-segment marker preserved. More...
 
struct  MeshEdgeBC
 
class  MeshGenerator
 Generate a 2D triangular mesh. More...
 
class  MeshHoverProbe
 
class  MeshObjectRef
 
struct  MeshResult
 Result of MeshGenerator::generate. More...
 
class  MeshStageCache
 
struct  MeshTriangle
 A cell in the mesh — a triangle or (since the engine's mixed tri-quad meshes, workplans/TRI_QUAD_MESHING_PLAN_2026-09-06.md) a convex quadrilateral — indices into MeshResult::vertices. More...
 
struct  MeshVertex
 A vertex in the generated mesh. More...
 
class  NaturalNeighbourInterpolator
 
struct  NodeMapResult
 Result of mapNodesToMesh. More...
 
struct  PatchMesh
 A generated patch in local indices. Quads are emitted CCW. More...
 
struct  QuadCleanupOptions
 
struct  QuadCleanupStats
 
struct  QuadMergeOptions
 Acceptance thresholds for a merged quad. More...
 
struct  QuadPairingOptions
 
struct  QuadPairingStats
 
struct  QuadPointOptions
 
struct  QuadPointSet
 
struct  QuadQuality
 
struct  QuadQualityBounds
 Acceptance bounds shared by pairing, cleanup, smoothing and the legacy tri-pair merge. Defaults are the plan's (§5): hard 60°/120°, SJ ≥ 0.866, aspect ≤ 2. More...
 
struct  QuadRegion
 
struct  QuadRegionReport
 Per-region outcome of generate() (MeshGenerator::quadRegionReports()). More...
 
struct  QuadStats
 Quadrilateral-cell statistics (workplans/TRI_QUAD_MESHING_PLAN §5): count, interior-angle range and bed non-planarity. More...
 
struct  QuadTemplate
 Four vertex ids in cyclic (CCW) order. Before the PSLG is built these are meshquadpoints' combined indices; MeshGenerator maps them to Triangle output vertex ids before pairing. More...
 
struct  RefineHook
 Callbacks consulted by Triangle's -u user test. More...
 
class  RefineHookGuard
 Installs hook as the active refinement hook for the current thread. More...
 
struct  RegionMarker
 A region attribute — an interior seed point with a value Triangle propagates into the triangle-attribute output array. We use it to tag triangles with a numeric id that maps back to subcatchment names etc. More...
 
struct  ResolvedInfil
 Result of resolving one triangle's infiltration. More...
 
class  SizeField
 Distance-to-feature field sampled as a max-area function. More...
 
struct  SizeFieldOptions
 
class  Sms2dmReader
 
struct  SteinerPoint
 A point that must appear as a vertex in the output mesh. More...
 
struct  StructuredPatch
 Four-sided patch: corners in cyclic order (either orientation); n subdivisions along corner0→corner1 (and corner3→corner2), m along corner0→corner3 (and corner1→corner2). More...
 
struct  SweptPatch
 Swept patch: the centreline is offset ±width/2 (mitred at interior vertices) and cut into across quads per station. along > 0 resamples every centreline segment to that target spacing (original vertices are kept); 0 = one station per centreline vertex. More...
 

Typedefs

using DTMProgressFn = std::function< bool(double)>
 Progress/cancel callback for DTMThinner::generatePoints().
 
using EdgeVertexPair = QPair< int, int >
 Undirected mesh edge, as (min, max) vertex indices.
 
using MeshCell = MeshTriangle
 Alias: a "triangle" row is any cell (triangle or quad).
 

Enumerations

enum class  MeshOutputMode {
  External ,
  Inline
}
 Output strategy for the four 2D mesh sections. More...
 
enum class  InfilMethod : int {
  None = -1 ,
  Horton = 0 ,
  ModHorton = 1 ,
  GreenAmpt = 2 ,
  ModGreenAmpt = 3 ,
  CurveNumber = 4 ,
  Constant = 5
}
 
enum class  InfilDest : int {
  Lost = 0 ,
  SubcatchAquifer = 1 ,
  Aquifer2D = 2
}
 
enum class  InfilProvenance : int {
  None = 0 ,
  Star = 1 ,
  Tag = 2 ,
  Override = 3
}
 
enum class  QuadRegionMode {
  Auto ,
  Mapped ,
  Submapped ,
  Free ,
  TrianglesOnly
}
 

Functions

bool unitsHeaderIsSI (const QString &unitsHeader)
 True when unitsHeader (the verbatim ;; UNITS: value) declares a metric mesh, i.e. one the engine will NOT rescale.
 
double defaultCoincidenceTol (const MeshResult &mesh)
 Scale-free coincidence tolerance: 1e-6 × the mesh bbox diagonal (min 1e-9) — exact coordinate match with float / .inp-rounding slop.
 
AutoCoupleResult findCoincidentNodes (const MeshResult &mesh, const QVector< QPair< QString, QPointF > > &nodes, const QList< int > &targets={}, double tol=-1.0)
 Match SWMM nodes to coincident mesh vertices.
 
constexpr int edgeSlot (int cell, int e) noexcept
 
constexpr int slotCell (int slot) noexcept
 
constexpr int slotLocal (int slot) noexcept
 
constexpr int edgeSlotCount (int nCells) noexcept
 
void edgeEndpoints (const MeshTriangle &t, int k, int &a, int &b) noexcept
 
bool rt0CellDischarge (int cell, int nv, const float *flux, const float *length, const float *nx, const float *ny, double &qx, double &qy) noexcept
 RT0 least-squares specific discharge (m²/s) of one cell from its outward-positive normal edge fluxes (m³/s).
 
CellGeom cellGeom (const QVector< MeshVertex > &vertices, const MeshTriangle &t)
 Geometry of cell t against vertices.
 
double cellSignedArea (const QVector< MeshVertex > &vertices, const MeshTriangle &t) noexcept
 Signed area of the polygon (positive = counter-clockwise).
 
bool cellIsConvex (const QVector< MeshVertex > &vertices, const MeshTriangle &t) noexcept
 Convexity test for a quad (every consecutive cross product has the same non-zero sign). Triangles are trivially convex.
 
bool cellContains (const QVector< MeshVertex > &vertices, const MeshTriangle &t, const QPointF &p, double eps=0.0) noexcept
 Point-in-cell test on the sub-triangle fan (barycentric per sub-triangle).
 
const QVector< CellParamSpec > & cellParamSpecs ()
 The registry, in display order. Stable for the process lifetime.
 
const CellParamSpeccellParamSpec (const QByteArray &key)
 Look up one spec by key; returns nullptr when unknown.
 
QString cellParamLabel (const QByteArray &key, const QString &depthUnitLabel)
 Full label for key including the unit suffix when the parameter is a length. depthUnitLabel comes from UnitSystem::depthLabel().
 
double cellParamValue (const MeshResult &mesh, int tri, const QByteArray &key)
 Current value of key on triangle tri.
 
double triangleArea (const MeshResult &mesh, int tri)
 Unsigned area of triangle tri (|cross| / 2), in project CRS units². Returns 0 for an out-of-range triangle or one referencing out-of-range vertices.
 
QPointF cellCentroid (const MeshResult &mesh, int cell)
 Area centroid of cell cell (mesh::cellGeom — the vertex mean for a triangle, the area-weighted sub-triangle centroid for a quad). A null point for an out-of-range cell.
 
QuadStats computeQuadStats (const MeshResult &mesh)
 
CellAreaStats computeCellAreaStats (const MeshResult &mesh)
 Compute cell-area statistics over all triangles in mesh.
 
QHash< EdgeVertexPair, QVector< int > > buildEdgeTriangles (const MeshResult &mesh)
 Map every undirected edge to the triangles incident on it.
 
QVector< doublecomputeCellLchar (const MeshResult &mesh)
 Per-cell L_char for mesh, indexed like mesh.triangles. Cells with invalid indices get 0.
 
CflStats computeCflStats (const MeshResult &mesh, int ltsTiers=4)
 Summarise computeCellLchar. ltsTiers mirrors the engine's [2D_OPTIONS] LTS_TIERS (1..8, default 4).
 
bool pushMeshEditsToEngine (SWMM_Engine engine, const MeshResult &mesh, const QVector< MeshEdgeBC > &bcs, QStringList *warnings=nullptr, bool *outTrianglesSynced=nullptr)
 Copy the layer's editable mesh state into the engine's 2D mesh.
 
ResolvedInfil resolveInfil (const MeshResult &mesh, int tri)
 Resolve one triangle's infiltration per engine D-I3 precedence: ‘override > tag row > ’*' row > none`.
 
InfilRow starDefault (const MeshResult &mesh)
 Convenience: the '*' row from mesh, or a None row when absent.
 
int indexOfDefault (const MeshResult &mesh, const QString &tag)
 Index of tag in MeshResult::infilDefaults, or -1.
 
bool infilUsesParam (InfilMethod method, int slot)
 True when method uses positional slot slot.
 
int infilParamCount (InfilMethod method)
 Number of meaningful positional parameters for method.
 
QString infilParamLabel (InfilMethod method, int slot)
 Display label for positional slot slot under method, e.g. ("Horton", 0) → "Max Rate (f0)". Empty when unused.
 
QByteArray infilParamKey (InfilMethod method, int slot)
 Registry key for positional slot slot under method, e.g. "infil.f0". Empty when unused.
 
int infilSlotForKey (InfilMethod method, const QByteArray &key)
 Inverse of infilParamKey(): maps a registry key to the positional slot it occupies under method, or -1 when method does not use it.
 
const QVector< QByteArray > & infilParamKeys ()
 Every named parameter key, in registration order. The attribute table and the assign dialog iterate this.
 
QString infilMethodToken (InfilMethod m)
 "HORTON", "CURVE_NUMBER", "NONE", …
 
InfilMethod infilMethodFromToken (const QString &token, bool *ok=nullptr)
 
QString infilMethodLabel (InfilMethod m)
 Translated UI label.
 
QStringList infilMethodLabels ()
 For EnumComboDelegate, in enum order.
 
QString infilDestToken (InfilDest d)
 "LOST", …
 
InfilDest infilDestFromToken (const QString &token, bool *ok=nullptr)
 
QString infilDestLabel (InfilDest d)
 
QStringList infilDestLabels ()
 
QString infilDestHint (InfilDest d)
 A one-sentence tooltip for destination d: where the water goes and what the choice needs.
 
bool saveLookupTableCsv (const InfilLookupTable &table, const QString &path, QString *err)
 CSV round-trip. Column order: key1[,key2],method,p0,p1,p2,p3,p4,dest, # comments, header row optional.
 
bool loadLookupTableCsv (InfilLookupTable *table, const QString &path, QString *err)
 
bool collapseSubScaleCells (MeshResult *mesh, const CleanupPolicy &policy, CleanupReport *report)
 Collapse sub-scale edges in mesh, protecting all constrained and coupled geometry.
 
NodeMapResult mapNodesToMesh (const MeshResult &mesh, const QVector< QPair< QString, QPointF > > &nodes, double tol=-1.0, bool preserveExisting=true)
 Map SWMM nodes onto an existing mesh.
 
QString validate (const StructuredPatch &p)
 Input checks. Empty string = valid.
 
QString validate (const SweptPatch &p)
 
QString validate (const PatchMesh &pm)
 Rejects a patch with a folded / concave / degenerate quad (mesh::cellIsConvex). Empty string = valid.
 
PatchMesh makeTransfinitePatch (const StructuredPatch &p, QString *err=nullptr)
 Transfinite interpolation on the four straight sides. The result has (n+1)×(m+1) vertices and n×m quads. On invalid input returns an empty PatchMesh and sets *err.
 
PatchMesh makeSweptPatch (const SweptPatch &p, QString *err=nullptr)
 Sweep the centreline: (stations)×(across+1) vertices, (stations-1)×across quads. On invalid input (or a folded offset) returns an empty PatchMesh and sets *err.
 
PatchMesh makeTransfinitePatch (const QVector< QVector< QPointF > > &sides, int n, int m, const QString &tag, QString *err=nullptr)
 Transfinite (Coons) interpolation on four POLYLINE sides forming a loop: sides[0] runs c0→c1, sides[1] c1→c2, sides[2] c2→c3, sides[3] c3→c0 (each side's last point equals the next side's first). Sides are arc-length parametrised; n subdivisions along sides 0/2, m along 1/3. Boundary vertices are placed ON the polylines (so the ring the caller emits as PSLG segments is exactly this patch's boundary loop). Returns an empty PatchMesh + *err on invalid input (side with < 2 points, endpoints not matching, n or m < 1, folded quad).
 
PatchMesh makeMappedPatch (const QPolygonF &ring, const QVector< int > &corners, double h, const QString &tag, QString *err=nullptr)
 Split a CCW ring at the four corners (ring vertex indices, ring order) into polyline sides, choose n = max(1, round(mean(len0, len2)/h)), m likewise from sides 1/3, and call the polyline overload.
 
QuadCleanupStats cleanupAndSmoothQuads (MeshResult &mesh, const QSet< int > &movable, const QuadCleanupOptions &opts, QVector< int > *vertexOldToNew)
 Run cleanup then smoothing. vertexOldToNew (optional) receives the vertex remap after doublet compaction (-1 = removed); identity when nothing was removed. Cells are rebuilt triangles-first afterwards.
 
QVector< int > reorderTrianglesFirst (MeshResult &mesh)
 Reorder cells triangles-first, stable within each class. Returns the old→new cell index map. Shared with meshquadmatch.
 
QuadPairingStats pairTrianglesIntoQuads (MeshResult &mesh, const QVector< int > &cellIds, const QVector< QuadTemplate > &templates, const QSet< QPair< int, int > > &lockedEdges, const QuadPairingOptions &opts, QVector< int > *oldToNew)
 Pair the triangles cellIds (indices into mesh.triangles; every one must be a triangle) into quads. templates carry OUTPUT vertex ids. lockedEdges (mesh::edgeKey pairs) are never straddled. On return oldToNew (optional) maps every old cell index to its new index (a paired triangle maps to its quad). Region triangles that were not paired keep their tag/mannings/initDepth; a quad inherits them from its first triangle (tags of the two triangles are equal inside a region).
 
QVector< int > maximumMatching (int n, const QVector< QPair< int, int > > &edges)
 Maximum-cardinality matching on a general graph — Edmonds' blossom algorithm (O(V·E)). edges are unordered pairs in [0, n). Returns mate[i] (-1 = unmatched). Exposed for the brute-force cross-check test.
 
bool unionQuad (const QVector< MeshVertex > &vertices, const MeshTriangle &t1, const MeshTriangle &t2, MeshTriangle &quad)
 The CCW quad formed by two triangles sharing edge (p,q): returns false when they do not share exactly two vertices or the union is not a simple quad. quad receives v0..v3 (tag etc. copied from t1).
 
QPair< int, int > edgeKey (int a, int b) noexcept
 Unordered vertex-pair key used for locked edges: (min, max).
 
int mergeTrianglePairs (MeshResult &mesh, const QuadMergeOptions &opts, const QSet< QPair< int, int > > &lockedEdges, QVector< int > *oldToNew=nullptr)
 Greedily merge adjacent triangle pairs of mesh into convex quads.
 
QuadPointSet placeQuadPoints (const QPolygonF &ring, const QVector< QPointF > &seeds, int ringCount, const CrossField &field, const QuadPointOptions &opts)
 Place lattice points inside ring (CCW, open) aligned to field. seeds = ring vertices (exactly ringCount of them, in ring order) followed by fixed interior points. Returns an empty set when h <= 0 or the ring has fewer than 3 vertices.
 
QuadPointSet placeQuadPoints (const QPolygonF &ring, const QVector< QPolygonF > &holes, const QVector< QPointF > &seeds, int ringCount, const CrossField &field, const QuadPointOptions &opts)
 Hole-aware overload: no point is placed inside any ring of holes, and the boundary clearance is kept from the hole rings as well as from ring (QUAD_EVERYWHERE_PLAN_2026-09-07.md §3.1). An empty holes is identical to the overload above.
 
double distanceToRing (const QPolygonF &ring, const QPointF &p)
 Distance from p to the closest ring edge.
 
double distanceToRings (const QPolygonF &ring, const QVector< QPolygonF > &holes, const QPointF &p)
 Distance from p to the closest edge of ring or of any hole.
 
QuadQuality quadQuality (const QPointF &a, const QPointF &b, const QPointF &c, const QPointF &d)
 Metrics for corners a,b,c,d in cyclic order.
 
QuadQuality quadQuality (const QVector< MeshVertex > &vertices, const MeshTriangle &t)
 Metrics for a quad cell of mesh (t.v3 >= 0 required).
 
bool quadAcceptable (const QuadQuality &q, const QuadQualityBounds &b)
 Hard acceptance test (convex + angle bounds + SJ floor + aspect cap).
 
double quadScore (const QuadQuality &q, const QuadQualityBounds &b)
 Combined score in [0,1] (plan §5): SJ · min(1, aspectMax/aspect) · sqrt(1 - skew). 0 for a non-convex quad. Used as the pairing benefit and the smoothing objective.
 
double triangleScaledJacobian (const QPointF &a, const QPointF &b, const QPointF &c)
 Minimum sine of a triangle's angles (1 is unattainable; equilateral = 0.866; right isosceles = 0.707). Used by the smoothing guard for the triangles that remain inside a quad region.
 
double cellCornerAngleDeg (const QVector< MeshVertex > &v, const MeshTriangle &t, int i)
 Interior angle at corner i of a cell (degrees), triangles and quads.
 
QPolygonF normalizeRingCCW (const QPolygonF &ring)
 Drop a closing duplicate, drop consecutive duplicates, make CCW.
 
double ringSignedArea (const QPolygonF &ring)
 Signed shoelace area (CCW positive).
 
bool pointInRing (const QPolygonF &ring, const QPointF &p)
 Odd-even point-in-polygon (closed ring, last == first optional).
 
bool pointInRegion (const QPolygonF &ring, const QVector< QPolygonF > &holes, const QPointF &p)
 Inside ring and outside every ring of holes — the region's meshable interior. With no holes this is exactly pointInRing().
 
bool ringIsSimple (const QPolygonF &ring)
 True when ring is simple (no proper self-intersection). O(n²).
 
QString validateQuadRegion (const QuadRegion &r, const QVector< QPolygonF > &domains, const QVector< QPolygonF > &holes)
 Validate one region: >= 3 distinct vertices, simple, area >= 4·h² (h = spacing when > 0, else skipped), every vertex inside exactly one of domains and outside every holes ring. Empty string = valid.
 
QString validateQuadRegionsDisjoint (const QVector< QuadRegion > &regions)
 Pairwise check: rings may share edges/vertices but no ring vertex of one may lie strictly inside another and edges may not properly cross. Returns the first offending pair as "region i overlaps region j", or "".
 
QuadRegionMode classifyQuadRegion (const QPolygonF &ring, QVector< int > *corners, double cornerTolDeg=25.0, double rectilinearTolDeg=2.0)
 Auto-classification (plan §4.1) on the normalised ring.
 
QPolygonF resampleRing (const QPolygonF &ring, double h, double keepTurnDeg=0.0)
 Resample a closed ring at spacing h: every edge is split into max(1, round(len/h)) equal parts; ring vertices whose |turn| >= keepTurnDeg are always kept, others are kept too (geometry is never simplified here — run pslg::simplifyPolyline first). Output is CCW, open (no closing duplicate).
 
double ringTurnDeg (const QPolygonF &ring, int i)
 Exterior turning angle (degrees, CCW positive) at ring vertex i.
 
void reorderMeshHilbert (MeshResult *m)
 
double meanVertexIndexSpread (const MeshResult &m)
 
bool ringIsRectilinear (const QPolygonF &ring, double tolDeg, double *frameAngleDeg)
 True when every edge of the (normalised) ring is parallel to one of two perpendicular axes within tolDeg. frameAngleDeg receives the frame rotation when non-null.
 
PatchMesh makeSubmappedPatch (const QPolygonF &ring, double h, const QString &tag, QString *err=nullptr, double tolDeg=2.0)
 Build the submapped patch. On failure returns an empty PatchMesh and sets *err ("not rectilinear", "spacing must be > 0", "degenerate ring").
 
bool refineHookWasCancelled () noexcept
 True if the hook active on this thread observed cancellation.
 
qint64 refineHookTestCount () noexcept
 Number of triunsuitable() invocations since the active guard was constructed. Useful for logging refinement cost.
 

Variables

constexpr int kEdgeStride = 4
 
constexpr int kInfilMaxParams = 5
 
constexpr double kCellCouplingDefaultCd = 0.65
 
constexpr double kCellCouplingDefaultArea = 2.0
 mesh length units²
 

Typedef Documentation

◆ DTMProgressFn

using mesh::DTMProgressFn = typedef std::function<bool(double)>

Progress/cancel callback for DTMThinner::generatePoints().

Called with a fraction in [0, 1], monotone non-decreasing. Return false to cancel — generatePoints() then returns empty with errorMsg() set to a cancellation message. Polled between raster read strips and between thinning passes (seconds-granularity at worst on huge DEMs).

◆ EdgeVertexPair

using mesh::EdgeVertexPair = typedef QPair<int, int>

Undirected mesh edge, as (min, max) vertex indices.

◆ MeshCell

using mesh::MeshCell = typedef MeshTriangle

Alias: a "triangle" row is any cell (triangle or quad).

Enumeration Type Documentation

◆ InfilDest

enum class mesh::InfilDest : int
strong

Destination of infiltrated water (engine Infil2DDest).

Enumerator
Lost 

Leaves the model.

SubcatchAquifer 

U3: recharges the containing subcatchment's aquifer.

Aquifer2D 

G1: recharges the integrated two-zone kernel.

◆ InfilMethod

enum class mesh::InfilMethod : int
strong

Infiltration method. Values mirror the engine's InfilModel plus an explicit None. Stored in files as the tokens returned by infilMethodToken().

Enumerator
None 
Horton 
ModHorton 
GreenAmpt 
ModGreenAmpt 
CurveNumber 
Constant 

◆ InfilProvenance

enum class mesh::InfilProvenance : int
strong

Where a cell's resolved parameters came from — drives the muted/italic "inherited" rendering in the attribute table and property panels, and is what undo must restore (GUI plan §3.5(3)).

Enumerator
None 

No model resolves for this cell.

Star 

From the '*' default row.

Tag 

From a tag default row.

Override 

From a per-cell override.

◆ MeshOutputMode

enum class mesh::MeshOutputMode
strong

Output strategy for the four 2D mesh sections.

External (default) keeps the main .inp clean and lets multiple SWMM models share a single mesh — the user-stated preference (2026-04-26). Inline is the fallback for callers who specifically want everything in one file.

Enumerator
External 

Write .2dm next to the .inp; reference via [2D_MESH_FILE].

Inline 

Inline the four sections directly in the .inp.

◆ QuadRegionMode

enum class mesh::QuadRegionMode
strong
Enumerator
Auto 

classifyQuadRegion() decides: Mapped → Submapped → Free.

Mapped 

Four logical sides (polylines) → transfinite quads. Needs 4 corners.

Submapped 

Exactly rectilinear ring → grid-based structured quads.

Free 

Cross-field aligned lattice + template pairing (quad-dominant).

TrianglesOnly 

Region ring is still a constraint loop, interior stays triangles.

Function Documentation

◆ buildEdgeTriangles()

QHash< EdgeVertexPair, QVector< int > > mesh::buildEdgeTriangles ( const MeshResult mesh)

Map every undirected edge to the triangles incident on it.

MeshResult stores no adjacency, and every pass that needs neighbours has so far rebuilt this by hand. Triangles with out-of-range indices are skipped. (meshminsizecleanup.cpp's Topo::build still has its own copy fused into a larger loop; converge them when that file is next touched.)

Here is the caller graph for this function:

◆ cellCentroid()

QPointF mesh::cellCentroid ( const MeshResult mesh,
int  cell 
)

Area centroid of cell cell (mesh::cellGeom — the vertex mean for a triangle, the area-weighted sub-triangle centroid for a quad). A null point for an out-of-range cell.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cellContains()

bool mesh::cellContains ( const QVector< MeshVertex > &  vertices,
const MeshTriangle t,
const QPointF &  p,
double  eps = 0.0 
)
inlinenoexcept

Point-in-cell test on the sub-triangle fan (barycentric per sub-triangle).

Here is the call graph for this function:

◆ cellCornerAngleDeg()

double mesh::cellCornerAngleDeg ( const QVector< MeshVertex > &  v,
const MeshTriangle t,
int  i 
)
inline

Interior angle at corner i of a cell (degrees), triangles and quads.

◆ cellGeom()

CellGeom mesh::cellGeom ( const QVector< MeshVertex > &  vertices,
const MeshTriangle t 
)
inline

Geometry of cell t against vertices.

A quad is split along the Begnudelli & Sanders (2007) diagonal: with the vertices ordered by elevation n1 ≤ n2 ≤ n3 ≤ n4 — Case 1: n1,n4 opposite → sub-triangles (n1,n2,n4),(n1,n3,n4); Case 2: n1,n4 adjacent and n2 adjacent to n1 → (n1,n2,n4),(n2,n3,n4); Case 3 → (n1,n3,n4),(n2,n3,n4). The centroid is the area-weighted centroid of the two sub-triangles (a property of the polygon, independent of the diagonal).

Here is the caller graph for this function:

◆ cellIsConvex()

bool mesh::cellIsConvex ( const QVector< MeshVertex > &  vertices,
const MeshTriangle t 
)
inlinenoexcept

Convexity test for a quad (every consecutive cross product has the same non-zero sign). Triangles are trivially convex.

Here is the caller graph for this function:

◆ cellParamLabel()

QString mesh::cellParamLabel ( const QByteArray &  key,
const QString &  depthUnitLabel 
)

Full label for key including the unit suffix when the parameter is a length. depthUnitLabel comes from UnitSystem::depthLabel().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cellParamSpec()

const CellParamSpec * mesh::cellParamSpec ( const QByteArray &  key)

Look up one spec by key; returns nullptr when unknown.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cellParamSpecs()

const QVector< CellParamSpec > & mesh::cellParamSpecs ( )

The registry, in display order. Stable for the process lifetime.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cellParamValue()

double mesh::cellParamValue ( const MeshResult mesh,
int  tri,
const QByteArray &  key 
)

Current value of key on triangle tri.

Returns
the stored value, or NaN when the triangle index is out of range, the key is unknown, or the attribute is unset (the NaN sentinel MeshTriangle uses for "column absent"). Callers substitute the spec's defaultValue for display.

The infil.* keys resolve through mesh::resolveInfil (override → tag row → '*' row), so an inherited value reads back here exactly as the engine would see it; a parameter the resolved METHOD does not use returns NaN, which is what drives the attribute table's per-row column masking. infil.method returns the mesh::InfilMethod integer (-1 = None).

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cellSignedArea()

double mesh::cellSignedArea ( const QVector< MeshVertex > &  vertices,
const MeshTriangle t 
)
inlinenoexcept

Signed area of the polygon (positive = counter-clockwise).

Here is the caller graph for this function:

◆ classifyQuadRegion()

QuadRegionMode mesh::classifyQuadRegion ( const QPolygonF &  ring,
QVector< int > *  corners,
double  cornerTolDeg = 25.0,
double  rectilinearTolDeg = 2.0 
)

Auto-classification (plan §4.1) on the normalised ring.

Turning angle at each vertex (exterior angle, CCW positive):

  • exactly four vertices with turn in [90 − cornerTolDeg, 90 + cornerTolDeg] and every other |turn| < cornerTolDeg → Mapped (corners = those four, in ring order);
  • every turn within rectilinearTolDeg of ±90° → Submapped;
  • otherwise Free. corners receives the Mapped corners when non-null (cleared otherwise).
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cleanupAndSmoothQuads()

QuadCleanupStats mesh::cleanupAndSmoothQuads ( MeshResult mesh,
const QSet< int > &  movable,
const QuadCleanupOptions opts,
QVector< int > *  vertexOldToNew 
)

Run cleanup then smoothing. vertexOldToNew (optional) receives the vertex remap after doublet compaction (-1 = removed); identity when nothing was removed. Cells are rebuilt triangles-first afterwards.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ collapseSubScaleCells()

bool mesh::collapseSubScaleCells ( MeshResult mesh,
const CleanupPolicy policy,
CleanupReport report 
)

Collapse sub-scale edges in mesh, protecting all constrained and coupled geometry.

Returns true when the mesh was left in a valid state — including the no-op cases (policy disabled, nothing to do). Returns false only when a pass had to be abandoned, in which case mesh holds the pre-pass geometry and is still perfectly usable.

Must run BEFORE mesh::reorderMeshHilbert: reorder is a pure permutation for locality, and collapsing cells afterwards would waste it. Downstream elevation fill and node mapping are coordinate-keyed and the coupling map is marker-keyed, so all three tolerate the vertex renumbering this performs — provided marker-bearing vertices survive, which the protection rules guarantee.

◆ computeCellAreaStats()

CellAreaStats mesh::computeCellAreaStats ( const MeshResult mesh)

Compute cell-area statistics over all triangles in mesh.

Area is triangleArea. Triangles referencing out-of-range vertex indices are skipped. Median of an even count is the average of the two middle values.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ computeCellLchar()

QVector< double > mesh::computeCellLchar ( const MeshResult mesh)

Per-cell L_char for mesh, indexed like mesh.triangles. Cells with invalid indices get 0.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ computeCflStats()

CflStats mesh::computeCflStats ( const MeshResult mesh,
int  ltsTiers = 4 
)

Summarise computeCellLchar. ltsTiers mirrors the engine's [2D_OPTIONS] LTS_TIERS (1..8, default 4).

Here is the call graph for this function:

◆ computeQuadStats()

QuadStats mesh::computeQuadStats ( const MeshResult mesh)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ defaultCoincidenceTol()

double mesh::defaultCoincidenceTol ( const MeshResult mesh)

Scale-free coincidence tolerance: 1e-6 × the mesh bbox diagonal (min 1e-9) — exact coordinate match with float / .inp-rounding slop.

Here is the caller graph for this function:

◆ distanceToRing()

double mesh::distanceToRing ( const QPolygonF &  ring,
const QPointF &  p 
)

Distance from p to the closest ring edge.

Here is the caller graph for this function:

◆ distanceToRings()

double mesh::distanceToRings ( const QPolygonF &  ring,
const QVector< QPolygonF > &  holes,
const QPointF &  p 
)

Distance from p to the closest edge of ring or of any hole.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ edgeEndpoints()

void mesh::edgeEndpoints ( const MeshTriangle t,
int  k,
int &  a,
int &  b 
)
inlinenoexcept

Endpoints (a, b) of local edge k of cell t: v[(k+1)nv], v[(k+2)nv].

Here is the caller graph for this function:

◆ edgeKey()

QPair< int, int > mesh::edgeKey ( int  a,
int  b 
)
inlinenoexcept

Unordered vertex-pair key used for locked edges: (min, max).

Here is the caller graph for this function:

◆ edgeSlot()

constexpr int mesh::edgeSlot ( int  cell,
int  e 
)
constexprnoexcept

Flat edge slot of local edge e of cell cell.

Here is the caller graph for this function:

◆ edgeSlotCount()

constexpr int mesh::edgeSlotCount ( int  nCells)
constexprnoexcept

Number of flat edge slots for nCells cells.

Here is the caller graph for this function:

◆ findCoincidentNodes()

AutoCoupleResult mesh::findCoincidentNodes ( const MeshResult mesh,
const QVector< QPair< QString, QPointF > > &  nodes,
const QList< int > &  targets = {},
double  tol = -1.0 
)

Match SWMM nodes to coincident mesh vertices.

Parameters
meshThe mesh whose vertices are candidates.
nodes(node id, map xy) pairs, same CRS as the mesh vertices.
targetsCandidate vertex indices; empty = every vertex.
tolMax distance for "coincident"; <= 0 uses defaultCoincidenceTol. The nearest in-tolerance vertex wins; already-coupled vertices are skipped (counted in AutoCoupleResult::alreadyCoupled).
Here is the call graph for this function:

◆ indexOfDefault()

int mesh::indexOfDefault ( const MeshResult mesh,
const QString &  tag 
)

Index of tag in MeshResult::infilDefaults, or -1.

Here is the caller graph for this function:

◆ infilDestFromToken()

InfilDest mesh::infilDestFromToken ( const QString &  token,
bool *  ok = nullptr 
)

◆ infilDestHint()

QString mesh::infilDestHint ( InfilDest  d)

A one-sentence tooltip for destination d: where the water goes and what the choice needs.

Replaces the former infilDestSupported(), which answered a per-release question the UI used to grey entries out with. Whether Aquifer2D works depends on the open model carrying a [2D_AQUIFER], which a static boolean cannot express — so nothing is disabled any more and the engine refuses the combination by name at resolve.

◆ infilDestLabel()

QString mesh::infilDestLabel ( InfilDest  d)
Here is the caller graph for this function:

◆ infilDestLabels()

QStringList mesh::infilDestLabels ( )
Here is the call graph for this function:

◆ infilDestToken()

QString mesh::infilDestToken ( InfilDest  d)

"LOST", …

◆ infilMethodFromToken()

InfilMethod mesh::infilMethodFromToken ( const QString &  token,
bool *  ok = nullptr 
)

◆ infilMethodLabel()

QString mesh::infilMethodLabel ( InfilMethod  m)

Translated UI label.

Here is the caller graph for this function:

◆ infilMethodLabels()

QStringList mesh::infilMethodLabels ( )

For EnumComboDelegate, in enum order.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ infilMethodToken()

QString mesh::infilMethodToken ( InfilMethod  m)

"HORTON", "CURVE_NUMBER", "NONE", …

◆ infilParamCount()

int mesh::infilParamCount ( InfilMethod  method)

Number of meaningful positional parameters for method.

◆ infilParamKey()

QByteArray mesh::infilParamKey ( InfilMethod  method,
int  slot 
)

Registry key for positional slot slot under method, e.g. "infil.f0". Empty when unused.

This is the bridge to mesh::cellParamSpecs(): the attribute table registers one column per NAMED key (the union across methods) and masks per row via infilUsesParam().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ infilParamKeys()

const QVector< QByteArray > & mesh::infilParamKeys ( )

Every named parameter key, in registration order. The attribute table and the assign dialog iterate this.

◆ infilParamLabel()

QString mesh::infilParamLabel ( InfilMethod  method,
int  slot 
)

Display label for positional slot slot under method, e.g. ("Horton", 0) → "Max Rate (f0)". Empty when unused.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ infilSlotForKey()

int mesh::infilSlotForKey ( InfilMethod  method,
const QByteArray &  key 
)

Inverse of infilParamKey(): maps a registry key to the positional slot it occupies under method, or -1 when method does not use it.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ infilUsesParam()

bool mesh::infilUsesParam ( InfilMethod  method,
int  slot 
)

True when method uses positional slot slot.

Drives the attribute table's per-row column masking: a cell whose method does not use a parameter renders "—" and refuses edits, exactly like MeshAttributeTableModel::rowIsBoundaryEdge() does for BC columns on interior edges.

Here is the caller graph for this function:

◆ loadLookupTableCsv()

bool mesh::loadLookupTableCsv ( InfilLookupTable table,
const QString &  path,
QString *  err 
)

◆ makeMappedPatch()

PatchMesh mesh::makeMappedPatch ( const QPolygonF &  ring,
const QVector< int > &  corners,
double  h,
const QString &  tag,
QString *  err = nullptr 
)

Split a CCW ring at the four corners (ring vertex indices, ring order) into polyline sides, choose n = max(1, round(mean(len0, len2)/h)), m likewise from sides 1/3, and call the polyline overload.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ makeSubmappedPatch()

PatchMesh mesh::makeSubmappedPatch ( const QPolygonF &  ring,
double  h,
const QString &  tag,
QString *  err = nullptr,
double  tolDeg = 2.0 
)

Build the submapped patch. On failure returns an empty PatchMesh and sets *err ("not rectilinear", "spacing must be > 0", "degenerate ring").

Here is the call graph for this function:
Here is the caller graph for this function:

◆ makeSweptPatch()

PatchMesh mesh::makeSweptPatch ( const SweptPatch p,
QString *  err = nullptr 
)

Sweep the centreline: (stations)×(across+1) vertices, (stations-1)×across quads. On invalid input (or a folded offset) returns an empty PatchMesh and sets *err.

Here is the call graph for this function:

◆ makeTransfinitePatch() [1/2]

PatchMesh mesh::makeTransfinitePatch ( const QVector< QVector< QPointF > > &  sides,
int  n,
int  m,
const QString &  tag,
QString *  err = nullptr 
)

Transfinite (Coons) interpolation on four POLYLINE sides forming a loop: sides[0] runs c0→c1, sides[1] c1→c2, sides[2] c2→c3, sides[3] c3→c0 (each side's last point equals the next side's first). Sides are arc-length parametrised; n subdivisions along sides 0/2, m along 1/3. Boundary vertices are placed ON the polylines (so the ring the caller emits as PSLG segments is exactly this patch's boundary loop). Returns an empty PatchMesh + *err on invalid input (side with < 2 points, endpoints not matching, n or m < 1, folded quad).

Here is the call graph for this function:

◆ makeTransfinitePatch() [2/2]

PatchMesh mesh::makeTransfinitePatch ( const StructuredPatch p,
QString *  err = nullptr 
)

Transfinite interpolation on the four straight sides. The result has (n+1)×(m+1) vertices and n×m quads. On invalid input returns an empty PatchMesh and sets *err.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mapNodesToMesh()

NodeMapResult mesh::mapNodesToMesh ( const MeshResult mesh,
const QVector< QPair< QString, QPointF > > &  nodes,
double  tol = -1.0,
bool  preserveExisting = true 
)

Map SWMM nodes onto an existing mesh.

Per node, first match wins:

  1. nearest uncoupled vertex within tol → vertex coupling;
  2. containing triangle (point-in-triangle, edges inclusive) → cell coupling with kCellCouplingDefaultCd / Area — several nodes may map to the same cell;
  3. otherwise → NodeMapResult::unmatched.
Parameters
meshTarget mesh (not modified).
nodes(node id, map xy) pairs, mesh CRS.
tolCoincidence tolerance; <= 0 uses defaultCoincidenceTol (meshautocouple.h).
preserveExistingWhen true (default), nodes that already appear as a vertex coupling or a cell-coupling row are reported in NodeMapResult::skippedExisting instead of being re-mapped. Pass false after clearing couplings for a full re-map.
Here is the call graph for this function:

◆ maximumMatching()

QVector< int > mesh::maximumMatching ( int  n,
const QVector< QPair< int, int > > &  edges 
)

Maximum-cardinality matching on a general graph — Edmonds' blossom algorithm (O(V·E)). edges are unordered pairs in [0, n). Returns mate[i] (-1 = unmatched). Exposed for the brute-force cross-check test.

Here is the caller graph for this function:

◆ meanVertexIndexSpread()

double mesh::meanVertexIndexSpread ( const MeshResult m)

Cheap locality proxy: mean |vi − vj| over the three vertex-index pairs of every triangle. O(nt), no allocation — safe to log on any mesh size.

◆ mergeTrianglePairs()

int mesh::mergeTrianglePairs ( MeshResult mesh,
const QuadMergeOptions opts,
const QSet< QPair< int, int > > &  lockedEdges,
QVector< int > *  oldToNew = nullptr 
)

Greedily merge adjacent triangle pairs of mesh into convex quads.

Parameters
meshMesh to rewrite in place. Existing quads are left as they are (they never take part in a merge).
optsAcceptance thresholds.
lockedEdgesUnordered vertex pairs (see edgeKey) that must never be merged across.
oldToNewOptional out-parameter: old cell index → new cell index. A triangle that was merged away maps to the index of the quad that absorbed it.
Returns
Number of quads created.

Pairing rules: both cells are triangles sharing exactly one edge, the edge is not locked, both tags are equal, both mannings and initDepth are equal (or both NaN), both have the same infiltration override (or none), the union is convex with every interior angle in [minAngleDeg, maxAngleDeg], and — when maxBedNonPlanarity > 0 — the four bed elevations are planar within that tolerance.

mesh.cellCouplings[].tri and the keys of mesh.infilOverrides are remapped inside; mesh.boundaryEdges are vertex pairs and stay valid.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ normalizeRingCCW()

QPolygonF mesh::normalizeRingCCW ( const QPolygonF &  ring)

Drop a closing duplicate, drop consecutive duplicates, make CCW.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pairTrianglesIntoQuads()

QuadPairingStats mesh::pairTrianglesIntoQuads ( MeshResult mesh,
const QVector< int > &  cellIds,
const QVector< QuadTemplate > &  templates,
const QSet< QPair< int, int > > &  lockedEdges,
const QuadPairingOptions opts,
QVector< int > *  oldToNew 
)

Pair the triangles cellIds (indices into mesh.triangles; every one must be a triangle) into quads. templates carry OUTPUT vertex ids. lockedEdges (mesh::edgeKey pairs) are never straddled. On return oldToNew (optional) maps every old cell index to its new index (a paired triangle maps to its quad). Region triangles that were not paired keep their tag/mannings/initDepth; a quad inherits them from its first triangle (tags of the two triangles are equal inside a region).

Here is the call graph for this function:
Here is the caller graph for this function:

◆ placeQuadPoints() [1/2]

QuadPointSet mesh::placeQuadPoints ( const QPolygonF &  ring,
const QVector< QPointF > &  seeds,
int  ringCount,
const CrossField field,
const QuadPointOptions opts 
)

Place lattice points inside ring (CCW, open) aligned to field. seeds = ring vertices (exactly ringCount of them, in ring order) followed by fixed interior points. Returns an empty set when h <= 0 or the ring has fewer than 3 vertices.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ placeQuadPoints() [2/2]

QuadPointSet mesh::placeQuadPoints ( const QPolygonF &  ring,
const QVector< QPolygonF > &  holes,
const QVector< QPointF > &  seeds,
int  ringCount,
const CrossField field,
const QuadPointOptions opts 
)

Hole-aware overload: no point is placed inside any ring of holes, and the boundary clearance is kept from the hole rings as well as from ring (QUAD_EVERYWHERE_PLAN_2026-09-07.md §3.1). An empty holes is identical to the overload above.

Here is the call graph for this function:

◆ pointInRegion()

bool mesh::pointInRegion ( const QPolygonF &  ring,
const QVector< QPolygonF > &  holes,
const QPointF &  p 
)

Inside ring and outside every ring of holes — the region's meshable interior. With no holes this is exactly pointInRing().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pointInRing()

bool mesh::pointInRing ( const QPolygonF &  ring,
const QPointF &  p 
)

Odd-even point-in-polygon (closed ring, last == first optional).

Here is the caller graph for this function:

◆ pushMeshEditsToEngine()

bool mesh::pushMeshEditsToEngine ( SWMM_Engine  engine,
const MeshResult mesh,
const QVector< MeshEdgeBC > &  bcs,
QStringList *  warnings = nullptr,
bool *  outTrianglesSynced = nullptr 
)

Copy the layer's editable mesh state into the engine's 2D mesh.

Pushes vertex elevations, per-edge conveyance factors, and per-edge boundary conditions by index. Indices line up because the layer was loaded from the same [2D_*] sections the engine parsed (file order is preserved on both sides).

Vertex Z and BC stage heads are converted from the layer's display/file units into the engine's internal SI metres using a factor derived from an (unedited) vertex's XY: engine_x / layer_x. This is exact and unit-system-agnostic — for US-FLOW_UNITS projects the engine scales the whole mesh by 0.3048 on load, so the same factor applies to Z.

Also synced: vertex coupling (MeshVertex::coupledNode -> SWMM node), the descriptive vertex/triangle TAG-column labels, per-triangle Manning's n, and SPECIFIED_FLOW discharge magnitudes (converted from the project's display flow units into the engine's SI m³/s). BC GROUP labels are not pushed (no engine setter), but the writer re-attaches them from the retained authored rows, so only a label on a brand-new edited edge would be lost.

Per-triangle INIT_DEPTH follows the same unit convention as vertex Z (it is a depth above the bed in mesh length units) and is scaled by the same derived factor.

Parameters
engineOpen engine handle with an active 2D mesh.
meshThe layer's current MeshResult.
bcsThe layer's per-edge BC vector (flat mesh::edgeSlot(cell, edge), stride mesh::kEdgeStride, sized mesh::edgeSlotCount(n_cells)); only a cell's real edges (3 or 4) are pushed. May be empty (then only Z is synced).
warningsOptional sink for non-fatal diagnostics.
outTrianglesSyncedOptional: set to true when the per-triangle attributes (Manning's n, initial depth, tag) reached the engine, false when the triangle counts disagreed and they were skipped. Callers that own the file (the save path) use this to fall back to patching the written text — the engine's mesh is stale whenever a mesh was generated or replaced in-session, and without a fallback every cell attribute edit is silently dropped on save.
Returns
true when the mesh was synced; false (with a warning) when the engine has no 2D mesh or its vertex counts do not match the layer, in which case nothing is written.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ quadAcceptable()

bool mesh::quadAcceptable ( const QuadQuality q,
const QuadQualityBounds b 
)
inline

Hard acceptance test (convex + angle bounds + SJ floor + aspect cap).

Here is the caller graph for this function:

◆ quadQuality() [1/2]

QuadQuality mesh::quadQuality ( const QPointF &  a,
const QPointF &  b,
const QPointF &  c,
const QPointF &  d 
)
inline

Metrics for corners a,b,c,d in cyclic order.

Here is the caller graph for this function:

◆ quadQuality() [2/2]

QuadQuality mesh::quadQuality ( const QVector< MeshVertex > &  vertices,
const MeshTriangle t 
)
inline

Metrics for a quad cell of mesh (t.v3 >= 0 required).

Here is the call graph for this function:

◆ quadScore()

double mesh::quadScore ( const QuadQuality q,
const QuadQualityBounds b 
)
inline

Combined score in [0,1] (plan §5): SJ · min(1, aspectMax/aspect) · sqrt(1 - skew). 0 for a non-convex quad. Used as the pairing benefit and the smoothing objective.

Here is the caller graph for this function:

◆ refineHookTestCount()

qint64 mesh::refineHookTestCount ( )
noexcept

Number of triunsuitable() invocations since the active guard was constructed. Useful for logging refinement cost.

◆ refineHookWasCancelled()

bool mesh::refineHookWasCancelled ( )
noexcept

True if the hook active on this thread observed cancellation.

Valid until the next RefineHookGuard is constructed on this thread. Because cancellation drains rather than aborts, triangulate() still returns success — callers must consult this to tell a completed mesh from an abandoned one.

Here is the caller graph for this function:

◆ reorderMeshHilbert()

void mesh::reorderMeshHilbert ( MeshResult m)

Renumber triangles along a Hilbert curve of their centroids and vertices by first appearance; remaps triangle/boundary-edge/cell-coupling indices. No-op on an empty mesh.

Here is the call graph for this function:

◆ reorderTrianglesFirst()

QVector< int > mesh::reorderTrianglesFirst ( MeshResult mesh)

Reorder cells triangles-first, stable within each class. Returns the old→new cell index map. Shared with meshquadmatch.

Here is the caller graph for this function:

◆ resampleRing()

QPolygonF mesh::resampleRing ( const QPolygonF &  ring,
double  h,
double  keepTurnDeg = 0.0 
)

Resample a closed ring at spacing h: every edge is split into max(1, round(len/h)) equal parts; ring vertices whose |turn| >= keepTurnDeg are always kept, others are kept too (geometry is never simplified here — run pslg::simplifyPolyline first). Output is CCW, open (no closing duplicate).

Here is the call graph for this function:
Here is the caller graph for this function:

◆ resolveInfil()

ResolvedInfil mesh::resolveInfil ( const MeshResult mesh,
int  tri 
)

Resolve one triangle's infiltration per engine D-I3 precedence: ‘override > tag row > ’*' row > none`.

Reads MeshResult::infilOverrides, MeshResult::infilDefaults and the triangle's MeshTriangle::tag. Never mutates the mesh.

Engine D-I3 precedence: ‘override > tag row > ’*' row > none`.

Provenance names the row's SOURCE, not whether a model ends up running: a tag row (or an override) spelling NONE still resolves to Tag / Override with an isNone() row. That distinction is load-bearing twice over — MeshSetTriangleInfilCommand::undo() uses it to decide between restoring a per-cell row and erasing the override back to inheritance, and the attribute table uses it to render a region-supplied "None" in the muted/italic inherited style rather than as a per-cell decision. The engine's own Infil2D::prov_ collapses those cases to NONE because it is solver-facing and only cares whether a kernel runs.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ringIsRectilinear()

bool mesh::ringIsRectilinear ( const QPolygonF &  ring,
double  tolDeg,
double frameAngleDeg 
)

True when every edge of the (normalised) ring is parallel to one of two perpendicular axes within tolDeg. frameAngleDeg receives the frame rotation when non-null.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ringIsSimple()

bool mesh::ringIsSimple ( const QPolygonF &  ring)

True when ring is simple (no proper self-intersection). O(n²).

Here is the caller graph for this function:

◆ ringSignedArea()

double mesh::ringSignedArea ( const QPolygonF &  ring)

Signed shoelace area (CCW positive).

Here is the caller graph for this function:

◆ ringTurnDeg()

double mesh::ringTurnDeg ( const QPolygonF &  ring,
int  i 
)

Exterior turning angle (degrees, CCW positive) at ring vertex i.

Here is the caller graph for this function:

◆ rt0CellDischarge()

bool mesh::rt0CellDischarge ( int  cell,
int  nv,
const float *  flux,
const float *  length,
const float *  nx,
const float *  ny,
double qx,
double qy 
)
inlinenoexcept

RT0 least-squares specific discharge (m²/s) of one cell from its outward-positive normal edge fluxes (m³/s).

The engine's own reconstruction (SurfaceFluxCalculator::computeFaceVelocity): with nv outward unit normals n_e and normal speeds q_e = flux_e/length_e, solve the nv×2 least-squares system N·q ≈ b via the normal equations (NᵀN) q = Nᵀ b. |q_e| is clamped to 10 against wet/dry-front spikes and a non-finite q_e is skipped so it cannot poison the 2×2 solve. Divide by the cell depth for velocity. The per-edge arrays are the flat edgeSlot layout (cell's slots are read, nothing else).

Returns
false when the normal matrix is degenerate (outputs untouched).
Here is the call graph for this function:

◆ saveLookupTableCsv()

bool mesh::saveLookupTableCsv ( const InfilLookupTable table,
const QString &  path,
QString *  err 
)

CSV round-trip. Column order: key1[,key2],method,p0,p1,p2,p3,p4,dest, # comments, header row optional.

Here is the call graph for this function:

◆ slotCell()

constexpr int mesh::slotCell ( int  slot)
constexprnoexcept

Cell / local edge of a flat slot.

Here is the caller graph for this function:

◆ slotLocal()

constexpr int mesh::slotLocal ( int  slot)
constexprnoexcept
Here is the caller graph for this function:

◆ starDefault()

InfilRow mesh::starDefault ( const MeshResult mesh)

Convenience: the '*' row from mesh, or a None row when absent.

Here is the call graph for this function:

◆ triangleArea()

double mesh::triangleArea ( const MeshResult mesh,
int  tri 
)

Unsigned area of triangle tri (|cross| / 2), in project CRS units². Returns 0 for an out-of-range triangle or one referencing out-of-range vertices.

The single definition of "cell area" in the GUI: the Metadata tab's statistics below and the Attribute Table's Cells column both read it, so a sliver hunted down by sorting the table is the same cell the min/max summary is reporting.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ triangleScaledJacobian()

double mesh::triangleScaledJacobian ( const QPointF &  a,
const QPointF &  b,
const QPointF &  c 
)
inline

Minimum sine of a triangle's angles (1 is unattainable; equilateral = 0.866; right isosceles = 0.707). Used by the smoothing guard for the triangles that remain inside a quad region.

◆ unionQuad()

bool mesh::unionQuad ( const QVector< MeshVertex > &  vertices,
const MeshTriangle t1,
const MeshTriangle t2,
MeshTriangle quad 
)

The CCW quad formed by two triangles sharing edge (p,q): returns false when they do not share exactly two vertices or the union is not a simple quad. quad receives v0..v3 (tag etc. copied from t1).

Here is the call graph for this function:
Here is the caller graph for this function:

◆ unitsHeaderIsSI()

bool mesh::unitsHeaderIsSI ( const QString &  unitsHeader)

True when unitsHeader (the verbatim ;; UNITS: value) declares a metric mesh, i.e. one the engine will NOT rescale.

Mirrors the engine's prescan2DUnitsHeader keyword set exactly — "SI (m)", "m", "metre(s)", "meter(s)", case-insensitive. Anything else, including an absent or explicitly imperial header, is not metric. Callers that need to know whether the engine converted the mesh to SI (issue #155) must apply this together with FLOW_UNITS: the engine scales only when FLOW_UNITS is US-customary AND this returns false.

◆ validate() [1/3]

QString mesh::validate ( const PatchMesh pm)

Rejects a patch with a folded / concave / degenerate quad (mesh::cellIsConvex). Empty string = valid.

Here is the call graph for this function:

◆ validate() [2/3]

QString mesh::validate ( const StructuredPatch p)

Input checks. Empty string = valid.

Here is the caller graph for this function:

◆ validate() [3/3]

QString mesh::validate ( const SweptPatch p)

◆ validateQuadRegion()

QString mesh::validateQuadRegion ( const QuadRegion r,
const QVector< QPolygonF > &  domains,
const QVector< QPolygonF > &  holes 
)

Validate one region: >= 3 distinct vertices, simple, area >= 4·h² (h = spacing when > 0, else skipped), every vertex inside exactly one of domains and outside every holes ring. Empty string = valid.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ validateQuadRegionsDisjoint()

QString mesh::validateQuadRegionsDisjoint ( const QVector< QuadRegion > &  regions)

Pairwise check: rings may share edges/vertices but no ring vertex of one may lie strictly inside another and edges may not properly cross. Returns the first offending pair as "region i overlaps region j", or "".

Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ kCellCouplingDefaultArea

constexpr double mesh::kCellCouplingDefaultArea = 2.0
constexpr

mesh length units²

◆ kCellCouplingDefaultCd

constexpr double mesh::kCellCouplingDefaultCd = 0.65
constexpr

Defaults for mapper-authored cell couplings (plan decision 2026-07-28). Vertex couplings keep the engine defaults (0.65 / 1.0). AREA is in the MESH's length units squared — the engine scales it with the mesh coordinates, so on a US project without an SI mesh tag this is 2.0 ft² (0.186 m²), not 2.0 m². [2D_OPTIONS] COUPLING_AREA AUTO overrides it from the connected conduit area either way.

◆ kEdgeStride

constexpr int mesh::kEdgeStride = 4
constexpr

Edge slots per cell in every flat per-edge array (== engine kMaxCellVerts).

◆ kInfilMaxParams

constexpr int mesh::kInfilMaxParams = 5
inlineconstexpr

Widest positional parameter count (Horton: f0 fmin decay dry_time Fmax).