From 11ff2747081dc07fd8ab2a47731380c73bafcced Mon Sep 17 00:00:00 2001 From: JoeBell Date: Sun, 2 Mar 2025 20:49:20 -0500 Subject: [PATCH] Created RawScanReading class Split off part ScanReading into RawScanReading to make modifying the raw distance values easier --- ExampleMultipleSonarReadings.ipynb | 2 +- ExampleSingleSonarReading.ipynb | 9 ++--- Raytrace/PlotRays.py | 10 +++--- Raytrace/SideScan.py | 55 +++++++++++++++++------------- 4 files changed, 43 insertions(+), 33 deletions(-) diff --git a/ExampleMultipleSonarReadings.ipynb b/ExampleMultipleSonarReadings.ipynb index f45c0f0..b453a68 100644 --- a/ExampleMultipleSonarReadings.ipynb +++ b/ExampleMultipleSonarReadings.ipynb @@ -51,7 +51,7 @@ "readings:list[ScanReading] = []\n", "for n,rays in enumerate(rays_list):\n", " print(n + 1, len(rays_list), sep='/', end='\\r')\n", - " readings.append(SideScan(mesh).scan_rays(rays))\n", + " readings.append(ScanReading(SideScan(mesh).scan_rays(rays)))\n", "\n", "print()\n", "\n", diff --git a/ExampleSingleSonarReading.ipynb b/ExampleSingleSonarReading.ipynb index 5787eb4..914a918 100644 --- a/ExampleSingleSonarReading.ipynb +++ b/ExampleSingleSonarReading.ipynb @@ -8,7 +8,7 @@ "source": [ "from Raytrace.TriangleMesh import Ray\n", "from Raytrace.BVHMesh import BVHMesh\n", - "from Raytrace.SideScan import SideScan\n", + "from Raytrace.SideScan import SideScan, ScanReading\n", "import numpy as np\n", "import time" ] @@ -43,10 +43,11 @@ "\n", "rays = SideScan.generate_rays(orientation, min_angle, max_angle, sample_ray_count)\n", "\n", - "reading = SideScan(mesh).scan_rays(rays)\n", + "raw_reading = SideScan(mesh).scan_rays(rays)\n", + "reading = ScanReading(raw_reading)\n", "\n", "print('Triangles:', mesh.triangles.shape[0])\n", - "reading.print_summary()" + "raw_reading.print_summary()" ] }, { @@ -56,7 +57,7 @@ "outputs": [], "source": [ "import plotly.graph_objs as go\n", - "from PlotRays import plot_mesh, plot_rays, plot_reading" + "from Raytrace.PlotRays import plot_mesh, plot_rays, plot_reading" ] }, { diff --git a/Raytrace/PlotRays.py b/Raytrace/PlotRays.py index bb7e01a..745c271 100644 --- a/Raytrace/PlotRays.py +++ b/Raytrace/PlotRays.py @@ -13,8 +13,8 @@ def plot_mesh(mesh:TriangleMesh, **kwargs) -> go.Mesh3d: return go.Mesh3d(x=x, y=y, z=z, i=i, j=j, k=k, **kwargs) def plot_rays(reading:ScanReading, **kwargs) -> go.Scatter3d: - origin = reading.origins[reading.finite] - inters = reading.intersections[reading.finite] + origin = reading.raw.origins[reading.raw.finite] + inters = reading.raw.intersections[reading.raw.finite] x, y, z = np.stack((origin, inters, origin)).swapaxes(0,1).reshape((-1,3)).swapaxes(0,1) return go.Scatter3d(x=x, y=y, z=z, **kwargs) @@ -32,12 +32,12 @@ def plot_reading(reading:ScanReading) -> go.Figure: 'mode': 'markers', 'name': 'Raw', 'showlegend': True, - 'x': reading.distances[reading.finite], - 'y': np.zeros(reading.intersection_count), + 'x': reading.raw.distances[reading.raw.finite], + 'y': np.zeros(reading.raw.intersection_count), }) ]) def plot_intersections(reading:ScanReading, **kwargs) -> go.Scatter3d: - inters = reading.intersections[reading.finite] + inters = reading.raw.intersections[reading.raw.finite] x, y, z = inters.reshape((-1,3)).swapaxes(0,1) return go.Scatter3d(x=x, y=y, z=z, **kwargs) diff --git a/Raytrace/SideScan.py b/Raytrace/SideScan.py index 598a084..54d1df4 100644 --- a/Raytrace/SideScan.py +++ b/Raytrace/SideScan.py @@ -1,8 +1,9 @@ from Raytrace.TriangleMesh import TriangleMesh, Ray +from typing import Self import numpy as np import time -class ScanReading: +class RawScanReading: distances:np.ndarray intersections:np.ndarray origins:np.ndarray @@ -10,53 +11,61 @@ class ScanReading: finite:np.ndarray intersection_count:int + start_time:float = -1 + end_time:float = -1 + + def __init__(self, distances:np.ndarray, rays:list[Ray]): + old_error_state = np.seterr(all='ignore') + self.distances = distances + self.origins = np.array([r.origin for r in rays]) + self.directions = np.array([r.direction for r in rays]) + self.intersections = self.origins + self.directions * self.distances.reshape((-1,1)) + self.finite = np.isfinite(self.distances) + self.intersection_count = np.count_nonzero(self.finite) + np.seterr(**old_error_state) + + def print_summary(self) -> None: + print('Intersections:', self.intersection_count , '/', len(self.distances)) + if self.end_time == -1 or self.start_time == -1: return + print('Time:', self.end_time - self.start_time, 'seconds') + print('Speed:', len(self.distances)/(self.end_time - self.start_time), 'rays/seconds') + +class ScanReading: + raw:RawScanReading + smooth_dist:float result_reselution:int min_dist:float max_dist:float result:np.ndarray - - start_time:float = -1 - end_time:float = -1 def __init__(self, - distances:np.ndarray, rays:list[Ray], + raw_reading:RawScanReading, smooth_dist:float = 0.05, result_reselution:int = 1000, min_dist:float = 0, max_dist:float = 2 ): old_error_state = np.seterr(all='ignore') - self.distances = distances - self.origins = np.array([r.origin for r in rays]) - self.directions = np.array([r.direction for r in rays]) - self.intersections = self.origins + self.directions * self.distances.reshape((-1,1)) - self.finite = np.isfinite(self.distances) - self.intersection_count = np.count_nonzero(self.finite) - + self.raw = raw_reading self.smooth_dist = smooth_dist self.result_reselution = result_reselution self.min_dist = min_dist self.max_dist = max_dist - self.convert_distances() + self.process_raw() np.seterr(**old_error_state) - def convert_distances(self) -> None: + def process_raw(self) -> None: old_error_state = np.seterr(all='ignore') - norm = (self.distances[self.finite] - self.min_dist) / (self.max_dist - self.min_dist) + norm = (self.raw.distances[self.raw.finite] - self.min_dist) / (self.max_dist - self.min_dist) ldist = norm - (np.arange(0,1,1/self.result_reselution) + 0.5/self.result_reselution).reshape((-1,1)) smooth_val = self.smooth_dist / (self.max_dist - self.min_dist) - lval = np.pow(np.maximum(0, np.square(smooth_val) - np.square(ldist)),3) / (32/35*smooth_val**7) / len(self.distances) + lval = np.pow(np.maximum(0, np.square(smooth_val) - np.square(ldist)),3) / (32/35*smooth_val**7) / len(self.raw.distances) self.result = np.sum(lval, axis = 1) np.seterr(**old_error_state) - def print_summary(self) -> None: - print('Intersections:', self.intersection_count , '/', len(self.distances)) - if self.end_time == -1 or self.start_time == -1: return - print('Time:', self.end_time - self.start_time, 'seconds') - print('Speed:', len(self.distances)/(self.end_time - self.start_time), 'rays/seconds') class SideScan: mesh:TriangleMesh smooth_dist:float @@ -65,7 +74,7 @@ def __init__(self, mesh:TriangleMesh, smooth_dist:float = 0.05, result_reselutio self.mesh = mesh self.smooth_dist = smooth_dist self.result_reselution = result_reselution - def scan_rays(self, rays:list[Ray]) -> ScanReading: + def scan_rays(self, rays:list[Ray]) -> RawScanReading: distances = np.empty((len(rays),), np.float32) start_time = time.time() @@ -73,7 +82,7 @@ def scan_rays(self, rays:list[Ray]) -> ScanReading: distances[n] = self.mesh.raytrace(ray) end_time = time.time() - out = ScanReading(distances, rays) + out = RawScanReading(distances, rays) out.start_time = start_time out.end_time = end_time