Repository navigation
Claude/awesome pascal eex2py - #60
Closed
HarmenGrosseDeters wants to merge 54 commits into
Closed
HarmenGrosseDeters wants to merge 54 commits into
HarmenGrosseDeters wants to merge 54 commits into
Conversation
Analysis of the library's behavior on topologically dirty input and floating point edge cases (docs/Robustheitsanalyse.md), backed by tests: - Red tests (category "KnownBug", 20 tests) documenting confirmed bugs: crossing segments producing invalid meshes, exceptions or a stack overflow; RobustPredicates.Default not being thread-safe; Dwyer stack overflow on identical points; SimpleSmoother failing far from the origin; missing NaN/Infinity validation; vertex id heuristic; Vertex Equals/GetHashCode contract; SweepLine not exactly Delaunay. - Green regression tests for degenerate input that is handled correctly. - MeshAssert helpers (consistency, inverted triangles, segment coverage, area, termination). - Scenarios that crash or hang the process run in a child process via a custom entry point of the test assembly. - CI runs KnownBug tests separately with continue-on-error. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
- Add SegmentNoder: split crossing segments in advance (exact crossing detection), merge new vertices with existing ones within a small tolerance and snap vertices lying almost on a segment onto it. Enabled by default via ConstraintOptions.ResolveIntersections. - ConstraintMesher: replace tail recursion in ScoutSegment/ConstrainedEdge by loops, guard against non-terminating insertion and check orientation after inserting intersection vertices (never return an invalid mesh). - RobustPredicates: thread-local workspace, so instances are thread-safe. - QualityMesher: choose the point location start edge for aCute locations by orientation test (inverted triangles) and fall back to the circumcenter if the aCute location hits an existing vertex. - Dwyer/SweepLine: return an empty mesh for identical input points. - SweepLine: restore the Delaunay property by exact edge flips. - SimpleSmoother: compute centroids relative to the generator. - Mesh: reject NaN/infinite coordinates, check user ids for uniqueness. - Vertex: hash code consistent with Point.Equals. All former KnownBug tests pass and are now regular regression tests; add tests for noding and quality refinement of noded input. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
ConstraintOptions.CanSplitSegment decides, based on the subsegment (e.g. its label), whether refinement may insert vertices on a segment. Locked segments (e.g. breaklines of a terrain model) keep their input vertices, except for intersections with other segments. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
Findings from triangulating the 2156 cases of the GEOS XML test suite (overlay/noding failures reported against JTS, GEOS, PostGIS, QGIS and Shapely) as PSLGs: - SegmentNoder: merge vertices closer than the snap tolerance (exact duplicates are kept), don't snap vertices that are within the tolerance of a segment endpoint, avoid duplicate new segments. Tiny rings with coordinate noise made the noder split segments forever. - SegmentNoder: if noding doesn't converge (many nearly coincident segments), retry with a larger snap tolerance (up to 2^-32 relative, like the GEOS snapping noder), otherwise throw instead of running forever. - QualityMesher: if splitting a subsegment would create a flat or inverted triangle (exact test) or the split point coincides with an endpoint, don't split it and exclude it from further splitting instead of silently inverting triangles or throwing "Ran out of precision". Leave triangles that can't be refined instead of throwing "new vertex at circumcenter". Check orientation after refinement. - RobustPredicates: guard reads past the end of an expansion in FastExpansionSumZeroElim (IndexOutOfRangeException for infinite input). - Tests: regression tests for the above; explicit corpus tests (category "Corpus") for the GEOS test suite and for NRW open data (ALKIS parcels, DGM1), each case in a child process. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
- ConstraintOptions.SnapTolerance: minimum noder tolerance in coordinate units (e.g. 0.01 = 1 cm) merges nearly coincident lines instead of meshing slivers - SegmentNoder: don't recreate already split segments from their pieces (snap cycle with large tolerance) - Corpus harness: snap tolerance support, even tile sampling, fix coverage check for subsegments beyond segment endpoints, treat rejected non-finite input as skipped - Tests for snap tolerance and snap cycle Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
…tion cycles - If the aCute location doesn't destroy the bad triangle (it may lie outside the circumcircle), insert the circumcenter instead. Before, the triangle was dropped from the queue: maximum area violated, many triangles below the minimum angle (ALKIS tile at 30 degrees: 618 instead of 9 bad triangles). - Accept an aCute location only strictly inside the circumcircle and not on a vertex of the triangle. - Relocate each vertex at most once. Region area constraints made aCute move the same vertex back and forth (upstream: exception, then cycling until the Steiner point limit with a coarse result). - Characterization suite: scenario catalog (point sets, polygons, real ALKIS tiles x algorithms, quality, conforming, segment splitting, locked segments, area constraints, refine, smooth), invariant tests (consistency, orientation, constrained/conforming Delaunay, area, segments, locked segments, angle and area guarantees) and golden fingerprints of the exact output. - Corpus harness: configurable angles, timing and quality statistics. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
…segment A crossing close to a segment endpoint was merged into that endpoint and the segment was 'split' there. Nothing changed, but the segment was retired, so snapping a nearly collinear vertex into it was blocked. Two segments with an angle of 0.0002 degrees remained, and quality refinement spent the whole Steiner point budget in that wedge (ALKIS Herne, parcels + buildings + land use, 1 cm snapping: tile with 203,175 triangles, 154,870 below 20 degrees -> 24,355 triangles, 222 below 20 degrees). The useless splits also used up the noding iterations: stacked squares with offsets of 1e-6 now converge. Also: BenchmarkDotNet project on the characterization scenarios, corpus summary with total bad triangles and the worst cases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
…chmark baseline Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
…d vertices Behavior-neutral (all golden fingerprints unchanged): - per-call work arrays of NewLocation are fields, cleared where they used to be allocated - GetNeighborsVertex only visits the neighbor across the matching edge - DoSmoothing computes vertex stars only for vertices that can be relocated ALKIS tile, 30 degrees: 810 -> 617 ms, 104 -> 73 MB allocated. Benchmarks: TRIANGLE_BENCH_SCENARIOS selects scenarios. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
Behavior-neutral (golden fingerprints unchanged). ALKIS tile, 30 degrees: 73 -> 60 MB allocated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
Instead of inserting the vertex, flipping and undoing everything when a subsegment is encroached, the cavity is determined with the same incircle tests and its boundary subsegments are checked in the same order. For large cavities (> 64 triangles) the search stops at the first encroached subsegments. Needle-shaped regions (GEOS TestRelateAA#74, 80,000 points): 79 s -> 2.1 s. Golden fingerprints of 7 scenarios change: inserting and undoing left stale bad-triangle entries in the queue, which could come back to life when a vertex with the same coordinates was inserted later (vertices are compared by coordinates). Without them, the processing order differs slightly; vertex counts differ by 0-3, bad triangle counts and minimum angles are identical. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
If the new vertex encroached upon or lay beyond a subsegment which must not be split (SegmentSplitting 1/2, CanSplitSegment), the bad triangle was dropped for good (upstream issue wo80#9: a 10x20 rectangle with maximum area 1.73 gave 8 triangles). Now the vertex is inserted anyway if it encroaches only upon such subsegments, and a too large triangle is split at its centroid if the vertex lies beyond one. Subsegments that can't be split because of the precision limit are excluded. Tests reproducing the bug reports of the upstream issue tracker, overview in the docs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
…etry, DCEL IO: segment endpoints written by list index (IDs of contour polygons were all 0), region areas written, region areas in scientific notation read, inline comments, attribute column of 6-node elements, invariant integer formatting, case-insensitive extensions, FileProcessor with mesh-only formats, consistent node numbering with Jettison, MFEM leaves the caller's stream open. Log is thread-safe. Coordinates beyond 1e70 (where the exact predicates overflow) are rejected. Mesh: unique triangle ids after Renumber (EdgeIterator skipped edges), Renumber(CuthillMcKee) with duplicate vertices, vertices reused from another mesh are reset, Refine of a point set keeps the convex hull and uses the mesh configuration, NumberOfEdges of an empty mesh, an invalid angle option no longer disables all quality constraints. TrianglePool: Contains off-by-one, Sample covers all slots and is bounded, Clear releases all blocks. Geometry: interior point of contours (hole points) with exact inside test and clearance (hole points landed on the hole boundary with UTM coordinates, thin contours threw), Rectangle copy constructor and Intersects, Point.CompareTo null. VertexCirculator: nested enumeration, vertices not in the mesh. DCEL: boundary edges at pinch vertices, Face.Empty no longer references a mesh. Tests from the class-by-class review (Review A, D, F). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
…noi, smoothing, tools Quality: MaximumAngle alone is enforced, NewLocation work arrays sized for both wedge methods (IndexOutOfRange after refining with a maximum angle), triangles after vertex deletion are always tested (too large triangles with SegmentSplitting 1/2), VariableArea on point-set meshes, BadTriQueue clamps extreme keys. Noding: unique ids for intersection vertices (user ids were renumbered), non-zero label wins for coinciding pieces, merged vertices keep their label, hole/region points inside collapsed contours are dropped (SnapTolerance larger than a hole emptied the mesh), sweep along the axis with less overlap (long parallel segments were quadratic) with the same pair order. Regions: last region point wins (values from the region, not the seed). Converter: ToDCEL at pinch vertices, ToMesh with arbitrary vertex ids. Voronoi: unique half-edge ids, StandardVoronoi doesn't modify the box, legacy diagrams skip duplicate vertices, SimpleVoronoi bounds include the mesh, BoundedVoronoi documents the conforming requirement. SimpleSmoother: separate pool per run (reusing the smoother corrupted the previous mesh), vertices restored on cancellation, stop criterion after two real iterations. VoronoiFactory resets pooled objects. Tools: Reverse Cuthill-McKee neighbor sorting (1-based leftovers), TriangleQuadTree exact point-in-triangle test, PolygonValidator null points and segment endpoints, relative tolerance in IsPointOnSegment, BoxRay- Intersection without direction. Golden fingerprints of three SegmentSplitting=1 scenarios change (fewer bad triangles). Tests from the review (B, C, E). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
- ConstraintOptions.GridSize: snap rounding of the input to the output grid (SegmentNoder.SnapRound, iterated snap rounding with hot pixels), Steiner points rounded to the grid during refinement (no aCute relocation, no angle refinement of triangles below two grid cells, shell rule with grid tolerance), remaining vertices moved by GridSnapper.SnapVertices where no triangle flips. Rounding the output no longer flips triangles. - ConstraintOptions.WedgeTolerance: merge segments running along another segment at a small angle (thin wedges) without raising the snap tolerance. - Tools.TerrainSimplifier: greedy insertion TIN simplification with a vertical error bound (and break lines), incremental with a max-heap. - Corpus harness: grid, wedge tolerance and flipped-by-rounding statistics. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
- Split vertices are projected onto the input segment before rounding to the grid, so deviations don't add up over splitting levels. - Wedge merging checks the distance to the original input segment, so chains of wedges can't drag a segment further than the tolerance. - Corpus harness: bad triangles after rounding to the output grid. - Docs: grid, wedge and terrain simplification results on ALKIS/DGM1 Herne. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
With a grid, subsegments where no grid point is a valid split are common. Triangles whose circumcenter encroached upon such a subsegment were dropped for good, leaving large bad triangles (edges up to 40 m). The vertex is now inserted anyway, as for locked segments (the grid floor prevents a cascade). ALKIS Herne, grid 1 cm + wedge 3 cm: bad triangles after rounding 5.3 % / 6.0 % -> 2.2 % / 2.2 % at 20 / 30 degrees. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
- Cocircular points (grid data) make the Delaunay triangulation ambiguous; errors are now evaluated over all triangles of each cocircular cluster, and triangles whose cluster may have changed are re-evaluated. The final check against a triangulation built from scratch finds no violations, so it runs once (DGM1, 5 cm: 57 s -> 28 s). - Fix: points added to an existing bucket could raise its error without queueing it (bound violated in rare cases). - Errors equal to the bound up to roundoff are accepted. - Docs: grid mode results after the insert-anyway fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
Bad triangles are classified as at a small input angle, below the grid floor, in a narrow strip (another segment closer than 5 cm), at a segment or interior. ALKIS Herne, grid 1 cm + wedge 3 cm: at most 0.19 % / 0.30 % of all triangles are possibly avoidable; most lie in 2-5 cm strips. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
The aCute relocation was computed and then discarded in grid mode (24 % of the time). SnapVertices builds vertex stars only for vertices off the grid. ALKIS tile, q30, grid 1 cm + wedge 3 cm: 1155 -> 846 ms, same mesh size. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
- Triangle stores its vertices, neighbors and subsegments as fields with ref-returning accessors (same syntax as the arrays before). A triangle is now one heap object instead of four; the garbage collection time of a quality mesh is dominated by the number of live objects. - The temporary arrays of InCircleAdapt and CounterClockwiseAdapt (about 40 per call) moved to the thread-local workspace. - aCute wedge intersection: rotations computed once per call. Behavior unchanged (golden fingerprints identical). ALKIS tile, q30: snap 1 cm -5 %, grid 1 cm + wedge 3 cm -13 % (GC pauses 266 -> 166 ms, allocations 84 -> 56 MB). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
Fewer heap objects per subsegment; about 5 % fewer allocations, no measurable time difference on the ALKIS tiles. Behavior unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
The library now also targets net8.0. There, the vertices, neighbors and subsegments of triangles and subsegments are [InlineArray] buffers (array indexing, no separate heap objects). netstandard2.0 keeps plain arrays. This replaces the ref-returning accessors, which were slower than arrays for small, CPU-bound meshes. CounterClockwiseAdapt keeps its local arrays (it is called very often for collinear input). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
…ex2py Add robustness analysis and red test suite for known bugs
Taken from the SoftSmile-Inc fork: with invalid topology the walk around a vertex went back and forth between two triangles until the work array was full. Never triggers in valid meshes (a free vertex has at least three incident triangles). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
- 1000 hard orient2d and 1000 hard incircle cases (Nanevski et al.) with the expected sign: all correct. - Ruppert's maple leaf (Canadian flag) at 0/20/30/33 degrees. - Synthetic edge cases: grids (cocircular, deterministic, Delaunay with all three triangulators, also at UTM coordinates), grid with diagonal constraints and quality, concentric circles with and without hole (constraints separate inside and outside), spiky stars with tip angles down to 1e-15 rad at three scales. - Corpus readers for Natural Earth coastlines (LineStrings) and the test inputs of artem-ogre/CDT (TRIANGLE_NATURAL_EARTH, TRIANGLE_CDT_INPUTS). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
- SegmentNoder.Node: if noding doesn't converge with any tolerance, snap round to the largest tolerance instead of throwing (issue-211 of the CDT test inputs: long edges crossing a polyline at tiny angles). - SnapRound routes segments through existing hot pixels before computing new intersections (the number of vertices exploded otherwise) and allows 100 iterations. Results of inputs that converged before are unchanged. - Corpus harness: spatial index for the coverage check and the strip classification (quadratic before: timeout on Natural Earth 10m), strip width relative to the extent, Steiner limit detected like the library. - Docs: performance results (interleaved A/B), standard CDT benchmarks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
Triangles and subsegments can store vertices, neighbors and subsegments as plain fields accessed through ref indexers, so .NET Framework 4.8 gets one heap object per triangle instead of four. Default stays InlineArray on net8.0 and arrays on netstandard2.0. Benchmarks also target net48. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
QualityOptions.ReduceSteinerPoints deletes free Steiner points whose retriangulated cavity meets all quality constraints, or collapses an edge to a free neighbor when that makes the point removable (exactly undoable flips otherwise). QualityOptions.SmoothingSteps moves free Steiner points towards the optimal Delaunay triangulation position (grid-rounded) and keeps only moves that improve the changed triangles. Input vertices, segments and segment vertices are never changed. Herne tile 30 deg with 1 cm grid: 17-18% fewer triangles and fewer bad triangles. Tests cover all catalog scenarios with full invariants. Docs: research summary and .NET 10 layout benchmark (Fields slower). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
TRIANGLE_CORPUS_REDUCE, TRIANGLE_CORPUS_SMOOTH and TRIANGLE_CORPUS_CONFORMING set the corresponding mesher options for the external corpus tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
…asurements Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
…ly too large aCute tried to relocate a vertex of every bad triangle whose off-center lies beyond the circumcenter, which includes all triangles that are bad only by area. Relocation improves angles, so it rarely helped there and cost ~80% of the time (unit square, area 0.001: 148 -> 14 ms, same triangle count). Only regions/q25-variable-area changes (463 -> 464 vertices). The encroachment pre-check now returns early when no boundary subsegment of the cavity is encroached, before building the boundary map (legacy area refinement back to upstream speed). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
… docs A hole contour without interior (all points on a line, fewer than three distinct points) no longer throws in Polygon.Add: it removes nothing, so its edges are added as segments (earcut fixtures water-huge, issue83). CorpusTest.PublicFixtures runs the test fixtures of mapbox/earcut, mapbox/delaunator and jhasse/poly2tri (TRIANGLE_PUBLIC_FIXTURES): 273 runs, all valid. Docs: comparison with upstream Triangle.NET, delaunator-sharp and BurstTriangulator (Delaunay grid/random, Lake Superior refinement). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
…al Earth polygons Prototype (Triangle.Tests/Prototype): the divide-and-conquer triangulation on arrays (vertices and encoded neighbors per triangle) instead of objects, same result. 1.05-1.8x faster on net10 with InlineArray, 1.2-2.4x with the array layout of net48, up to 3.2x with a small gen0 budget. Corpus tests CgalData (Polygon_repair, Straight_skeleton_2) and NaturalEarthPolygons (10m layers as a whole and per feature). Docs: results for ALKIS Muenster, Koeln, Hoexter, CGAL, Natural Earth polygons. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
Triangles get a mark field; the cavity search uses a per-mesh stamp (Mesh.NextMark) instead of a HashSet, whose Clear cost grows with the largest cavity seen. Results identical (all golden fingerprints unchanged); Herne tile 30 deg with grid -6%. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
…the first relocatable vertex 72% of the half-plane intersections in the wedge computation leave the polygon unchanged and 2% empty it; these are detected by the signs of the vertices (with a margin that rules out the tolerance cases of the general code) and give the same result. DoSmoothing returns as soon as the origin (or destination) can be relocated, since that result was preferred anyway. Results identical (all golden fingerprints unchanged); Herne tile 30 deg -4%. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
PredicatesBenchmark measures the orientation and incircle tests through the interface, directly and as an experimental fast path (same arithmetic and bounds, checked against the library). Fast path 4-8 ns, exact stages on grid data 140 ns; the predicates cost about 2% of a quality mesh, no worthwhile optimization (documented). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
Triangle is now a handle (pool + index) to the data of the triangle in the arrays of the TrianglePool: vertices, neighbors (encoded index << 2 | orient), subsegments, ids, labels, area constraints, infection and search marks. The outer space triangle is position 0 of the pool. Otri, the mesh primitives and the algorithms are unchanged except for the few places that wrote neighbor references directly or compared triangles with null (now errors, CS8073). Public API: Triangle is a readonly struct implementing ITriangle; two handles are equal if they refer to the same triangle (ITriangle values from a mesh must be compared with Equals, not ==). TrianglePool keeps its API, so reusing a pool across meshes (Configuration) reuses the arrays. All tests pass, all golden fingerprints unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
…outer space triangle, pre-sized pool Otri stores the pool and index directly (16 instead of 24 bytes); the 73 checks against the outer space triangle compare the index with 0 instead of reading the id from the pool; the pool is sized for 2n triangles of n input points. All tests pass, golden fingerprints unchanged. BenchmarkDotNet against the object layouts (net10): large Herne tiles equal (snap) or 9% faster (grid) than InlineArray and 10-13% faster than the array layout of net48; small meshes 10-16% slower than InlineArray. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
…ex2py Claude/awesome pascal eex2py
…mple, viewer IndexBuffer.Create takes any IEnumerable<T> of ITriangle (mesh.Triangles is a collection of Triangle values; covariance doesn't apply to value types). Example7 casts the quad tree result instead of 'as'; the viewer compares the handle with default instead of null. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
Debug-Tests dauern rund 15 Minuten, Release rund 3,5 Minuten. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
Debug-Tests dauern rund 15 Minuten, Release rund 3,5 Minuten. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
Claude/index struktur
Ganze Natural-Earth-Ebenen (z. B. US-Landkreise, 148.000 Punkte) brauchen mehr als die festen 100.000 Steiner-Punkte. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
Öffentliche Fixtures von earcut, delaunator und poly2tri, an denen das ursprüngliche Triangle.NET scheitert (Exception, Endlosschleife, inkonsistentes Netz), jetzt fest im Repo und im CI: je ohne Qualität, 20° und 30°. Dazu die fast deckungsgleiche Hin-und-zurück-Grenze aus den Natural-Earth-US-Landkreisen (Steiner-Limit greift; mit Snap-Toleranz keine schlechten Dreiecke). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
Bei sehr kleinen oder sehr großen Koordinaten werden die Produkte subnormal bzw. unendlich; dann gelten Shewchuks Fehlerschranken nicht und das Vorzeichen war falsch (InCircle ab 1e-100 bzw. 1e100 etwa die Hälfte der fast kozirkulären Fälle, Orient ab 1e-160) oder NaN. - Orient: Absicherung nur in den Zweigen, in denen Unterlauf das Vorzeichen ändern kann (Produkt null, Filter bei subnormaler Summe). - InCircle: Filter nur, wenn alle Differenzen 0 oder in [2^-200, 2^200] liegen (ein subnormales Produkt mal großem Lift kann die Schranke sonst überschreiten). - Adaptive Stufen nur für Koordinaten in [2^-100, 2^100] (oder 0), sonst exaktes Vorzeichen mit BigInteger. Idee aus geometry3Sharp (ExactPredicates). Normale Daten: Orient unverändert, InCircle etwa 3 ns langsamer pro Aufruf. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012bnBWGQoVJCM7Rtx2a6Z86
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.