trenchfoot 0.1.1__py3-none-any.whl → 0.2.2__py3-none-any.whl

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 (58) hide show
  1. trenchfoot/generate_scenarios.py +104 -27
  2. trenchfoot/gmsh_sloped_trench_mesher.py +125 -25
  3. trenchfoot/scenarios/S01_straight_vwalls/metrics.json +4 -4
  4. trenchfoot/scenarios/S01_straight_vwalls/preview_oblique.png +0 -0
  5. trenchfoot/scenarios/S01_straight_vwalls/preview_side.png +0 -0
  6. trenchfoot/scenarios/S01_straight_vwalls/preview_top.png +0 -0
  7. trenchfoot/scenarios/S01_straight_vwalls/scene.json +2 -2
  8. trenchfoot/scenarios/S01_straight_vwalls/trench_scene.obj +30 -27
  9. trenchfoot/scenarios/S01_straight_vwalls/volumetric/trench_volume.msh +540 -802
  10. trenchfoot/scenarios/S02_straight_slope_pipe/metrics.json +10 -10
  11. trenchfoot/scenarios/S02_straight_slope_pipe/preview_oblique.png +0 -0
  12. trenchfoot/scenarios/S02_straight_slope_pipe/preview_side.png +0 -0
  13. trenchfoot/scenarios/S02_straight_slope_pipe/preview_top.png +0 -0
  14. trenchfoot/scenarios/S02_straight_slope_pipe/scene.json +3 -3
  15. trenchfoot/scenarios/S02_straight_slope_pipe/trench_scene.obj +4977 -4974
  16. trenchfoot/scenarios/S02_straight_slope_pipe/volumetric/trench_volume.msh +1694 -1969
  17. trenchfoot/scenarios/S03_L_slope_two_pipes_box/metrics.json +14 -14
  18. trenchfoot/scenarios/S03_L_slope_two_pipes_box/preview_oblique.png +0 -0
  19. trenchfoot/scenarios/S03_L_slope_two_pipes_box/preview_side.png +0 -0
  20. trenchfoot/scenarios/S03_L_slope_two_pipes_box/preview_top.png +0 -0
  21. trenchfoot/scenarios/S03_L_slope_two_pipes_box/scene.json +4 -4
  22. trenchfoot/scenarios/S03_L_slope_two_pipes_box/trench_scene.obj +10547 -10540
  23. trenchfoot/scenarios/S03_L_slope_two_pipes_box/volumetric/trench_volume.msh +3101 -3767
  24. trenchfoot/scenarios/S04_U_slope_multi_noise/metrics.json +17 -17
  25. trenchfoot/scenarios/S04_U_slope_multi_noise/preview_oblique.png +0 -0
  26. trenchfoot/scenarios/S04_U_slope_multi_noise/preview_side.png +0 -0
  27. trenchfoot/scenarios/S04_U_slope_multi_noise/preview_top.png +0 -0
  28. trenchfoot/scenarios/S04_U_slope_multi_noise/scene.json +8 -7
  29. trenchfoot/scenarios/S04_U_slope_multi_noise/trench_scene.obj +17999 -17988
  30. trenchfoot/scenarios/S04_U_slope_multi_noise/volumetric/trench_volume.msh +4991 -6506
  31. trenchfoot/scenarios/S05_wide_slope_pair/metrics.json +14 -14
  32. trenchfoot/scenarios/S05_wide_slope_pair/preview_oblique.png +0 -0
  33. trenchfoot/scenarios/S05_wide_slope_pair/preview_side.png +0 -0
  34. trenchfoot/scenarios/S05_wide_slope_pair/preview_top.png +0 -0
  35. trenchfoot/scenarios/S05_wide_slope_pair/scene.json +6 -6
  36. trenchfoot/scenarios/S05_wide_slope_pair/trench_scene.obj +10547 -10540
  37. trenchfoot/scenarios/S05_wide_slope_pair/volumetric/trench_volume.msh +5081 -0
  38. trenchfoot/scenarios/S06_bumpy_wide_loop/metrics.json +16 -16
  39. trenchfoot/scenarios/S06_bumpy_wide_loop/preview_oblique.png +0 -0
  40. trenchfoot/scenarios/S06_bumpy_wide_loop/preview_side.png +0 -0
  41. trenchfoot/scenarios/S06_bumpy_wide_loop/preview_top.png +0 -0
  42. trenchfoot/scenarios/S06_bumpy_wide_loop/scene.json +6 -6
  43. trenchfoot/scenarios/S06_bumpy_wide_loop/trench_scene.obj +12812 -12793
  44. trenchfoot/scenarios/S06_bumpy_wide_loop/volumetric/trench_volume.msh +10402 -0
  45. trenchfoot/scenarios/S07_circular_well/metrics.json +48 -0
  46. trenchfoot/scenarios/S07_circular_well/preview_oblique.png +0 -0
  47. trenchfoot/scenarios/S07_circular_well/preview_side.png +0 -0
  48. trenchfoot/scenarios/S07_circular_well/preview_top.png +0 -0
  49. trenchfoot/scenarios/S07_circular_well/scene.json +203 -0
  50. trenchfoot/scenarios/S07_circular_well/trench_scene.obj +64401 -0
  51. trenchfoot/scenarios/S07_circular_well/volumetric/trench_volume.msh +22370 -0
  52. trenchfoot/scenarios/SUMMARY.json +343 -32
  53. trenchfoot/trench_scene_generator_v3.py +323 -46
  54. {trenchfoot-0.1.1.dist-info → trenchfoot-0.2.2.dist-info}/METADATA +16 -18
  55. {trenchfoot-0.1.1.dist-info → trenchfoot-0.2.2.dist-info}/RECORD +58 -49
  56. {trenchfoot-0.1.1.dist-info → trenchfoot-0.2.2.dist-info}/WHEEL +1 -1
  57. {trenchfoot-0.1.1.dist-info → trenchfoot-0.2.2.dist-info}/entry_points.txt +0 -0
  58. {trenchfoot-0.1.1.dist-info → trenchfoot-0.2.2.dist-info}/licenses/LICENSE +0 -0
