trenchfoot 0.4.1__py3-none-any.whl → 0.4.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.
- trenchfoot/trench_scene_generator_v3.py +677 -37
- {trenchfoot-0.4.1.dist-info → trenchfoot-0.4.2.dist-info}/METADATA +1 -1
- {trenchfoot-0.4.1.dist-info → trenchfoot-0.4.2.dist-info}/RECORD +7 -7
- /trenchfoot/scenarios/S03_L_slope_two_pipes_box/point_clouds/full/{resolution0p050.pth → resolutio} +0 -0
- {trenchfoot-0.4.1.dist-info → trenchfoot-0.4.2.dist-info}/WHEEL +0 -0
- {trenchfoot-0.4.1.dist-info → trenchfoot-0.4.2.dist-info}/entry_points.txt +0 -0
- {trenchfoot-0.4.1.dist-info → trenchfoot-0.4.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -18,7 +18,7 @@ Outputs:
|
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
20
|
import io
|
|
21
|
-
import os, json, math, argparse
|
|
21
|
+
import os, json, math, argparse
|
|
22
22
|
from dataclasses import dataclass, field, asdict
|
|
23
23
|
from pathlib import Path
|
|
24
24
|
from typing import Dict, List, Tuple, Optional, Any
|
|
@@ -614,41 +614,202 @@ def _frame_from_axis(axis_dir: np.ndarray) -> np.ndarray:
|
|
|
614
614
|
u=_normalize(np.cross(helper,v)); w=np.cross(v,u)
|
|
615
615
|
return np.column_stack([u,v,w])
|
|
616
616
|
|
|
617
|
-
def make_cylinder(
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
617
|
+
def make_cylinder(
|
|
618
|
+
center: np.ndarray,
|
|
619
|
+
axis_dir: np.ndarray,
|
|
620
|
+
radius: float,
|
|
621
|
+
length: float,
|
|
622
|
+
n_theta: int = 64,
|
|
623
|
+
n_along: int = 32,
|
|
624
|
+
with_caps: bool = True,
|
|
625
|
+
neg_extent: Optional[float] = None,
|
|
626
|
+
pos_extent: Optional[float] = None,
|
|
627
|
+
cap_plane_neg: Optional[Tuple[np.ndarray, np.ndarray]] = None,
|
|
628
|
+
cap_plane_pos: Optional[Tuple[np.ndarray, np.ndarray]] = None,
|
|
629
|
+
) -> Dict[str, Tuple[np.ndarray, np.ndarray]]:
|
|
630
|
+
"""Generate a cylinder mesh with optional truncation and angled caps.
|
|
631
|
+
|
|
632
|
+
Parameters
|
|
633
|
+
----------
|
|
634
|
+
center : np.ndarray
|
|
635
|
+
Center point of the cylinder (3D).
|
|
636
|
+
axis_dir : np.ndarray
|
|
637
|
+
Unit vector along the cylinder axis (3D).
|
|
638
|
+
radius : float
|
|
639
|
+
Cylinder radius.
|
|
640
|
+
length : float
|
|
641
|
+
Total cylinder length (used if neg/pos_extent not specified).
|
|
642
|
+
n_theta : int
|
|
643
|
+
Number of angular divisions.
|
|
644
|
+
n_along : int
|
|
645
|
+
Number of divisions along the axis.
|
|
646
|
+
with_caps : bool
|
|
647
|
+
Whether to generate end caps.
|
|
648
|
+
neg_extent : float, optional
|
|
649
|
+
Distance from center to negative end. If None, uses -length/2.
|
|
650
|
+
pos_extent : float, optional
|
|
651
|
+
Distance from center to positive end. If None, uses +length/2.
|
|
652
|
+
cap_plane_neg : tuple, optional
|
|
653
|
+
(normal, point) defining the plane for negative cap. If provided,
|
|
654
|
+
generates an elliptical cap on this plane instead of a flat circular cap.
|
|
655
|
+
cap_plane_pos : tuple, optional
|
|
656
|
+
(normal, point) for positive cap.
|
|
657
|
+
|
|
658
|
+
Returns
|
|
659
|
+
-------
|
|
660
|
+
dict
|
|
661
|
+
Dictionary with 'pipe_side' and optionally 'pipe_cap_neg', 'pipe_cap_pos'.
|
|
662
|
+
"""
|
|
663
|
+
n_theta = max(8, int(n_theta))
|
|
664
|
+
n_along = max(1, int(n_along))
|
|
665
|
+
|
|
666
|
+
# Use extents if provided, otherwise symmetric from length
|
|
667
|
+
y_neg = neg_extent if neg_extent is not None else -length / 2.0
|
|
668
|
+
y_pos = pos_extent if pos_extent is not None else length / 2.0
|
|
669
|
+
|
|
670
|
+
# Build coordinate frame
|
|
671
|
+
M = _frame_from_axis(axis_dir)
|
|
672
|
+
|
|
673
|
+
def xform(V: np.ndarray) -> np.ndarray:
|
|
674
|
+
return (center + V @ M.T).astype(float)
|
|
675
|
+
|
|
676
|
+
# Generate cylinder side surface
|
|
677
|
+
thetas = np.linspace(0, 2 * np.pi, n_theta + 1)
|
|
678
|
+
ys = np.linspace(y_neg, y_pos, n_along + 1)
|
|
679
|
+
Vloc = []
|
|
680
|
+
for j in range(n_along + 1):
|
|
681
|
+
y = ys[j]
|
|
682
|
+
for i in range(n_theta + 1):
|
|
683
|
+
th = thetas[i]
|
|
684
|
+
x = radius * np.cos(th)
|
|
685
|
+
z = radius * np.sin(th)
|
|
686
|
+
Vloc.append([x, y, z])
|
|
687
|
+
Vloc = np.array(Vloc, float)
|
|
688
|
+
|
|
689
|
+
def idx(i: int, j: int) -> int:
|
|
690
|
+
return j * (n_theta + 1) + i
|
|
691
|
+
|
|
692
|
+
F = []
|
|
630
693
|
for j in range(n_along):
|
|
631
694
|
for i in range(n_theta):
|
|
632
|
-
v00
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
Fp=np.array([[0,1+i,1+(i+1)%len(ring)] for i in range(len(ring))],int)
|
|
643
|
-
caps['pipe_cap_neg']=(Vn,Fn); caps['pipe_cap_pos']=(Vp,Fp)
|
|
644
|
-
M=_frame_from_axis(axis_dir)
|
|
645
|
-
def xform(V): return (center + V @ M.T).astype(float)
|
|
646
|
-
out={"pipe_side": (xform(Vloc), F)}
|
|
695
|
+
v00 = idx(i, j)
|
|
696
|
+
v10 = idx(i + 1, j)
|
|
697
|
+
v01 = idx(i, j + 1)
|
|
698
|
+
v11 = idx(i + 1, j + 1)
|
|
699
|
+
F.append([v00, v01, v11])
|
|
700
|
+
F.append([v00, v11, v10])
|
|
701
|
+
F = np.array(F, int)
|
|
702
|
+
|
|
703
|
+
out: Dict[str, Tuple[np.ndarray, np.ndarray]] = {"pipe_side": (xform(Vloc), F)}
|
|
704
|
+
|
|
647
705
|
if with_caps:
|
|
648
|
-
|
|
649
|
-
|
|
706
|
+
# Generate caps (either flat circular or angled elliptical)
|
|
707
|
+
Vn, Fn = _make_cylinder_cap(
|
|
708
|
+
radius, y_neg, thetas[:-1], M, center, axis_dir,
|
|
709
|
+
cap_plane_neg, is_negative=True
|
|
710
|
+
)
|
|
711
|
+
Vp, Fp = _make_cylinder_cap(
|
|
712
|
+
radius, y_pos, thetas[:-1], M, center, axis_dir,
|
|
713
|
+
cap_plane_pos, is_negative=False
|
|
714
|
+
)
|
|
715
|
+
out['pipe_cap_neg'] = (Vn, Fn)
|
|
716
|
+
out['pipe_cap_pos'] = (Vp, Fp)
|
|
717
|
+
|
|
650
718
|
return out
|
|
651
719
|
|
|
720
|
+
|
|
721
|
+
def _make_cylinder_cap(
|
|
722
|
+
radius: float,
|
|
723
|
+
y_extent: float,
|
|
724
|
+
thetas: np.ndarray,
|
|
725
|
+
M: np.ndarray,
|
|
726
|
+
center: np.ndarray,
|
|
727
|
+
axis_dir: np.ndarray,
|
|
728
|
+
cap_plane: Optional[Tuple[np.ndarray, np.ndarray]],
|
|
729
|
+
is_negative: bool,
|
|
730
|
+
) -> Tuple[np.ndarray, np.ndarray]:
|
|
731
|
+
"""Generate a cylinder end cap, either flat or angled.
|
|
732
|
+
|
|
733
|
+
For angled caps, we compute where each point on the cylinder rim
|
|
734
|
+
intersects the cap plane, creating an elliptical cap.
|
|
735
|
+
"""
|
|
736
|
+
n_theta = len(thetas)
|
|
737
|
+
|
|
738
|
+
if cap_plane is None:
|
|
739
|
+
# Flat circular cap perpendicular to axis
|
|
740
|
+
ring = np.array([
|
|
741
|
+
[radius * np.cos(t), y_extent, radius * np.sin(t)]
|
|
742
|
+
for t in thetas
|
|
743
|
+
], float)
|
|
744
|
+
cap_center = np.array([[0.0, y_extent, 0.0]], float)
|
|
745
|
+
V = np.vstack([cap_center, ring])
|
|
746
|
+
|
|
747
|
+
# Apply transformation to world coordinates
|
|
748
|
+
V_world = center + V @ M.T
|
|
749
|
+
|
|
750
|
+
# Generate fan triangles
|
|
751
|
+
if is_negative:
|
|
752
|
+
# Negative cap: winding for outward normal (toward -axis)
|
|
753
|
+
F = np.array([[0, 1 + (i + 1) % n_theta, 1 + i] for i in range(n_theta)], int)
|
|
754
|
+
else:
|
|
755
|
+
# Positive cap: winding for outward normal (toward +axis)
|
|
756
|
+
F = np.array([[0, 1 + i, 1 + (i + 1) % n_theta] for i in range(n_theta)], int)
|
|
757
|
+
|
|
758
|
+
return V_world.astype(float), F
|
|
759
|
+
else:
|
|
760
|
+
# Angled cap: intersect cylinder rim with plane
|
|
761
|
+
plane_normal, plane_point = cap_plane
|
|
762
|
+
plane_normal = _normalize(plane_normal)
|
|
763
|
+
|
|
764
|
+
# Points on the cylinder rim at y_extent (in local coords before xform)
|
|
765
|
+
ring_local = np.array([
|
|
766
|
+
[radius * np.cos(t), y_extent, radius * np.sin(t)]
|
|
767
|
+
for t in thetas
|
|
768
|
+
], float)
|
|
769
|
+
|
|
770
|
+
# Transform ring to world coordinates
|
|
771
|
+
ring_world = center + ring_local @ M.T
|
|
772
|
+
|
|
773
|
+
# For each ring point, project along axis onto the cap plane
|
|
774
|
+
# Line: P = ring_point + t * axis_dir
|
|
775
|
+
# Plane: dot(P - plane_point, plane_normal) = 0
|
|
776
|
+
# => t = dot(plane_point - ring_point, plane_normal) / dot(axis_dir, plane_normal)
|
|
777
|
+
denom = np.dot(axis_dir, plane_normal)
|
|
778
|
+
if abs(denom) < 1e-10:
|
|
779
|
+
# Axis is parallel to plane - fall back to flat cap
|
|
780
|
+
V_world = np.vstack([
|
|
781
|
+
center + np.array([0.0, y_extent, 0.0]) @ M.T,
|
|
782
|
+
ring_world
|
|
783
|
+
])
|
|
784
|
+
if is_negative:
|
|
785
|
+
F = np.array([[0, 1 + (i + 1) % n_theta, 1 + i] for i in range(n_theta)], int)
|
|
786
|
+
else:
|
|
787
|
+
F = np.array([[0, 1 + i, 1 + (i + 1) % n_theta] for i in range(n_theta)], int)
|
|
788
|
+
return V_world.astype(float), F
|
|
789
|
+
|
|
790
|
+
# Project ring points onto plane
|
|
791
|
+
cap_verts = []
|
|
792
|
+
for ring_pt in ring_world:
|
|
793
|
+
t = np.dot(plane_point - ring_pt, plane_normal) / denom
|
|
794
|
+
cap_pt = ring_pt + t * axis_dir
|
|
795
|
+
cap_verts.append(cap_pt)
|
|
796
|
+
cap_verts = np.array(cap_verts, float)
|
|
797
|
+
|
|
798
|
+
# Cap center: project axis center onto plane
|
|
799
|
+
axis_pt = center + y_extent * axis_dir
|
|
800
|
+
t_center = np.dot(plane_point - axis_pt, plane_normal) / denom
|
|
801
|
+
cap_center = axis_pt + t_center * axis_dir
|
|
802
|
+
|
|
803
|
+
V_world = np.vstack([cap_center.reshape(1, 3), cap_verts])
|
|
804
|
+
|
|
805
|
+
# Generate fan triangles
|
|
806
|
+
if is_negative:
|
|
807
|
+
F = np.array([[0, 1 + (i + 1) % n_theta, 1 + i] for i in range(n_theta)], int)
|
|
808
|
+
else:
|
|
809
|
+
F = np.array([[0, 1 + i, 1 + (i + 1) % n_theta] for i in range(n_theta)], int)
|
|
810
|
+
|
|
811
|
+
return V_world.astype(float), F
|
|
812
|
+
|
|
652
813
|
def make_box(center: np.ndarray, frame_cols: np.ndarray, dims: Tuple[float,float,float]):
|
|
653
814
|
a,b,h=dims; u=frame_cols[:,0]; v=frame_cols[:,1]; w=frame_cols[:,2]
|
|
654
815
|
corners=[]
|
|
@@ -1082,6 +1243,433 @@ def make_ground_surface_plane(path_xy: List[Tuple[float,float]], width_top: floa
|
|
|
1082
1243
|
def _half_width_at_depth(half_top: float, slope: float, top_z: float, z: float) -> float:
|
|
1083
1244
|
return max(1e-6, half_top - slope * (top_z - z))
|
|
1084
1245
|
|
|
1246
|
+
|
|
1247
|
+
# ---------------- Object Truncation Helpers ----------------
|
|
1248
|
+
|
|
1249
|
+
|
|
1250
|
+
@dataclass
|
|
1251
|
+
class TrenchLocalFrame:
|
|
1252
|
+
"""Local coordinate frame at a point along the trench."""
|
|
1253
|
+
centerline_xy: np.ndarray # 2D position on centerline
|
|
1254
|
+
tangent: np.ndarray # 2D unit tangent along path
|
|
1255
|
+
left_normal: np.ndarray # 2D unit normal pointing left
|
|
1256
|
+
top_z: float # Ground elevation at this point
|
|
1257
|
+
half_width_top: float # Half-width at ground level
|
|
1258
|
+
depth: float # Trench depth
|
|
1259
|
+
wall_slope: float # Slope of walls
|
|
1260
|
+
|
|
1261
|
+
|
|
1262
|
+
def _find_trench_frame_at_xy(
|
|
1263
|
+
x: float, y: float,
|
|
1264
|
+
path_xy: List[Tuple[float, float]],
|
|
1265
|
+
half_top: float,
|
|
1266
|
+
depth: float,
|
|
1267
|
+
wall_slope: float,
|
|
1268
|
+
ground: GroundSpec,
|
|
1269
|
+
) -> Tuple[TrenchLocalFrame, float]:
|
|
1270
|
+
"""Find the trench local frame for a given XY position.
|
|
1271
|
+
|
|
1272
|
+
Returns the local coordinate frame and the local 'u' offset (signed
|
|
1273
|
+
distance from centerline in left_normal direction).
|
|
1274
|
+
"""
|
|
1275
|
+
_, total = _polyline_lengths(path_xy)
|
|
1276
|
+
|
|
1277
|
+
# Find closest point on path by sampling
|
|
1278
|
+
best_dist_sq = float("inf")
|
|
1279
|
+
best_s = 0.0
|
|
1280
|
+
n_samples = max(200, int(total * 50)) # ~50 samples per unit length for precision
|
|
1281
|
+
for s_val in np.linspace(0, 1, n_samples):
|
|
1282
|
+
pos, _ = _sample_polyline_at_s(path_xy, s_val)
|
|
1283
|
+
dist_sq = (pos[0] - x) ** 2 + (pos[1] - y) ** 2
|
|
1284
|
+
if dist_sq < best_dist_sq:
|
|
1285
|
+
best_dist_sq = dist_sq
|
|
1286
|
+
best_s = s_val
|
|
1287
|
+
|
|
1288
|
+
pos, tangent = _sample_polyline_at_s(path_xy, best_s)
|
|
1289
|
+
left_normal = _rotate_ccw(tangent)
|
|
1290
|
+
gfun = _ground_fn(ground)
|
|
1291
|
+
top_z = gfun(pos[0], pos[1])
|
|
1292
|
+
|
|
1293
|
+
# Compute local u offset
|
|
1294
|
+
offset_vec = np.array([x - pos[0], y - pos[1]])
|
|
1295
|
+
local_u = float(np.dot(offset_vec, left_normal))
|
|
1296
|
+
|
|
1297
|
+
frame = TrenchLocalFrame(
|
|
1298
|
+
centerline_xy=pos,
|
|
1299
|
+
tangent=tangent,
|
|
1300
|
+
left_normal=left_normal,
|
|
1301
|
+
top_z=top_z,
|
|
1302
|
+
half_width_top=half_top,
|
|
1303
|
+
depth=depth,
|
|
1304
|
+
wall_slope=wall_slope,
|
|
1305
|
+
)
|
|
1306
|
+
return frame, local_u
|
|
1307
|
+
|
|
1308
|
+
|
|
1309
|
+
def _point_inside_trench(
|
|
1310
|
+
x: float, y: float, z: float,
|
|
1311
|
+
path_xy: List[Tuple[float, float]],
|
|
1312
|
+
half_top: float,
|
|
1313
|
+
depth: float,
|
|
1314
|
+
wall_slope: float,
|
|
1315
|
+
ground: GroundSpec,
|
|
1316
|
+
) -> bool:
|
|
1317
|
+
"""Check if a 3D point is inside the trench void."""
|
|
1318
|
+
frame, local_u = _find_trench_frame_at_xy(x, y, path_xy, half_top, depth, wall_slope, ground)
|
|
1319
|
+
|
|
1320
|
+
# Check vertical bounds
|
|
1321
|
+
if z > frame.top_z:
|
|
1322
|
+
return False # Above ground
|
|
1323
|
+
if z < frame.top_z - depth:
|
|
1324
|
+
return False # Below floor
|
|
1325
|
+
|
|
1326
|
+
# Check horizontal bounds (accounting for wall slope)
|
|
1327
|
+
half_w = _half_width_at_depth(half_top, wall_slope, frame.top_z, z)
|
|
1328
|
+
return abs(local_u) <= half_w
|
|
1329
|
+
|
|
1330
|
+
|
|
1331
|
+
@dataclass
|
|
1332
|
+
class TruncationResult:
|
|
1333
|
+
"""Result of computing pipe truncation."""
|
|
1334
|
+
neg_extent: float # Distance from center to negative end
|
|
1335
|
+
pos_extent: float # Distance from center to positive end
|
|
1336
|
+
neg_cap_plane: Optional[Tuple[np.ndarray, np.ndarray]] # (normal, point) or None
|
|
1337
|
+
pos_cap_plane: Optional[Tuple[np.ndarray, np.ndarray]] # (normal, point) or None
|
|
1338
|
+
was_truncated: bool # True if any truncation occurred
|
|
1339
|
+
|
|
1340
|
+
|
|
1341
|
+
def _compute_pipe_truncation(
|
|
1342
|
+
center: np.ndarray,
|
|
1343
|
+
axis_dir: np.ndarray,
|
|
1344
|
+
radius: float,
|
|
1345
|
+
half_length: float,
|
|
1346
|
+
path_xy: List[Tuple[float, float]],
|
|
1347
|
+
half_top: float,
|
|
1348
|
+
wall_slope: float,
|
|
1349
|
+
ground: GroundSpec,
|
|
1350
|
+
depth: float,
|
|
1351
|
+
) -> TruncationResult:
|
|
1352
|
+
"""Compute where a pipe axis exits the trench void.
|
|
1353
|
+
|
|
1354
|
+
Samples points along the pipe axis and finds where the pipe surface
|
|
1355
|
+
(considering radius) would exit the trench. Returns truncated extents
|
|
1356
|
+
and the wall/floor planes at each truncation point.
|
|
1357
|
+
|
|
1358
|
+
The truncation includes a safety margin to account for cap projection.
|
|
1359
|
+
When the pipe is truncated at an angle, the cap vertices project beyond
|
|
1360
|
+
the truncation point. The cap_margin ensures the entire cap stays inside.
|
|
1361
|
+
"""
|
|
1362
|
+
# Cap safety margin: accounts for cap projection when pipe is at an angle
|
|
1363
|
+
# to the trench wall. The margin is proportional to radius with a minimum.
|
|
1364
|
+
cap_margin = max(0.02, 0.4 * radius)
|
|
1365
|
+
|
|
1366
|
+
def pipe_surface_inside(t: float) -> bool:
|
|
1367
|
+
"""Check if pipe surface at axis position t is inside trench.
|
|
1368
|
+
|
|
1369
|
+
Includes cap_margin to ensure angled caps stay inside the boundary.
|
|
1370
|
+
"""
|
|
1371
|
+
point = center + t * axis_dir
|
|
1372
|
+
x, y, z = point
|
|
1373
|
+
|
|
1374
|
+
# Get local trench frame
|
|
1375
|
+
frame, local_u = _find_trench_frame_at_xy(
|
|
1376
|
+
x, y, path_xy, half_top, depth, wall_slope, ground
|
|
1377
|
+
)
|
|
1378
|
+
|
|
1379
|
+
# Effective radius includes cap margin for conservative truncation
|
|
1380
|
+
effective_radius = radius + cap_margin
|
|
1381
|
+
|
|
1382
|
+
# Check floor clearance: pipe bottom must be above floor
|
|
1383
|
+
floor_z = frame.top_z - depth
|
|
1384
|
+
if z - effective_radius < floor_z:
|
|
1385
|
+
return False
|
|
1386
|
+
|
|
1387
|
+
# Check ceiling clearance: pipe top must be below ground
|
|
1388
|
+
if z + effective_radius > frame.top_z:
|
|
1389
|
+
return False
|
|
1390
|
+
|
|
1391
|
+
# Check wall clearance: pipe surface must not penetrate walls
|
|
1392
|
+
half_w = _half_width_at_depth(half_top, wall_slope, frame.top_z, z)
|
|
1393
|
+
if abs(local_u) + effective_radius > half_w:
|
|
1394
|
+
return False
|
|
1395
|
+
|
|
1396
|
+
return True
|
|
1397
|
+
|
|
1398
|
+
def binary_search_boundary(t_inside: float, t_outside: float, tol: float = 0.001) -> float:
|
|
1399
|
+
"""Binary search to find boundary between inside and outside."""
|
|
1400
|
+
for _ in range(50): # Max iterations
|
|
1401
|
+
if abs(t_outside - t_inside) < tol:
|
|
1402
|
+
break
|
|
1403
|
+
t_mid = (t_inside + t_outside) / 2
|
|
1404
|
+
if pipe_surface_inside(t_mid):
|
|
1405
|
+
t_inside = t_mid
|
|
1406
|
+
else:
|
|
1407
|
+
t_outside = t_mid
|
|
1408
|
+
return t_inside
|
|
1409
|
+
|
|
1410
|
+
# Find negative extent
|
|
1411
|
+
neg_extent = -half_length
|
|
1412
|
+
was_neg_truncated = False
|
|
1413
|
+
if pipe_surface_inside(0):
|
|
1414
|
+
# Search from center toward negative end
|
|
1415
|
+
step = 0.02 # 2cm steps
|
|
1416
|
+
t = 0
|
|
1417
|
+
while t > -half_length:
|
|
1418
|
+
t -= step
|
|
1419
|
+
if not pipe_surface_inside(t):
|
|
1420
|
+
# Found exit, binary search for exact boundary
|
|
1421
|
+
neg_extent = binary_search_boundary(t + step, t)
|
|
1422
|
+
was_neg_truncated = True
|
|
1423
|
+
break
|
|
1424
|
+
if not was_neg_truncated:
|
|
1425
|
+
# Never exited, use full length
|
|
1426
|
+
neg_extent = -half_length
|
|
1427
|
+
|
|
1428
|
+
# Find positive extent
|
|
1429
|
+
pos_extent = half_length
|
|
1430
|
+
was_pos_truncated = False
|
|
1431
|
+
if pipe_surface_inside(0):
|
|
1432
|
+
step = 0.02
|
|
1433
|
+
t = 0
|
|
1434
|
+
while t < half_length:
|
|
1435
|
+
t += step
|
|
1436
|
+
if not pipe_surface_inside(t):
|
|
1437
|
+
pos_extent = binary_search_boundary(t - step, t)
|
|
1438
|
+
was_pos_truncated = True
|
|
1439
|
+
break
|
|
1440
|
+
if not was_pos_truncated:
|
|
1441
|
+
pos_extent = half_length
|
|
1442
|
+
|
|
1443
|
+
# Compute cap planes at truncation points
|
|
1444
|
+
neg_cap_plane = None
|
|
1445
|
+
pos_cap_plane = None
|
|
1446
|
+
|
|
1447
|
+
if was_neg_truncated:
|
|
1448
|
+
neg_cap_plane = _compute_cap_plane_at_truncation(
|
|
1449
|
+
center + neg_extent * axis_dir, radius,
|
|
1450
|
+
path_xy, half_top, wall_slope, ground, depth
|
|
1451
|
+
)
|
|
1452
|
+
|
|
1453
|
+
if was_pos_truncated:
|
|
1454
|
+
pos_cap_plane = _compute_cap_plane_at_truncation(
|
|
1455
|
+
center + pos_extent * axis_dir, radius,
|
|
1456
|
+
path_xy, half_top, wall_slope, ground, depth
|
|
1457
|
+
)
|
|
1458
|
+
|
|
1459
|
+
was_truncated = was_neg_truncated or was_pos_truncated
|
|
1460
|
+
return TruncationResult(
|
|
1461
|
+
neg_extent=neg_extent,
|
|
1462
|
+
pos_extent=pos_extent,
|
|
1463
|
+
neg_cap_plane=neg_cap_plane,
|
|
1464
|
+
pos_cap_plane=pos_cap_plane,
|
|
1465
|
+
was_truncated=was_truncated,
|
|
1466
|
+
)
|
|
1467
|
+
|
|
1468
|
+
|
|
1469
|
+
def _compute_cap_plane_at_truncation(
|
|
1470
|
+
point: np.ndarray,
|
|
1471
|
+
radius: float,
|
|
1472
|
+
path_xy: List[Tuple[float, float]],
|
|
1473
|
+
half_top: float,
|
|
1474
|
+
wall_slope: float,
|
|
1475
|
+
ground: GroundSpec,
|
|
1476
|
+
depth: float,
|
|
1477
|
+
) -> Tuple[np.ndarray, np.ndarray]:
|
|
1478
|
+
"""Compute the plane where the pipe intersects the trench boundary.
|
|
1479
|
+
|
|
1480
|
+
Determines which boundary (left wall, right wall, floor) the pipe exits
|
|
1481
|
+
through and returns (normal, point) for that plane.
|
|
1482
|
+
"""
|
|
1483
|
+
x, y, z = point
|
|
1484
|
+
frame, local_u = _find_trench_frame_at_xy(
|
|
1485
|
+
x, y, path_xy, half_top, depth, wall_slope, ground
|
|
1486
|
+
)
|
|
1487
|
+
|
|
1488
|
+
floor_z = frame.top_z - depth
|
|
1489
|
+
half_w = _half_width_at_depth(half_top, wall_slope, frame.top_z, z)
|
|
1490
|
+
|
|
1491
|
+
# Determine which boundary was hit
|
|
1492
|
+
dist_to_floor = z - radius - floor_z
|
|
1493
|
+
dist_to_ceiling = frame.top_z - (z + radius)
|
|
1494
|
+
dist_to_left_wall = half_w - (local_u + radius)
|
|
1495
|
+
dist_to_right_wall = half_w - (-local_u + radius)
|
|
1496
|
+
|
|
1497
|
+
# For sloped walls, the wall normal has a horizontal and vertical component
|
|
1498
|
+
# Wall slope means the wall goes inward as we go down
|
|
1499
|
+
# Wall normal = (left_normal_2d_x, left_normal_2d_y, slope) normalized
|
|
1500
|
+
if wall_slope > 0:
|
|
1501
|
+
wall_normal_3d = np.array([
|
|
1502
|
+
frame.left_normal[0],
|
|
1503
|
+
frame.left_normal[1],
|
|
1504
|
+
wall_slope
|
|
1505
|
+
], float)
|
|
1506
|
+
wall_normal_3d = wall_normal_3d / np.linalg.norm(wall_normal_3d)
|
|
1507
|
+
else:
|
|
1508
|
+
wall_normal_3d = np.array([frame.left_normal[0], frame.left_normal[1], 0.0], float)
|
|
1509
|
+
|
|
1510
|
+
# Find which boundary is closest (most violated)
|
|
1511
|
+
min_dist = min(dist_to_floor, dist_to_ceiling, dist_to_left_wall, dist_to_right_wall)
|
|
1512
|
+
|
|
1513
|
+
if min_dist == dist_to_floor or dist_to_floor < 0:
|
|
1514
|
+
# Hit floor - horizontal plane at floor level
|
|
1515
|
+
plane_normal = np.array([0.0, 0.0, 1.0], float)
|
|
1516
|
+
plane_point = np.array([x, y, floor_z], float)
|
|
1517
|
+
elif min_dist == dist_to_ceiling or dist_to_ceiling < 0:
|
|
1518
|
+
# Hit ceiling (ground) - horizontal plane at ground level
|
|
1519
|
+
plane_normal = np.array([0.0, 0.0, -1.0], float)
|
|
1520
|
+
plane_point = np.array([x, y, frame.top_z], float)
|
|
1521
|
+
elif min_dist == dist_to_left_wall or dist_to_left_wall < 0:
|
|
1522
|
+
# Hit left wall
|
|
1523
|
+
plane_normal = -wall_normal_3d # Points inward (into trench)
|
|
1524
|
+
wall_x = frame.centerline_xy[0] + half_w * frame.left_normal[0]
|
|
1525
|
+
wall_y = frame.centerline_xy[1] + half_w * frame.left_normal[1]
|
|
1526
|
+
plane_point = np.array([wall_x, wall_y, z], float)
|
|
1527
|
+
else:
|
|
1528
|
+
# Hit right wall
|
|
1529
|
+
plane_normal = wall_normal_3d # Flip for right wall
|
|
1530
|
+
plane_normal[0] = -plane_normal[0]
|
|
1531
|
+
plane_normal[1] = -plane_normal[1]
|
|
1532
|
+
wall_x = frame.centerline_xy[0] - half_w * frame.left_normal[0]
|
|
1533
|
+
wall_y = frame.centerline_xy[1] - half_w * frame.left_normal[1]
|
|
1534
|
+
plane_point = np.array([wall_x, wall_y, z], float)
|
|
1535
|
+
|
|
1536
|
+
return plane_normal, plane_point
|
|
1537
|
+
|
|
1538
|
+
|
|
1539
|
+
def _compute_box_fit(
|
|
1540
|
+
center: np.ndarray,
|
|
1541
|
+
along: float,
|
|
1542
|
+
across: float,
|
|
1543
|
+
height: float,
|
|
1544
|
+
path_xy: List[Tuple[float, float]],
|
|
1545
|
+
half_top: float,
|
|
1546
|
+
wall_slope: float,
|
|
1547
|
+
ground: GroundSpec,
|
|
1548
|
+
depth: float,
|
|
1549
|
+
clearance: float = 0.02,
|
|
1550
|
+
) -> Tuple[float, float, float]:
|
|
1551
|
+
"""Compute shrunk box dimensions to fit within trench.
|
|
1552
|
+
|
|
1553
|
+
Returns (along, across, height) that fit within the trench at the given
|
|
1554
|
+
center position.
|
|
1555
|
+
"""
|
|
1556
|
+
x, y, z = center
|
|
1557
|
+
frame, local_u = _find_trench_frame_at_xy(
|
|
1558
|
+
x, y, path_xy, half_top, depth, wall_slope, ground
|
|
1559
|
+
)
|
|
1560
|
+
|
|
1561
|
+
floor_z = frame.top_z - depth
|
|
1562
|
+
|
|
1563
|
+
# Max height: from floor to ground, minus clearance
|
|
1564
|
+
max_height = (frame.top_z - floor_z) - 2 * clearance
|
|
1565
|
+
fit_height = min(height, max_height)
|
|
1566
|
+
|
|
1567
|
+
# Recompute z to center the box if height was shrunk
|
|
1568
|
+
if fit_height < height:
|
|
1569
|
+
# Center box vertically in trench
|
|
1570
|
+
z_new = floor_z + clearance + fit_height / 2
|
|
1571
|
+
else:
|
|
1572
|
+
z_new = z
|
|
1573
|
+
|
|
1574
|
+
# At the box center depth, what's the half-width?
|
|
1575
|
+
half_w = _half_width_at_depth(half_top, wall_slope, frame.top_z, z_new)
|
|
1576
|
+
|
|
1577
|
+
# Max across: must fit within walls accounting for offset from centerline
|
|
1578
|
+
# The box extends ±across/2 from center, so:
|
|
1579
|
+
# local_u + across/2 <= half_w - clearance
|
|
1580
|
+
# local_u - across/2 >= -(half_w - clearance)
|
|
1581
|
+
# => across/2 <= min(half_w - clearance - local_u, half_w - clearance + local_u)
|
|
1582
|
+
max_across = 2 * (half_w - clearance - abs(local_u))
|
|
1583
|
+
fit_across = max(0.01, min(across, max_across))
|
|
1584
|
+
|
|
1585
|
+
# Along dimension: no shrinking needed for typical cases
|
|
1586
|
+
# (pipes along trench axis can be arbitrarily long within path bounds)
|
|
1587
|
+
fit_along = along
|
|
1588
|
+
|
|
1589
|
+
return fit_along, fit_across, fit_height
|
|
1590
|
+
|
|
1591
|
+
|
|
1592
|
+
def _compute_sphere_fit(
|
|
1593
|
+
center: np.ndarray,
|
|
1594
|
+
radius: float,
|
|
1595
|
+
path_xy: List[Tuple[float, float]],
|
|
1596
|
+
half_top: float,
|
|
1597
|
+
wall_slope: float,
|
|
1598
|
+
ground: GroundSpec,
|
|
1599
|
+
depth: float,
|
|
1600
|
+
clearance: float = 0.02,
|
|
1601
|
+
) -> float:
|
|
1602
|
+
"""Compute shrunk sphere radius to fit within trench.
|
|
1603
|
+
|
|
1604
|
+
Returns the maximum radius that fits within the trench at the given center.
|
|
1605
|
+
"""
|
|
1606
|
+
x, y, z = center
|
|
1607
|
+
frame, local_u = _find_trench_frame_at_xy(
|
|
1608
|
+
x, y, path_xy, half_top, depth, wall_slope, ground
|
|
1609
|
+
)
|
|
1610
|
+
|
|
1611
|
+
floor_z = frame.top_z - depth
|
|
1612
|
+
|
|
1613
|
+
# Distance to floor
|
|
1614
|
+
dist_floor = z - floor_z - clearance
|
|
1615
|
+
|
|
1616
|
+
# Distance to ground
|
|
1617
|
+
dist_ground = frame.top_z - z - clearance
|
|
1618
|
+
|
|
1619
|
+
# Distance to nearest wall (accounting for offset)
|
|
1620
|
+
half_w = _half_width_at_depth(half_top, wall_slope, frame.top_z, z)
|
|
1621
|
+
dist_wall = half_w - abs(local_u) - clearance
|
|
1622
|
+
|
|
1623
|
+
# Maximum radius is minimum of all distances
|
|
1624
|
+
max_radius = max(0.01, min(dist_floor, dist_ground, dist_wall))
|
|
1625
|
+
|
|
1626
|
+
return min(radius, max_radius)
|
|
1627
|
+
|
|
1628
|
+
|
|
1629
|
+
def _clip_vertices_to_trench(
|
|
1630
|
+
V: np.ndarray,
|
|
1631
|
+
path_xy: List[Tuple[float, float]],
|
|
1632
|
+
half_top: float,
|
|
1633
|
+
wall_slope: float,
|
|
1634
|
+
ground: GroundSpec,
|
|
1635
|
+
depth: float,
|
|
1636
|
+
) -> np.ndarray:
|
|
1637
|
+
"""Clip vertices to stay inside the trench boundary.
|
|
1638
|
+
|
|
1639
|
+
Any vertex outside the trench is projected back to the nearest boundary.
|
|
1640
|
+
This handles edge cases where cap projection pushes vertices outside.
|
|
1641
|
+
"""
|
|
1642
|
+
V_clipped = V.copy()
|
|
1643
|
+
|
|
1644
|
+
for i, vert in enumerate(V):
|
|
1645
|
+
x, y, z = vert
|
|
1646
|
+
frame, local_u = _find_trench_frame_at_xy(
|
|
1647
|
+
x, y, path_xy, half_top, depth, wall_slope, ground
|
|
1648
|
+
)
|
|
1649
|
+
|
|
1650
|
+
floor_z = frame.top_z - depth
|
|
1651
|
+
half_w = _half_width_at_depth(half_top, wall_slope, frame.top_z, z)
|
|
1652
|
+
|
|
1653
|
+
# Clip z to floor/ceiling
|
|
1654
|
+
z_clipped = np.clip(z, floor_z, frame.top_z)
|
|
1655
|
+
|
|
1656
|
+
# Clip u to walls (need to update xy)
|
|
1657
|
+
if abs(local_u) > half_w:
|
|
1658
|
+
# Project point back to wall
|
|
1659
|
+
u_clipped = np.sign(local_u) * half_w
|
|
1660
|
+
# Adjust xy: move toward centerline
|
|
1661
|
+
delta_u = u_clipped - local_u
|
|
1662
|
+
x_clipped = x + delta_u * frame.left_normal[0]
|
|
1663
|
+
y_clipped = y + delta_u * frame.left_normal[1]
|
|
1664
|
+
else:
|
|
1665
|
+
x_clipped = x
|
|
1666
|
+
y_clipped = y
|
|
1667
|
+
|
|
1668
|
+
V_clipped[i] = [x_clipped, y_clipped, z_clipped]
|
|
1669
|
+
|
|
1670
|
+
return V_clipped
|
|
1671
|
+
|
|
1672
|
+
|
|
1085
1673
|
# ---------------- Noise ----------------
|
|
1086
1674
|
|
|
1087
1675
|
def vertex_normals(V: np.ndarray, F: np.ndarray) -> np.ndarray:
|
|
@@ -1189,16 +1777,40 @@ def _build_surface_groups(
|
|
|
1189
1777
|
top_z = gfun(pos_xy[0], pos_xy[1])
|
|
1190
1778
|
req_u = float(p.offset_u)
|
|
1191
1779
|
req_z = float(p.z if p.z is not None else (top_z - spec.depth * 0.5))
|
|
1192
|
-
|
|
1193
|
-
|
|
1780
|
+
|
|
1781
|
+
# Cap margin accounts for cap projection when pipe is at angle to wall
|
|
1782
|
+
cap_margin = max(0.02, 0.4 * p.radius)
|
|
1783
|
+
effective_radius = p.radius + cap_margin
|
|
1784
|
+
|
|
1785
|
+
z_min = top_z - spec.depth + (effective_radius + clearance)
|
|
1786
|
+
z_max = top_z - (effective_radius + clearance)
|
|
1194
1787
|
zc = float(np.clip(req_z, z_min, z_max))
|
|
1195
1788
|
half_w = _half_width_at_depth(half_top, spec.wall_slope, top_z, zc)
|
|
1196
|
-
umax = max(0.0, half_w - (
|
|
1789
|
+
umax = max(0.0, half_w - (effective_radius + clearance))
|
|
1197
1790
|
u = float(np.clip(req_u, -umax, umax))
|
|
1198
1791
|
ctr_xy = pos_xy + u * left_normal
|
|
1199
1792
|
center = np.array([ctr_xy[0], ctr_xy[1], zc], float)
|
|
1200
|
-
|
|
1793
|
+
|
|
1794
|
+
# Compute pipe truncation at trench boundaries
|
|
1795
|
+
trunc = _compute_pipe_truncation(
|
|
1796
|
+
center, axis_dir, p.radius, p.length / 2.0,
|
|
1797
|
+
spec.path_xy, half_top, spec.wall_slope, spec.ground, spec.depth
|
|
1798
|
+
)
|
|
1799
|
+
|
|
1800
|
+
cyl = make_cylinder(
|
|
1801
|
+
center, axis_dir, p.radius, p.length,
|
|
1802
|
+
p.n_theta, p.n_along, with_caps=True,
|
|
1803
|
+
neg_extent=trunc.neg_extent,
|
|
1804
|
+
pos_extent=trunc.pos_extent,
|
|
1805
|
+
cap_plane_neg=trunc.neg_cap_plane,
|
|
1806
|
+
cap_plane_pos=trunc.pos_cap_plane,
|
|
1807
|
+
)
|
|
1201
1808
|
for key, (V, F) in cyl.items():
|
|
1809
|
+
# Clip cap vertices to trench boundary to handle projection overshoot
|
|
1810
|
+
if "cap" in key:
|
|
1811
|
+
V = _clip_vertices_to_trench(
|
|
1812
|
+
V, spec.path_xy, half_top, spec.wall_slope, spec.ground, spec.depth
|
|
1813
|
+
)
|
|
1202
1814
|
groups[f"pipe{idx}_{key}"] = (V, F)
|
|
1203
1815
|
|
|
1204
1816
|
for j, b in enumerate(spec.boxes):
|
|
@@ -1215,6 +1827,19 @@ def _build_surface_groups(
|
|
|
1215
1827
|
u = float(np.clip(req_u, -umax, umax))
|
|
1216
1828
|
ctr_xy = pos_xy + u * left_normal
|
|
1217
1829
|
center = np.array([ctr_xy[0], ctr_xy[1], zc], float)
|
|
1830
|
+
|
|
1831
|
+
# Compute shrunk box dimensions to fit within trench
|
|
1832
|
+
fit_along, fit_across, fit_height = _compute_box_fit(
|
|
1833
|
+
center, b.along, b.across, b.height,
|
|
1834
|
+
spec.path_xy, half_top, spec.wall_slope, spec.ground, spec.depth, clearance
|
|
1835
|
+
)
|
|
1836
|
+
|
|
1837
|
+
# Re-center if height was shrunk
|
|
1838
|
+
if fit_height < b.height:
|
|
1839
|
+
floor_z = top_z - spec.depth
|
|
1840
|
+
zc = floor_z + clearance + fit_height / 2
|
|
1841
|
+
center = np.array([ctr_xy[0], ctr_xy[1], zc], float)
|
|
1842
|
+
|
|
1218
1843
|
frame_cols = np.column_stack(
|
|
1219
1844
|
[
|
|
1220
1845
|
np.array([tangent[0], tangent[1], 0.0]),
|
|
@@ -1222,7 +1847,7 @@ def _build_surface_groups(
|
|
|
1222
1847
|
np.array([0.0, 0.0, 1.0]),
|
|
1223
1848
|
]
|
|
1224
1849
|
)
|
|
1225
|
-
Vb, Fb = make_box(center, frame_cols, (
|
|
1850
|
+
Vb, Fb = make_box(center, frame_cols, (fit_along, fit_across, fit_height))
|
|
1226
1851
|
groups[f"box{j}"] = (Vb, Fb)
|
|
1227
1852
|
|
|
1228
1853
|
for k, s in enumerate(spec.spheres):
|
|
@@ -1239,7 +1864,22 @@ def _build_surface_groups(
|
|
|
1239
1864
|
u = float(np.clip(req_u, -umax, umax))
|
|
1240
1865
|
ctr_xy = pos_xy + u * left_normal
|
|
1241
1866
|
center = np.array([ctr_xy[0], ctr_xy[1], zc], float)
|
|
1242
|
-
|
|
1867
|
+
|
|
1868
|
+
# Compute shrunk sphere radius to fit within trench
|
|
1869
|
+
fit_radius = _compute_sphere_fit(
|
|
1870
|
+
center, s.radius,
|
|
1871
|
+
spec.path_xy, half_top, spec.wall_slope, spec.ground, spec.depth, clearance
|
|
1872
|
+
)
|
|
1873
|
+
|
|
1874
|
+
# Re-center if radius was shrunk significantly
|
|
1875
|
+
if fit_radius < s.radius:
|
|
1876
|
+
floor_z = top_z - spec.depth
|
|
1877
|
+
# Center the smaller sphere optimally
|
|
1878
|
+
zc = floor_z + clearance + fit_radius
|
|
1879
|
+
zc = min(zc, top_z - clearance - fit_radius) # Also respect ceiling
|
|
1880
|
+
center = np.array([ctr_xy[0], ctr_xy[1], zc], float)
|
|
1881
|
+
|
|
1882
|
+
Vs, Fs = make_sphere(center, fit_radius, n_theta=64, n_phi=32)
|
|
1243
1883
|
groups[f"sphere{k}"] = (Vs, Fs)
|
|
1244
1884
|
|
|
1245
1885
|
if spec.noise and spec.noise.enable:
|
|
@@ -6,7 +6,7 @@ trenchfoot/gmsh_sloped_trench_mesher.py,sha256=D7EL6V0wkE6tvDARmm006yZE6KEzCl25O
|
|
|
6
6
|
trenchfoot/plot_mesh.py,sha256=26dOlVfaM1WsUfr_sXVqA7axtY9qjY3WCNM7cUBTS7Q,3810
|
|
7
7
|
trenchfoot/render_colors.py,sha256=CWMre6DYa2EyrCgZsEY0bv313WqEhQdr3CdPF1xI-40,1649
|
|
8
8
|
trenchfoot/scene_spec_example.json,sha256=UcV25ku422UO0ZZPDrJwrT1zwmjoOIpnBdLuEdh-AZA,1028
|
|
9
|
-
trenchfoot/trench_scene_generator_v3.py,sha256=
|
|
9
|
+
trenchfoot/trench_scene_generator_v3.py,sha256=ZWashBnNSWyv6Z_hh_zg8nngO4ySIuijgHtlCnqs0rY,75147
|
|
10
10
|
trenchfoot/scenarios/SUMMARY.json,sha256=uylEzgzIqk5pGBfWVchVFnwwIDGBjNTDY_E23L_iakI,9372
|
|
11
11
|
trenchfoot/scenarios/S01_straight_vwalls/ground_truth_isosurface.html,sha256=SLPROqEefBB8OgmZSW6DBmJxuSDxVQhWTn9eG3q6QRU,5880178
|
|
12
12
|
trenchfoot/scenarios/S01_straight_vwalls/metrics.json,sha256=7VDscjZdxNPgNZaPHzRHYBJ1a5amNgJ7XYKCezVJJKQ,691
|
|
@@ -45,7 +45,7 @@ trenchfoot/scenarios/S03_L_slope_two_pipes_box/sdf_metadata.json,sha256=6ESVHVGu
|
|
|
45
45
|
trenchfoot/scenarios/S03_L_slope_two_pipes_box/trench_scene.obj,sha256=APHNgcc715-lk360CAOpr6zPVcsEDrY4eHEV6z6dU38,655978
|
|
46
46
|
trenchfoot/scenarios/S03_L_slope_two_pipes_box/meshes/trench_scene_culled.obj,sha256=At4lipowr_3MY1rxmcKa479F_mQ-jJDVQJe0yHTrFSc,1835
|
|
47
47
|
trenchfoot/scenarios/S03_L_slope_two_pipes_box/point_clouds/culled/resolution0p050.pth,sha256=KqbuoZ1tUPDhlnDgmhd-7WBb92TABsEmOzEsB__KtlA,2456029
|
|
48
|
-
trenchfoot/scenarios/S03_L_slope_two_pipes_box/point_clouds/full/
|
|
48
|
+
trenchfoot/scenarios/S03_L_slope_two_pipes_box/point_clouds/full/resolutio,sha256=4fXvfu0TMO9FJaoqYrW21SCGe3eKuSLkSUl9CdE14rw,2622685
|
|
49
49
|
trenchfoot/scenarios/S03_L_slope_two_pipes_box/volumetric/trench_volume.msh,sha256=cPgHKHlzPPtWX8H1yaxAYsEgYba3fr2JjfPvgg2a000,87383
|
|
50
50
|
trenchfoot/scenarios/S04_U_slope_multi_noise/ground_truth_isosurface.html,sha256=E7sa8dlDyICJBlnL9X2C8IEopEJzDMhHdLbW-WpoPFc,7184880
|
|
51
51
|
trenchfoot/scenarios/S04_U_slope_multi_noise/metrics.json,sha256=3dm1ciLvFDj66ouuzhPo6-W0fPg0NRdbh2NPpg8tN-0,1293
|
|
@@ -85,8 +85,8 @@ trenchfoot/scenarios/S07_circular_well/scene.json,sha256=bvror2YX6aNbsEc25-N7JO3
|
|
|
85
85
|
trenchfoot/scenarios/S07_circular_well/sdf_metadata.json,sha256=5_D_rA_CqWgg2uSgVlqWCO4zQg0Gg5NWUnXHtCERBUA,4776
|
|
86
86
|
trenchfoot/scenarios/S07_circular_well/trench_scene.obj,sha256=leTTT0i5xE-fvFSzHLNf_JBsU0AN3YqadDx4HmNmFhU,1618101
|
|
87
87
|
trenchfoot/scenarios/S07_circular_well/volumetric/trench_volume.msh,sha256=dqhtd3SFKj5RLT_BcWIIvVGCbAqvOx7RX25-K7NKX10,615212
|
|
88
|
-
trenchfoot-0.4.
|
|
89
|
-
trenchfoot-0.4.
|
|
90
|
-
trenchfoot-0.4.
|
|
91
|
-
trenchfoot-0.4.
|
|
92
|
-
trenchfoot-0.4.
|
|
88
|
+
trenchfoot-0.4.2.dist-info/METADATA,sha256=y_KwrW-9rsUL7Csf7x-32FDt69-gtgZ_Yz5nOj-Vths,5292
|
|
89
|
+
trenchfoot-0.4.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
90
|
+
trenchfoot-0.4.2.dist-info/entry_points.txt,sha256=5TejAGmc4GnNYLn7MhhLtSCNz9240RvzcNaetF4IHfg,119
|
|
91
|
+
trenchfoot-0.4.2.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
|
|
92
|
+
trenchfoot-0.4.2.dist-info/RECORD,,
|
/trenchfoot/scenarios/S03_L_slope_two_pipes_box/point_clouds/full/{resolution0p050.pth → resolutio}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|