trenchfoot 0.1.1__tar.gz → 0.2.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of trenchfoot might be problematic. Click here for more details.

Files changed (118) hide show
  1. trenchfoot-0.2.3/.env +1 -0
  2. trenchfoot-0.2.3/CHANGELOG.md +52 -0
  3. trenchfoot-0.2.3/CLAUDE.md +68 -0
  4. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/PKG-INFO +16 -18
  5. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/README.md +15 -17
  6. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/docs/scenario_gallery.md +1 -0
  7. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/generate_scenarios.py +104 -27
  8. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/gmsh_sloped_trench_mesher.py +125 -25
  9. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/scenarios/S01_straight_vwalls/metrics.json +4 -4
  10. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S01_straight_vwalls/preview_oblique.png +0 -0
  11. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S01_straight_vwalls/preview_side.png +0 -0
  12. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S01_straight_vwalls/preview_top.png +0 -0
  13. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/scenarios/S01_straight_vwalls/scene.json +2 -2
  14. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S01_straight_vwalls/trench_scene.obj +49 -0
  15. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S01_straight_vwalls/volumetric/trench_volume.msh +755 -0
  16. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/scenarios/S02_straight_slope_pipe/metrics.json +10 -10
  17. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S02_straight_slope_pipe/preview_oblique.png +0 -0
  18. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S02_straight_slope_pipe/preview_side.png +0 -0
  19. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S02_straight_slope_pipe/preview_top.png +0 -0
  20. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/scenarios/S02_straight_slope_pipe/scene.json +3 -3
  21. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S02_straight_slope_pipe/trench_scene.obj +14407 -0
  22. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S02_straight_slope_pipe/volumetric/trench_volume.msh +2114 -0
  23. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/metrics.json +42 -0
  24. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/preview_oblique.png +0 -0
  25. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/preview_side.png +0 -0
  26. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/preview_top.png +0 -0
  27. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/scene.json +4 -4
  28. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/trench_scene.obj +10547 -10540
  29. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/volumetric/trench_volume.msh +3797 -0
  30. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S04_U_slope_multi_noise/metrics.json +46 -0
  31. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S04_U_slope_multi_noise/preview_oblique.png +0 -0
  32. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S04_U_slope_multi_noise/preview_side.png +0 -0
  33. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S04_U_slope_multi_noise/preview_top.png +0 -0
  34. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/scenarios/S04_U_slope_multi_noise/scene.json +8 -7
  35. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/scenarios/S04_U_slope_multi_noise/trench_scene.obj +17999 -17988
  36. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S04_U_slope_multi_noise/volumetric/trench_volume.msh +6095 -0
  37. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S05_wide_slope_pair/metrics.json +42 -0
  38. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S05_wide_slope_pair/preview_oblique.png +0 -0
  39. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S05_wide_slope_pair/preview_side.png +0 -0
  40. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S05_wide_slope_pair/preview_top.png +0 -0
  41. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/scenarios/S05_wide_slope_pair/scene.json +6 -6
  42. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S05_wide_slope_pair/trench_scene.obj +28810 -0
  43. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S05_wide_slope_pair/volumetric/trench_volume.msh +5081 -0
  44. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S06_bumpy_wide_loop/metrics.json +43 -0
  45. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S06_bumpy_wide_loop/preview_oblique.png +0 -0
  46. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S06_bumpy_wide_loop/preview_side.png +0 -0
  47. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S06_bumpy_wide_loop/preview_top.png +0 -0
  48. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/scenarios/S06_bumpy_wide_loop/scene.json +6 -6
  49. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/scenarios/S06_bumpy_wide_loop/trench_scene.obj +12812 -12793
  50. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S06_bumpy_wide_loop/volumetric/trench_volume.msh +10402 -0
  51. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S07_circular_well/metrics.json +48 -0
  52. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S07_circular_well/preview_oblique.png +0 -0
  53. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S07_circular_well/preview_side.png +0 -0
  54. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S07_circular_well/preview_top.png +0 -0
  55. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S07_circular_well/scene.json +203 -0
  56. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S07_circular_well/trench_scene.obj +64401 -0
  57. trenchfoot-0.2.3/packages/trenchfoot/scenarios/S07_circular_well/volumetric/trench_volume.msh +22370 -0
  58. trenchfoot-0.2.3/packages/trenchfoot/scenarios/SUMMARY.json +470 -0
  59. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/trench_scene_generator_v3.py +311 -46
  60. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/pyproject.toml +1 -1
  61. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/tests/test_trenchfoot_generation.py +203 -0
  62. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/uv.lock +1 -1
  63. trenchfoot-0.1.1/.env +0 -1
  64. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S01_straight_vwalls/preview_oblique.png +0 -0
  65. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S01_straight_vwalls/preview_side.png +0 -0
  66. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S01_straight_vwalls/preview_top.png +0 -0
  67. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S01_straight_vwalls/trench_scene.obj +0 -46
  68. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S01_straight_vwalls/volumetric/trench_volume.msh +0 -1017
  69. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S02_straight_slope_pipe/preview_oblique.png +0 -0
  70. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S02_straight_slope_pipe/preview_side.png +0 -0
  71. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S02_straight_slope_pipe/preview_top.png +0 -0
  72. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S02_straight_slope_pipe/trench_scene.obj +0 -14404
  73. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S02_straight_slope_pipe/volumetric/trench_volume.msh +0 -2389
  74. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/metrics.json +0 -42
  75. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/preview_oblique.png +0 -0
  76. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/preview_side.png +0 -0
  77. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/preview_top.png +0 -0
  78. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/volumetric/trench_volume.msh +0 -4463
  79. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S04_U_slope_multi_noise/metrics.json +0 -46
  80. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S04_U_slope_multi_noise/preview_oblique.png +0 -0
  81. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S04_U_slope_multi_noise/preview_side.png +0 -0
  82. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S04_U_slope_multi_noise/preview_top.png +0 -0
  83. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S04_U_slope_multi_noise/volumetric/trench_volume.msh +0 -7610
  84. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S05_wide_slope_pair/metrics.json +0 -42
  85. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S05_wide_slope_pair/preview_oblique.png +0 -0
  86. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S05_wide_slope_pair/preview_side.png +0 -0
  87. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S05_wide_slope_pair/preview_top.png +0 -0
  88. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S05_wide_slope_pair/trench_scene.obj +0 -28803
  89. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S06_bumpy_wide_loop/metrics.json +0 -43
  90. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S06_bumpy_wide_loop/preview_oblique.png +0 -0
  91. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S06_bumpy_wide_loop/preview_side.png +0 -0
  92. trenchfoot-0.1.1/packages/trenchfoot/scenarios/S06_bumpy_wide_loop/preview_top.png +0 -0
  93. trenchfoot-0.1.1/packages/trenchfoot/scenarios/SUMMARY.json +0 -159
  94. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/.github/workflows/ci.yml +0 -0
  95. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/.github_token.env +0 -0
  96. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/LICENSE +0 -0
  97. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/STATUS.md +0 -0
  98. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/__init__.py +0 -0
  99. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/Dockerfile +0 -0
  100. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/README.md +0 -0
  101. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/__init__.py +0 -0
  102. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/plot_mesh.py +0 -0
  103. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/render_colors.py +0 -0
  104. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/scenarios/S01_straight_vwalls/meshes/trench_scene_culled.obj +0 -0
  105. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/scenarios/S01_straight_vwalls/point_clouds/culled/resolution0p050.pth +0 -0
  106. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/scenarios/S01_straight_vwalls/point_clouds/full/resolution0p050.pth +0 -0
  107. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/scenarios/S01_straight_vwalls/preview.png +0 -0
  108. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/scenarios/S02_straight_slope_pipe/meshes/trench_scene_culled.obj +0 -0
  109. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/scenarios/S02_straight_slope_pipe/point_clouds/culled/resolution0p050.pth +0 -0
  110. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/scenarios/S02_straight_slope_pipe/point_clouds/full/resolution0p050.pth +0 -0
  111. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/scenarios/S02_straight_slope_pipe/preview.png +0 -0
  112. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/meshes/trench_scene_culled.obj +0 -0
  113. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/point_clouds/culled/resolution0p050.pth +0 -0
  114. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/point_clouds/full/resolution0p050.pth +0 -0
  115. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/preview.png +0 -0
  116. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/scenarios/S04_U_slope_multi_noise/meshes/trench_scene_culled.obj +0 -0
  117. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/scenarios/S04_U_slope_multi_noise/preview.png +0 -0
  118. {trenchfoot-0.1.1 → trenchfoot-0.2.3}/packages/trenchfoot/scene_spec_example.json +0 -0
