trenchfoot 0.3.1__tar.gz → 0.4.0__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 (105) hide show
  1. trenchfoot-0.4.0/.gitignore +9 -0
  2. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/CHANGELOG.md +20 -0
  3. trenchfoot-0.4.0/Makefile +35 -0
  4. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/PKG-INFO +1 -1
  5. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/generate_scenarios.py +27 -27
  6. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/render_colors.py +1 -0
  7. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/trench_scene_generator_v3.py +58 -10
  8. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/pyproject.toml +1 -1
  9. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/uv.lock +1 -1
  10. trenchfoot-0.3.1/.env +0 -1
  11. trenchfoot-0.3.1/.github_token.env +0 -1
  12. trenchfoot-0.3.1/.pypi_token.env +0 -1
  13. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/.github/workflows/ci.yml +0 -0
  14. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/CLAUDE.md +0 -0
  15. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/LICENSE +0 -0
  16. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/README.md +0 -0
  17. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/STATUS.md +0 -0
  18. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/docs/scenario_gallery.md +0 -0
  19. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/__init__.py +0 -0
  20. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/Dockerfile +0 -0
  21. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/README.md +0 -0
  22. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/__init__.py +0 -0
  23. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/gmsh_sloped_trench_mesher.py +0 -0
  24. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/plot_mesh.py +0 -0
  25. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S01_straight_vwalls/ground_truth_isosurface.html +0 -0
  26. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S01_straight_vwalls/meshes/trench_scene_culled.obj +0 -0
  27. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S01_straight_vwalls/metrics.json +0 -0
  28. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S01_straight_vwalls/point_clouds/culled/resolution0p050.pth +0 -0
  29. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S01_straight_vwalls/point_clouds/full/resolution0p050.pth +0 -0
  30. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S01_straight_vwalls/preview.png +0 -0
  31. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S01_straight_vwalls/preview_oblique.png +0 -0
  32. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S01_straight_vwalls/preview_side.png +0 -0
  33. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S01_straight_vwalls/preview_top.png +0 -0
  34. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S01_straight_vwalls/scene.json +0 -0
  35. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S01_straight_vwalls/sdf_metadata.json +0 -0
  36. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S01_straight_vwalls/trench_scene.obj +0 -0
  37. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S01_straight_vwalls/volumetric/trench_volume.msh +0 -0
  38. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S02_straight_slope_pipe/ground_truth_isosurface.html +0 -0
  39. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S02_straight_slope_pipe/meshes/trench_scene_culled.obj +0 -0
  40. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S02_straight_slope_pipe/metrics.json +0 -0
  41. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S02_straight_slope_pipe/point_clouds/culled/resolution0p050.pth +0 -0
  42. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S02_straight_slope_pipe/point_clouds/full/resolution0p050.pth +0 -0
  43. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S02_straight_slope_pipe/preview.png +0 -0
  44. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S02_straight_slope_pipe/preview_oblique.png +0 -0
  45. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S02_straight_slope_pipe/preview_side.png +0 -0
  46. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S02_straight_slope_pipe/preview_top.png +0 -0
  47. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S02_straight_slope_pipe/scene.json +0 -0
  48. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S02_straight_slope_pipe/sdf_metadata.json +0 -0
  49. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S02_straight_slope_pipe/trench_scene.obj +0 -0
  50. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S02_straight_slope_pipe/volumetric/trench_volume.msh +0 -0
  51. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/ground_truth_isosurface.html +0 -0
  52. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/meshes/trench_scene_culled.obj +0 -0
  53. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/metrics.json +0 -0
  54. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/point_clouds/culled/resolution0p050.pth +0 -0
  55. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/point_clouds/full/resolution0p050.pth +0 -0
  56. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/preview.png +0 -0
  57. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/preview_oblique.png +0 -0
  58. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/preview_side.png +0 -0
  59. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/preview_top.png +0 -0
  60. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/scene.json +0 -0
  61. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/sdf_metadata.json +0 -0
  62. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/trench_scene.obj +0 -0
  63. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S03_L_slope_two_pipes_box/volumetric/trench_volume.msh +0 -0
  64. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S04_U_slope_multi_noise/ground_truth_isosurface.html +0 -0
  65. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S04_U_slope_multi_noise/meshes/trench_scene_culled.obj +0 -0
  66. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S04_U_slope_multi_noise/metrics.json +0 -0
  67. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S04_U_slope_multi_noise/preview.png +0 -0
  68. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S04_U_slope_multi_noise/preview_oblique.png +0 -0
  69. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S04_U_slope_multi_noise/preview_side.png +0 -0
  70. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S04_U_slope_multi_noise/preview_top.png +0 -0
  71. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S04_U_slope_multi_noise/scene.json +0 -0
  72. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S04_U_slope_multi_noise/sdf_metadata.json +0 -0
  73. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S04_U_slope_multi_noise/trench_scene.obj +0 -0
  74. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S04_U_slope_multi_noise/volumetric/trench_volume.msh +0 -0
  75. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S05_wide_slope_pair/ground_truth_isosurface.html +0 -0
  76. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S05_wide_slope_pair/metrics.json +0 -0
  77. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S05_wide_slope_pair/preview_oblique.png +0 -0
  78. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S05_wide_slope_pair/preview_side.png +0 -0
  79. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S05_wide_slope_pair/preview_top.png +0 -0
  80. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S05_wide_slope_pair/scene.json +0 -0
  81. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S05_wide_slope_pair/sdf_metadata.json +0 -0
  82. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S05_wide_slope_pair/trench_scene.obj +0 -0
  83. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S05_wide_slope_pair/volumetric/trench_volume.msh +0 -0
  84. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S06_bumpy_wide_loop/ground_truth_isosurface.html +0 -0
  85. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S06_bumpy_wide_loop/metrics.json +0 -0
  86. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S06_bumpy_wide_loop/preview_oblique.png +0 -0
  87. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S06_bumpy_wide_loop/preview_side.png +0 -0
  88. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S06_bumpy_wide_loop/preview_top.png +0 -0
  89. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S06_bumpy_wide_loop/scene.json +0 -0
  90. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S06_bumpy_wide_loop/sdf_metadata.json +0 -0
  91. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S06_bumpy_wide_loop/trench_scene.obj +0 -0
  92. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S06_bumpy_wide_loop/volumetric/trench_volume.msh +0 -0
  93. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S07_circular_well/ground_truth_isosurface.html +0 -0
  94. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S07_circular_well/metrics.json +0 -0
  95. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S07_circular_well/preview_oblique.png +0 -0
  96. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S07_circular_well/preview_side.png +0 -0
  97. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S07_circular_well/preview_top.png +0 -0
  98. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S07_circular_well/scene.json +0 -0
  99. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S07_circular_well/sdf_metadata.json +0 -0
  100. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S07_circular_well/trench_scene.obj +0 -0
  101. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/S07_circular_well/volumetric/trench_volume.msh +0 -0
  102. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scenarios/SUMMARY.json +0 -0
  103. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/packages/trenchfoot/scene_spec_example.json +0 -0
  104. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/tests/test_sdf_readiness.py +0 -0
  105. {trenchfoot-0.3.1 → trenchfoot-0.4.0}/tests/test_trenchfoot_generation.py +0 -0