@@ -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
 
@@ -48,6 +48,42 @@ def _normalize(v):
48
48
 
49
49
  def _rotate_ccw(v): return np.array([-v[1], v[0]], float)
50
50
 
51
+ def _is_path_closed(path, threshold=0.01):
52
+ """Detect if path is explicitly closed (first and last points nearly identical)."""
53
+ if len(path) < 3:
54
+ return False
55
+ P = np.array(path, float)
56
+ first_last_dist = np.linalg.norm(P[0] - P[-1])
57
+ return first_last_dist < threshold
58
+
59
+ def _offset_closed_polyline(path, offset):
60
+ """Offset a closed polyline, returning a single closed ring."""
61
+ P = np.array(path, float)
62
+ n = len(P)
63
+ if n < 3:
64
+ raise ValueError("Closed polyline needs at least 3 points")
65
+ tangents = []
66
+ normals = []
67
+ for i in range(n):
68
+ t = _normalize(P[(i+1) % n] - P[i])
69
+ if np.linalg.norm(t) < 1e-12:
70
+ t = np.array([1.0, 0.0])
71
+ tangents.append(t)
72
+ normals.append(np.array([-t[1], t[0]], float))
73
+ offset_pts = []
74
+ for k in range(n):
75
+ t_prev, n_prev = tangents[(k-1) % n], normals[(k-1) % n]
76
+ t_next, n_next = tangents[k], normals[k]
77
+ L1_p = P[k] + offset * n_prev
78
+ L1_d = t_prev
79
+ L2_p = P[k] + offset * n_next
80
+ L2_d = t_next
81
+ pt = _line_intersection_2d(L1_p, L1_d, L2_p, L2_d)
82
+ if pt is None:
83
+ pt = 0.5 * (L1_p + L2_p)
84
+ offset_pts.append(pt)
85
+ return offset_pts
86
+
51
87
  def _line_intersection_2d(p, d, q, e):