trenchfoot-0.2.3/.env ADDED
@@ -0,0 +1 @@
1
+ PYPI_API_TOKEN=pypi-AgEIcHlwaS5vcmcCJGZjZTM1MzQwLTFiZGQtNGQ5MS1hNzIyLTc1MmU1YTJhYzE1NQACGFsxLFsicHl0ZXN0LWNocm9uaWNsZSJdXQACLFsyLFsiMzg4ZTYxZTMtMDk2NC00ZjNiLWE5ODItYzc4NTMxNDlhM2FjIl1dAAAGID45Pzb1Xm05EgS5M8C2_5BbgSEULSUwP3GpDCia6vTP
@@ -0,0 +1,52 @@
1
+ # Changelog
2
+
3
+ ## [0.2.3] - 2025-12-20
4
+
5
+ ### Fixed
6
+ - **Closed path offset direction bug**: `_offset_closed_polyline` was using CCW rotation for normals, causing positive offsets to go inward instead of outward. Fixed to use CW rotation for correct outward-pointing normals on CCW polygons.
7
+ - **Circular well ground surface**: Removed incorrect center island from closed path ground surfaces. For circular wells, only the outer ground ring exists, leaving the trench opening completely open.
8
+
9
+ ### Added
10
+ - **Open-topped trench tests**: New tests to verify trenches are truly open (no geometry covering the trench opening):
11
+ - `test_trench_opening_is_open_for_straight_trench`
12
+ - `test_circular_well_trench_opening_is_open`
13
+ - `test_ground_surface_annular_structure`
14
+
15
+ ## [0.2.2] - 2025-12-20
16
+
17
+ ### Fixed
18
+ - **Closed path handling for S07 circular well**: Explicitly close the circular path by repeating the first point. The previous heuristic was incorrectly detecting L-shaped and U-shaped paths as closed.
19
+ - **Volumetric meshing for closed paths**: Added proper annular geometry support to the gmsh mesher for closed circular paths with outer and inner walls.
20
+
21
+ ## [0.2.1] - 2025-12-20
22
+
23
+ ### Fixed
24
+ - **Annular triangulation bug**: Ground plane was incorrectly filling in the trench opening with triangles instead of leaving it as a hole. Replaced bridge+ear-clipping algorithm with proper annular triangulation that "zips" around both polygon boundaries.
25
+
26
+ ## [0.2.0] - 2025-12-19
27
+
28
+ ### Added
29
+ - **S07 circular well scenario**: Deep cylindrical well with 4 criss-crossing pipes at different elevations and diameters
30
+ - **Offset polygon ground plane**: Ground surface now follows trench outline instead of axis-aligned bounding box, reducing wasted space for L-shaped, U-shaped, and curved trenches
31
+ - **Open-topped trenches**: Trench cap (`trench_cap_for_volume`) is kept internally for metrics calculations but excluded from OBJ export and preview renders
32
+ - New tests for cap exclusion, offset ground, and circular well scenario
33
+
34
+ ### Changed
35
+ - **Shallower trench depths**: All scenarios adjusted to be less extreme (S01: 0.6m, S02: 0.9m, S03: 1.1m, S04: 1.2m, S05: 0.7m, S06: 0.85m)
36
+ - Reduced ground `size_margin` values to work better with offset polygon ground
37
+ - Pipe z-positions adjusted proportionally to fit within shallower trenches
38
+
39
+ ### Fixed
40
+ - Ground plane no longer wastes space on flat areas away from the trench path
41
+
42
+ ## [0.1.1] - 2025-10-30
43
+
44
+ - CI hardening for PyPI token handling
45
+ - Initial PyPI release
46
+
47
+ ## [0.1.0] - 2025-10-30
48
+
49
+ - Initial release with surface and volumetric mesh generation
50
+ - Scenarios S01-S06 with increasing complexity
51
+ - Plotly HTML viewer support
52
+ - Python SDK with `generate_surface_mesh()` and `generate_trench_volume()`
@@ -0,0 +1,68 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ Trenchfoot is a synthetic trench mesh generator that produces surface meshes (OBJ) and volumetric meshes (via Gmsh). It generates semi-realistic trench scenes with embedded pipes, boxes, and spheres, useful for creating synthetic datasets.
8
+
9
+ ## Commands
10
+
11
+ ```bash
12
+ # Install with uv (development)
13
+ uv pip install -e ".[dev,preview,mesher,viz]"
14
+
15
+ # Run tests
16
+ uv run pytest -rs
17
+
18
+ # Run a single test
19
+ uv run pytest tests/test_trenchfoot_generation.py::test_build_scene_produces_surface -v
20
+
21
+ # Generate scenario previews (writes to TRENCHFOOT_SCENARIO_OUT_ROOT or packages/trenchfoot/scenarios/)
22
+ uv run python -m trenchfoot.generate_scenarios --preview --skip-volumetric
23
+
24
+ # Generate with volumetric meshes (requires gmsh)
25
+ uv run python -m trenchfoot.generate_scenarios --volumetric --lc 0.4
26
+
27
+ # Generate gallery markdown
28
+ uv run python -m trenchfoot.generate_scenarios --preview --skip-volumetric --gallery docs/scenario_gallery.md
29
+
30
+ # Interactive Plotly mesh viewer (requires viz extra)
31
+ trenchfoot-plot path/to/trench_scene.obj --open
32
+ ```
33
+
34
+ Set `TRENCHFOOT_SCENARIO_OUT_ROOT=/tmp/trench-previews` to keep generated assets out of the repository.
35
+
36
+ ## Architecture
37
+
38
+ The package lives in `packages/trenchfoot/` with these core modules:
39
+
40
+ - **`trench_scene_generator_v3.py`**: Surface mesh generator. Produces OBJ files with polyline trenches, sloped walls, ground planes, and embedded geometry (pipes/boxes/spheres). Handles noise application and preview rendering. Key types: `SceneSpec`, `SurfaceMeshResult`.
41
+
42
+ - **`gmsh_sloped_trench_mesher.py`**: Volumetric mesher using Gmsh. Creates tetrahedral meshes with physical groups (`TrenchAir`, `Pipe0`, etc.). Has adaptive clearance logic that scales guard bands based on pipe radius and wall slope. Key types: `VolumeMeshResult`.
43
+
44
+ - **`generate_scenarios.py`**: CLI and scenario runner. Defines preset scenarios (S01-S06) and orchestrates both surface and volumetric generation. Handles gallery markdown output and SUMMARY.json diagnostics.
45
+
46
+ - **`__init__.py`**: Public API exports. Gracefully handles missing gmsh dependency.
47
+
48
+ ## Scene Specification
49
+
50
+ Trenches are defined by JSON specs with:
51
+ - `path_xy`: 2D polyline defining trench centerline
52
+ - `width`, `depth`, `wall_slope`: Cross-section parameters
53
+ - `ground`: Elevation, slope, and margin for ground plane
54
+ - `pipes`, `boxes`, `spheres`: Embedded objects positioned along the trench
55
+ - `noise`: Perlin-style surface perturbation settings
56
+
57
+ Objects use `s` or `s_center` (0-1 arc-length parameter) to position along the trench path.
58
+
59
+ ## Optional Dependencies
60
+
61
+ - `[preview]` - matplotlib for PNG previews
62
+ - `[mesher]` - gmsh for volumetric mesh generation
63
+ - `[viz]` - plotly for interactive HTML viewers
64
+ - `[dev]` - pytest
65
+
66
+ ## Testing Notes
67
+
68
+ Tests skip volumetric tests if gmsh runtime prerequisites (e.g., libGLU) are unavailable. The `_require_gmsh_runtime()` helper handles this gracefully.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: trenchfoot
3
- Version: 0.1.1
3
+ Version: 0.2.3
4
4
  Summary: Synthetic trench scenario generator bundle (surfaces + volumetrics).