@@ -0,0 +1,9 @@
1
+
2
+ # Secrets
3
+ .env
4
+ *.env
5
+ .pypi_token.env
6
+ .github_token.env
7
+
8
+ # Generated mesh data for local inspection
9
+ data/
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.4.0] - 2026-01-26
4
+
5
+ ### Added
6
+ - **Makefile**: Added `make dump-meshes`, `make dump-meshes-volumetric`, and `make clean-meshes` targets for local mesh inspection
7
+ - **Inner column lid for circular wells**: S07 and other closed-path trenches now have a proper ground surface capping the central column
8
+ - **`fill_interior` option for GroundSpec**: Closed-path trenches can optionally fill the interior island with ground surface (used in S06)
9
+ - **`inner_column_lid` render color**: Gray color matching ground surface
10
+
11
+ ### Fixed
12
+ - **S03 box-pipe intersection**: Reduced box size to create clearance from nearby pipe
13
+ - **S04 diagonal pipe clipping**: Adjusted pipe offset to prevent intersection with inner corner
14
+ - **S05 pipe-box intersection**: Moved box position and offset to avoid pipe collision
15
+ - **S06 ground overhang at open ends**: Closed the loop path to use proper annulus triangulation
16
+ - **S07 pipe positions**: Repositioned all pipes with tangential orientation and negative offset to avoid crossing the central opening
17
+ - **Circular path seam artifact**: `_offset_closed_polyline` now removes duplicate closing point that caused triangular protrusion on inner walls
18
+ - **`.gitignore`**: Added `data/` directory for generated mesh inspection
19
+
20
+ ### Changed
21
+ - **S07 pipe configuration**: All pipes now tangential (angle_deg=0) with offset_u=-0.4, lengths increased to 7.0-8.0 for wall penetration
22
+
3
23
  ## [0.3.1] - 2026-01-08