52
88
  M = np.array([d, -e], float).T; det = np.linalg.det(M)
53
89
  if abs(det) < 1e-12: return None
@@ -173,35 +209,99 @@ def generate_trench_volume(
173
209
  half_top = width_top / 2.0
174
210
  half_bot = max(1e-3, half_top - slope * depth)
175
211
 
176
- Ltop, Rtop = _offset_polyline(path_xy, half_top)
177
- Lbot, Rbot = _offset_polyline(path_xy, half_bot)
178
- ring_top = _ring_from_LR(Ltop, Rtop)
179
- ring_bot = _ring_from_LR(Lbot, Rbot)
212
+ is_closed = _is_path_closed(path_xy)
180
213
 
181
- ring_top_xyz = [(x, y, g(x, y)) for (x, y) in ring_top]
182
- ring_bot_xyz = [(x, y, g(x, y) - depth) for (x, y) in ring_bot]
214
+ if is_closed:
215
+ # For closed paths, create annular (ring-shaped) trench with outer and inner walls
216
+ outer_top = np.array(_offset_closed_polyline(path_xy, half_top), float)
217
+ inner_top = np.array(_offset_closed_polyline(path_xy, -half_top), float)
218
+ outer_bot = np.array(_offset_closed_polyline(path_xy, half_bot), float)
219
+ inner_bot = np.array(_offset_closed_polyline(path_xy, -half_bot), float)
183
220
 
184
- top_loop = _add_closed_wire_xyz(ring_top_xyz)
185
- bot_loop = _add_closed_wire_xyz(ring_bot_xyz)
221
+ outer_top_xyz = [(x, y, g(x, y)) for (x, y) in outer_top]
222
+ inner_top_xyz = [(x, y, g(x, y)) for (x, y) in inner_top]
223
+ outer_bot_xyz = [(x, y, g(x, y) - depth) for (x, y) in outer_bot]
224
+ inner_bot_xyz = [(x, y, g(x, y) - depth) for (x, y) in inner_bot]
186
225
 
187
- outDimTags = []
188
- try:
189
- gmsh.model.occ.addThruSections(
190
- [top_loop, bot_loop], makeSolid=True, makeRuled=True, outDimTags=outDimTags
191
- )
192
- except TypeError: # gmsh >= 4.14 removed outDimTags kwarg
193
- outDimTags = gmsh.model.occ.addThruSections(
194
- [top_loop, bot_loop], makeSolid=True, makeRuled=True
195
- )
196
- if outDimTags is None:
197
- outDimTags = []
198
- gmsh.model.occ.healShapes()
199
- gmsh.model.occ.removeAllDuplicates()
200
- gmsh.model.occ.synchronize()
226
+ # Create outer and inner wire loops at top and bottom
227
+ outer_top_loop = _add_closed_wire_xyz(outer_top_xyz)
228
+ inner_top_loop = _add_closed_wire_xyz(inner_top_xyz)
229
+ outer_bot_loop = _add_closed_wire_xyz(outer_bot_xyz)
230
+ inner_bot_loop = _add_closed_wire_xyz(inner_bot_xyz)
231
+
232
+ # Outer wall: loft from outer_top to outer_bot
233
+ outDimTags_outer = []
234
+ try:
235
+ gmsh.model.occ.addThruSections(
236
+ [outer_top_loop, outer_bot_loop], makeSolid=False, makeRuled=True, outDimTags=outDimTags_outer
237
+ )
238
+ except TypeError:
239
+ outDimTags_outer = gmsh.model.occ.addThruSections(
240
+ [outer_top_loop, outer_bot_loop], makeSolid=False, makeRuled=True
241
+ ) or []
242
+
243
+ # Inner wall: loft from inner_top to inner_bot
244
+ outDimTags_inner = []
245
+ try:
246
+ gmsh.model.occ.addThruSections(
247
+ [inner_top_loop, inner_bot_loop], makeSolid=False, makeRuled=True, outDimTags=outDimTags_inner
248
+ )
249
+ except TypeError:
250
+ outDimTags_inner = gmsh.model.occ.addThruSections(
251
+ [inner_top_loop, inner_bot_loop], makeSolid=False, makeRuled=True
252
+ ) or []
253
+
254
+ # Create top and bottom surfaces (annular)
255
+ top_surf = gmsh.model.occ.addPlaneSurface([outer_top_loop, inner_top_loop])
256
+ bot_surf = gmsh.model.occ.addPlaneSurface([outer_bot_loop, inner_bot_loop])
257
+
258
+ # Collect all surfaces to form a shell
259
+ all_surfs = [top_surf, bot_surf]
260
+ all_surfs.extend([tag for (dim, tag) in outDimTags_outer if dim == 2])
261
+ all_surfs.extend([tag for (dim, tag) in outDimTags_inner if dim == 2])
262
+
263
+ # Create surface loop and volume
264
+ gmsh.model.occ.synchronize()
265
+ surf_loop = gmsh.model.occ.addSurfaceLoop(all_surfs)
266
+ trench_vol = gmsh.model.occ.addVolume([surf_loop])
267
+
268
+ gmsh.model.occ.healShapes()
269
+ gmsh.model.occ.removeAllDuplicates()
270
+ gmsh.model.occ.synchronize()
271
+
272
+ # Use outer_top for ring_top in clearance calculations
273
+ ring_top = outer_top
274
+ else:
275
+ # Original logic for open paths
276
+ Ltop, Rtop = _offset_polyline(path_xy, half_top)
277
+ Lbot, Rbot = _offset_polyline(path_xy, half_bot)
278
+ ring_top = _ring_from_LR(Ltop, Rtop)
279
+ ring_bot = _ring_from_LR(Lbot, Rbot)
280
+
281
+ ring_top_xyz = [(x, y, g(x, y)) for (x, y) in ring_top]
282
+ ring_bot_xyz = [(x, y, g(x, y) - depth) for (x, y) in ring_bot]
283
+
284
+ top_loop = _add_closed_wire_xyz(ring_top_xyz)
285
+ bot_loop = _add_closed_wire_xyz(ring_bot_xyz)
286
+
287
+ outDimTags = []
288
+ try:
289
+ gmsh.model.occ.addThruSections(
290
+ [top_loop, bot_loop], makeSolid=True, makeRuled=True, outDimTags=outDimTags
291
+ )
292
+ except TypeError: # gmsh >= 4.14 removed outDimTags kwarg
293
+ outDimTags = gmsh.model.occ.addThruSections(
294
+ [top_loop, bot_loop], makeSolid=True, makeRuled=True
295
+ )
296
+ if outDimTags is None:
297
+ outDimTags = []
298
+ gmsh.model.occ.healShapes()
299
+ gmsh.model.occ.removeAllDuplicates()
300
+ gmsh.model.occ.synchronize()
201
301
 
202
- vols = [tag for (dim, tag) in outDimTags if dim == 3]
203
- assert len(vols) >= 1, "Loft did not create a volume"
204
- trench_vol = vols[0]
302
+ vols = [tag for (dim, tag) in outDimTags if dim == 3]
303
+ assert len(vols) >= 1, "Loft did not create a volume"
304
+ trench_vol = vols[0]
205
305
 
206
306
  pipe_cfgs = cfg.get("pipes", [])
207
307
  cum_lengths, total_length = _polyline_lengths(path_xy)
@@ -2,8 +2,8 @@
2
2
  "surface_area_by_group": {
3
3
  "trench_bottom": 5.0,
4
4
  "trench_cap_for_volume": 5.0,
5
- "trench_walls": 12.0,
6
- "ground_surface": 77.0
5
+ "trench_walls": 7.2,
6
+ "ground_surface": 10.0
7
7
  },
8
8
  "closed_surface_sets": {
9
9
  "trench_closed_groups": [
@@ -13,8 +13,8 @@
13
13
  ]
14
14
  },
15
15
  "volumes": {
16
- "trench_from_surface": -1.6666666666666667,
17
- "trench_flux_integral_div1": -1.6666666666666667
16
+ "trench_from_surface": -1.0,
17
+ "trench_flux_integral_div1": -1.0
18
18
  },
19
19
  "footprint_area_top": 5.0,
20
20
  "footprint_area_bottom": 5.0,
@@ -10,7 +10,7 @@
10
10
  ]