5
5
  Author: Liam Moore
6
6
  License-File: LICENSE
@@ -43,29 +43,27 @@ Color key: trench surfaces use warm soil tones; embedded geometry is colour-code
43
43
  | S04_U_slope_multi_noise | ![S04 top](packages/trenchfoot/scenarios/S04_U_slope_multi_noise/preview_top.png) | ![S04 side](packages/trenchfoot/scenarios/S04_U_slope_multi_noise/preview_side.png) | ![S04 oblique](packages/trenchfoot/scenarios/S04_U_slope_multi_noise/preview_oblique.png) |
44
44
  | S05_wide_slope_pair | ![S05 top](packages/trenchfoot/scenarios/S05_wide_slope_pair/preview_top.png) | ![S05 side](packages/trenchfoot/scenarios/S05_wide_slope_pair/preview_side.png) | ![S05 oblique](packages/trenchfoot/scenarios/S05_wide_slope_pair/preview_oblique.png) |
45
45
  | S06_bumpy_wide_loop | ![S06 top](packages/trenchfoot/scenarios/S06_bumpy_wide_loop/preview_top.png) | ![S06 side](packages/trenchfoot/scenarios/S06_bumpy_wide_loop/preview_side.png) | ![S06 oblique](packages/trenchfoot/scenarios/S06_bumpy_wide_loop/preview_oblique.png) |
