# Angle.java

    package io.github.js0ny.ilp_coursework.data.common;

    /**
     * Represents the data transfer object for angle
     *
     * @param val value of the angle in degrees
     */
    public record Angle(double degrees) {
        private static final double STEP = 22.5;
        private static final double EPSILON = 1e-10;

        public Angle {
            if (degrees < 0 || degrees >= 360) {
                throw new IllegalArgumentException("Angle must be in range [0, 360). Got: " + degrees);
            }

            // Should be a multiple of 22.5 (one of the 16 major directions)
            double remainder = degrees % STEP;

            // Floating point modulo may have tiny errors, e.g. 45.0 % 22.5 could be 0.0 or
            // 1.0e-15
            // So we need to check if the remainder is small enough, or close enough to STEP
            // (handling negative errors)
            if (Math.abs(remainder) > EPSILON && Math.abs(remainder - STEP) > EPSILON) {
                throw new IllegalArgumentException(
                        "Angle must be a multiple of 22.5 (one of the 16 major directions). Got: "
                                + degrees);
            }
        }

        public static Angle fromIndex(int index) {
            if (index < 0 || index > 15) {
                throw new IllegalArgumentException("Direction index must be between 0 and 15");
            }
            return new Angle(index * STEP);
        }

        public static Angle snap(double rawAngle) {
            double normalized = normalize(rawAngle);
            double snapped = Math.round(normalized / STEP) * STEP;
            return new Angle(normalize(snapped));
        }

        public Angle offset(int increments) {
            double rotated = degrees + increments * STEP;
            return new Angle(normalize(rotated));
        }

        private static double normalize(double angle) {
            double normalized = angle % 360;
            if (normalized < 0) {
                normalized += 360;
            }
            return normalized;
        }

        public static double toRadians(double degrees) {
            return Math.toRadians(degrees);
        }

        public double toRadians() {
            return Math.toRadians(degrees);
        }
    }