11
11
  ],
12
12
  "width": 1.0,
13
- "depth": 1.0,
13
+ "depth": 0.6,
14
14
  "wall_slope": 0.0,
15
15
  "ground_margin": 0.5,
16
16
  "ground": {
@@ -19,7 +19,7 @@
19
19
  0.0,
20
20
  0.0
21
21
  ],
22
- "size_margin": 3.0
22
+ "size_margin": 1.0
23
23
  },
24
24
  "pipes": [],
25
25
  "boxes": [],
@@ -1,46 +1,49 @@
1
1
  g trench_bottom
2
- v 0 -0.5 -1
3
- v 5 -0.5 -1
4
- v 5 0.5 -1
5
- v 0 0.5 -1
2
+ v 0 -0.5 -0.6
3
+ v 5 -0.5 -0.6
4
+ v 5 0.5 -0.6
5
+ v 0 0.5 -0.6
6
6
  f 2 1 4
7
7
  f 4 3 2
8
- g trench_cap_for_volume
9
- v 0 -0.5 0
10
- v 5 -0.5 0
11
- v 5 0.5 0
12
- v 0 0.5 0
13
- f 8 5 6
14
- f 6 7 8
15
8
  g trench_walls
16
9
  v 0 -0.5 0
17
10
  v 5 -0.5 0