46
+ | S07_circular_well | ![S07 top](packages/trenchfoot/scenarios/S07_circular_well/preview_top.png) | ![S07 side](packages/trenchfoot/scenarios/S07_circular_well/preview_side.png) | ![S07 oblique](packages/trenchfoot/scenarios/S07_circular_well/preview_oblique.png) |
46
47
 
47
- ### S06 preset at a glance
48
+ ### S07 circular well preset
49
+
50
+ A deep cylindrical well with criss-crossing pipes at different elevations:
48
51
 
49
52
  ```json
50
53
  {
51
- "path_xy": [[0, 0], [4, -1], [8, 0], [8, 5], [2, 5], [-1, 2]],
52
- "width": 2.6,
53
- "depth": 1.4,
54
- "wall_slope": 0.12,
55
- "ground": {"z0": 0.2, "slope": [0.015, 0.03], "size_margin": 7.0},
54
+ "path_xy": "<<32-vertex circle approximation, radius=1.5>>",
55
+ "width": 2.0,
56
+ "depth": 2.5,
57
+ "wall_slope": 0.05,
58
+ "ground": {"z0": 0.0, "slope": [0.0, 0.0], "size_margin": 2.0},
56
59
  "pipes": [
57
- {"radius": 0.18, "length": 6.0, "angle_deg": 35, "s_center": 0.3, "z": -0.9, "offset_u": 0.35},
58
- {"radius": 0.14, "length": 4.8, "angle_deg": -40, "s_center": 0.6, "z": -0.95, "offset_u": -0.45}
60
+ {"radius": 0.20, "length": 4.0, "angle_deg": 0, "s_center": 0.25, "z": -0.5},
61
+ {"radius": 0.15, "length": 3.5, "angle_deg": 45, "s_center": 0.5, "z": -1.2},
62
+ {"radius": 0.10, "length": 3.0, "angle_deg": -60, "s_center": 0.75, "z": -1.8},
63
+ {"radius": 0.12, "length": 3.2, "angle_deg": 90, "s_center": 0.0, "z": -2.2}
59
64
  ],
60
- "spheres": [{"radius": 0.35, "s": 0.82, "offset_u": 0.3, "z": -0.65}],
61
- "noise": {
62
- "enable": true,
63
- "amplitude": 0.035,
64
- "corr_length": 0.5,
65
- "octaves": 4,
66
- "gain": 0.55,
67
- "apply_to": ["trench_walls", "trench_bottom", "pipe*_pipe_side"]
68
- }
65
+ "spheres": [{"radius": 0.25, "s": 0.4, "z": -1.5}],
66
+ "noise": {"enable": true, "amplitude": 0.02, "corr_length": 0.4, "octaves": 2, "gain": 0.5}
69
67
  }
70
68
  ```
