# Program Title: Projection
# Roll Number: 23071263
# Name: Manpreet Singh
# Date of Submission: 28-10-2024
import numpy as np
import [Link] as plt
import math
def round_coordinates(x: float) -> int:
return int(x + 0.5)
class Point3D:
def __init__(self, x: float, y: float, z: float, w: float = 1.0):
self.x = x
self.y = y
self.z = z
self.w = w
def to_homogeneous(self):
return [Link]([self.x, self.y, self.z, self.w])
class Shape:
def __init__(self, points: list, edges: list):
[Link] = points
[Link] = edges
@staticmethod
def create_cube(w: float) -> 'Shape':
points = [
Point3D(0, 0, 0),
Point3D(w, 0, 0),
Point3D(w, w, 0),
Point3D(0, w, 0),
Point3D(0, 0, w),
Point3D(w, 0, w),
Point3D(w, w, w),
Point3D(0, w, w),
edges = [
(0, 1), (1, 2), (2, 3), (3, 0),
(4, 5), (5, 6), (6, 7), (7, 4),
(0, 4), (1, 5), (2, 6), (3, 7),
return Shape(points, edges)
@staticmethod
def create_pyramid(w: float) -> 'Shape':
points = [
Point3D(0, 0, 0),
Point3D(w, 0, 0),
Point3D(w, w, 0),
Point3D(0, w, 0),
Point3D(w / 2, w / 2, w),
]
edges = [
(0, 1), (1, 2), (2, 3), (3, 0),
(0, 4), (1, 4), (2, 4), (3, 4),
return Shape(points, edges)
class ProjectionTransformer:
@staticmethod
def perspective(a: float, b: float, c: float) -> [Link]:
return [Link]([
[1, 0, -a / c, 0],
[0, 1, -b / c, 0],
[0, 0, 0, 0],
[0, 0, -1 / c, 1]
], dtype=float)
@staticmethod
def parallel(a: float, b: float, c: float) -> [Link]:
return [Link]([
[1, 0, a, 0],
[0, 1, b, 0],
[0, 0, c, 0],
[0, 0, 0, 1]
], dtype=float)
@staticmethod
def oblique(f: float, q: float) -> [Link]:
theta = [Link](q)
return [Link]([
[1, 0, f * [Link](theta), 0],
[0, 1, f * [Link](theta), 0],
[0, 0, 0, 0],
[0, 0, 0, 1]
], dtype=float)
class Visualizer:
def __init__(self, width: int = 800, height: int = 800):
[Link] = width
[Link] = height
def plot_shape(self, shape: Shape, transformed_points: list, title: str):
[Link](figsize=(10, 10))
[Link](title)
for start_idx, end_idx in [Link]:
start = transformed_points[start_idx]
end = transformed_points[end_idx]
[Link]([start.x, end.x], [start.y, end.y], 'b-' if len([Link]) == 8 else 'r-')
[Link]('equal')
[Link](True)
[Link]()
class ProjectionApp:
def __init__(self):
[Link] = ProjectionTransformer()
[Link] = Visualizer()
[Link] = 100 # Default shape width
def apply_projection(self, shape: Shape, projection_matrix: [Link]) -> list:
transformed_points = []
for point in [Link]:
homogeneous_point = point.to_homogeneous()
transformed_point = [Link](projection_matrix, homogeneous_point)
transformed_points.append(Point3D(
transformed_point[0] / transformed_point[3],
transformed_point[1] / transformed_point[3],
transformed_point[2] / transformed_point[3]
))
return transformed_points
def run(self):
while True:
print("\n3D Projection System")
print("1. Perspective with CoP (0, 0, -100)")
print("2. Perspective with Custom CoP (a, b, c)")
print("3. Parallel Projection")
print("4. Oblique Projection (General)")
print("5. Oblique Projection (Cavalier)")
print("6. Oblique Projection (Cabinet)")
print("7. Exit")
choice = input("Select projection type (1-7): ")
if choice == '7':
break
shape_type = input("Select shape (1-Cube, 2-Pyramid): ")
shape = Shape.create_cube([Link]) if shape_type == '1' else Shape.create_pyramid([Link])
if choice == '1': # Standard Perspective with CoP (0, 0, -100)
projection = [Link](0, 0, -100)
title = "Perspective Projection (CoP at 0,0,-100)"
elif choice == '2': # Perspective with custom CoP (a, b, c)
a = float(input("Enter value for a: "))
b = float(input("Enter value for b: "))
c = float(input("Enter value for c: "))
projection = [Link](a, b, c)
title = f"Perspective Projection (CoP at {a},{b},{c})"
elif choice == '3': # Parallel Projection
a = float(input("Enter value for a: "))
b = float(input("Enter value for b: "))
c = float(input("Enter value for c: "))
projection = [Link](a, b, c)
title = f"Parallel Projection (Direction {a},{b},{c})"
elif choice == '4': # General Oblique Projection
f = float(input("Enter foreshortening factor f: "))
q = float(input("Enter angle q (in degrees): "))
projection = [Link](f, q)
title = f"Oblique Projection (f={f}, q={q})"
elif choice == '5': # Cavalier Oblique Projection
projection = [Link](1.0, 45)
title = "Cavalier Oblique Projection"
elif choice == '6': # Cabinet Oblique Projection
projection = [Link](0.5, 63.4)
title = "Cabinet Oblique Projection"
else:
continue
transformed_points = self.apply_projection(shape, projection)
[Link].plot_shape(shape, transformed_points, title)
# Main driver function
if __name__ == "__main__":
app = ProjectionApp()
[Link]()
OUTPUT: