Corriger le sens de la flèche du nord, éviter les débordements de texte et hachurer les mailles sans donnée de la planche PDF

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Antoine Jacquin
2026-09-27 16:00:04 +02:00
parent 1336571da7
commit b85c29e5f1
2 changed files with 154 additions and 32 deletions

View File

@ -203,7 +203,7 @@ def test_build_pdf_a4_landscape(tmp_path, monkeypatch):
w, h = _mediabox(pdf)
assert abs(w - 841.89) < 0.5 and abs(h - 595.28) < 0.5
assert name.startswith("relief_1054.") and name.endswith("_1-2000.pdf")
for s in (b"Prospection ? bois", b"1:2 000", b"Densit", b"2023-03-15", b"LiDAR HD"):
for s in (b"Prospection ? bois", b"1:2 000", b"Densit", b"2023-03-15", b"LiDAR HD", b"6,5 pts"):
assert s in pdf, s
@ -228,7 +228,7 @@ def test_build_pdf_partial_zone_hatched(tmp_path, monkeypatch):
lon, lat = _transformer("EPSG:2154", "EPSG:4326").transform(1055000.0, 6881500.0)
pdf, _ = build_pdf(tmp_path, lat, lon, "A4", "paysage", 2000, compress=False)
assert pdf.startswith(b"%PDF") and b"1055_6882" in pdf
assert b"non renseign" in pdf
assert b"Donn" in pdf and b"manquante" in pdf
def test_build_pdf_no_data_raises(tmp_path):
@ -241,3 +241,56 @@ def test_build_pdf_no_data_raises(tmp_path):
def test_fmt_int():
from lidar_pipeline.export_pdf import _fmt_int
assert _fmt_int(2000) == "2 000" and _fmt_int(500) == "500"
def test_north_arrow_angle_matches_pyproj_reference():
"""L'angle de rotation reportlab doit amener la flèche (dessinée vers le
nord du quadrillage) sur le nord géographique, dans le bon sens, à l'est
et à l'ouest du méridien central (3°E)."""
import math
from lidar_pipeline.export_pdf import _north_arrow_angle, _to_wgs84
from lidar_pipeline.tiles import _transformer, wgs84_to_l93
to_l93 = _transformer("EPSG:4326", "EPSG:2154")
def _reference_angle(cx, cy):
lat0, lon0 = _to_wgs84(cx, cy)
x0, y0 = to_l93.transform(lon0, lat0)
x1, y1 = to_l93.transform(lon0, lat0 + 0.001)
# azimut (sens horaire depuis le nord du quadrillage) du nord géographique
psi = math.degrees(math.atan2(x1 - x0, y1 - y0))
return -psi # rotation reportlab (antihoraire) amenant "haut" sur ce nord
east = wgs84_to_l93(6.0, 46.0) # à l'est du méridien central
west = wgs84_to_l93(0.0, 46.0) # à l'ouest du méridien central
for cx, cy in (east, west):
assert abs(_north_arrow_angle(cx, cy) - _reference_angle(cx, cy)) < 0.05
assert _north_arrow_angle(*east) > 0
assert _north_arrow_angle(*west) < 0
def test_wrap_text_lines_fit_width():
from reportlab.pdfgen import canvas as rl_canvas
from reportlab.lib.units import mm
from io import BytesIO
from lidar_pipeline.export_pdf import _wrap_text
c = rl_canvas.Canvas(BytesIO())
text = "Donnée manquante (sans relief) : " + ", ".join(
f"{1050 + i}_6882" for i in range(12))
max_width = 60 * mm
lines = _wrap_text(c, text, "Helvetica", 5.8, max_width, sep=", ")
assert len(lines) > 1
for line in lines:
assert c.stringWidth(line, "Helvetica", 5.8) <= max_width + 1e-6
def test_fit_title_shrinks_then_elides():
from reportlab.pdfgen import canvas as rl_canvas
from reportlab.lib.units import mm
from io import BytesIO
from lidar_pipeline.export_pdf import _fit_title
c = rl_canvas.Canvas(BytesIO())
long_title = "Relief orienté - " + ", ".join(f"{1050 + i:04d}_6882" for i in range(6))
text, size = _fit_title(c, long_title, "Helvetica-Bold", 10, 60 * mm, min_size=7.0)
assert size >= 7.0
assert c.stringWidth(text, "Helvetica-Bold", size) <= 60 * mm + 1e-6