Vector3D and Line3D
Vector3D and Line3D are geometric classes for representing 3D vectors and lines in the YRT-PET framework. These classes are used to define Lines of Response (LORs) as 3D lines, which are used in various cases, most notably in projection operations.
Vector3D
Vector3D represents a 3D vector with single or double precision. By default, we use single precision (32 bits).
Python Usage
import pyyrtpet as yrt
import math
# ============================================================================
# Creating Vectors
# ============================================================================
# Create a vector with x, y, z components
v = yrt.Vector3D(1.0, 2.0, 3.0)
# Access individual components
x = v.x
y = v.y
z = v.z
assert x == 1.0
assert y == 2.0
assert z == 3.0
# Create a default vector (all zeros)
v_zero = yrt.Vector3D()
# ============================================================================
# Vector Operations
# ============================================================================
v1 = yrt.Vector3D(1.0, 2.0, 3.0)
v2 = yrt.Vector3D(4.0, 5.0, 6.0)
# Addition
v_sum = v1 + v2
assert v_sum.x == 5.0
assert v_sum.y == 7.0
assert v_sum.z == 9.0
# Subtraction
v_diff = v2 - v1
assert v_diff.x == 3.0
assert v_diff.y == 3.0
assert v_diff.z == 3.0
# Scalar multiplication
v_mult = v1 * 2.0
assert v_mult.x == 2.0
assert v_mult.y == 4.0
assert v_mult.z == 6.0
# Scalar addition
v_add = v1 + 1.0
assert v_add.x == 2.0
assert v_add.y == 3.0
assert v_add.z == 4.0
# Scalar subtraction
v_sub = v1 - 1.0
assert v_sub.x == 0.0
assert v_sub.y == 1.0
assert v_sub.z == 2.0
# Scalar division
v_div = v1 / 2.0
assert v_div.x == 0.5
assert v_div.y == 1.0
assert v_div.z == 1.5
# ============================================================================
# Vector Properties and Methods
# ============================================================================
v = yrt.Vector3D(3.0, 4.0, 0.0)
# Get the Euclidean norm (length) of the vector
norm = v.getNorm()
assert abs(norm - 5.0) < 0.001, "3-4-0 triangle has norm 5"
# Normalize the vector (make it a unit vector)
v_normalized = v.getNormalized()
assert abs(v_normalized.getNorm() - 1.0) < 0.001
# In-place normalization
v_to_normalize = yrt.Vector3D(3.0, 4.0, 0.0)
v_to_normalize.normalize()
assert abs(v_to_normalize.getNorm() - 1.0) < 0.001
# Check if vector is normalized
assert v_normalized.isNormalized() == True
assert v_to_normalize.isNormalized() == True
assert v.isNormalized() == False
# Update vector components
v = yrt.Vector3D(1.0, 2.0, 3.0)
v.update(10.0, 20.0, 30.0)
assert v.x == 10.0
assert v.y == 20.0
assert v.z == 30.0
# Update from another vector
v1 = yrt.Vector3D(1.0, 2.0, 3.0)
v2 = yrt.Vector3D(4.0, 5.0, 6.0)
v1.update(v2)
assert v1.x == 4.0
assert v1.y == 5.0
assert v1.z == 6.0
# ============================================================================
# Dot product and cross product
# ============================================================================
v1 = yrt.Vector3D(1.0, 0.0, 0.0)
v2 = yrt.Vector3D(0.0, 1.0, 0.0)
# Dot product
dot = v1.x * v2.x + v1.y * v2.y + v1.z * v2.z
assert dot == 0.0 # Orthogonal vectors
# Cross product (vector product)
# Note: We use the multiplication operator (*) for cross product (not dot product)
cross = v1 * v2 # Using the * operator for cross product
assert cross.x == 0.0
assert cross.y == 0.0
assert cross.z == 1.0
# ============================================================================
# Comparison and Equality
# ============================================================================
v1 = yrt.Vector3D(1.0, 2.0, 3.0)
v2 = yrt.Vector3D(1.0, 2.0, 3.0)
v3 = yrt.Vector3D(4.0, 5.0, 6.0)
assert (v1 == v2) == True
assert (v1 == v3) == False
# ============================================================================
# String Representation
# ============================================================================
v = yrt.Vector3D(1.5, 2.5, 3.5)
repr_str = str(v)
# Output: (1.5, 2.5, 3.5)
assert "1.5" in repr_str
assert "2.5" in repr_str
assert "3.5" in repr_str
# ============================================================================
# Double Precision Version
# ============================================================================
# For higher precision calculations, use Vector3DDouble
v_double = yrt.Vector3DDouble(1.0, 2.0, 3.0)
norm_double = v_double.getNorm()
Line3D
Line3D represents a 3D line segment defined by two endpoints (point1 and point2).
Python Usage
import pyyrtpet as yrt
import math
# ============================================================================
# Creating Lines
# ============================================================================
# Create a line from two Vector3D points
p1 = yrt.Vector3D(0.0, -100.0, 0.0)
p2 = yrt.Vector3D(0.0, 100.0, 0.0)
line = yrt.Line3D(p1, p2)
# Access the endpoints
assert line.point1.x == 0.0
assert line.point1.y == -100.0
assert line.point2.x == 0.0
assert line.point2.y == 100.0
# Create a default line (both points at origin)
line_default = yrt.Line3D()
# ============================================================================
# Line Properties
# ============================================================================
# Get the length (distance between endpoints)
length = line.getNorm()
assert abs(length - 200.0) < 0.001
# ============================================================================
# Line Operations
# ============================================================================
# Update line endpoints
p1_new = yrt.Vector3D(-50.0, -50.0, -50.0)
p2_new = yrt.Vector3D(50.0, 50.0, 50.0)
line.update(p1_new, p2_new)
assert line.point1.x == -50.0
assert line.point2.x == 50.0
# ============================================================================
# Line Comparison
# ============================================================================
# Check if two lines are equal (same endpoints)
line1 = yrt.Line3D(yrt.Vector3D(0, 0, 0), yrt.Vector3D(1, 1, 1))
line2 = yrt.Line3D(yrt.Vector3D(0, 0, 0), yrt.Vector3D(1, 1, 1))
line3 = yrt.Line3D(yrt.Vector3D(1, 1, 1), yrt.Vector3D(2, 2, 2))
assert line1.isEqual(line2) == True
assert line1.isEqual(line3) == False
# ============================================================================
# Line Parallelism
# ============================================================================
# Check if two lines are parallel
line_a = yrt.Line3D(yrt.Vector3D(0, 0, 0), yrt.Vector3D(1, 0, 0))
line_b = yrt.Line3D(yrt.Vector3D(0, 1, 0), yrt.Vector3D(1, 1, 0))
line_c = yrt.Line3D(yrt.Vector3D(0, 0, 0), yrt.Vector3D(0, 0, 1))
assert line_a.isParallel(line_b) == True # Both along x-axis
assert line_a.isParallel(line_c) == False # Different directions
# ============================================================================
# Tuple Conversion
# ============================================================================
# Convert line to tuple format
p1 = yrt.Vector3D(1.0, 2.0, 3.0)
p2 = yrt.Vector3D(4.0, 5.0, 6.0)
line = yrt.Line3D(p1, p2)
# toTuple returns ((x1, y1, z1), (x2, y2, z2))
tup = line.toTuple()
assert tup == ((1.0, 2.0, 3.0), (4.0, 5.0, 6.0))
# ============================================================================
# String Representation
# ============================================================================
line = yrt.Line3D(yrt.Vector3D(1.0, 2.0, 3.0), yrt.Vector3D(4.0, 5.0, 6.0))
repr_str = str(line)
# Output contains both points
# ============================================================================
# Double Precision Version
# ============================================================================
# For higher precision, use Line3DDouble
p1d = yrt.Vector3DDouble(0.0, -100.0, 0.0)
p2d = yrt.Vector3DDouble(0.0, 100.0, 0.0)
line_double = yrt.Line3DDouble(p1d, p2d)
Practical Example: Creating LORs for Projection
import pyyrtpet as yrt
# Create a scanner with a regular geometry (without specifying a custom a LUT)
scanner = yrt.Scanner(
scanner_name='EXAMPLE',
axial_fov=100.0,
crystal_size_z=2.0,
crystal_size_trans=2.0,
crystal_depth=10.0,
scanner_radius=200.0,
dets_per_ring=64,
num_rings=10,
num_doi=1,
max_ring_diff=9,
min_ang_diff=1,
dets_per_block=16
)
# Gather the 17th detector's position
p1 = scanner.getDetectorPos(17)
# Gather another detector
p2 = scanner.getDetectorPos(142)
# Build an LOR
lor = yrt.Line3D(p1, p2)
# You can then use this LOR with the Siddon or DD projector
# for forward/backward projections
Notes
Both Vector3D and Line3D support single (float) and double precision versions
The single precision versions are named
Vector3DandLine3DThe double precision versions are named
Vector3DDoubleandLine3DDoubleLine3D stores two Vector3D endpoints, so any vector operations can be performed on
line.point1andline.point2individually