/ spoolman / math.py
math.py
 1  """Various math-related functions."""
 2  
 3  # ruff: noqa: PLR2004
 4  
 5  import math
 6  
 7  
 8  def weight_from_length(*, length: float, diameter: float, density: float) -> float:
 9      """Calculate the weight of a piece of filament.
10  
11      Args:
12          length (float): Filament length in mm
13          diameter (float): Filament diameter in mm
14          density (float): Density of filament material in g/cm3
15  
16      Returns:
17          float: Weight in g
18  
19      """
20      volume_mm3 = length * math.pi * (diameter / 2) ** 2
21      volume_cm3 = volume_mm3 / 1000
22      return density * volume_cm3
23  
24  
25  def length_from_weight(*, weight: float, diameter: float, density: float) -> float:
26      """Calculate the length of a piece of filament.
27  
28      Args:
29          weight (float): Filament weight in g
30          diameter (float): Filament diameter in mm
31          density (float): Density of filament material in g/cm3
32  
33      Returns:
34          float: Length in mm
35  
36      """
37      volume_cm3 = weight / density
38      volume_mm3 = volume_cm3 * 1000
39      return volume_mm3 / (math.pi * (diameter / 2) ** 2)
40  
41  
42  def rgb_to_lab(rgb: list[int]) -> list[float]:
43      """Convert a RGB color to CIELAB.
44  
45      Input is of form [r, g, b] where r, g, and b are integers between 0 and 255.
46      Output is of form [l, a, b] where l, a, and b are floats.
47      """
48      r, g, b = rgb[0] / 255, rgb[1] / 255, rgb[2] / 255
49  
50      r = (r / 12.92) if (r <= 0.04045) else math.pow((r + 0.055) / 1.055, 2.4)
51      g = (g / 12.92) if (g <= 0.04045) else math.pow((g + 0.055) / 1.055, 2.4)
52      b = (b / 12.92) if (b <= 0.04045) else math.pow((b + 0.055) / 1.055, 2.4)
53  
54      x = (r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047
55      y = (r * 0.2126 + g * 0.7152 + b * 0.0722) / 1.00000
56      z = (r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883
57  
58      x = math.pow(x, 1 / 3) if (x > 0.008856) else (7.787 * x) + 16 / 116
59      y = math.pow(y, 1 / 3) if (y > 0.008856) else (7.787 * y) + 16 / 116
60      z = math.pow(z, 1 / 3) if (z > 0.008856) else (7.787 * z) + 16 / 116
61  
62      return [(116 * y) - 16, 500 * (x - y), 200 * (y - z)]
63  
64  
65  def delta_e(lab_a: list[float], lab_b: list[float]) -> float:
66      """Calculate the color difference between two CIELAB colors."""
67      delta_l = lab_a[0] - lab_b[0]
68      delta_a = lab_a[1] - lab_b[1]
69      delta_b = lab_a[2] - lab_b[2]
70      c1 = math.sqrt(lab_a[1] * lab_a[1] + lab_a[2] * lab_a[2])
71      c2 = math.sqrt(lab_b[1] * lab_b[1] + lab_b[2] * lab_b[2])
72      delta_c = c1 - c2
73      delta_h = delta_a * delta_a + delta_b * delta_b - delta_c * delta_c
74      delta_h = math.sqrt(delta_h) if delta_h > 0 else 0
75      sc = 1.0 + 0.045 * c1
76      sh = 1.0 + 0.015 * c1
77      delta_l_kl_sl = delta_l / 1.0
78      delta_c_kc_sc = delta_c / sc
79      delta_h_kh_sh = delta_h / sh
80      i = delta_l_kl_sl * delta_l_kl_sl + delta_c_kc_sc * delta_c_kc_sc + delta_h_kh_sh * delta_h_kh_sh
81      return math.sqrt(i) if i > 0 else 0
82  
83  
84  def hex_to_rgb(hex_code: str) -> list[int]:
85      """Convert a hex color code to RGB.
86  
87      Input is of form #RRGGBB where RR, GG, and BB are hexadecimal numbers.
88      Output is of form [r, g, b] where r, g, and b are integers between 0 and 255.
89      """
90      hex_code = hex_code.lstrip("#")
91  
92      r = int(hex_code[0:2], 16)
93      g = int(hex_code[2:4], 16)
94      b = int(hex_code[4:6], 16)
95  
96      return [r, g, b]