sdf-sampler 0.1.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.
Files changed (35) hide show
  1. sdf_sampler-0.1.0/.github_token.env +1 -0
  2. sdf_sampler-0.1.0/.gitignore +81 -0
  3. sdf_sampler-0.1.0/CHANGELOG.md +44 -0
  4. sdf_sampler-0.1.0/LICENSE +21 -0
  5. sdf_sampler-0.1.0/PKG-INFO +226 -0
  6. sdf_sampler-0.1.0/README.md +182 -0
  7. sdf_sampler-0.1.0/pyproject.toml +75 -0
  8. sdf_sampler-0.1.0/src/sdf_sampler/__init__.py +78 -0
  9. sdf_sampler-0.1.0/src/sdf_sampler/algorithms/__init__.py +19 -0
  10. sdf_sampler-0.1.0/src/sdf_sampler/algorithms/flood_fill.py +233 -0
  11. sdf_sampler-0.1.0/src/sdf_sampler/algorithms/normal_idw.py +99 -0
  12. sdf_sampler-0.1.0/src/sdf_sampler/algorithms/normal_offset.py +111 -0
  13. sdf_sampler-0.1.0/src/sdf_sampler/algorithms/pocket.py +146 -0
  14. sdf_sampler-0.1.0/src/sdf_sampler/algorithms/voxel_grid.py +339 -0
  15. sdf_sampler-0.1.0/src/sdf_sampler/algorithms/voxel_regions.py +80 -0
  16. sdf_sampler-0.1.0/src/sdf_sampler/analyzer.py +299 -0
  17. sdf_sampler-0.1.0/src/sdf_sampler/config.py +171 -0
  18. sdf_sampler-0.1.0/src/sdf_sampler/io.py +178 -0
  19. sdf_sampler-0.1.0/src/sdf_sampler/models/__init__.py +49 -0
  20. sdf_sampler-0.1.0/src/sdf_sampler/models/analysis.py +85 -0
  21. sdf_sampler-0.1.0/src/sdf_sampler/models/constraints.py +192 -0
  22. sdf_sampler-0.1.0/src/sdf_sampler/models/samples.py +49 -0
  23. sdf_sampler-0.1.0/src/sdf_sampler/sampler.py +439 -0
  24. sdf_sampler-0.1.0/src/sdf_sampler/sampling/__init__.py +15 -0
  25. sdf_sampler-0.1.0/src/sdf_sampler/sampling/box.py +131 -0
  26. sdf_sampler-0.1.0/src/sdf_sampler/sampling/brush.py +63 -0
  27. sdf_sampler-0.1.0/src/sdf_sampler/sampling/ray_carve.py +134 -0
  28. sdf_sampler-0.1.0/src/sdf_sampler/sampling/sphere.py +57 -0
  29. sdf_sampler-0.1.0/tests/__init__.py +2 -0
  30. sdf_sampler-0.1.0/tests/test_analyzer.py +246 -0
  31. sdf_sampler-0.1.0/tests/test_equivalence.py +761 -0
  32. sdf_sampler-0.1.0/tests/test_integration.py +265 -0
  33. sdf_sampler-0.1.0/tests/test_models.py +189 -0
  34. sdf_sampler-0.1.0/tests/test_sampler.py +231 -0
  35. sdf_sampler-0.1.0/uv.lock +1071 -0
