Geometry Concepts¶
This page explains the mathematical concepts and geometric principles underlying twod's design and functionality.
Coordinate Systems¶
Cartesian Coordinates¶
twod uses the standard Cartesian coordinate system where: - x-axis: Horizontal axis (positive goes right) - y-axis: Vertical axis (positive goes up) - Origin: Point (0, 0) where axes intersect
from twod import Point
origin = Point(0, 0)
right = Point(1, 0) # 1 unit right
up = Point(0, 1) # 1 unit up
diagonal = Point(1, 1) # 1 unit right and up
Polar Coordinates¶
Points can also be represented in polar form using: - Radius ®: Distance from origin - Angle (θ): Angle from positive x-axis (counter-clockwise)
from twod import Point
import math
# Create point from polar coordinates
radius = 5
angle = math.pi / 4 # 45 degrees
point = Point.from_polar(radius, angle)
print(f"Point: {point}") # Point(3.535..., 3.535...)
# Convert Cartesian to polar
p = Point(3, 4)
print(f"Radius: {p.radius}") # 5.0
print(f"Angle: {p.radians}") # 0.9272952180016122
Distance Calculations¶
Euclidean Distance¶
The distance between two points \((x_1, y_1)\) and \((x_2, y_2)\) is:
\[d = \sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2}\]
Distance Squared¶
For performance, when you only need relative distances, use squared distance:
\[d^2 = (x_2 - x_1)^2 + (y_2 - y_1)^2\]
from twod import Point
p1 = Point(0, 0)
p2 = Point(3, 4)
dist_squared = p1.distance_squared(p2) # 25.0 (faster than distance)
Vector Operations¶
Dot Product¶
The dot product of two vectors a = (a₁, a₂) and b = (b₁, b₂) is:
\[\mathbf{a} \cdot \mathbf{b} = a_1 b_1 + a_2 b_2\]
The dot product has important geometric properties: - Perpendicular vectors: dot product = 0 - Parallel vectors: dot product = ±|a||b| - Angle between vectors: \(\cos \theta = \frac{\mathbf{a} \cdot \mathbf{b}}{|\mathbf{a}||\mathbf{b}|}\)
from twod import Point
a = Point(3, 4)
b = Point(1, 2)
dot_product = a.dot(b) # 3*1 + 4*2 = 11
# Check if vectors are perpendicular
perpendicular = Point(1, 0)
vertical = Point(0, 1)
print(perpendicular.dot(vertical)) # 0 (perpendicular)
Cross Product (2D)¶
In 2D, the cross product gives a scalar representing the z-component of the 3D cross product:
\[\mathbf{a} \times \mathbf{b} = a_1 b_2 - a_2 b_1\]
This is useful for: - Orientation: positive = counter-clockwise, negative = clockwise, zero = collinear - Area calculation: |cross product| = 2 × area of triangle
from twod import Point
a = Point(1, 0)
b = Point(0, 1)
cross = a.cross(b) # 1*1 - 0*0 = 1 (counter-clockwise)
# Check orientation
p1 = Point(0, 0)
p2 = Point(1, 0)
p3 = Point(1, 1)
orientation = p1.ccw(p2, p3) # > 0 (counter-clockwise)
Line Geometry¶
Line Representation¶
Lines in twod are represented as line segments with start and end points. Key properties:
- Length: Distance between endpoints
- Direction: Unit vector from start to end
- Slope: Rise over run (dy/dx)
- Angle: Angle from positive x-axis
from twod import Point, Line
line = Line(Point(0, 0), Point(3, 4))
print(f"Length: {line.length}") # 5.0
print(f"Direction: {line.direction}") # Unit vector (0.6, 0.8)
print(f"Slope: {line.slope}") # 4/3 ≈ 1.333
print(f"Angle: {line.angle_degrees}") # ~53.13°
Line Intersection¶
Two lines intersect if their direction vectors are not parallel. The intersection point can be found using parametric equations:
- Line 1: P₁ + t₁(P₂ - P₁)
- Line 2: P₃ + t₂(P₄ - P₃)
from twod import Point, Line
line1 = Line(Point(0, 0), Point(2, 2))
line2 = Line(Point(0, 2), Point(2, 0))
intersection = line1.intersection_point(line2) # Point(1, 1)
Distance from Point to Line¶
The shortest distance from a point to a line segment involves: 1. Project the point onto the infinite line 2. Clamp the projection to the line segment 3. Calculate distance to the clamped point
from twod import Point, Line
line = Line(Point(0, 0), Point(10, 0)) # Horizontal line
point = Point(5, 3)
distance = line.distance_to_point(point) # 3.0
closest = line.closest_point_on_line(point) # Point(5, 0)
Angle Calculations¶
Angle Between Vectors¶
The angle between two vectors is found using the dot product:
\[\theta = \arccos\left(\frac{\mathbf{a} \cdot \mathbf{b}}{|\mathbf{a}||\mathbf{b}|}\right)\]
from twod import Point, Line
import math
line1 = Line(Point(0, 0), Point(1, 0)) # Horizontal
line2 = Line(Point(0, 0), Point(1, 1)) # 45° diagonal
angle_rad = line1.angle_between(line2) # π/4 radians
angle_deg = angle_rad * 180 / math.pi # 45 degrees
Angle Normalization¶
Angles in twod are typically normalized to: - Radians: [0, 2π) or [-π, π) - Degrees: [0, 360°) or [-180°, 180°)
Complex Number Geometry¶
Complex Numbers as Points¶
Complex numbers provide an elegant way to represent 2D points: - Real part: x-coordinate - Imaginary part: y-coordinate - Magnitude: Distance from origin - Argument: Angle from positive x-axis
from twod import CPoint
# Complex number 3+4j represents point (3, 4)
cp = CPoint(3+4j)
print(f"X: {cp.x}") # 3.0
print(f"Y: {cp.y}") # 4.0
print(f"Radius: {cp.radius}") # 5.0
print(f"Angle: {cp.radians}") # 0.9272952180016122
Complex Arithmetic¶
Complex number arithmetic naturally represents geometric operations: - Addition: Translation - Multiplication by real: Scaling - Multiplication by complex: Rotation and scaling
from twod import CPoint
import cmath
# Translation
cp1 = CPoint(1+2j)
cp2 = CPoint(3+4j)
translated = cp1 + cp2 # CPoint(4+6j)
# Rotation by 90° (multiply by i)
rotated = cp1 * CPoint(1j) # CPoint(-2+1j)
# Rotation by arbitrary angle
angle = 0.5 # radians
rotation = cmath.exp(1j * angle)
rotated = cp1 * CPoint(rotation)
Geometric Relationships¶
Collinearity¶
Three points are collinear if they lie on the same line. This can be tested using the cross product:
from twod import Point
p1 = Point(0, 0)
p2 = Point(1, 1)
p3 = Point(2, 2)
# Points are collinear if cross product is zero
collinear = p1.is_colinear(p2, p3) # True
Orientation¶
The orientation of three points can be: - Counter-clockwise: Cross product > 0 - Clockwise: Cross product < 0 - Collinear: Cross product = 0
from twod import Point
p1 = Point(0, 0)
p2 = Point(1, 0)
p3 = Point(1, 1)
ccw_test = p1.ccw(p2, p3) # > 0 (counter-clockwise)
is_ccw = p1.is_ccw(p2, p3) # True
Point in Rectangle¶
A point is inside a rectangle if: - x-coordinate is between left and right bounds - y-coordinate is between bottom and top bounds
from twod import Point, Rect
rect = Rect(Point(0, 0), Point(10, 10))
test_point = Point(5, 5)
# Check if point is inside
inside = test_point.inside(rect.bottom_left, rect.top_right) # True
Performance Considerations¶
Squared Distance vs Distance¶
When comparing distances, use squared distance to avoid expensive square root calculation:
from twod import Point
points = [Point(1, 1), Point(2, 2), Point(3, 3)]
origin = Point(0, 0)
# Efficient: compare squared distances
closest = min(points, key=lambda p: origin.distance_squared(p))
# Less efficient: compare actual distances
# closest = min(points, key=lambda p: origin.distance(p))
Complex vs Float Operations¶
Complex number operations can be more efficient for: - Rotations - Polar coordinate conversions - Repeated geometric transformations
from twod import Point, CPoint
# Traditional rotation (slower)
def rotate_point(point, angle):
import math
cos_a = math.cos(angle)
sin_a = math.sin(angle)
return Point(
point.x * cos_a - point.y * sin_a,
point.x * sin_a + point.y * cos_a
)
# Complex rotation (faster)
def rotate_cpoint(cpoint, angle):
import cmath
return cpoint * CPoint(cmath.exp(1j * angle))
Numerical Precision¶
Floating Point Considerations¶
When working with floating-point numbers, be aware of: - Precision limits: Not all decimal numbers can be represented exactly - Comparison tolerance: Use tolerance for equality checks - Accumulated errors: Errors can accumulate in long calculations
from twod import Point
# Floating point precision issues
p1 = Point(0.1, 0.2)
p2 = Point(0.3, 0.0)
sum_point = p1 + p2 # May not be exactly Point(0.4, 0.2)
# Use tolerance for comparisons
def points_equal(p1, p2, tolerance=1e-10):
return p1.distance(p2) <= tolerance
Tolerance in Geometric Operations¶
Many geometric operations in twod use tolerance for robust comparisons:
from twod import Point, Line
line = Line(Point(0, 0), Point(10, 0))
point = Point(5, 1e-12) # Very close to line
# Contains point uses tolerance
contains = line.contains_point(point) # True (within default tolerance)
contains_strict = line.contains_point(point, tolerance=1e-15) # False
Understanding these concepts will help you use twod effectively and write robust geometric code.