18
- v 5 -0.5 -1
19
- v 0 -0.5 -1
11
+ v 5 -0.5 -0.6
12
+ v 0 -0.5 -0.6
20
13
  v 5 -0.5 0
21
14
  v 5 0.5 0
22
- v 5 0.5 -1
23
- v 5 -0.5 -1
15
+ v 5 0.5 -0.6
16
+ v 5 -0.5 -0.6
24
17
  v 5 0.5 0
25
18
  v 0 0.5 0
26
- v 0 0.5 -1
27
- v 5 0.5 -1
19
+ v 0 0.5 -0.6
20
+ v 5 0.5 -0.6
28
21
  v 0 0.5 0
29
22
  v 0 -0.5 0
30
- v 0 -0.5 -1
31
- v 0 0.5 -1
23
+ v 0 -0.5 -0.6
24
+ v 0 0.5 -0.6
25
+ f 5 6 7
26
+ f 5 7 8
32
27
  f 9 10 11
33
28
  f 9 11 12
34
29
  f 13 14 15
35
30
  f 13 15 16
36
31
  f 17 18 19
37
32
  f 17 19 20
38
- f 21 22 23
39
- f 21 23 24
40
33
  g ground_surface
41
- v -3 -3.5 0
42
- v 8 -3.5 0
43
- v 8 3.5 0
44
- v -3 3.5 0
45
- f 25 26 27
46
- f 25 27 28
34
+ v 0 -1.5 0
35
+ v 5 -1.5 0
36
+ v 5 1.5 0
37
+ v 0 1.5 0
38
+ v 0 -0.5 0
39
+ v 5 -0.5 0
40
+ v 5 0.5 0
41
+ v 0 0.5 0
42
+ f 21 22 25
43
+ f 22 26 25
44
+ f 22 23 26
45
+ f 23 27 26
46
+ f 23 24 27
47
+ f 24 28 27
48
+ f 24 21 28
49
+ f 21 25 28