"""Tutorial 11 — LiDAR Point Cloud Simulation

ALS (airborne) and TLS (terrestrial) LiDAR simulation of a forest scene."""

import less
import numpy as np

# ──Constructing a forest scene───────────────────────────────────────────
scene = less.Scene()
scene.size = 50.0
scene.repetitive = False

scene.terrain = less.Terrain(property=less.Lambertian(reflectance=0.15))
scene.illumination = less.Illumination(source=less.Sun(zenith=30, azimuth=150), atmosphere=less.NoAtmosphere())

tree = less.Object("ash", mesh=less.examples.asset_path("FREX.obj"))
tree.set_property("leaves", less.Prospect(cab=40, car=10, cw=0.012, cm=0.008, N=1.5))
tree.set_property("stem_branch", less.Lambertian(reflectance=0.08))

rng = np.random.RandomState(42)
positions = less.place.random(scene, n=60, min_dist=3.0, seed=42)
n = len(positions)
scene.add(tree, positions=positions,
          scales=less.place.uniform_scale(n, 0.6, 1.5, seed=42),
          rotations=less.place.random_rotation(n, seed=42))
print("ALS simulation...")
sensor_als = less.LiDARSurvey(
    scanner=less.Scanner(
        beam_divergence=0.5, pulse_rate=200_000,
        scan_freq=80.0, scan_angle=27.0,
        wavelengths=[1064], beam_samples=8,
    ),
    platform=less.UAV(altitude=50.0, speed=5.0),
    legs=[
        less.Waypoint(-10, 25, active=True),
        less.Waypoint(60, 25, active=True),
    ],
    range_resolution=0.15,
    name="ALS LiDAR",
)
pc_als = scene.simulate(sensor_als)
pc_als.save("11_als_pointcloud.ply")
print(f"  ALS: {pc_als.num_points} points")
print(f"  Z range: {pc_als.points[:, 2].min():.1f} ~ {pc_als.points[:, 2].max():.1f} m")

# ── TLS Simulation ─────────────────────────────────────────────
print("TLS simulation...")
sensor_tls = less.LiDARSurvey(
    scanner=less.Scanner(
        beam_divergence=0.2, wavelengths=[1550],
        beam_samples=1, angular_resolution=0.1,
    ),
    platform=less.Tripod(height=1.5),
    legs=[
        less.ScanPosition(
            x=25, y=25,
            azimuth_range=(0, 360),
            zenith_range=(5, 70),
        ),
    ],
    range_resolution=0.02,
    name="TLS",
)
pc_tls = scene.simulate(sensor_tls)
pc_tls.save("11_tls_pointcloud.ply")
print(f"  TLS: {pc_tls.num_points} points")

print("Tutorial 11 completed!")
