0.1.8
Loading...
Searching...
No Matches
DataTypes.py
Go to the documentation of this file.
1import ctypes
2import math
3from typing import Any, List
4from enum import IntEnum
5
6
7class PrimitiveType(IntEnum):
8 """Helios primitive type enumeration."""
9 Patch = 0
10 Triangle = 1
11 Disk = 2
12 Tile = 3
13 Sphere = 4
14 Tube = 5
15 Box = 6
16 Cone = 7
17 Polymesh = 8
18
19class int2(ctypes.Structure):
20 _fields_ = [('x', ctypes.c_int32), ('y', ctypes.c_int32)]
21
22 def __repr__(self) -> str:
23 return f'int2({self.x}, {self.y})'
24
25 def __str__(self) -> str:
26 return f'int2({self.x}, {self.y})'
27
28 def __init__(self, x:int=0, y:int=0):
29 # Validate integer inputs
30 if not isinstance(x, int):
31 raise ValueError(f"int2.x must be an integer, got {type(x).__name__}: {x}")
32 if not isinstance(y, int):
33 raise ValueError(f"int2.y must be an integer, got {type(y).__name__}: {y}")
34
35 self.x = x
36 self.y = y
37
38 def from_list(self, input_list:List[int]):
39 self.x = input_list[0]
40 self.y = input_list[1]
42 def to_list(self) -> List[int]:
43 return [self.x, self.y]
44
46
47class int3(ctypes.Structure):
48 _fields_ = [('x', ctypes.c_int32), ('y', ctypes.c_int32), ('z', ctypes.c_int32)]
49
50 def __repr__(self) -> str:
51 return f'int3({self.x}, {self.y}, {self.z})'
52
53 def __str__(self) -> str:
54 return f'int3({self.x}, {self.y}, {self.z})'
55
56 def __init__(self, x:int=0, y:int=0, z:int=0):
57 # Validate integer inputs
58 if not isinstance(x, int):
59 raise ValueError(f"int3.x must be an integer, got {type(x).__name__}: {x}")
60 if not isinstance(y, int):
61 raise ValueError(f"int3.y must be an integer, got {type(y).__name__}: {y}")
62 if not isinstance(z, int):
63 raise ValueError(f"int3.z must be an integer, got {type(z).__name__}: {z}")
64
65 self.x = x
66 self.y = y
67 self.z = z
68
69 def from_list(self, input_list:List[int]):
70 self.x = input_list[0]
71 self.y = input_list[1]
72 self.z = input_list[2]
74 def to_list(self) -> List[int]:
75 return [self.x, self.y, self.z]
76
77
78
79class int4(ctypes.Structure):
80 _fields_ = [('x', ctypes.c_int32), ('y', ctypes.c_int32), ('z', ctypes.c_int32), ('w', ctypes.c_int32)]
81
82 def __repr__(self) -> str:
83 return f'int4({self.x}, {self.y}, {self.z}, {self.w})'
84
85 def __str__(self) -> str:
86 return f'int4({self.x}, {self.y}, {self.z}, {self.w})'
87
88 def __init__(self, x:int=0, y:int=0, z:int=0, w:int=0):
89 # Validate integer inputs
90 if not isinstance(x, int):
91 raise ValueError(f"int4.x must be an integer, got {type(x).__name__}: {x}")
92 if not isinstance(y, int):
93 raise ValueError(f"int4.y must be an integer, got {type(y).__name__}: {y}")
94 if not isinstance(z, int):
95 raise ValueError(f"int4.z must be an integer, got {type(z).__name__}: {z}")
96 if not isinstance(w, int):
97 raise ValueError(f"int4.w must be an integer, got {type(w).__name__}: {w}")
98
99 self.x = x
100 self.y = y
101 self.z = z
102 self.w = w
103
104 def from_list(self, input_list:List[int]):
105 self.x = input_list[0]
106 self.y = input_list[1]
107 self.z = input_list[2]
108 self.w = input_list[3]
110 def to_list(self) -> List[int]:
111 return [self.x, self.y, self.z, self.w]
112
114
115class vec2(ctypes.Structure):
116 _fields_ = [('x', ctypes.c_float), ('y', ctypes.c_float)]
117
118 def __repr__(self) -> str:
119 return f'vec2({self.x}, {self.y})'
120
121 def __str__(self) -> str:
122 return f'vec2({self.x}, {self.y})'
123
124 def __init__(self, x:float=0, y:float=0):
125 # Validate finite numeric inputs
126 if not self._is_finite_numeric(x):
127 raise ValueError(f"vec2.x must be a finite number, got {type(x).__name__}: {x}. "
128 f"Vector components must be finite (not NaN or infinity).")
129 if not self._is_finite_numeric(y):
130 raise ValueError(f"vec2.y must be a finite number, got {type(y).__name__}: {y}. "
131 f"Vector components must be finite (not NaN or infinity).")
132
133 self.x = float(x)
134 self.y = float(y)
135
136 def from_list(self, input_list:List[float]):
137 self.x = input_list[0]
138 self.y = input_list[1]
139
140 def to_list(self) -> List[float]:
141 return [self.x, self.y]
142
143 @staticmethod
144 def _is_finite_numeric(value) -> bool:
145 """Check if value is a finite number (not NaN or inf)."""
146 try:
147 float_value = float(value)
148 return math.isfinite(float_value)
149 except (ValueError, TypeError, OverflowError):
150 return False
151
152class vec3(ctypes.Structure):
153 _fields_ = [('x', ctypes.c_float), ('y', ctypes.c_float), ('z', ctypes.c_float)]
154
155 def __repr__(self) -> str:
156 return f'vec3({self.x}, {self.y}, {self.z})'
157
158 def __str__(self) -> str:
159 return f'vec3({self.x}, {self.y}, {self.z})'
160
161 def __init__(self, x:float=0, y:float=0, z:float=0):
162 # Validate finite numeric inputs
163 if not self._is_finite_numeric(x):
164 raise ValueError(f"vec3.x must be a finite number, got {type(x).__name__}: {x}. "
165 f"Vector components must be finite (not NaN or infinity).")
166 if not self._is_finite_numeric(y):
167 raise ValueError(f"vec3.y must be a finite number, got {type(y).__name__}: {y}. "
168 f"Vector components must be finite (not NaN or infinity).")
169 if not self._is_finite_numeric(z):
170 raise ValueError(f"vec3.z must be a finite number, got {type(z).__name__}: {z}. "
171 f"Vector components must be finite (not NaN or infinity).")
173 self.x = float(x)
174 self.y = float(y)
175 self.z = float(z)
176
177 def from_list(self, input_list:List[float]):
178 self.x = input_list[0]
179 self.y = input_list[1]
180 self.z = input_list[2]
181
182 def to_list(self) -> List[float]:
183 return [self.x, self.y, self.z]
184
185 def to_tuple(self) -> tuple:
186 return (self.x, self.y, self.z)
187
188 @staticmethod
189 def _is_finite_numeric(value) -> bool:
190 """Check if value is a finite number (not NaN or inf)."""
191 try:
192 float_value = float(value)
193 return math.isfinite(float_value)
194 except (ValueError, TypeError, OverflowError):
195 return False
196
197
198class vec4(ctypes.Structure):
199 _fields_ = [('x', ctypes.c_float), ('y', ctypes.c_float), ('z', ctypes.c_float), ('w', ctypes.c_float)]
200
201 def __repr__(self) -> str:
202 return f'vec4({self.x}, {self.y}, {self.z}, {self.w})'
203
204 def __str__(self) -> str:
205 return f'vec4({self.x}, {self.y}, {self.z}, {self.w})'
206
207 def __init__(self, x:float=0, y:float=0, z:float=0, w:float=0):
208 # Validate finite numeric inputs
209 if not self._is_finite_numeric(x):
210 raise ValueError(f"vec4.x must be a finite number, got {type(x).__name__}: {x}. "
211 f"Vector components must be finite (not NaN or infinity).")
212 if not self._is_finite_numeric(y):
213 raise ValueError(f"vec4.y must be a finite number, got {type(y).__name__}: {y}. "
214 f"Vector components must be finite (not NaN or infinity).")
215 if not self._is_finite_numeric(z):
216 raise ValueError(f"vec4.z must be a finite number, got {type(z).__name__}: {z}. "
217 f"Vector components must be finite (not NaN or infinity).")
218 if not self._is_finite_numeric(w):
219 raise ValueError(f"vec4.w must be a finite number, got {type(w).__name__}: {w}. "
220 f"Vector components must be finite (not NaN or infinity).")
222 self.x = float(x)
223 self.y = float(y)
224 self.z = float(z)
225 self.w = float(w)
227 def from_list(self, input_list:List[float]):
228 self.x = input_list[0]
229 self.y = input_list[1]
230 self.z = input_list[2]
231 self.w = input_list[3]
232
233 def to_list(self) -> List[float]:
234 return [self.x, self.y, self.z, self.w]
235
236 @staticmethod
237 def _is_finite_numeric(value) -> bool:
238 """Check if value is a finite number (not NaN or inf)."""
239 try:
240 float_value = float(value)
241 return math.isfinite(float_value)
242 except (ValueError, TypeError, OverflowError):
243 return False
247class RGBcolor(ctypes.Structure):
248 _fields_ = [('r', ctypes.c_float), ('g', ctypes.c_float), ('b', ctypes.c_float)]
250 def __repr__(self) -> str:
251 return f'RGBcolor({self.r}, {self.g}, {self.b})'
252
253 def __str__(self) -> str:
254 return f'RGBcolor({self.r}, {self.g}, {self.b})'
256 def __init__(self, r:float=0, g:float=0, b:float=0):
257 # Validate color components are finite and in range [0,1]
258 self._validate_color_component(r, 'r')
259 self._validate_color_component(g, 'g')
260 self._validate_color_component(b, 'b')
261
262 self.r = float(r)
263 self.g = float(g)
264 self.b = float(b)
265
266 def from_list(self, input_list:List[float]):
267 self.r = input_list[0]
268 self.g = input_list[1]
269 self.b = input_list[2]
270
271 def to_list(self) -> List[float]:
272 return [self.r, self.g, self.b]
273
274 @staticmethod
275 def _is_finite_numeric(value) -> bool:
276 """Check if value is a finite number (not NaN or inf)."""
277 try:
278 float_value = float(value)
279 return math.isfinite(float_value)
280 except (ValueError, TypeError, OverflowError):
281 return False
282
283 def _validate_color_component(self, value, component_name):
284 """Validate a color component is finite and in range [0,1]."""
285 if not self._is_finite_numeric(value):
286 raise ValueError(f"RGBcolor.{component_name} must be a finite number, "
287 f"got {type(value).__name__}: {value}. "
288 f"Color components must be finite values between 0 and 1.")
290 if not (0.0 <= value <= 1.0):
291 raise ValueError(f"RGBcolor.{component_name}={value} is outside valid range [0,1]. "
292 f"Color components must be normalized values between 0 and 1.")
294
295
296
297class RGBAcolor(ctypes.Structure):
298 _fields_ = [('r', ctypes.c_float), ('g', ctypes.c_float), ('b', ctypes.c_float), ('a', ctypes.c_float)]
299
300 def __repr__(self) -> str:
301 return f'RGBAcolor({self.r}, {self.g}, {self.b}, {self.a})'
302
303 def __str__(self) -> str:
304 return f'RGBAcolor({self.r}, {self.g}, {self.b}, {self.a})'
306 def __init__(self, r:float=0, g:float=0, b:float=0, a:float=0):
307 # Validate color components are finite and in range [0,1]
308 self._validate_color_component(r, 'r')
309 self._validate_color_component(g, 'g')
310 self._validate_color_component(b, 'b')
311 self._validate_color_component(a, 'a')
312
313 self.r = float(r)
314 self.g = float(g)
315 self.b = float(b)
316 self.a = float(a)
317
318 def from_list(self, input_list:List[float]):
319 self.r = input_list[0]
320 self.g = input_list[1]
321 self.b = input_list[2]
322 self.a = input_list[3]
323
324 def to_list(self) -> List[float]:
325 return [self.r, self.g, self.b, self.a]
326
327 @staticmethod
328 def _is_finite_numeric(value) -> bool:
329 """Check if value is a finite number (not NaN or inf)."""
330 try:
331 float_value = float(value)
332 return math.isfinite(float_value)
333 except (ValueError, TypeError, OverflowError):
334 return False
335
336 def _validate_color_component(self, value, component_name):
337 """Validate a color component is finite and in range [0,1]."""
338 if not self._is_finite_numeric(value):
339 raise ValueError(f"RGBAcolor.{component_name} must be a finite number, "
340 f"got {type(value).__name__}: {value}. "
341 f"Color components must be finite values between 0 and 1.")
342
343 if not (0.0 <= value <= 1.0):
344 raise ValueError(f"RGBAcolor.{component_name}={value} is outside valid range [0,1]. "
345 f"Color components must be normalized values between 0 and 1.")
346
349class SphericalCoord(ctypes.Structure):
350 _fields_ = [
351 ('radius', ctypes.c_float),
352 ('elevation', ctypes.c_float),
353 ('zenith', ctypes.c_float),
354 ('azimuth', ctypes.c_float)
355 ]
356
357 def __repr__(self) -> str:
358 return f'SphericalCoord({self.radius}, {self.elevation}, {self.zenith}, {self.azimuth})'
359
360 def __str__(self) -> str:
361 return f'SphericalCoord({self.radius}, {self.elevation}, {self.zenith}, {self.azimuth})'
362
363 def __init__(self, radius:float=1, elevation:float=0, azimuth:float=0):
364 """
365 Initialize SphericalCoord matching C++ constructor.
366
367 Args:
368 radius: Radius (default: 1)
369 elevation: Elevation angle in radians (default: 0)
370 azimuth: Azimuthal angle in radians (default: 0)
371
372 Note: zenith is automatically computed as (Ï€/2 - elevation) to match C++ behavior
373 """
374 # Validate inputs
375 if not self._is_finite_numeric(radius) or radius <= 0:
376 raise ValueError(f"SphericalCoord.radius must be a positive finite number, "
377 f"got {type(radius).__name__}: {radius}. "
378 f"Radius must be greater than 0.")
379
380 if not self._is_finite_numeric(elevation):
381 raise ValueError(f"SphericalCoord.elevation must be a finite number, "
382 f"got {type(elevation).__name__}: {elevation}. "
383 f"Elevation angle must be finite (not NaN or infinity).")
384
385 if not self._is_finite_numeric(azimuth):
386 raise ValueError(f"SphericalCoord.azimuth must be a finite number, "
387 f"got {type(azimuth).__name__}: {azimuth}. "
388 f"Azimuth angle must be finite (not NaN or infinity).")
389
390 self.radius = float(radius)
391 self.elevation = float(elevation)
392 self.zenith = 0.5 * math.pi - elevation # zenith = π/2 - elevation (matches C++)
393 self.azimuth = float(azimuth)
394
395 def from_list(self, input_list:List[float]):
396 self.radius = input_list[0]
397 self.elevation = input_list[1]
398 self.zenith = input_list[2]
399 self.azimuth = input_list[3]
400
401 def to_list(self) -> List[float]:
402 return [self.radius, self.elevation, self.zenith, self.azimuth]
403
404 @staticmethod
405 def _is_finite_numeric(value) -> bool:
406 """Check if value is a finite number (not NaN or inf)."""
407 try:
408 float_value = float(value)
409 return math.isfinite(float_value)
410 except (ValueError, TypeError, OverflowError):
411 return False
412
413
415class AxisRotation(ctypes.Structure):
416 """
417 Axis rotation structure for specifying shoot orientation in PlantArchitecture.
418
419 Represents rotation using pitch, yaw, and roll angles in degrees.
420 Used to define the orientation of shoots, stems, and branches during plant construction.
421 """
422 _fields_ = [
423 ('pitch', ctypes.c_float),
424 ('yaw', ctypes.c_float),
425 ('roll', ctypes.c_float)
426 ]
427
428 def __repr__(self) -> str:
429 return f'AxisRotation({self.pitch}, {self.yaw}, {self.roll})'
430
431 def __str__(self) -> str:
432 return f'AxisRotation({self.pitch}, {self.yaw}, {self.roll})'
434 def __init__(self, pitch:float=0, yaw:float=0, roll:float=0):
435 """
436 Initialize AxisRotation with pitch, yaw, and roll angles.
437
438 Args:
439 pitch: Pitch angle in degrees (rotation about transverse axis)
440 yaw: Yaw angle in degrees (rotation about vertical axis)
441 roll: Roll angle in degrees (rotation about longitudinal axis)
443 Raises:
444 ValueError: If any angle value is not finite
445 """
446 # Validate finite numeric inputs
447 if not self._is_finite_numeric(pitch):
448 raise ValueError(f"AxisRotation.pitch must be a finite number, got {type(pitch).__name__}: {pitch}. "
449 f"Rotation angles must be finite (not NaN or infinity).")
450 if not self._is_finite_numeric(yaw):
451 raise ValueError(f"AxisRotation.yaw must be a finite number, got {type(yaw).__name__}: {yaw}. "
452 f"Rotation angles must be finite (not NaN or infinity).")
453 if not self._is_finite_numeric(roll):
454 raise ValueError(f"AxisRotation.roll must be a finite number, got {type(roll).__name__}: {roll}. "
455 f"Rotation angles must be finite (not NaN or infinity).")
456
457 self.pitch = float(pitch)
458 self.yaw = float(yaw)
459 self.roll = float(roll)
460
461 def from_list(self, input_list:List[float]):
462 """Initialize from list [pitch, yaw, roll]"""
463 if len(input_list) < 3:
464 raise ValueError("AxisRotation.from_list requires a list with at least 3 elements [pitch, yaw, roll]")
465 self.pitch = input_list[0]
466 self.yaw = input_list[1]
467 self.roll = input_list[2]
469 def to_list(self) -> List[float]:
470 """Convert to list [pitch, yaw, roll]"""
471 return [self.pitch, self.yaw, self.roll]
472
473 @staticmethod
474 def _is_finite_numeric(value) -> bool:
475 """Check if value is a finite number (not NaN or inf)."""
476 try:
477 float_value = float(value)
478 return math.isfinite(float_value)
479 except (ValueError, TypeError, OverflowError):
480 return False
481
482
483# Factory functions to match C++ API
484def make_int2(x: int, y: int) -> int2:
485 """Make an int2 from two integers"""
486 return int2(x, y)
487
488def make_SphericalCoord(elevation_radians: float, azimuth_radians: float) -> SphericalCoord:
489 """
490 Make a SphericalCoord by specifying elevation and azimuth (C++ API compatibility).
492 Args:
493 elevation_radians: Elevation angle in radians
494 azimuth_radians: Azimuthal angle in radians
495
496 Returns:
497 SphericalCoord with radius=1, and automatically computed zenith
498 """
499 return SphericalCoord(radius=1, elevation=elevation_radians, azimuth=azimuth_radians)
500
501def make_int3(x: int, y: int, z: int) -> int3:
502 """Make an int3 from three integers"""
503 return int3(x, y, z)
505def make_int4(x: int, y: int, z: int, w: int) -> int4:
506 """Make an int4 from four integers"""
507 return int4(x, y, z, w)
509def make_vec2(x: float, y: float) -> vec2:
510 """Make a vec2 from two floats"""
511 return vec2(x, y)
512
513def make_vec3(x: float, y: float, z: float) -> vec3:
514 """Make a vec3 from three floats"""
515 return vec3(x, y, z)
517def make_vec4(x: float, y: float, z: float, w: float) -> vec4:
518 """Make a vec4 from four floats"""
519 return vec4(x, y, z, w)
520
521def make_RGBcolor(r: float, g: float, b: float) -> RGBcolor:
522 """Make an RGBcolor from three floats"""
523 return RGBcolor(r, g, b)
524
525def make_RGBAcolor(r: float, g: float, b: float, a: float) -> RGBAcolor:
526 """Make an RGBAcolor from four floats"""
527 return RGBAcolor(r, g, b, a)
528
529def make_AxisRotation(pitch: float, yaw: float, roll: float) -> AxisRotation:
530 """Make an AxisRotation from three angles in degrees"""
531 return AxisRotation(pitch, yaw, roll)
532
534class Time(ctypes.Structure):
535 """Helios Time structure for representing time values."""
536 _fields_ = [('second', ctypes.c_int32), ('minute', ctypes.c_int32), ('hour', ctypes.c_int32)]
537
538 def __repr__(self) -> str:
539 return f'Time({self.hour:02d}:{self.minute:02d}:{self.second:02d})'
540
541 def __str__(self) -> str:
542 return f'{self.hour:02d}:{self.minute:02d}:{self.second:02d}'
543
544 def __init__(self, hour: int = 0, minute: int = 0, second: int = 0):
545 """
546 Initialize a Time object.
547
548 Args:
549 hour: Hour (0-23)
550 minute: Minute (0-59)
551 second: Second (0-59)
552 """
553 # Validate inputs
554 if not isinstance(hour, int):
555 raise ValueError(f"Time.hour must be an integer, got {type(hour).__name__}: {hour}")
556 if not isinstance(minute, int):
557 raise ValueError(f"Time.minute must be an integer, got {type(minute).__name__}: {minute}")
558 if not isinstance(second, int):
559 raise ValueError(f"Time.second must be an integer, got {type(second).__name__}: {second}")
560
561 if hour < 0 or hour > 23:
562 raise ValueError(f"Time.hour must be between 0 and 23, got: {hour}")
563 if minute < 0 or minute > 59:
564 raise ValueError(f"Time.minute must be between 0 and 59, got: {minute}")
565 if second < 0 or second > 59:
566 raise ValueError(f"Time.second must be between 0 and 59, got: {second}")
567
568 self.hour = hour
569 self.minute = minute
570 self.second = second
571
572 def from_list(self, input_list: List[int]):
573 """Initialize from a list [hour, minute, second]"""
574 if len(input_list) < 3:
575 raise ValueError("Time.from_list requires a list with at least 3 elements [hour, minute, second]")
576 self.hour = input_list[0]
577 self.minute = input_list[1]
578 self.second = input_list[2]
579
580 def to_list(self) -> List[int]:
581 """Convert to list [hour, minute, second]"""
582 return [self.hour, self.minute, self.second]
584 def __eq__(self, other) -> bool:
585 """Check equality with another Time object"""
586 if not isinstance(other, Time):
587 return False
588 return (self.hour == other.hour and
589 self.minute == other.minute and
590 self.second == other.second)
591
592 def __ne__(self, other) -> bool:
593 """Check inequality with another Time object"""
594 return not self.__eq__(other)
595
596
597class Date(ctypes.Structure):
598 """Helios Date structure for representing date values."""
599 _fields_ = [('day', ctypes.c_int32), ('month', ctypes.c_int32), ('year', ctypes.c_int32)]
600
601 def __repr__(self) -> str:
602 return f'Date({self.year}-{self.month:02d}-{self.day:02d})'
604 def __str__(self) -> str:
605 return f'{self.year}-{self.month:02d}-{self.day:02d}'
606
607 def __init__(self, year: int = 2023, month: int = 1, day: int = 1):
608 """
609 Initialize a Date object.
610
611 Args:
612 year: Year (1900-3000)
613 month: Month (1-12)
614 day: Day (1-31)
615 """
616 # Validate inputs
617 if not isinstance(year, int):
618 raise ValueError(f"Date.year must be an integer, got {type(year).__name__}: {year}")
619 if not isinstance(month, int):
620 raise ValueError(f"Date.month must be an integer, got {type(month).__name__}: {month}")
621 if not isinstance(day, int):
622 raise ValueError(f"Date.day must be an integer, got {type(day).__name__}: {day}")
623
624 if year < 1900 or year > 3000:
625 raise ValueError(f"Date.year must be between 1900 and 3000, got: {year}")
626 if month < 1 or month > 12:
627 raise ValueError(f"Date.month must be between 1 and 12, got: {month}")
628 if day < 1 or day > 31:
629 raise ValueError(f"Date.day must be between 1 and 31, got: {day}")
630
631 self.year = year
632 self.month = month
633 self.day = day
634
635 def from_list(self, input_list: List[int]):
636 """Initialize from a list [year, month, day]"""
637 if len(input_list) < 3:
638 raise ValueError("Date.from_list requires a list with at least 3 elements [year, month, day]")
639 self.year = input_list[0]
640 self.month = input_list[1]
641 self.day = input_list[2]
642
643 def to_list(self) -> List[int]:
644 """Convert to list [year, month, day]"""
645 return [self.year, self.month, self.day]
646
647 def __eq__(self, other) -> bool:
648 """Check equality with another Date object"""
649 if not isinstance(other, Date):
650 return False
651 return (self.year == other.year and
652 self.month == other.month and
653 self.day == other.day)
654
655 def __ne__(self, other) -> bool:
656 """Check inequality with another Date object"""
657 return not self.__eq__(other)
659
660def make_Time(hour: int, minute: int, second: int) -> Time:
661 """Make a Time from hour, minute, second"""
662 return Time(hour, minute, second)
663
664def make_Date(year: int, month: int, day: int) -> Date:
665 """Make a Date from year, month, day"""
666 return Date(year, month, day)
667
668# Removed duplicate make_SphericalCoord function - keeping only the 2-parameter version above
Axis rotation structure for specifying shoot orientation in PlantArchitecture.
Definition DataTypes.py:464
bool _is_finite_numeric(value)
Check if value is a finite number (not NaN or inf).
Definition DataTypes.py:523
List[float] to_list(self)
Convert to list [pitch, yaw, roll].
Definition DataTypes.py:516
Helios Date structure for representing date values.
Definition DataTypes.py:649
bool __ne__(self, other)
Check inequality with another Date object.
Definition DataTypes.py:710
bool __eq__(self, other)
Check equality with another Date object.
Definition DataTypes.py:702
Helios primitive type enumeration.
Definition DataTypes.py:8
_validate_color_component(self, value, component_name)
Validate a color component is finite and in range [0,1].
Definition DataTypes.py:375
bool _is_finite_numeric(value)
Check if value is a finite number (not NaN or inf).
Definition DataTypes.py:365
__init__(self, float r=0, float g=0, float b=0, float a=0)
Definition DataTypes.py:340
__init__(self, float r=0, float g=0, float b=0)
Definition DataTypes.py:283
_validate_color_component(self, value, component_name)
Validate a color component is finite and in range [0,1].
Definition DataTypes.py:315
from_list(self, List[float] input_list)
Definition DataTypes.py:293
bool _is_finite_numeric(value)
Check if value is a finite number (not NaN or inf).
Definition DataTypes.py:305
from_list(self, List[float] input_list)
Definition DataTypes.py:436
bool _is_finite_numeric(value)
Check if value is a finite number (not NaN or inf).
Definition DataTypes.py:449
__init__(self, float radius=1, float elevation=0, float azimuth=0)
Initialize SphericalCoord matching C++ constructor.
Definition DataTypes.py:414
Helios Time structure for representing time values.
Definition DataTypes.py:583
List[int] to_list(self)
Convert to list [hour, minute, second].
Definition DataTypes.py:632
from_list(self, List[int] input_list)
Initialize from a list [hour, minute, second].
Definition DataTypes.py:624
__init__(self, int hour=0, int minute=0, int second=0)
Initialize a Time object.
Definition DataTypes.py:603
bool __eq__(self, other)
Check equality with another Time object.
Definition DataTypes.py:636
bool __ne__(self, other)
Check inequality with another Time object.
Definition DataTypes.py:644
from_list(self, List[int] input_list)
Definition DataTypes.py:41
__init__(self, int x=0, int y=0)
Definition DataTypes.py:31
__init__(self, int x=0, int y=0, int z=0)
Definition DataTypes.py:62
from_list(self, List[int] input_list)
Definition DataTypes.py:75
from_list(self, List[int] input_list)
Definition DataTypes.py:113
__init__(self, int x=0, int y=0, int z=0, int w=0)
Definition DataTypes.py:97
from_list(self, List[float] input_list)
Definition DataTypes.py:148
bool _is_finite_numeric(value)
Check if value is a finite number (not NaN or inf).
Definition DataTypes.py:159
__init__(self, float x=0, float y=0)
Definition DataTypes.py:136
__init__(self, float x=0, float y=0, float z=0)
Definition DataTypes.py:178
from_list(self, List[float] input_list)
Definition DataTypes.py:194
bool _is_finite_numeric(value)
Check if value is a finite number (not NaN or inf).
Definition DataTypes.py:209
bool _is_finite_numeric(value)
Check if value is a finite number (not NaN or inf).
Definition DataTypes.py:262
__init__(self, float x=0, float y=0, float z=0, float w=0)
Definition DataTypes.py:229
from_list(self, List[float] input_list)
Definition DataTypes.py:249
RGBAcolor make_RGBAcolor(float r, float g, float b, float a)
Make an RGBAcolor from four floats.
Definition DataTypes.py:574
AxisRotation make_AxisRotation(float pitch, float yaw, float roll)
Make an AxisRotation from three angles in degrees.
Definition DataTypes.py:578
int3 make_int3(int x, int y, int z)
Make an int3 from three integers.
Definition DataTypes.py:550
Time make_Time(int hour, int minute, int second)
Make a Time from hour, minute, second.
Definition DataTypes.py:715
RGBcolor make_RGBcolor(float r, float g, float b)
Make an RGBcolor from three floats.
Definition DataTypes.py:570
Date make_Date(int year, int month, int day)
Make a Date from year, month, day.
Definition DataTypes.py:719
int4 make_int4(int x, int y, int z, int w)
Make an int4 from four integers.
Definition DataTypes.py:554
SphericalCoord make_SphericalCoord(float elevation_radians, float azimuth_radians)
Make a SphericalCoord by specifying elevation and azimuth (C++ API compatibility).
Definition DataTypes.py:546
vec2 make_vec2(float x, float y)
Make a vec2 from two floats.
Definition DataTypes.py:558
vec4 make_vec4(float x, float y, float z, float w)
Make a vec4 from four floats.
Definition DataTypes.py:566
int2 make_int2(int x, int y)
Make an int2 from two integers.
Definition DataTypes.py:533
vec3 make_vec3(float x, float y, float z)
Make a vec3 from three floats.
Definition DataTypes.py:562