71
69
 
@@ -25,29 +25,27 @@ Color key: trench surfaces use warm soil tones; embedded geometry is colour-code
25
25
  | S04_U_slope_multi_noise | ![S04 top](packages/trenchfoot/scenarios/S04_U_slope_multi_noise/preview_top.png) | ![S04 side](packages/trenchfoot/scenarios/S04_U_slope_multi_noise/preview_side.png) | ![S04 oblique](packages/trenchfoot/scenarios/S04_U_slope_multi_noise/preview_oblique.png) |
26
26
  | S05_wide_slope_pair | ![S05 top](packages/trenchfoot/scenarios/S05_wide_slope_pair/preview_top.png) | ![S05 side](packages/trenchfoot/scenarios/S05_wide_slope_pair/preview_side.png) | ![S05 oblique](packages/trenchfoot/scenarios/S05_wide_slope_pair/preview_oblique.png) |
27
27
  | S06_bumpy_wide_loop | ![S06 top](packages/trenchfoot/scenarios/S06_bumpy_wide_loop/preview_top.png) | ![S06 side](packages/trenchfoot/scenarios/S06_bumpy_wide_loop/preview_side.png) | ![S06 oblique](packages/trenchfoot/scenarios/S06_bumpy_wide_loop/preview_oblique.png) |
28
+ | S07_circular_well | ![S07 top](packages/trenchfoot/scenarios/S07_circular_well/preview_top.png) | ![S07 side](packages/trenchfoot/scenarios/S07_circular_well/preview_side.png) | ![S07 oblique](packages/trenchfoot/scenarios/S07_circular_well/preview_oblique.png) |
28
29
 
29
- ### S06 preset at a glance
30
+ ### S07 circular well preset
31
+
32
+ A deep cylindrical well with criss-crossing pipes at different elevations:
30
33
 
31
34
  ```json
32
35
  {
33
- "path_xy": [[0, 0], [4, -1], [8, 0], [8, 5], [2, 5], [-1, 2]],
34
- "width": 2.6,
35
- "depth": 1.4,
36
- "wall_slope": 0.12,
37
- "ground": {"z0": 0.2, "slope": [0.015, 0.03], "size_margin": 7.0},
36
+ "path_xy": "<<32-vertex circle approximation, radius=1.5>>",
37
+ "width": 2.0,
38
+ "depth": 2.5,
39
+ "wall_slope": 0.05,
40
+ "ground": {"z0": 0.0, "slope": [0.0, 0.0], "size_margin": 2.0},
38
41
  "pipes": [
39
- {"radius": 0.18, "length": 6.0, "angle_deg": 35, "s_center": 0.3, "z": -0.9, "offset_u": 0.35},
40
- {"radius": 0.14, "length": 4.8, "angle_deg": -40, "s_center": 0.6, "z": -0.95, "offset_u": -0.45}
42
+ {"radius": 0.20, "length": 4.0, "angle_deg": 0, "s_center": 0.25, "z": -0.5},
43
+ {"radius": 0.15, "length": 3.5, "angle_deg": 45, "s_center": 0.5, "z": -1.2},
44
+ {"radius": 0.10, "length": 3.0, "angle_deg": -60, "s_center": 0.75, "z": -1.8},
45
+ {"radius": 0.12, "length": 3.2, "angle_deg": 90, "s_center": 0.0, "z": -2.2}
41
46
  ],
42
- "spheres": [{"radius": 0.35, "s": 0.82, "offset_u": 0.3, "z": -0.65}],
43
- "noise": {
44
- "enable": true,
45
- "amplitude": 0.035,
46
- "corr_length": 0.5,
47
- "octaves": 4,
48
- "gain": 0.55,
49
- "apply_to": ["trench_walls", "trench_bottom", "pipe*_pipe_side"]
50
- }
47
+ "spheres": [{"radius": 0.25, "s": 0.4, "z": -1.5}],
48
+ "noise": {"enable": true, "amplitude": 0.02, "corr_length": 0.4, "octaves": 2, "gain": 0.5}
51
49
  }
52
50
  ```