@@ -0,0 +1 @@
1
+ GITHUB_TOKEN=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
@@ -0,0 +1,81 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ *.egg-info/
24
+ .installed.cfg
25
+ *.egg
26
+
27
+ # PyInstaller
28
+ *.manifest
29
+ *.spec
30
+
31
+ # Installer logs
32
+ pip-log.txt
33
+ pip-delete-this-directory.txt
34
+
35
+ # Unit test / coverage reports
36
+ htmlcov/
37
+ .tox/
38
+ .nox/
39
+ .coverage
40
+ .coverage.*
41
+ .cache
42
+ nosetests.xml
43
+ coverage.xml
44
+ *.cover
45
+ *.py,cover
46
+ .hypothesis/
47
+ .pytest_cache/
48
+
49
+ # Translations
50
+ *.mo
51
+ *.pot
52
+
53
+ # Environments
54
+ .env
55
+ .venv
56
+ env/
57
+ venv/
58
+ ENV/
59
+ env.bak/
60
+ venv.bak/
61
+
62
+ # IDEs
63
+ .idea/
64
+ .vscode/
65
+ *.swp
66
+ *.swo
67
+
68
+ # mypy
69
+ .mypy_cache/
70
+ .dmypy.json
71
+ dmypy.json
72
+
73
+ # Ruff
74
+ .ruff_cache/
75
+
76
+ # Local development
77
+ *.parquet
78
+ *.npz
79
+
80
+ # Secrets
81
+ .pypi_token.env
@@ -0,0 +1,44 @@
1
+ # Changelog
2
+
3
+ All notable changes to sdf-sampler will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.0] - 2025-01-29
9
+
10
+ ### Added
11
+
12
+ - Initial release extracted from sdf-labeler backend
13
+ - **SDFAnalyzer** class for auto-analysis of point clouds
14
+ - `flood_fill` algorithm: EMPTY region detection via ray propagation from sky
15
+ - `voxel_regions` algorithm: SOLID region detection from underground
16
+ - `normal_offset` algorithm: Paired SOLID/EMPTY boxes along surface normals
17
+ - `normal_idw` algorithm: Inverse distance weighted sampling along normals
18
+ - `pocket` algorithm: Interior cavity detection via voxel flood fill
19
+ - Hull filtering to remove constraints outside X-Y alpha shape
20
+ - Configurable via `AnalyzerConfig` dataclass
21
+ - **SDFSampler** class for training sample generation
22
+ - Supports multiple constraint types: box, sphere, halfspace, brush_stroke, etc.
23
+ - Three sampling strategies: CONSTANT, DENSITY, INVERSE_SQUARE
24
+ - Export to Parquet and DataFrame
25
+ - Configurable via `SamplerConfig` dataclass
26
+ - **I/O helpers**
27
+ - `load_point_cloud()` for PLY, LAS/LAZ, CSV, NPZ, Parquet formats
28
+ - `export_parquet()` for survi-compatible training data export
29
+ - Pydantic models for all constraint types and training samples
30
+ - Comprehensive test suite (56 tests including equivalence tests vs sdf-labeler backend)
31
+
32
+ ### Dependencies
33
+
34
+ - pydantic>=2.5.0 (data validation)
35
+ - numpy>=1.26.0 (core arrays)
36
+ - pandas>=2.1.0 (Parquet I/O)
37
+ - scipy>=1.11.0 (KDTree, spatial, ndimage)
38
+ - alphashape>=1.3.1 (concave hull filtering)
39
+ - pyarrow>=14.0.0 (Parquet export)
40
+
41
+ ### Optional Dependencies
42
+
43
+ - trimesh>=4.0.0 (PLY loading, `[io]` extra)
44
+ - laspy[laszip]>=2.5.0 (LAS/LAZ loading, `[io]` extra)
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Liam
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,226 @@
1
+ Metadata-Version: 2.4
2
+ Name: sdf-sampler
3
+ Version: 0.1.0
4
+ Summary: Auto-analysis and sampling of point clouds for SDF (Signed Distance Field) training data generation
5
+ Project-URL: Repository, https://github.com/chiark/sdf-sampler
6
+ Author-email: Liam <liam@example.com>
7
+ License: MIT
8
+ License-File: LICENSE
9
+ Keywords: machine-learning,point-cloud,sampling,sdf,signed-distance-field
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: Scientific/Engineering
18
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
+ Requires-Python: >=3.11
20
+ Requires-Dist: alphashape>=1.3.1
21
+ Requires-Dist: numpy>=1.26.0
22
+ Requires-Dist: pandas>=2.1.0
23
+ Requires-Dist: pyarrow>=14.0.0
24
+ Requires-Dist: pydantic>=2.5.0
25
+ Requires-Dist: scipy>=1.11.0
26
+ Provides-Extra: all
27
+ Requires-Dist: laspy[laszip]>=2.5.0; extra == 'all'
28
+ Requires-Dist: mypy>=1.8.0; extra == 'all'
29
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'all'
30
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'all'
31
+ Requires-Dist: pytest>=8.0.0; extra == 'all'
32
+ Requires-Dist: ruff>=0.5.0; extra == 'all'
33
+ Requires-Dist: trimesh>=4.0.0; extra == 'all'
34
+ Provides-Extra: dev
35
+ Requires-Dist: mypy>=1.8.0; extra == 'dev'
36
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
37
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
38
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
39
+ Requires-Dist: ruff>=0.5.0; extra == 'dev'
40
+ Provides-Extra: io
41
+ Requires-Dist: laspy[laszip]>=2.5.0; extra == 'io'
42
+ Requires-Dist: trimesh>=4.0.0; extra == 'io'
43
+ Description-Content-Type: text/markdown
44
+
45
+ # sdf-sampler
46
+
47
+ Auto-analysis and sampling of point clouds for SDF (Signed Distance Field) training data generation.
48
+
49
+ A lightweight, standalone Python package for generating SDF training hints from point clouds. Automatically detects SOLID (inside) and EMPTY (outside) regions and generates training samples suitable for SDF regression models.
50
+
51
+ ## Installation
52
+
53
+ ```bash
54
+ pip install sdf-sampler
55
+ ```
56
+
57
+ For additional I/O format support (PLY, LAS/LAZ):
58
+
59
+ ```bash
60
+ pip install sdf-sampler[io]
61
+ ```
62
+
63
+ ## Quick Start
64
+
65
+ ```python
66
+ from sdf_sampler import SDFAnalyzer, SDFSampler, load_point_cloud
67
+
68
+ # 1. Load point cloud (supports PLY, LAS, CSV, NPZ, Parquet)
69
+ xyz, normals = load_point_cloud("scan.ply")
70
+
71
+ # 2. Auto-analyze to detect EMPTY/SOLID regions
72
+ analyzer = SDFAnalyzer()
73
+ result = analyzer.analyze(xyz=xyz, normals=normals)
74
+ print(f"Generated {len(result.constraints)} constraints")
75
+
76
+ # 3. Generate training samples
77
+ sampler = SDFSampler()
78
+ samples = sampler.generate(
79
+ xyz=xyz,
80
+ constraints=result.constraints,
81
+ strategy="inverse_square",
82
+ total_samples=50000,
83
+ )
84
+
85
+ # 4. Export to parquet
86
+ sampler.export_parquet(samples, "training_data.parquet")
87
+ ```
88
+
89
+ ## Features
90
+
91
+ ### Auto-Analysis Algorithms
92
+
93
+ - **flood_fill**: Detects EMPTY (outside) regions by ray propagation from sky
94
+ - **voxel_regions**: Detects SOLID (underground) regions
95
+ - **normal_offset**: Generates paired SOLID/EMPTY boxes along surface normals
96
+ - **normal_idw**: Inverse distance weighted sampling along normals
97
+ - **pocket**: Detects interior cavities
98
+
99
+ ### Sampling Strategies
100
+
101
+ - **CONSTANT**: Fixed number of samples per constraint
102
+ - **DENSITY**: Samples proportional to constraint volume
103
+ - **INVERSE_SQUARE**: More samples near surface, fewer far away (recommended)
104
+
105
+ ## API Reference
106
+
107
+ ### SDFAnalyzer
108
+
109
+ ```python
110
+ from sdf_sampler import SDFAnalyzer, AnalyzerConfig
111
+
112
+ # With default config
113
+ analyzer = SDFAnalyzer()
114
+
115
+ # With custom config
116
+ analyzer = SDFAnalyzer(config=AnalyzerConfig(
117
+ min_gap_size=0.10, # Minimum gap for flood fill
118
+ max_grid_dim=200, # Maximum voxel grid dimension
119
+ cone_angle=15.0, # Ray propagation cone angle
120
+ hull_filter_enabled=True, # Filter outside X-Y hull
121
+ ))
122
+
123
+ # Run analysis
124
+ result = analyzer.analyze(
125
+ xyz=xyz, # (N, 3) point positions
126
+ normals=normals, # (N, 3) point normals (optional)
127
+ algorithms=["flood_fill", "voxel_regions"], # Which algorithms to run
128
+ )
129
+
130
+ # Access results
131
+ print(f"Total constraints: {result.summary.total_constraints}")
132
+ print(f"SOLID: {result.summary.solid_constraints}")
133
+ print(f"EMPTY: {result.summary.empty_constraints}")
134
+
135
+ # Get constraint dicts for sampling
136
+ constraints = result.constraints
137
+ ```
138
+
139
+ ### SDFSampler
140
+
141
+ ```python
142
+ from sdf_sampler import SDFSampler, SamplerConfig
143
+
144
+ # With default config
145
+ sampler = SDFSampler()
146
+
147
+ # With custom config
148
+ sampler = SDFSampler(config=SamplerConfig(
149
+ total_samples=10000,
150
+ inverse_square_base_samples=100,
151
+ inverse_square_falloff=2.0,
152
+ near_band=0.02,
153
+ ))
154
+
155
+ # Generate samples
156
+ samples = sampler.generate(
157
+ xyz=xyz, # Point cloud for distance computation
158
+ constraints=constraints, # From analyzer.analyze().constraints
159
+ strategy="inverse_square", # Sampling strategy
160
+ seed=42, # For reproducibility
161
+ )
162
+
163
+ # Export
164
+ sampler.export_parquet(samples, "output.parquet")
165
+
166
+ # Or get DataFrame
167
+ df = sampler.to_dataframe(samples)
168
+ ```
169
+
170
+ ### Constraint Types
171
+
172
+ The analyzer generates various constraint types:
173
+
174
+ - **BoxConstraint**: Axis-aligned bounding box
175
+ - **SphereConstraint**: Spherical region
176
+ - **SamplePointConstraint**: Direct point with signed distance
177
+ - **PocketConstraint**: Detected cavity region
178
+
179
+ Each constraint has:
180
+ - `sign`: "solid" (negative SDF) or "empty" (positive SDF)
181
+ - `weight`: Sample weight (default 1.0)
182
+
183
+ ## Output Format
184
+
185
+ The exported parquet file contains columns:
186
+
187
+ | Column | Type | Description |
188
+ |--------|------|-------------|
189
+ | x, y, z | float | 3D position |
190
+ | phi | float | Signed distance (negative=solid, positive=empty) |
191
+ | nx, ny, nz | float | Normal vector (if available) |
192
+ | weight | float | Sample weight |
193
+ | source | string | Sample origin (e.g., "box_solid", "flood_fill_empty") |
194
+ | is_surface | bool | Whether sample is on surface |
195
+ | is_free | bool | Whether sample is in free space (EMPTY) |
196
+
197
+ ## Configuration Options
198
+
199
+ ### AnalyzerConfig
200
+
201
+ | Option | Default | Description |
202
+ |--------|---------|-------------|
203
+ | min_gap_size | 0.10 | Minimum gap size for flood fill (meters) |
204
+ | max_grid_dim | 200 | Maximum voxel grid dimension |
205
+ | cone_angle | 15.0 | Ray propagation cone half-angle (degrees) |
206
+ | normal_offset_pairs | 40 | Number of box pairs for normal_offset |
207
+ | idw_sample_count | 1000 | Total IDW samples |
208
+ | idw_max_distance | 0.5 | Maximum IDW distance (meters) |
209
+ | hull_filter_enabled | True | Filter outside X-Y alpha shape |
210
+ | hull_alpha | 1.0 | Alpha shape parameter |
211
+
212
+ ### SamplerConfig
213
+
214
+ | Option | Default | Description |
215
+ |--------|---------|-------------|
216
+ | total_samples | 10000 | Default total samples |
217
+ | samples_per_primitive | 100 | Samples per constraint (CONSTANT) |
218
+ | samples_per_cubic_meter | 10000 | Sample density (DENSITY) |
219
+ | inverse_square_base_samples | 100 | Base samples (INVERSE_SQUARE) |
220
+ | inverse_square_falloff | 2.0 | Falloff exponent |
221
+ | near_band | 0.02 | Near-band width |
222
+ | seed | 0 | Random seed |
223
+
224
+ ## License
225
+
226
+ MIT
@@ -0,0 +1,182 @@
1
+ # sdf-sampler
2
+
3
+ Auto-analysis and sampling of point clouds for SDF (Signed Distance Field) training data generation.
4
+
5
+ A lightweight, standalone Python package for generating SDF training hints from point clouds. Automatically detects SOLID (inside) and EMPTY (outside) regions and generates training samples suitable for SDF regression models.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pip install sdf-sampler
11
+ ```
12
+
13
+ For additional I/O format support (PLY, LAS/LAZ):
14
+
15
+ ```bash
16
+ pip install sdf-sampler[io]
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ ```python
22
+ from sdf_sampler import SDFAnalyzer, SDFSampler, load_point_cloud
23
+
24
+ # 1. Load point cloud (supports PLY, LAS, CSV, NPZ, Parquet)
25
+ xyz, normals = load_point_cloud("scan.ply")
26
+
27
+ # 2. Auto-analyze to detect EMPTY/SOLID regions
28
+ analyzer = SDFAnalyzer()
29
+ result = analyzer.analyze(xyz=xyz, normals=normals)
30
+ print(f"Generated {len(result.constraints)} constraints")
31
+
32
+ # 3. Generate training samples
33
+ sampler = SDFSampler()
34
+ samples = sampler.generate(
35
+ xyz=xyz,
36
+ constraints=result.constraints,
37
+ strategy="inverse_square",
38
+ total_samples=50000,
39
+ )
40
+
41
+ # 4. Export to parquet
42
+ sampler.export_parquet(samples, "training_data.parquet")
43
+ ```
44
+
45
+ ## Features
46
+
47
+ ### Auto-Analysis Algorithms
48
+
49
+ - **flood_fill**: Detects EMPTY (outside) regions by ray propagation from sky
50
+ - **voxel_regions**: Detects SOLID (underground) regions
51
+ - **normal_offset**: Generates paired SOLID/EMPTY boxes along surface normals
52
+ - **normal_idw**: Inverse distance weighted sampling along normals
53
+ - **pocket**: Detects interior cavities
54
+
55
+ ### Sampling Strategies
56
+
57
+ - **CONSTANT**: Fixed number of samples per constraint
58
+ - **DENSITY**: Samples proportional to constraint volume
59
+ - **INVERSE_SQUARE**: More samples near surface, fewer far away (recommended)
60
+
61
+ ## API Reference
62
+
63
+ ### SDFAnalyzer
64
+
65
+ ```python
66
+ from sdf_sampler import SDFAnalyzer, AnalyzerConfig
67
+
68
+ # With default config
69
+ analyzer = SDFAnalyzer()
70
+
71
+ # With custom config
72
+ analyzer = SDFAnalyzer(config=AnalyzerConfig(
73
+ min_gap_size=0.10, # Minimum gap for flood fill
74
+ max_grid_dim=200, # Maximum voxel grid dimension
75
+ cone_angle=15.0, # Ray propagation cone angle
76
+ hull_filter_enabled=True, # Filter outside X-Y hull
77
+ ))
78
+
79
+ # Run analysis
80
+ result = analyzer.analyze(
81
+ xyz=xyz, # (N, 3) point positions
82
+ normals=normals, # (N, 3) point normals (optional)
83
+ algorithms=["flood_fill", "voxel_regions"], # Which algorithms to run
84
+ )
85
+
86
+ # Access results
87
+ print(f"Total constraints: {result.summary.total_constraints}")
88
+ print(f"SOLID: {result.summary.solid_constraints}")
89
+ print(f"EMPTY: {result.summary.empty_constraints}")
90
+
91
+ # Get constraint dicts for sampling
92
+ constraints = result.constraints
93
+ ```
94
+
95
+ ### SDFSampler
96
+
97
+ ```python
98
+ from sdf_sampler import SDFSampler, SamplerConfig
99
+
100
+ # With default config
101
+ sampler = SDFSampler()
102
+
103
+ # With custom config
104
+ sampler = SDFSampler(config=SamplerConfig(
105
+ total_samples=10000,
106
+ inverse_square_base_samples=100,
107
+ inverse_square_falloff=2.0,
108
+ near_band=0.02,
109
+ ))
110
+
111
+ # Generate samples
112
+ samples = sampler.generate(
113
+ xyz=xyz, # Point cloud for distance computation
114
+ constraints=constraints, # From analyzer.analyze().constraints
115
+ strategy="inverse_square", # Sampling strategy
116
+ seed=42, # For reproducibility
117
+ )
118
+
119
+ # Export
120
+ sampler.export_parquet(samples, "output.parquet")
121
+
122
+ # Or get DataFrame
123
+ df = sampler.to_dataframe(samples)
124
+ ```
125
+
126
+ ### Constraint Types
127
+
128
+ The analyzer generates various constraint types:
129
+
130
+ - **BoxConstraint**: Axis-aligned bounding box
131
+ - **SphereConstraint**: Spherical region
132
+ - **SamplePointConstraint**: Direct point with signed distance
133
+ - **PocketConstraint**: Detected cavity region
134
+
135
+ Each constraint has:
136
+ - `sign`: "solid" (negative SDF) or "empty" (positive SDF)
137
+ - `weight`: Sample weight (default 1.0)
138
+
139
+ ## Output Format
140
+
141
+ The exported parquet file contains columns:
142
+
143
+ | Column | Type | Description |
144
+ |--------|------|-------------|
145
+ | x, y, z | float | 3D position |
146
+ | phi | float | Signed distance (negative=solid, positive=empty) |
147
+ | nx, ny, nz | float | Normal vector (if available) |
148
+ | weight | float | Sample weight |
149
+ | source | string | Sample origin (e.g., "box_solid", "flood_fill_empty") |
150
+ | is_surface | bool | Whether sample is on surface |
151
+ | is_free | bool | Whether sample is in free space (EMPTY) |
152
+
153
+ ## Configuration Options
154
+
155
+ ### AnalyzerConfig
156
+
157
+ | Option | Default | Description |
158
+ |--------|---------|-------------|
159
+ | min_gap_size | 0.10 | Minimum gap size for flood fill (meters) |
160
+ | max_grid_dim | 200 | Maximum voxel grid dimension |
161
+ | cone_angle | 15.0 | Ray propagation cone half-angle (degrees) |
162
+ | normal_offset_pairs | 40 | Number of box pairs for normal_offset |
163
+ | idw_sample_count | 1000 | Total IDW samples |
164
+ | idw_max_distance | 0.5 | Maximum IDW distance (meters) |
165
+ | hull_filter_enabled | True | Filter outside X-Y alpha shape |
166
+ | hull_alpha | 1.0 | Alpha shape parameter |
167
+
168
+ ### SamplerConfig
169
+
170
+ | Option | Default | Description |
171
+ |--------|---------|-------------|
172
+ | total_samples | 10000 | Default total samples |
173
+ | samples_per_primitive | 100 | Samples per constraint (CONSTANT) |
174
+ | samples_per_cubic_meter | 10000 | Sample density (DENSITY) |
175
+ | inverse_square_base_samples | 100 | Base samples (INVERSE_SQUARE) |
176
+ | inverse_square_falloff | 2.0 | Falloff exponent |
177
+ | near_band | 0.02 | Near-band width |
178
+ | seed | 0 | Random seed |
179
+
180
+ ## License
181
+
182
+ MIT
@@ -0,0 +1,75 @@
1
+ [project]
2
+ name = "sdf-sampler"
3
+ version = "0.1.0"
4
+ description = "Auto-analysis and sampling of point clouds for SDF (Signed Distance Field) training data generation"
5
+ readme = "README.md"
6
+ license = { text = "MIT" }
7
+ authors = [{ name = "Liam", email = "liam@example.com" }]
8
+ requires-python = ">=3.11"
9
+ classifiers = [
10
+ "Development Status :: 4 - Beta",
11
+ "Intended Audience :: Developers",
12
+ "Intended Audience :: Science/Research",
13
+ "License :: OSI Approved :: MIT License",
14
+ "Programming Language :: Python :: 3",
15
+ "Programming Language :: Python :: 3.11",
16
+ "Programming Language :: Python :: 3.12",
17
+ "Topic :: Scientific/Engineering",
18
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
19
+ ]
20
+ keywords = ["sdf", "signed-distance-field", "point-cloud", "sampling", "machine-learning"]
21
+
22
+ dependencies = [
23
+ "pydantic>=2.5.0",
24
+ "numpy>=1.26.0",
25
+ "pandas>=2.1.0",
26
+ "scipy>=1.11.0",
27
+ "alphashape>=1.3.1",
28
+ "pyarrow>=14.0.0",
29
+ ]
30
+
31
+ [project.optional-dependencies]
32
+ io = [
33
+ "trimesh>=4.0.0",
34
+ "laspy[laszip]>=2.5.0",
35
+ ]
36
+ dev = [
37
+ "pytest>=8.0.0",
38
+ "pytest-asyncio>=0.23.0",
39
+ "pytest-cov>=4.0.0",
40
+ "ruff>=0.5.0",
41
+ "mypy>=1.8.0",
42
+ ]
43
+ all = ["sdf-sampler[io,dev]"]
44
+
45
+ [project.urls]
46
+ Repository = "https://github.com/chiark/sdf-sampler"
47
+
48
+ [build-system]
49
+ requires = ["hatchling"]
50
+ build-backend = "hatchling.build"
51
+
52
+ [tool.hatch.build.targets.wheel]
53
+ packages = ["src/sdf_sampler"]
54
+
55
+ [tool.ruff]
56
+ line-length = 100
57
+ target-version = "py311"
58
+
59
+ [tool.ruff.lint]
60
+ select = ["E", "F", "I", "UP", "B", "SIM"]
61
+ ignore = ["E501"]
62
+
63
+ [tool.ruff.lint.isort]
64
+ known-first-party = ["sdf_sampler"]
65
+
66
+ [tool.pytest.ini_options]
67
+ testpaths = ["tests"]
68
+ asyncio_mode = "auto"
69
+ asyncio_default_fixture_loop_scope = "function"
70
+
71
+ [tool.mypy]
72
+ python_version = "3.11"
73
+ warn_return_any = true
74
+ warn_unused_configs = true
75
+ ignore_missing_imports = true