# SPDX-FileCopyrightText: 2021-2026 Julien Rippinger, Ian Bertin <alicelab.be>
#
# SPDX-License-Identifier: GPL-3.0-or-later
"""Contains all usefull functions for the add-on."""
from math import degrees, radians
from types import SimpleNamespace
from typing import Literal
import bpy
from .data import CAMERA_SETTINGS
from .geometry_math import (
calculate_axonometric_altitude,
calculate_axonometric_rotation,
calculate_oblique_attributes,
compute_scales,
normalize_factors,
)
[docs]
def camera_attributes_updated(
props: bpy.types.PropertyGroup | bpy.types.Operator,
updated_angle: str,
) -> None:
"""Calculate the new camera parameters when an angle (alpha or beta) changes.
Parameters
----------
props : Union[bpy.types.PropertyGroup, bpy.types.Operator]
The Blender object containing the camera projection parameters
updated_angle : str
The changed angle ("beta" or "alpha")
"""
if props.projection_type == "OBLIQUE":
if updated_angle == "beta":
props.alpha = calculate_oblique_attributes(props.beta)
else:
props.beta = calculate_oblique_attributes(props.alpha)
props.altitude_oblique = props.alpha
props.rotation = props.beta
camera_type = CAMERA_SETTINGS.get_preset_name(
props.projection_type,
props.alpha,
props.beta,
props.z_value,
)
props.oblique_type = camera_type
else:
if props.alpha == props.beta == 0:
if updated_angle == "alpha":
props.beta = radians(1)
if updated_angle == "beta":
props.alpha = radians(1)
elif props.alpha + props.beta >= radians(90):
if updated_angle == "alpha":
props.beta = radians(89) - props.alpha
if updated_angle == "beta":
props.alpha = radians(89) - props.beta
props.altitude = calculate_axonometric_altitude(props.beta, props.alpha)
props.rotation = calculate_axonometric_rotation(props.beta, props.alpha)
y, z, x = compute_scales(props.beta, props.alpha)
props.x_value, props.y_value, props.z_value = x, y, z
props.normalized_x_value, props.normalized_y_value, props.normalized_z_value = (
normalize_factors(x, y, z)
)
camera_type = CAMERA_SETTINGS.get_preset_name(
props.projection_type,
props.alpha,
props.beta,
0,
)
props.axonometric_type = camera_type
[docs]
def camera_type_updated(
props: bpy.types.PropertyGroup | bpy.types.Operator,
) -> None:
"""Calculate the new camera parameters when the camera type changes.
Parameters
----------
props : Union[bpy.types.PropertyGroup, bpy.types.Operator]
The Blender object containing the camera projection parameters
"""
if (props.projection_type == "AXONOMETRIC" and props.axonometric_type != "CUSTOM") or (
props.projection_type == "OBLIQUE" and props.oblique_type != "CUSTOM"
):
settings = CAMERA_SETTINGS.get_preset_menu_items(props.projection_type)
cameraType = "AXONOMETRIC_#1"
if props.projection_type == "AXONOMETRIC":
if props.oblique_type == "CUSTOM":
props.oblique_type = "OBLIQUE_#1"
cameraType = (
settings[props.axonometric_type]
if props.axonometric_type != "CUSTOM"
else settings["AXONOMETRIC_#1"]
)
props.alpha = cameraType["alpha"]
props.beta = cameraType["beta"]
props.altitude = calculate_axonometric_altitude(props.beta, props.alpha)
props.rotation = calculate_axonometric_rotation(props.beta, props.alpha)
y, z, x = compute_scales(cameraType["beta"], cameraType["alpha"])
props.x_value, props.y_value, props.z_value = x, y, z
(
props.normalized_x_value,
props.normalized_y_value,
props.normalized_z_value,
) = normalize_factors(x, y, z)
else:
if props.axonometric_type == "CUSTOM":
props.axonometric_type = "AXONOMETRIC_#1"
cameraType = (
settings[props.oblique_type]
if props.oblique_type != "CUSTOM"
else settings["OBLIQUE_#1"]
)
props.alpha = cameraType["alpha"]
props.beta = cameraType["beta"]
props.altitude_oblique = props.alpha
props.rotation = props.beta
props.x_value = 1
props.y_value = 1
props.z_value = cameraType["shortening"]
[docs]
class GraphicalScale:
"""Static class to produce the graphical scale figure.
It is common to display a graphical scale on drawings in order to
display the properties of the chosen axonometric or oblique projection.
"""
_props: SimpleNamespace = SimpleNamespace()
@classmethod
[docs]
def populate_props(
cls,
alpha: float,
beta: float,
shortening: float | None = None,
) -> None:
"""Populate internal attributes with the necessary info for the figure.
Parameters
----------
alpha : float
Angle in radians.
beta : float
Angle in radians.
shortening : {None, float}, optional
Oblique scale factor for z.
"""
cls._props.alpha = alpha
cls._props.beta = beta
cls._props.projection_type = "OBLIQUE" if shortening else "AXONOMETRIC"
if cls._props.projection_type == "OBLIQUE":
cls._props.x_value = 1
cls._props.y_value = 1
cls._props.z_value = shortening
elif cls._props.projection_type == "AXONOMETRIC":
cls._props.x_value, cls._props.z_value, cls._props.y_value = compute_scales(
alpha,
beta,
)
(
cls._props.normalized_x_value,
cls._props.normalized_z_value,
cls._props.normalized_y_value,
) = normalize_factors(
cls._props.x_value,
cls._props.z_value,
cls._props.y_value,
)
@classmethod