53
51
 
@@ -6,3 +6,4 @@
6
6
  | S04_U_slope_multi_noise | ![S04_U_slope_multi_noise top](../packages/trenchfoot/scenarios/S04_U_slope_multi_noise/preview_top.png) | ![S04_U_slope_multi_noise side](../packages/trenchfoot/scenarios/S04_U_slope_multi_noise/preview_side.png) | ![S04_U_slope_multi_noise oblique](../packages/trenchfoot/scenarios/S04_U_slope_multi_noise/preview_oblique.png) |
7
7
  | S05_wide_slope_pair | ![S05_wide_slope_pair top](../packages/trenchfoot/scenarios/S05_wide_slope_pair/preview_top.png) | ![S05_wide_slope_pair side](../packages/trenchfoot/scenarios/S05_wide_slope_pair/preview_side.png) | ![S05_wide_slope_pair oblique](../packages/trenchfoot/scenarios/S05_wide_slope_pair/preview_oblique.png) |
8
8
  | S06_bumpy_wide_loop | ![S06_bumpy_wide_loop top](../packages/trenchfoot/scenarios/S06_bumpy_wide_loop/preview_top.png) | ![S06_bumpy_wide_loop side](../packages/trenchfoot/scenarios/S06_bumpy_wide_loop/preview_side.png) | ![S06_bumpy_wide_loop oblique](../packages/trenchfoot/scenarios/S06_bumpy_wide_loop/preview_oblique.png) |
9
+ | S07_circular_well | ![S07_circular_well top](../packages/trenchfoot/scenarios/S07_circular_well/preview_top.png) | ![S07_circular_well side](../packages/trenchfoot/scenarios/S07_circular_well/preview_side.png) | ![S07_circular_well oblique](../packages/trenchfoot/scenarios/S07_circular_well/preview_oblique.png) |
@@ -135,18 +135,35 @@ def gmsh_available() -> bool:
135
135
  return _gmsh_mesher is not None
136
136
 
137
137
 
138
+ def _generate_circular_path(
139
+ center: tuple[float, float], radius: float, n_vertices: int = 32
140
+ ) -> List[List[float]]:
141
+ """Generate vertices for a closed circular polyline.
142
+
143
+ The path is explicitly closed by repeating the first point at the end.
144
+ This ensures proper handling as a closed loop in mesh generation.
145
+ """
146
+ import math
147
+ cx, cy = center
148
+ angles = [2 * math.pi * i / n_vertices for i in range(n_vertices)]
149
+ points = [[cx + radius * math.cos(a), cy + radius * math.sin(a)] for a in angles]
150
+ # Close the path by repeating the first point
151
+ points.append(points[0].copy())
152
+ return points
153
+
154
+
138
155
  def default_scenarios() -> List[ScenarioDefinition]:
