Python example: mrpt_math_example.py

Geometry primitives, polygons, histograms and matrices with mrpt.math.

Modules: mrpt.math

  1#!/usr/bin/env python3
  2"""
  3Geometry primitives, polygons, histograms and matrices with mrpt.math.
  4
  5Demonstrates:
  6  - TPoint2D / TPoint3D: 2D and 3D points
  7  - TPose2D / TPose3D: 2D and 3D poses (position + orientation)
  8  - TSegment2D / TSegment3D: line segments
  9  - TLine2D / TLine3D: infinite lines
 10  - TPlane: 3D plane
 11  - TBoundingBox: axis-aligned bounding box
 12  - TTwist2D / TTwist3D: velocity twists
 13  - CPolygon: 2D polygon
 14  - CHistogram: 1D histogram
 15  - wrapToPi / wrapTo2Pi: angle normalisation
 16  - CMatrixDouble / CVectorDouble: dynamic matrices (bridge to numpy)
 17"""
 18
 19import math, numpy as np
 20from mrpt.math import (
 21    TPoint2D, TPoint3D,
 22    TPose2D, TPose3D,
 23    TSegment2D, TSegment3D,
 24    TLine2D, TLine3D,
 25    TPlane,
 26    TBoundingBox,
 27    TTwist2D, TTwist3D,
 28    CPolygon,
 29    CHistogram,
 30    wrapToPi, wrapTo2Pi,
 31    CMatrixDouble, CVectorDouble,
 32)
 33
 34# ---------------------------------------------------------------------------
 35# Points and poses
 36# ---------------------------------------------------------------------------
 37p2 = TPoint2D(1.0, 2.0)
 38p3 = TPoint3D(1.0, 2.0, 3.0)
 39print(f"TPoint2D: {p2}")
 40print(f"TPoint3D: {p3}")
 41assert p2.x == 1.0 and p2.y == 2.0
 42assert p3.z == 3.0
 43
 44pose2 = TPose2D(1.0, 0.5, math.pi / 4)
 45pose3 = TPose3D(1.0, 2.0, 0.5, 0.1, 0.2, 0.3)
 46print(f"\nTPose2D: {pose2}")
 47print(f"TPose3D: {pose3}")
 48
 49# ---------------------------------------------------------------------------
 50# Segment distance
 51# ---------------------------------------------------------------------------
 52seg = TSegment2D(TPoint2D(0, 0), TPoint2D(4, 0))
 53dist = seg.distance(TPoint2D(2, 3))
 54print(f"\nTSegment2D distance to (2,3): {dist:.4f}")   # should be 3
 55assert abs(dist - 3.0) < 1e-6
 56
 57# ---------------------------------------------------------------------------
 58# Line from two points
 59# ---------------------------------------------------------------------------
 60line = TLine2D(TPoint2D(0, 0), TPoint2D(1, 1))
 61print(f"\nTLine2D: {line}")
 62d = line.distance(TPoint2D(1, 0))
 63print(f"  distance to (1,0): {d:.4f}")   # sqrt(2)/2 ≈ 0.7071
 64assert abs(d - math.sqrt(2) / 2) < 1e-6
 65
 66# ---------------------------------------------------------------------------
 67# Plane
 68# ---------------------------------------------------------------------------
 69plane = TPlane(TPoint3D(0,0,0), TPoint3D(1,0,0), TPoint3D(0,1,0))  # XY plane
 70print(f"\nTPlane (XY plane): {plane}")
 71d3 = plane.distance(TPoint3D(0, 0, 5))
 72print(f"  distance to (0,0,5): {d3:.4f}")   # should be 5
 73assert abs(d3 - 5.0) < 1e-6
 74
 75# ---------------------------------------------------------------------------
 76# BoundingBox
 77# ---------------------------------------------------------------------------
 78bb = TBoundingBox(TPoint3D(-1,-1,-1), TPoint3D(1,1,1))
 79print(f"\nTBoundingBox: {bb}")
 80ctr_x = (bb.min.x + bb.max.x) / 2
 81ctr_y = (bb.min.y + bb.max.y) / 2
 82ctr_z = (bb.min.z + bb.max.z) / 2
 83print(f"  center: ({ctr_x},{ctr_y},{ctr_z})")
 84assert ctr_x == 0.0 and ctr_y == 0.0
 85
 86# ---------------------------------------------------------------------------
 87# Twists
 88# ---------------------------------------------------------------------------
 89tw2 = TTwist2D(1.0, 0.0, 0.1)   # vx, vy, omega
 90tw3 = TTwist3D(1.0, 0.0, 0.0, 0.0, 0.0, 0.1)
 91print(f"\nTTwist2D: {tw2}")
 92print(f"TTwist3D: {tw3}")
 93
 94# ---------------------------------------------------------------------------
 95# CPolygon
 96# ---------------------------------------------------------------------------
 97poly = CPolygon()
 98poly.add_vertex(0, 0)
 99poly.add_vertex(1, 0)
100poly.add_vertex(1, 1)
101poly.add_vertex(0, 1)
102print(f"\nCPolygon: {len(poly)} vertices")
103assert len(poly) == 4
104
105# ---------------------------------------------------------------------------
106# CHistogram
107# ---------------------------------------------------------------------------
108hist = CHistogram(0.0, 10.0, 10)   # [0,10], 10 bins
109for v in [1.5, 2.5, 2.5, 7.0]:
110    hist.add(v)
111bins, counts = hist.getHistogramNormalized()
112n_bins = len(counts)  # getBinCount(i) returns count for bin i, not total bins
113print(f"\nCHistogram ({n_bins} bins): {counts}")
114assert n_bins == 10
115
116# ---------------------------------------------------------------------------
117# Angle wrapping
118# ---------------------------------------------------------------------------
119print(f"\nwrapToPi(3π/2)  = {wrapToPi(3*math.pi/2):.4f}  (expect ~-1.5708)")
120print(f"wrapTo2Pi(-π/4) = {wrapTo2Pi(-math.pi/4):.4f} (expect ~4.7124)")
121assert abs(wrapToPi(3*math.pi/2)  - (-math.pi/2)) < 1e-9
122assert abs(wrapTo2Pi(-math.pi/4)  - (7*math.pi/4)) < 1e-9
123print("  wrap checks ✓")
124
125# ---------------------------------------------------------------------------
126# CMatrixDouble — numpy bridge (minimal API)
127# ---------------------------------------------------------------------------
128m = CMatrixDouble(3, 3)
129print(f"\nCMatrixDouble(3,3): {m}")
130arr = np.array([[1.0, 2.0], [3.0, 4.0]])
131m2 = CMatrixDouble(arr)     # construct from numpy
132np_out = m2.as_numpy()
133print(f"  CMatrixDouble from numpy, back to numpy: {np_out}")
134np.testing.assert_allclose(np_out, arr)
135print("  matrix numpy bridge ✓")