0.1.8
Loading...
Searching...
No Matches
datatypes.py
Go to the documentation of this file.
1"""
2Validation for PyHelios DataTypes (vec2, vec3, vec4, colors, etc.)
3
4Provides comprehensive validation for all geometric data types,
5ensuring finite values and appropriate ranges before C++ operations.
6"""
7
8from typing import Any
9from .core import is_finite_numeric
10from .exceptions import ValidationError, create_validation_error
11
12
13def validate_color_component(value: float, component_name: str, param_name: str, function_name: str = None):
14 """Validate a color component is in valid range [0,1]."""
15 if not is_finite_numeric(value):
16 raise create_validation_error(
17 f"Color component {component_name} must be a finite number, got {value} ({type(value).__name__})",
18 param_name=f"{param_name}.{component_name}",
19 function_name=function_name,
20 expected_type="finite number in range [0,1]",
21 actual_value=value,
22 suggestion="Color components must be normalized values between 0 and 1."
23 )
24
25 if not (0.0 <= value <= 1.0):
26 raise create_validation_error(
27 f"Color component {component_name}={value} is outside valid range [0,1]",
28 param_name=f"{param_name}.{component_name}",
29 function_name=function_name,
30 expected_type="number in range [0,1]",
31 actual_value=value,
32 suggestion="Color components must be normalized values between 0 and 1."
33 )
34
35
36def validate_rgb_color(color: Any, param_name: str = "color", function_name: str = None):
37 """
38 Validate RGBcolor has finite values in [0,1] range.
39
40 Args:
41 color: RGBcolor object to validate
42 param_name: Parameter name for error messages
43 function_name: Function name for error messages
44
45 Raises:
46 ValidationError: If color is invalid or components out of range
47 """
48 if color is None:
49 return
50
51 # Check if it has the expected attributes
52 if not hasattr(color, 'r') or not hasattr(color, 'g') or not hasattr(color, 'b'):
53 raise create_validation_error(
54 f"Parameter must be an RGBcolor object with .r, .g, .b attributes",
55 param_name=param_name,
56 function_name=function_name,
57 expected_type="RGBcolor",
58 actual_value=color,
59 suggestion="Use RGBcolor(r, g, b) where r, g, b are values between 0 and 1."
60 )
61
62 validate_color_component(color.r, 'r', param_name, function_name)
63 validate_color_component(color.g, 'g', param_name, function_name)
64 validate_color_component(color.b, 'b', param_name, function_name)
65
66
67def validate_rgba_color(color: Any, param_name: str = "color", function_name: str = None):
68 """
69 Validate RGBAcolor has finite values in [0,1] range.
70
71 Args:
72 color: RGBAcolor object to validate
73 param_name: Parameter name for error messages
74 function_name: Function name for error messages
75
76 Raises:
77 ValidationError: If color is invalid or components out of range
78 """
79 if color is None:
80 return
81
82 # Check if it has the expected attributes
83 if not hasattr(color, 'r') or not hasattr(color, 'g') or not hasattr(color, 'b') or not hasattr(color, 'a'):
84 raise create_validation_error(
85 f"Parameter must be an RGBAcolor object with .r, .g, .b, .a attributes",
86 param_name=param_name,
87 function_name=function_name,
88 expected_type="RGBAcolor",
89 actual_value=color,
90 suggestion="Use RGBAcolor(r, g, b, a) where all values are between 0 and 1."
91 )
92
93 validate_color_component(color.r, 'r', param_name, function_name)
94 validate_color_component(color.g, 'g', param_name, function_name)
95 validate_color_component(color.b, 'b', param_name, function_name)
96 validate_color_component(color.a, 'a', param_name, function_name)
97
98
99def validate_vector_finite(vector: Any, param_name: str = "vector", expected_dims: int = 3, function_name: str = None):
100 """
101 Validate vector has finite components.
102
103 Args:
104 vector: Vector object to validate (vec2, vec3, vec4, etc.)
105 param_name: Parameter name for error messages
106 expected_dims: Expected number of dimensions
107 function_name: Function name for error messages
108
109 Raises:
110 ValidationError: If vector is invalid or has non-finite components
111 """
112 if vector is None:
113 return
114
115 # Get the expected attribute names based on dimensions
116 attrs = ['x', 'y', 'z', 'w'][:expected_dims]
117
118 # Check if it has the expected attributes
119 for attr in attrs:
120 if not hasattr(vector, attr):
121 raise create_validation_error(
122 f"Parameter must be a vector with {'.'.join(attrs)} attributes",
123 param_name=param_name,
124 function_name=function_name,
125 expected_type=f"vec{expected_dims}",
126 actual_value=vector,
127 suggestion=f"Use vec{expected_dims}() constructor or provide object with {'.'.join(attrs)} attributes."
128 )
129
130 value = getattr(vector, attr)
131 if not is_finite_numeric(value):
132 raise create_validation_error(
133 f"Vector component {attr} must be a finite number, got {value} ({type(value).__name__})",
134 param_name=f"{param_name}.{attr}",
135 function_name=function_name,
136 expected_type="finite number",
137 actual_value=value,
138 suggestion="Ensure all vector components are finite numbers (not NaN or infinity)."
139 )
140
141
142def validate_vec2(vector: Any, param_name: str = "vector", function_name: str = None):
143 """
144 Validate vec2 has finite x,y components.
145
146 Args:
147 vector: vec2 object to validate
148 param_name: Parameter name for error messages
149 function_name: Function name for error messages
150
151 Returns:
152 The validated vec2 object
153 """
154 validate_vector_finite(vector, param_name, expected_dims=2, function_name=function_name)
155 return vector
156
157
158def validate_vec3(vector: Any, param_name: str = "vector", function_name: str = None):
159 """
160 Validate vec3 has finite x,y,z components.
161
162 Args:
163 vector: vec3 object to validate
164 param_name: Parameter name for error messages
165 function_name: Function name for error messages
166
167 Returns:
168 The validated vec3 object
169 """
170 validate_vector_finite(vector, param_name, expected_dims=3, function_name=function_name)
171 return vector
172
173
174def validate_vec4(vector: Any, param_name: str = "vector", function_name: str = None):
175 """
176 Validate vec4 has finite x,y,z,w components.
177
178 Args:
179 vector: vec4 object to validate
180 param_name: Parameter name for error messages
181 function_name: Function name for error messages
182 """
183 validate_vector_finite(vector, param_name, expected_dims=4, function_name=function_name)
184
185
186def validate_spherical_coord(coord: Any, param_name: str = "coordinate", function_name: str = None):
187 """
188 Validate SphericalCoord has valid values.
189
190 Args:
191 coord: SphericalCoord object to validate
192 param_name: Parameter name for error messages
193 function_name: Function name for error messages
194
195 Raises:
196 ValidationError: If coordinate has invalid values
197 """
198 if coord is None:
199 return
200
201 if not hasattr(coord, 'radius') or not hasattr(coord, 'elevation') or not hasattr(coord, 'azimuth'):
202 raise create_validation_error(
203 f"Parameter must be a SphericalCoord with .radius, .elevation, .azimuth attributes",
204 param_name=param_name,
205 function_name=function_name,
206 expected_type="SphericalCoord",
207 actual_value=coord,
208 suggestion="Use SphericalCoord(radius, elevation, azimuth) constructor."
209 )
210
211 # Validate radius is positive
212 if not is_finite_numeric(coord.radius) or coord.radius <= 0:
213 raise create_validation_error(
214 f"SphericalCoord radius must be a positive finite number, got {coord.radius}",
215 param_name=f"{param_name}.radius",
216 function_name=function_name,
217 expected_type="positive finite number",
218 actual_value=coord.radius,
219 suggestion="Radius must be greater than 0."
220 )
221
222 # Elevation and azimuth can be any finite values (angles wrap around)
223 if not is_finite_numeric(coord.elevation):
224 raise create_validation_error(
225 f"SphericalCoord elevation must be a finite number, got {coord.elevation} ({type(coord.elevation).__name__})",
226 param_name=f"{param_name}.elevation",
227 function_name=function_name,
228 expected_type="finite number",
229 actual_value=coord.elevation,
230 suggestion="Elevation angle must be a finite number (not NaN or infinity)."
231 )
232
233 if not is_finite_numeric(coord.azimuth):
234 raise create_validation_error(
235 f"SphericalCoord azimuth must be a finite number, got {coord.azimuth} ({type(coord.azimuth).__name__})",
236 param_name=f"{param_name}.azimuth",
237 function_name=function_name,
238 expected_type="finite number",
239 actual_value=coord.azimuth,
240 suggestion="Azimuth angle must be a finite number (not NaN or infinity)."
241 )
242
243
244def validate_integer_vector(vector: Any, param_name: str = "vector", expected_dims: int = 3, function_name: str = None):
245 """
246 Validate integer vector (int2, int3, int4) has valid integer components.
247
248 Args:
249 vector: Integer vector object to validate
250 param_name: Parameter name for error messages
251 expected_dims: Expected number of dimensions
252 function_name: Function name for error messages
253
254 Raises:
255 ValidationError: If vector has invalid or non-integer components
256 """
257 if vector is None:
258 return
259
260 # Get the expected attribute names based on dimensions
261 attrs = ['x', 'y', 'z', 'w'][:expected_dims]
262
263 # Check if it has the expected attributes
264 for attr in attrs:
265 if not hasattr(vector, attr):
266 raise create_validation_error(
267 f"Parameter must be an integer vector with {'.'.join(attrs)} attributes",
268 param_name=param_name,
269 function_name=function_name,
270 expected_type=f"int{expected_dims}",
271 actual_value=vector,
272 suggestion=f"Use int{expected_dims}() constructor or provide object with {'.'.join(attrs)} attributes."
273 )
274
275 value = getattr(vector, attr)
276 if not isinstance(value, int):
277 raise create_validation_error(
278 f"Integer vector component {attr} must be an integer, got {value} ({type(value).__name__})",
279 param_name=f"{param_name}.{attr}",
280 function_name=function_name,
281 expected_type="integer",
282 actual_value=value,
283 suggestion="Ensure all vector components are integers."
284 )
285
286
287def validate_int2(vector: Any, param_name: str = "vector", function_name: str = None):
288 """
289 Validate int2 has valid integer x,y components.
290
291 Args:
292 vector: int2 object to validate
293 param_name: Parameter name for error messages
294 function_name: Function name for error messages
295
296 Returns:
297 The validated vector
298 """
299 validate_integer_vector(vector, param_name, expected_dims=2, function_name=function_name)
300 return vector
301
302
303def validate_int3(vector: Any, param_name: str = "vector", function_name: str = None):
304 """
305 Validate int3 has valid integer x,y,z components.
306
307 Args:
308 vector: int3 object to validate
309 param_name: Parameter name for error messages
310 function_name: Function name for error messages
311 """
312 validate_integer_vector(vector, param_name, expected_dims=3, function_name=function_name)
313
314
315def validate_int4(vector: Any, param_name: str = "vector", function_name: str = None):
316 """
317 Validate int4 has valid integer x,y,z,w components.
318
319 Args:
320 vector: int4 object to validate
321 param_name: Parameter name for error messages
322 function_name: Function name for error messages
323 """
324 validate_integer_vector(vector, param_name, expected_dims=4, function_name=function_name)
validate_vector_finite(Any vector, str param_name="vector", int expected_dims=3, str function_name=None)
Validate vector has finite components.
Definition datatypes.py:111
validate_integer_vector(Any vector, str param_name="vector", int expected_dims=3, str function_name=None)
Validate integer vector (int2, int3, int4) has valid integer components.
Definition datatypes.py:256
validate_vec4(Any vector, str param_name="vector", str function_name=None)
Validate vec4 has finite x,y,z,w components.
Definition datatypes.py:182
validate_vec3(Any vector, str param_name="vector", str function_name=None)
Validate vec3 has finite x,y,z components.
Definition datatypes.py:169
validate_int4(Any vector, str param_name="vector", str function_name=None)
Validate int4 has valid integer x,y,z,w components.
Definition datatypes.py:323
validate_int3(Any vector, str param_name="vector", str function_name=None)
Validate int3 has valid integer x,y,z components.
Definition datatypes.py:311
validate_rgba_color(Any color, str param_name="color", str function_name=None)
Validate RGBAcolor has finite values in [0,1] range.
Definition datatypes.py:78
validate_int2(Any vector, str param_name="vector", str function_name=None)
Validate int2 has valid integer x,y components.
Definition datatypes.py:298
validate_vec2(Any vector, str param_name="vector", str function_name=None)
Validate vec2 has finite x,y components.
Definition datatypes.py:153
validate_rgb_color(Any color, str param_name="color", str function_name=None)
Validate RGBcolor has finite values in [0,1] range.
Definition datatypes.py:47
validate_spherical_coord(Any coord, str param_name="coordinate", str function_name=None)
Validate SphericalCoord has valid values.
Definition datatypes.py:197
validate_color_component(float value, str component_name, str param_name, str function_name=None)
Validate a color component is in valid range [0,1].
Definition datatypes.py:14