4
24
 
5
25
  ### Added
@@ -0,0 +1,35 @@
1
+ # ABOUTME: Makefile for trenchfoot development tasks.
2
+ # ABOUTME: Provides targets for testing, mesh generation, and other common operations.
3
+
4
+ .PHONY: test dump-meshes dump-meshes-volumetric clean-meshes
5
+
6
+ # Default data directory for generated meshes
7
+ DATA_DIR := data/scenarios
8
+
9
+ # Run tests
10
+ test:
11
+ uv run pytest -rs
12
+
13
+ # Generate scenario meshes (surface only, with previews) for inspection
14
+ dump-meshes:
15
+ @mkdir -p $(DATA_DIR)
16
+ uv run python -m trenchfoot.generate_scenarios \
17
+ --out $(DATA_DIR) \
18
+ --preview \
19
+ --skip-volumetric
20
+ @echo "Meshes written to $(DATA_DIR)"
21
+
22
+ # Generate scenario meshes including volumetric (requires gmsh)
23
+ dump-meshes-volumetric:
24
+ @mkdir -p $(DATA_DIR)
25
+ uv run python -m trenchfoot.generate_scenarios \
26
+ --out $(DATA_DIR) \
27
+ --preview \
28
+ --volumetric \
29
+ --lc 0.4
30
+ @echo "Meshes (including volumetric) written to $(DATA_DIR)"
31
+
32
+ # Remove generated mesh data
33
+ clean-meshes:
34
+ rm -rf $(DATA_DIR)
35
+ @echo "Cleaned $(DATA_DIR)"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: trenchfoot
3
- Version: 0.3.1
3
+ Version: 0.4.0
4
4
  Summary: Synthetic trench scenario generator bundle (surfaces + volumetrics).
5
5
  Author: Liam Moore
6
6
  License-File: LICENSE
@@ -223,9 +223,9 @@ def default_scenarios() -> List[ScenarioDefinition]:
223
223
  ],
224
224
  "boxes": [
225
225
  {
226
- "along": 0.8,
227
- "across": 0.5,
228
- "height": 0.4,
226
+ "along": 0.4,
227
+ "across": 0.3,
228
+ "height": 0.25,
229
229
  "s": 0.55,
230
230
  "offset_u": 0.0,
231
231
  }
@@ -266,7 +266,7 @@ def default_scenarios() -> List[ScenarioDefinition]:
266
266
  "angle_deg": 45,
267
267
  "s_center": 0.55,
268
268
  "z": -0.65,
269
- "offset_u": -0.2,
269
+ "offset_u": -0.4,
270
270
  },
271
271
  {
272
272
  "radius": 0.08,
@@ -304,7 +304,7 @@ def default_scenarios() -> List[ScenarioDefinition]:
304
304
  "radius": 0.2,
305
305
  "length": 5.5,
306
306
  "angle_deg": 10,
307
- "s_center": 0.35,
307
+ "s_center": 0.2,
308
308
  "z": -0.4,
309
309
  "offset_u": 0.3,
310
310
  "clearance_scale": 0.9,
@@ -324,8 +324,8 @@ def default_scenarios() -> List[ScenarioDefinition]:
324
324
  "along": 1.2,
325
325
  "across": 0.9,
326
326
  "height": 0.35,
327
- "s": 0.55,
328
- "offset_u": -0.25,
327
+ "s": 0.45,
328
+ "offset_u": -0.4,
329
329
  "z": -0.35,
330
330
  }
331
331
  ],
