WUT_Computer_Science/Programming/TRAK/main.py
Krzysztof kuhy Rudnicki bd24dd57ea Hold the coursework to the same lint bar as the tooling
kuhy overruled the "do not fix coursework to be better than it was submitted"
rule: git history is the archive, so the working tree can be clean. This lands
the config and the mechanical half of the cleanup -- 9,281 ruff findings under
the fleet config down to 3,686, with no per-file-ignores anywhere.

What is in here:

- pyproject.toml, the first one in this repo. select = ["ALL"], mypy strict,
  and the vendored list mirrored into ruff exclude and coverage omit. Five
  rules are off and each says why; CPY001 is the only judgement call, because
  stamping a copyright header onto 137 university assignments would assert a
  licence that was never claimed. No hook is wired up yet -- a gate lands only
  once its subject is clean.

- ruff format + the safe fixes, then a second pass over the docstring rules
  ruff marks unsafe (they only edit docstring text). 108 files.

- TRAK/sightpy is vendored, not coursework: it is rafael-fuente/Python-Raytracer
  (BSD 3-Clause). Verified against a fresh upstream clone with line endings
  normalised -- 30 of 32 files byte-identical, ray.py and scene.py carrying a
  12- and 13-line local patch that counts rays for the report. 35 files that
  should never have been linted, now excluded and restored.

- WDWR, SPD, MOM and ECRYPT are fully clean, by hand and verified by running
  them: WDWR's three plot scripts print the same statistics as before, MOM's
  PuLP model solves to the same cost. WDWR's graph.py had a 342-character CSV
  header embedded as a string literal, which cannot be wrapped -- the data
  moved to data/pareto_front.csv. Two 0-byte .py stubs are deleted; an empty
  file is not a deliverable and git still has it.

Three harness bugs found by actually running things:

- `run` now forces MPLBACKEND=Agg. TRAK finished its ray trace in 37 seconds
  and then sat for 45 minutes: plt.show() had opened an image viewer and was
  waiting for someone to close the window.
- TRAK's main.py only pops that viewer with --show now, and its runner writes
  to a gitignored build/ via the new --entry-args. The default output path is
  outputs/output.png, which is TRACKED -- a plain run overwrote a submitted
  deliverable.
- course_lib.sh was 357 lines, over this repo's own cap. Split into
  course_probe.sh and course_run.sh.

Verified: ECOTE 26 tests pass, ECRYPT_PROJECT 99 pass, TRAK renders
cornell_box in 37s and exits 0, every module compiles, and every import ruff
removed was checked to be genuinely unused.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0172dj34FDpao6wsix8ZuCzE
2026-08-28 19:53:04 +02:00

156 lines
4.9 KiB
Python

import argparse
import importlib
import os
import matplotlib.pyplot as plt
from photon_mapping import render_photon_mapping
from rendering import ray_trace
from utils import load_config, parse_resolution
def main():
# default config
config = load_config("config.ini")
# Parse
parser = argparse.ArgumentParser(description="Rendering Program")
parser.add_argument(
"--algorithm",
type=str,
help="Algorithm to use",
default=config.get("DEFAULT", "algorithm"),
)
parser.add_argument(
"--scene",
type=str,
help="Name of the scene to render (without .py).",
default=config.get("DEFAULT", "scene"),
)
parser.add_argument(
"--environment",
type=str,
help="Environment file",
default=config.get("DEFAULT", "environment"),
)
parser.add_argument(
"--env_blur",
type=str,
help="Environment blur",
default=config.get("DEFAULT", "env_blur"),
)
parser.add_argument(
"--resolution",
type=str,
help="Image resolution (WIDTHxHEIGHT)",
default=config.get("DEFAULT", "resolution"),
)
parser.add_argument(
"--samples_per_pixel",
type=int,
default=config.get("ray_tracing", "samples_per_pixel"),
help="Samples per pixel for rendering.",
)
parser.add_argument(
"--output",
type=str,
default=config.get("DEFAULT", "output"),
help="Output file name.",
)
parser.add_argument(
"--num_spheres",
type=int,
default=3,
help="Number of spheres in the scene for Ray Tracing 0",
)
parser.add_argument(
"--num_photons",
type=int,
default=config.getint("photon_mapping", "num_photons"),
help="Number of photons for photon mapping",
)
parser.add_argument(
"--max_depth",
type=int,
default=config.getint("photon_mapping", "max_depth"),
help="Maximum depth for photon tracing",
)
parser.add_argument(
"--gather_radius",
type=float,
default=config.getfloat("photon_mapping", "gather_radius"),
help="Radius for radiance estimation in photon mapping",
)
# The render is always written to outputs/; this only controls whether a
# viewer is ALSO popped up. It defaults off because img.show() shells out
# to xdg-open and then blocks until a human closes the window -- which
# left ../../run.sh run Programming/TRAK hanging for 45 minutes after the
# ray trace had actually finished.
parser.add_argument(
"--show",
action="store_true",
help="also open the finished image in a viewer (blocks until closed)",
)
args = parser.parse_args()
width, height = parse_resolution(args.resolution)
# Run the selected algorithm
if args.algorithm == "ray_tracing0":
print("Starting ray tracing zero...")
# ray_trace(args.scene, args.environment_map, image_width=width, image_height=height, output_file="output_ray_traced.png")
ray_trace(
args.num_spheres,
args.environment_map,
image_width=width,
image_height=height, # na razie generujemy w kodzie, ale potem trzeba będzie obj wczytywać
output_file="output_ray_traced.png",
)
elif args.algorithm == "ray_tracing":
print("Starting ray tracing...")
try:
print(args.scene)
scene_module = importlib.import_module(f"scenes.{args.scene}")
except ModuleNotFoundError:
print(f"Error: Scene '{args.scene}' not found in the 'scenes' directory.")
return
try:
scene = scene_module.setup_scene(
width=width, height=height, environment=f"{args.environment}"
)
except AttributeError:
print(
f"Error: Scene '{args.scene}' does not define a `setup_scene` function."
)
return
# Renderowanie
print(
f"Rendering scene '{args.scene}' with {args.samples_per_pixel} samples per pixel..."
)
img = scene.render(samples_per_pixel=args.samples_per_pixel)
output_path = os.path.join("outputs", args.output)
img.save(output_path)
print(f"Image saved to {output_path}")
if args.show:
img.show()
elif args.algorithm == "photon_mapping":
print("Starting photon mapping...")
image = render_photon_mapping(
width, height, args.num_photons, args.max_depth, args.gather_radius
)
plt.imshow(image)
plt.axis("off")
output_path = os.path.join("outputs", args.output)
plt.savefig(output_path)
print(f"Image saved to {output_path}")
if args.show:
plt.show()
else:
print(f"Unknown algorithm: {args.algorithm}")
return
if __name__ == "__main__":
main()