Smesh – Mesh→Point-Cloud Sensor Simulator (core skeleton)
Project description
Smesh – filthy-fast mesh→point cloud simulator
This is a minimal, type-annotated implementation of the critical core components for the Smesh simulator:
MeshScene(mesh IO + attribute probing via VTK)Intersector(VTK OBBTree + optional Embree viatrimesh[ray])PointBatchcontainerAttributeComputerplug-ins (range, incidence, scan angle, returns, intensity, gps time, color/normal probe, beam footprint)LasWriterwith streaming support and dynamic ExtraBytesSamplerorchestrator which glues everything together
Installation
Smesh is available on PyPI:
pip install smesh
Optional extras expose faster intersectors and LAS compression:
pip install "smesh[vtk]" # VTK-backed attribute probing & intersector
pip install "smesh[embree]" # Embree (via trimesh[ray])
pip install "smesh[laz]" # LAZ compression
Prefer to develop against the repo?
pip install -e .
Installing straight from GitHub
To pull the latest main branch directly into a virtual environment:
pip install git+https://github.com/Chiark-Collective/smesh.git
For a reproducible install, pin to a tag (e.g., git+https://github.com/Chiark-Collective/smesh.git@v0.1.0).
Quick taste
import numpy as np
from smesh import MeshScene, Sampler, SamplerConfig, AutoIntersector, LasWriter
from smesh.core.intersector import RayBundle
scene = MeshScene(mesh_path="scene.ply")
# Make a tiny fan of rays from above
M = 1000
origins = np.tile(np.array([[0,0,10.0]]), (M,1))
dirs = np.tile(np.array([[0,0,-1.0]]), (M,1))
bundle = RayBundle(origins=origins, directions=dirs, max_range=100.0, multi_hit=False, meta={"gps_time": np.arange(M)*1e-3})
sampler = Sampler(scene, intersector=AutoIntersector(), cfg=SamplerConfig())
writer = LasWriter("out.las", compress=False)
stats = sampler.run_to_writer(writer, ray_batches=[bundle])
print(stats)
Note: for VTK-backed attribute probing and fast VTK intersector, install
vtk. For Embree, installtrimesh[ray]which pullspyembree(and requires Intel Embree runtime).
Preview Gallery
Regenerate the lightweight preview assets (including a raw-mesh baseline) at any time:
python scripts/render_examples.py # preview configs + raw mesh
python scripts/render_examples.py --full # full-resolution configs
Outputs land in examples/outputs/ and PNG composites in examples/images/. The raw-mesh baseline is rendered with VTK when available (falling back to a shaded Matplotlib view otherwise) so you can see the synthetic geometry before sampling.
Workflow Examples
| Capture | Preview | Command |
|---|---|---|
| Raw Mesh Baseline | python scripts/render_examples.py --example raw_mesh |
|
| Aerial LiDAR | smesh sample examples/configs/preview/aerial_lidar_preview.yaml |
|
| Mobile LiDAR | smesh sample examples/configs/preview/mobile_lidar_preview.yaml |
|
| Total Station | smesh sample examples/configs/preview/total_station_preview.yaml |
|
| Photogrammetry | smesh sample examples/configs/preview/photogrammetry_preview.yaml |
Each preview config runs in under a minute on CPU-only machines, producing lightweight outputs for quick inspection. Higher fidelity counterparts live in examples/configs/ and can be regenerated by rerunning scripts/render_examples.py --full.
One Scenario, Three Entry Points
The aerial preview (examples/configs/preview/aerial_lidar_preview.yaml) is reproduced below via config, pure CLI options, and the Python SDK.
Config
smesh sample examples/configs/preview/aerial_lidar_preview.yaml
CLI arguments (no YAML)
mkdir -p scratch
smesh sample-lidar --mesh examples/meshes/preview_scene.ply \
--output scratch/aerial_cli.las --seed 101
SDK
import numpy as np
from smesh import MeshScene, Sampler, SamplerConfig, LasWriter
from smesh.core.intersector import AutoIntersector
from smesh.motion.trajectory import LawnmowerTrajectory
from smesh.sensors.patterns import OscillatingMirrorPattern
from smesh.sensors.lidar import LidarSensor
from smesh.sensors.noise import LidarNoise
scene = MeshScene(mesh_path="examples/meshes/preview_scene.ply")
trajectory = LawnmowerTrajectory(scene, altitude_m=40.0, speed_mps=20.0, line_spacing_m=30.0)
pattern = OscillatingMirrorPattern(fov_deg=50.0, line_rate_hz=20.0, pulses_per_line=200)
noise = LidarNoise(sigma_range_m=0.05, sigma_angle_deg=0.1, keep_prob=0.99)
sensor = LidarSensor(pattern=pattern, trajectory=trajectory, noise=noise, max_range_m=200.0, multi_return=True)
sampler = Sampler(scene, intersector=AutoIntersector(), cfg=SamplerConfig(batch_size_rays=20000,
attributes=["range","incidence","scan_angle","intensity","returns","gps_time"],
beam_divergence_mrad=0.3))
rng = np.random.default_rng(101)
bundles = [batch.bundle for batch in sensor.batches(rng)]
writer = LasWriter("examples/outputs/aerial_sdk.las", compress=False)
sampler.run_to_writer(writer, bundles)
If you already have a YAML scenario, you can now run it directly from Python:
from smesh.sdk import sample_from_config
result = sample_from_config("examples/configs/preview/aerial_lidar_preview.yaml")
print(result.output_path, result.stats["points"])
Output writers
LasWriterstreams directly to disk batch-by-batch (compression optional).PlyWriterandNpzWriterbuffer incoming batches in memory and emit a single file whenclose()is called. Callclose()explicitly if you manage the writer yourself.
Attribute pipeline notes
The sampler now orders attribute computers based on their declared dependencies. Custom attribute chains still work—dependencies like range_m for intensity will be inserted automatically so long as a matching producer exists.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file smesh-0.0.2.tar.gz.
File metadata
- Download URL: smesh-0.0.2.tar.gz
- Upload date:
- Size: 47.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c411827954af042ce508257de858e29dd19f633aa990079fe90db681bbadcba7
|
|
| MD5 |
196e9fab24cbd408267277195732f656
|
|
| BLAKE2b-256 |
9f4068dee70a6789c6017be766cd2916d94f732f41ed56af091fbb8d588001cf
|
File details
Details for the file smesh-0.0.2-py3-none-any.whl.
File metadata
- Download URL: smesh-0.0.2-py3-none-any.whl
- Upload date:
- Size: 55.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0ebac73bd7df67b5265153c210057ab5b985258c93da09bc8b5ef6910a542f9b
|
|
| MD5 |
5d9a2e134ada167ddba8c2ff9376c46d
|
|
| BLAKE2b-256 |
c1b436a704189e038f3f1a6a4f4b702e8a64497420e0344656c68ec4ee68b237
|