differt.rt.image_method#
- image_method(from_vertices, to_vertices, mirror_vertices, mirror_normals)[source]#
Return the ray paths between pairs of vertices, that reflect on a given list of mirrors in between.
The Image Method is a very simple but effective path tracing technique that can rapidly compute a ray path undergoing a series of specular reflections on a pre-defined list of mirrors.
The method assumes infinitely long mirrors, and will return invalid paths in some degenerated cases such as consecutive collinear mirrors, or impossible configurations. It is the user’s responsibility to make sure that the returned path is correct.
Otherwise, the returned path will, for each reflection, have equal angles of incidence and of reflection.
Warning
NaNs and infinity values should be treated as invalid paths, and will naturally occur when image paths are impossible to trace, e.g., when a mirror is parallel to a ray segment that it is supposed to reflect.
- Parameters:
from_vertices (
Float[ArrayLike, '*#batch 3']) – An array offromvertices, i.e., vertices from which the ray paths start. In a radio communications context, this is usually an array of transmitters.to_vertices (
Float[ArrayLike, '*#batch 3']) – An array oftovertices, i.e., vertices to which the ray paths end. In a radio communications context, this is usually an array of receivers.mirror_vertices (
Float[ArrayLike, '*#batch num_mirrors 3']) – An array of mirror vertices. For each mirror, any vertex on the infinite plane that describes the mirror is considered to be a valid vertex.mirror_normals (
Float[ArrayLike, '*#batch num_mirrors 3']) – An array of mirror normals, where each normal has a unit length and is perpendicular to the corresponding mirror.
- Return type:
- Returns:
An array of ray paths obtained with the image method.
Note
The paths do not contain the starting and ending vertices.
You can easily create the complete ray paths using
assemble_paths:paths = image_method( from_vertices, to_vertices, mirror_vertices, mirror_normals, ) full_paths = assemble_paths( from_vertices, paths, to_vertices, )
Examples
The following image shows how the Image Method (IM) can be applied to find a path between two nodes (i.e., BS and UE).
Fig. 3 Example application of IM in RT. The method determines the only valid path that can be taken to join BS and UE with, in between, reflection with two mirrors (the interaction order is important). First, the consecutive images of the BS are determined through each mirror, using line symmetry. Second, intersections with mirrors are computed backward, i.e., from last mirror to first, by joining the UE, then the intersection points, with the images of the BS. Finally, the valid path can be obtained by joining BS, the intermediary intersection points, and the UE [1, fig. 5, p. 3].#
Next, we show how to reproduce the above results using
image_method.>>> from differt.geometry import TriangleMesh, normalize, assemble_paths >>> from differt.plotting import draw_markers, draw_paths, reuse >>> from differt.rt import image_method >>> >>> from_vertex = jnp.array([+2.0, -1.0, +0.0]) >>> to_vertex = jnp.array([+2.0, +4.0, +0.0]) >>> mirror_vertices = jnp.array([ ... [3.0, 3.0, 0.0], ... [4.0, 3.4, 0.0], ... ]) >>> mirror_normals = jnp.array([ ... [+1.0, -1.0, +0.0], ... [-1.0, +0.0, +0.0], ... ]) >>> mirror_normals, _ = normalize(mirror_normals) >>> path = image_method( ... from_vertex, ... to_vertex, ... mirror_vertices, ... mirror_normals, ... ) >>> with reuse(backend="plotly") as fig: ... TriangleMesh.plane( ... mirror_vertices[0], normal=mirror_normals[0], rotate=-0.954 ... ).plot(color="red") ... TriangleMesh.plane( ... mirror_vertices[1], normal=mirror_normals[1] ... ).plot(color="red") ... ... full_path = assemble_paths( ... from_vertex, ... path, ... to_vertex, ... ) ... draw_paths( ... full_path, ... mode="lines+markers", ... marker={"color": "green"}, ... name="Final path", ... ) ... markers = jnp.vstack((from_vertex, to_vertex)) ... draw_markers( ... markers, ... labels=["BS", "UE"], ... marker={"color": "black"}, ... name="BS/UE", ... ) ... fig.update_layout(scene_aspectmode="data") >>> fig