139
- """Built-in scenario presets."""
156
+ """Built-in scenario presets with shallower depths and offset polygon ground."""
140
157
  return [
141
158
  ScenarioDefinition(
142
159
  "S01_straight_vwalls",
143
160
  {
144
161
  "path_xy": [[0, 0], [5, 0]],
145
162
  "width": 1.0,
146
- "depth": 1.0,
163
+ "depth": 0.6,
147
164
  "wall_slope": 0.0,
148
165
  "ground_margin": 0.5,
149
- "ground": {"z0": 0.0, "slope": [0.0, 0.0], "size_margin": 3.0},
166
+ "ground": {"z0": 0.0, "slope": [0.0, 0.0], "size_margin": 1.0},
150
167
  "pipes": [],
151
168
  "boxes": [],
152
169
  "spheres": [],
@@ -158,17 +175,17 @@ def default_scenarios() -> List[ScenarioDefinition]:
158
175
  {
159
176
  "path_xy": [[0, 0], [6, 0]],
160
177
  "width": 1.2,
161
- "depth": 1.5,
178
+ "depth": 0.9,
162
179
  "wall_slope": 0.2,
163
180
  "ground_margin": 0.5,
164
- "ground": {"z0": 0.0, "slope": [0.0, 0.0], "size_margin": 3.0},
181
+ "ground": {"z0": 0.0, "slope": [0.0, 0.0], "size_margin": 1.0},
165
182
  "pipes": [
166
183
  {
167
184
  "radius": 0.15,
168
185
  "length": 7.0,
169
186
  "angle_deg": 0,
170
187
  "s_center": 0.5,
171
- "z": -0.7,
188
+ "z": -0.45,
172
189
  "offset_u": 0.0,
173
190
  }
174
191
  ],
@@ -182,17 +199,17 @@ def default_scenarios() -> List[ScenarioDefinition]:
182
199
  {
183
200
  "path_xy": [[0, 0], [6, 0], [6, 4]],
184
201
  "width": 1.2,
185
- "depth": 1.8,
202
+ "depth": 1.1,
186
203
  "wall_slope": 0.15,
187
204
  "ground_margin": 1.0,
188
- "ground": {"z0": 0.0, "slope": [0.0, 0.0], "size_margin": 4.0},
205
+ "ground": {"z0": 0.0, "slope": [0.0, 0.0], "size_margin": 1.2},
189
206
  "pipes": [
190
207
  {
191
208
  "radius": 0.15,
192
209
  "length": 8.0,
193
210
  "angle_deg": 0,
194
211
  "s_center": 0.35,
195
- "z": -1.0,
212
+ "z": -0.6,
196
213
  "offset_u": 0.0,
197
214
  },
198
215
  {
@@ -200,7 +217,7 @@ def default_scenarios() -> List[ScenarioDefinition]:
200
217
  "length": 5.0,
201
218
  "angle_deg": 90,
202
219
  "s_center": 0.75,
203
- "z": -0.9,
220
+ "z": -0.55,
204
221
  "offset_u": 0.2,
205
222
  },
206
223
  ],
@@ -230,17 +247,17 @@ def default_scenarios() -> List[ScenarioDefinition]:
230
247
  {
231
248
  "path_xy": [[0, 0], [6, 0], [6, 4], [0, 4]],
232
249
  "width": 1.4,
233
- "depth": 2.0,
250
+ "depth": 1.2,
234
251
  "wall_slope": 0.25,
235
252
  "ground_margin": 1.2,
236
- "ground": {"z0": 0.0, "slope": [0.0, 0.0], "size_margin": 5.0},
253
+ "ground": {"z0": 0.0, "slope": [0.0, 0.0], "size_margin": 1.5},
237
254
  "pipes": [
238
255
  {
239
256
  "radius": 0.18,
240
257
  "length": 9.0,
241
258
  "angle_deg": 0,
242
259
  "s_center": 0.25,
243
- "z": -1.0,
260
+ "z": -0.6,
244
261
  "offset_u": 0.0,
245
262
  },
246
263
  {
@@ -248,7 +265,7 @@ def default_scenarios() -> List[ScenarioDefinition]:
248
265
  "length": 5.0,
249
266
  "angle_deg": 45,
250
267
  "s_center": 0.55,
251
- "z": -1.1,
268
+ "z": -0.65,
252
269
  "offset_u": -0.2,
253
270
  },
254
271
  {
@@ -256,12 +273,12 @@ def default_scenarios() -> List[ScenarioDefinition]:
256
273
  "length": 3.5,
257
274
  "angle_deg": -60,
258
275
  "s_center": 0.75,
259
- "z": -1.3,
276
+ "z": -0.8,
260
277
  "offset_u": 0.25,
261
278
  },
262
279
  ],
263
280
  "boxes": [],
264
- "spheres": [{"radius": 0.3, "s": 0.85, "offset_u": -0.2}],
281
+ "spheres": [{"radius": 0.25, "s": 0.85, "offset_u": -0.2, "z": -0.7}],
265
282
  "noise": {
266
283
  "enable": True,
267
284
  "amplitude": 0.02,
@@ -278,17 +295,17 @@ def default_scenarios() -> List[ScenarioDefinition]:
278
295
  {
279
296
  "path_xy": [[0, 0], [9, 0], [9, 3]],
280
297
  "width": 2.4,
281
- "depth": 1.2,
298
+ "depth": 0.7,
282
299
  "wall_slope": 0.08,
283
300
  "ground_margin": 1.5,
284
- "ground": {"z0": 0.0, "slope": [0.02, -0.015], "size_margin": 6.0},
301
+ "ground": {"z0": 0.0, "slope": [0.02, -0.015], "size_margin": 1.5},
285
302
  "pipes": [
286
303
  {
287
304
  "radius": 0.2,
288
305
  "length": 5.5,
289
306
  "angle_deg": 10,
290
307
  "s_center": 0.35,
291
- "z": -0.7,
308
+ "z": -0.4,
292
309
  "offset_u": 0.3,
293
310
  "clearance_scale": 0.9,
294
311
  },
@@ -297,7 +314,7 @@ def default_scenarios() -> List[ScenarioDefinition]:
297
314
  "length": 4.2,
298
315
  "angle_deg": -15,
299
316
  "s_center": 0.7,
300
- "z": -0.8,
317
+ "z": -0.45,
301
318
  "offset_u": -0.4,
302
319
  "clearance_scale": 1.1,
303
320
  },
@@ -306,10 +323,10 @@ def default_scenarios() -> List[ScenarioDefinition]:
306
323
  {
307
324
  "along": 1.2,
308
325
  "across": 0.9,
309
- "height": 0.5,
326
+ "height": 0.35,
310
327
  "s": 0.55,
311
328
  "offset_u": -0.25,
312
- "z": -0.6,
329
+ "z": -0.35,
313
330
  }
314
331
  ],
315
332
  "spheres": [],
@@ -329,17 +346,17 @@ def default_scenarios() -> List[ScenarioDefinition]:
329
346
  {
330
347
  "path_xy": [[0, 0], [4, -1], [8, 0], [8, 5], [2, 5], [-1, 2]],
331
348
  "width": 2.6,
332
- "depth": 1.4,
349
+ "depth": 0.85,
333
350
  "wall_slope": 0.12,
334
351
  "ground_margin": 2.0,
335
- "ground": {"z0": 0.2, "slope": [0.015, 0.03], "size_margin": 7.0},
352
+ "ground": {"z0": 0.2, "slope": [0.015, 0.03], "size_margin": 1.8},
336
353
  "pipes": [
337
354
  {
338
355
  "radius": 0.18,
339
356
  "length": 6.0,
340
357
  "angle_deg": 35,
341
358
  "s_center": 0.3,
342
- "z": -0.9,
359
+ "z": -0.55,
343
360
  "offset_u": 0.35,
344
361
  "clearance_scale": 1.0,
345
362
  },
@@ -348,14 +365,14 @@ def default_scenarios() -> List[ScenarioDefinition]:
348
365
  "length": 4.8,
349
366
  "angle_deg": -40,
350
367
  "s_center": 0.6,
351
- "z": -0.95,
368
+ "z": -0.6,
352
369
  "offset_u": -0.45,
353
370
  "clearance_scale": 0.85,
354
371
  },
355
372
  ],
356
373
  "boxes": [],
357
374
  "spheres": [
358
- {"radius": 0.35, "s": 0.82, "offset_u": 0.3, "z": -0.65}
375
+ {"radius": 0.3, "s": 0.82, "offset_u": 0.3, "z": -0.4}
359
376
  ],
360
377
  "noise": {
361
378
  "enable": True,
@@ -368,6 +385,66 @@ def default_scenarios() -> List[ScenarioDefinition]:
368
385
  },
369
386
  },
370
387
  ),
388
+ ScenarioDefinition(
389
+ "S07_circular_well",
390
+ {
391
+ "path_xy": _generate_circular_path((0.0, 0.0), radius=1.5, n_vertices=32),
392
+ "width": 2.0,
393
+ "depth": 2.5,
394
+ "wall_slope": 0.05,
395
+ "ground_margin": 1.0,
396
+ "ground": {"z0": 0.0, "slope": [0.0, 0.0], "size_margin": 2.0},
397
+ "pipes": [
398
+ # Upper pipe - large diameter, horizontal
399
+ {
400
+ "radius": 0.20,
401
+ "length": 4.0,
402
+ "angle_deg": 0,
403
+ "s_center": 0.25,
404
+ "z": -0.5,
405
+ "offset_u": 0.0,
406
+ },
407
+ # Middle pipe - medium, angled
408
+ {
409
+ "radius": 0.15,
410
+ "length": 3.5,
411
+ "angle_deg": 45,
412
+ "s_center": 0.5,
413
+ "z": -1.2,
414
+ "offset_u": 0.1,
415
+ },
416
+ # Lower pipe - small, opposite angle
417
+ {
418
+ "radius": 0.10,
419
+ "length": 3.0,
420
+ "angle_deg": -60,
421
+ "s_center": 0.75,
422
+ "z": -1.8,
423
+ "offset_u": -0.15,
424
+ },
425
+ # Deep pipe - crossing at bottom
426
+ {
427
+ "radius": 0.12,
428
+ "length": 3.2,
429
+ "angle_deg": 90,
430
+ "s_center": 0.0,
431
+ "z": -2.2,
432
+ "offset_u": 0.0,
433
+ },
434
+ ],
435
+ "boxes": [],
436
+ "spheres": [{"radius": 0.25, "s": 0.4, "offset_u": 0.0, "z": -1.5}],
437
+ "noise": {
438
+ "enable": True,
439
+ "amplitude": 0.02,
440
+ "corr_length": 0.4,
441
+ "octaves": 2,
442
+ "gain": 0.5,
443
+ "seed": 37,
444
+ "apply_to": ["trench_walls", "trench_bottom"],
445
+ },
446
+ },
447
+ ),
371
448
  ]
372
449
 
373
450