camera_analyze/utils.py
2025-04-24 17:44:30 +02:00

164 lines
4.7 KiB
Python

from numpy import zeros
from numpy.typing import NDArray
from typing import NamedTuple, Any
def compute_matrix(number: int):
"""
Compute the index order (from 1 because it will be used by MATLAB) of measurmenet taken with a "snail" shape.
Used for the backscattermeter analysis MATLAB script
Parameters
----------
number: int
Number of block from center to the extremity of the map
"""
matrix = zeros((number * 2 + 1, number * 2 + 1), dtype=int)
cursor = [number, number]
counter = 1
matrix[*cursor] = counter
for i in range(number * 2):
for _ in range(i + 1):
if i % 2 == 0:
cursor[1] += 1
else:
cursor[1] -= 1
counter += 1
matrix[*cursor] = counter
for _ in range(i + 1):
if i % 2 == 0:
cursor[0] -= 1
else:
cursor[0] += 1
counter += 1
matrix[*cursor] = counter
for i in range(number):
cursor[1] += 1
counter += 1
matrix[*cursor] = counter
for i in range(number):
cursor[1] += 1
counter += 1
matrix[*cursor] = counter
return matrix
def diff_matrix(number: int) -> list[list[int]]:
posX, negX, posY, negY = [], [], [], []
index = 0
for i in range(number * 2):
for _ in range(i + 1):
if i % 2 == 0:
posX.append(index)
else:
negX.append(index)
index += 1
for _ in range(i + 1):
if i % 2 == 0:
posY.append(index)
else:
negY.append(index)
index += 1
for _ in range(number):
posX.append(index)
index += 1
for _ in range(number):
posY.append(index)
index += 1
return [posX, negX, posY, negY]
def python2matlab(array: NDArray[Any]):
"""
Return the MATLAB representation of a 2d python numpy array
Parameters
----------
array: NDArray[Any]
2d array
"""
if len(array.shape) != 2:
raise ValueError("Can only show the representation of 2D numpy array")
result = "matrix = [ "
for column_index in range(array.shape[1]):
for row_index in range(array.shape[0]):
result += "{} ".format(array[row_index, column_index])
if column_index != array.shape[1] - 1:
result += "; "
result += "]';"
return result
class Vector(NamedTuple):
x: float
y: float
def __truediv__(self, other: "Vector | float | int") -> "Vector":
if type(other) is type(self):
return Vector(x=self.x / other.x, y=self.y / other.y)
return Vector(x=self.x / other, y=self.y / other)
def __mul__(self, other: "Vector | float | int") -> "Vector":
if type(other) is type(self):
return Vector(x=self.x * other.x, y=self.y * other.y)
return Vector(x=self.x * other, y=self.y * other)
def add(self, other: "Point | Vector | float | int") -> "Vector":
if type(other) == type(self) or type(other) is Point:
return Vector(x=self.x + other.x, y=self.y + other.y)
return Vector(x=self.x + other, y=self.y + other)
class Point(NamedTuple):
x: float
y: float
def add(self, other: "Point | Vector | float | int") -> "Point":
if type(other) == type(self) or type(other) is Vector:
return Point(x=self.x + other.x, y=self.y + other.y)
return Point(x=self.x + other, y=self.y + other)
class Axis(NamedTuple):
pos: Vector
neg: Vector
class Directions(NamedTuple):
x: Axis
y: Axis
def convert_to_base(base: tuple[Vector, Vector], vector: Vector) -> Vector:
y = (vector.y - (base[0].y * vector.x / base[0].x)) / (
base[1].y - (base[0].y * base[1].x / base[0].x)
)
x = vector.x / base[0].x - y * (base[1].x / base[0].x)
return Vector(x=x, y=y)
def move_snail(
n_grid: int, point: Point, directions: Directions
) -> tuple[list[Vector], Point]:
movement: list[Vector] = []
for i in range(2 * n_grid):
for _ in range(i + 1):
if (i % 2) == 0:
movement.append(directions.x.pos)
else:
movement.append(directions.x.neg)
point = point.add(movement[-1])
for _ in range(i + 1):
if (i % 2) == 0:
movement.append(directions.y.pos)
else:
movement.append(directions.y.neg)
point = point.add(movement[-1])
# go back
for i in range(n_grid):
movement.append(directions.x.pos)
point = point.add(movement[-1])
for i in range(n_grid):
movement.append(directions.y.pos)
point = point.add(movement[-1])
return movement, point