@@ -344,12 +344,12 @@ def default_scenarios() -> List[ScenarioDefinition]:
344
344
  ScenarioDefinition(
345
345
  "S06_bumpy_wide_loop",
346
346
  {
347
- "path_xy": [[0, 0], [4, -1], [8, 0], [8, 5], [2, 5], [-1, 2]],
347
+ "path_xy": [[0, 0], [4, -1], [8, 0], [8, 5], [2, 5], [-1, 2], [0, 0]],
348
348
  "width": 2.6,
349
349
  "depth": 0.85,
350
350
  "wall_slope": 0.12,
351
351
  "ground_margin": 2.0,
352
- "ground": {"z0": 0.2, "slope": [0.015, 0.03], "size_margin": 1.8},
352
+ "ground": {"z0": 0.2, "slope": [0.015, 0.03], "size_margin": 1.8, "fill_interior": True},
353
353
  "pipes": [
354
354
  {
355
355
  "radius": 0.18,
@@ -395,41 +395,41 @@ def default_scenarios() -> List[ScenarioDefinition]:
395
395
  "ground_margin": 1.0,
396
396
  "ground": {"z0": 0.0, "slope": [0.0, 0.0], "size_margin": 2.0},
397
397
  "pipes": [
398
- # Upper pipe - large diameter, horizontal
398
+ # Upper pipe - tangential
399
399
  {
400
400
  "radius": 0.20,
401
- "length": 4.0,
401
+ "length": 8.0,
402
402
  "angle_deg": 0,
403
- "s_center": 0.25,
403
+ "s_center": 0.0,
404
404
  "z": -0.5,
405
- "offset_u": 0.0,
405
+ "offset_u": -0.4,
406
406
  },
407
- # Middle pipe - medium, angled
407
+ # Middle pipe - tangential
408
408
  {
409
409
  "radius": 0.15,
410
- "length": 3.5,
411
- "angle_deg": 45,
410
+ "length": 7.5,
411
+ "angle_deg": 0,
412
412
  "s_center": 0.5,
413
413
  "z": -1.2,
414
- "offset_u": 0.1,
414
+ "offset_u": -0.4,
415
415
  },
416
- # Lower pipe - small, opposite angle
416
+ # Lower pipe - tangential
417
417
  {
418
418
  "radius": 0.10,
419
- "length": 3.0,
420
- "angle_deg": -60,
421
- "s_center": 0.75,
419
+ "length": 7.0,
420
+ "angle_deg": 0,
421
+ "s_center": 0.25,
422
422
  "z": -1.8,
423
- "offset_u": -0.15,
423
+ "offset_u": -0.4,
424
424
  },
425
- # Deep pipe - crossing at bottom
425
+ # Deep pipe - tangential
426
426
  {
427
427
  "radius": 0.12,
428
- "length": 3.2,
429
- "angle_deg": 90,
430
- "s_center": 0.0,
428
+ "length": 7.5,
429
+ "angle_deg": 0,
430
+ "s_center": 0.75,
431
431
  "z": -2.2,
432
- "offset_u": 0.0,
432
+ "offset_u": -0.4,
433
433
  },
434
434
  ],
435
435
  "boxes": [],
@@ -6,6 +6,7 @@ _TRENCH_COLORS = {
6
6
  "trench_bottom": "#d2a679",
7
7
  "trench_cap_for_volume": "#e6cfa4",
8
8
  "ground_surface": "#b0b0b0",
9
+ "inner_column_lid": "#b0b0b0", # same as ground
9
10
  }
10
11
 
11
12
  _PIPE_COLORS = ["#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd", "#8c564b"]
@@ -34,7 +34,7 @@ except Exception:
34
34
  Poly3DCollection = None
35
35
 
36
36
  # Groups kept for internal metrics but excluded from OBJ export and previews
37
- _INTERNAL_GROUPS = frozenset({"trench_cap_for_volume"})
37
+ _INTERNAL_GROUPS = frozenset({"trench_cap_for_volume", "inner_column_lid"})
38
38
 
39
39
  # ---------------- Geometry helpers ----------------
40
40
 
@@ -123,6 +123,9 @@ def _offset_closed_polyline(path: List[Tuple[float,float]], offset: float) -> Li
123
123
  this returns a single continuous closed ring for paths where first ≈ last point.
124
124
  """
125
125
  P = np.array(path, float)
126
+ # Remove duplicate closing point if present (first ≈ last)
127
+ if len(P) > 1 and np.linalg.norm(P[0] - P[-1]) < 0.01:
128
+ P = P[:-1]
126
129
  n = len(P)
127
130
  if n < 3:
128
131
  raise ValueError("Closed polyline needs at least 3 points")
@@ -405,6 +408,7 @@ class GroundSpec:
405
408
  z0: float = 0.0
406
409
  slope: Tuple[float,float] = (0.0, 0.0) # (dz/dx, dz/dy)
407
410
  size_margin: float = 3.0
411
+ fill_interior: bool = False # For closed paths: fill the interior with ground surface
408
412
 
409
413
  @dataclass
410
414
  class SceneSpec:
@@ -735,6 +739,16 @@ def make_trench_from_path_sloped(path_xy: List[Tuple[float,float]], width_top: f
735
739
  V_walls = np.array(walls_V, float)
736
740
  F_walls = np.array(walls_F, int)
737
741
 
742
+ # Inner column lid: cap the top of the inner column at ground level
743
+ # Reverse inner_top to get CCW winding for upward-facing normals
744
+ inner_top_ccw = inner_top[::-1].copy()
745
+ z_inner_top_ccw = z_inner_top[::-1].copy()
746
+ lid_xy, lid_faces = _triangulate_polygon_fan(inner_top_ccw)
747
+ # Assign z-values: polygon vertices use z_inner_top_ccw, centroid uses average
748
+ z_lid = np.concatenate([z_inner_top_ccw, [np.mean(z_inner_top_ccw)]])
749
+ V_lid = np.column_stack([lid_xy, z_lid])
750
+ F_lid = _ensure_upward_normals(V_lid, lid_faces)
751
+
738
752
  # For closed path, poly_top is the outer ring (used for ground plane hole)
739
753
  poly_top = outer_top
740
754
  poly_bot = outer_bot
@@ -796,6 +810,10 @@ def make_trench_from_path_sloped(path_xy: List[Tuple[float,float]], width_top: f
796
810
  "trench_walls": (V_walls, F_walls)
797
811
  }
798
812
 
813
+ # Add inner column lid for closed paths
814
+ if is_closed:
815
+ groups["inner_column_lid"] = (V_lid, F_lid)
816
+
799
817
  return groups, poly_top, poly_bot, extra
800
818
 
801
819
  def _ensure_upward_normals(V: np.ndarray, F: np.ndarray) -> np.ndarray:
@@ -830,6 +848,28 @@ def _ensure_upward_normals(V: np.ndarray, F: np.ndarray) -> np.ndarray:
830
848
  return F_out
831
849
 
832
850
 
851
+ def _triangulate_polygon_fan(polygon: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
852
+ """Triangulate a simple polygon using fan triangulation from centroid.
853
+
854
+ Works well for convex or nearly-convex polygons. Returns (vertices, faces)
855
+ where vertices includes the original polygon points plus the centroid.
856
+ """
857
+ n = len(polygon)
858
+ centroid = polygon.mean(axis=0)
859
+
860
+ # Vertices: polygon points first, then centroid at the end
861
+ verts = np.vstack([polygon, centroid.reshape(1, -1)])
862
+ centroid_idx = n
863
+
864
+ # Fan triangles from centroid to each edge
865
+ tris = []
866
+ for i in range(n):
867
+ j = (i + 1) % n
868
+ tris.append([centroid_idx, i, j])
869
+
870
+ return verts, np.array(tris, dtype=int)
871
+
872
+
833
873
  def _triangulate_annulus(outer: np.ndarray, inner: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
834
874
  """Triangulate the annular region between outer and inner polygons.
835
875
 
@@ -919,9 +959,8 @@ def make_ground_surface_plane(path_xy: List[Tuple[float,float]], width_top: floa
919
959
  is_closed = _is_path_closed(path_xy)
920
960
 
921
961
  if is_closed:
922
- # For closed paths (like circular wells), the ground is an annulus
923
- # from the outer ground boundary to the outer edge of the trench opening.
924
- # The center (inside the trench) is left completely open.
962
+ # For closed paths, ground is an annulus from outer boundary to trench edge.
963
+ # Optionally, if fill_interior is set, also fill the interior island.
925
964
 
926
965
  # Trench outer boundary (edge of trench opening)
927
966
  trench_outer = np.array(_offset_closed_polyline(path_xy, half_top), float)
@@ -933,14 +972,23 @@ def make_ground_surface_plane(path_xy: List[Tuple[float,float]], width_top: floa
933
972
  trench_outer = _ensure_ccw(trench_outer)
934
973
  ground_outer = _ensure_ccw(ground_outer)
935
974
 
936
- # Ground annulus: from ground_outer to trench_outer
937
- combined_xy, tris = _triangulate_annulus(ground_outer, trench_outer)
938
- Vg = np.array([[x, y, gfun(x, y)] for (x, y) in combined_xy], float)
975
+ # Outer ground annulus: from ground_outer to trench_outer
976
+ outer_xy, outer_tris = _triangulate_annulus(ground_outer, trench_outer)
977
+ Vg_outer = np.array([[x, y, gfun(x, y)] for (x, y) in outer_xy], float)
978
+ outer_tris = _ensure_upward_normals(Vg_outer, outer_tris)
939
979
 
940
- # Ground normals should point UP (+z) into the air
941
- tris = _ensure_upward_normals(Vg, tris)
980
+ result = {"ground_surface": (Vg_outer, outer_tris)}
942
981
 
943
- return {"ground_surface": (Vg, tris)}
982
+ # Optionally fill the interior island (for loop trenches, not wells/pits)
983
+ if getattr(ground, 'fill_interior', False):
984
+ trench_inner = np.array(_offset_closed_polyline(path_xy, -half_top), float)
985
+ trench_inner = _ensure_ccw(trench_inner)
986
+ inner_xy, inner_tris = _triangulate_polygon_fan(trench_inner)
987
+ Vg_inner = np.array([[x, y, gfun(x, y)] for (x, y) in inner_xy], float)
988
+ inner_tris = _ensure_upward_normals(Vg_inner, inner_tris)
989
+ result["ground_island"] = (Vg_inner, inner_tris)
990
+
991
+ return result
944
992
  else:
945
993
  # Open paths: ground forms annulus with extensions past trench endpoints.
946
994
  # The outer ring (ground boundary) is extended, but the inner ring (trench
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "trenchfoot"
7
- version = "0.3.1"
7
+ version = "0.4.0"
8
8
  description = "Synthetic trench scenario generator bundle (surfaces + volumetrics)."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -501,7 +501,7 @@ wheels = [
501
501
 
502
502
  [[package]]
503
503
  name = "trenchfoot"
504
- version = "0.3.0"
504
+ version = "0.3.1"
505
505
  source = { editable = "." }
506
506
  dependencies = [
507
507
  { name = "numpy" },
trenchfoot-0.3.1/.env DELETED
@@ -1 +0,0 @@
1
- PYPI_API_TOKEN=pypi-AgEIcHlwaS5vcmcCJGZjZTM1MzQwLTFiZGQtNGQ5MS1hNzIyLTc1MmU1YTJhYzE1NQACGFsxLFsicHl0ZXN0LWNocm9uaWNsZSJdXQACLFsyLFsiMzg4ZTYxZTMtMDk2NC00ZjNiLWE5ODItYzc4NTMxNDlhM2FjIl1dAAAGID45Pzb1Xm05EgS5M8C2_5BbgSEULSUwP3GpDCia6vTP
@@ -1 +0,0 @@
1
- GITHUB_TOKEN=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
@@ -1 +0,0 @@
1
- PYPI_API_TOKEN="pypi-AgEIcHlwaS5vcmcCJDU5NWZhMThiLTcwZDAtNGQ1NS04NzY5LTUzOWFjNzUyMzBhOQACKlszLCJiYTQ1Nzc2Ni01MDg0LTQ4ZmYtOGU5Yi05MjY4NjM3MTNiY2EiXQAABiCDzIFj_CDx2Hr1RoMANFCByB8X_u1VLbmPLNpe-oOFow"
File without changes
File without changes
File without changes
File without changes