math-tompy 2024.8.13.13.26__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4 @@
1
+ .idea/
2
+ __pycache__/
3
+ venv*/
4
+ dist/
@@ -0,0 +1,14 @@
1
+ Metadata-Version: 2.3
2
+ Name: math-tompy
3
+ Version: 2024.8.13.13.26
4
+ Summary: Extra math for tompy projects
5
+ Author: tompy
6
+ Classifier: Development Status :: 3 - Alpha
7
+ Classifier: Intended Audience :: Developers
8
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
9
+ Classifier: Operating System :: OS Independent
10
+ Classifier: Programming Language :: Python :: 3.9
11
+ Requires-Python: >=3.9
12
+ Description-Content-Type: text/markdown
13
+
14
+ Extra math for tompy projects
@@ -0,0 +1 @@
1
+ Extra math for tompy projects
@@ -0,0 +1,24 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "math-tompy"
7
+ version = "2024.08.13.13.26"
8
+ dependencies = []
9
+ authors = [
10
+ { name = "tompy" },
11
+ ]
12
+ description = "Extra math for tompy projects"
13
+ readme = "README.md"
14
+ requires-python = ">=3.9"
15
+ classifiers = [
16
+ "Development Status :: 3 - Alpha",
17
+ "Intended Audience :: Developers",
18
+ "Programming Language :: Python :: 3.9",
19
+ "License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
20
+ "Operating System :: OS Independent",
21
+ ]
22
+
23
+ [tool.hatch.build.targets.wheel]
24
+ packages = ["src/math_tompy"]
File without changes
@@ -0,0 +1,27 @@
1
+ from decimal import Decimal
2
+
3
+
4
+ def normalize_value(value: Decimal, minimum: Decimal, maximum: Decimal) -> Decimal:
5
+ """Scale value position between minimum and maximum to [0:1] bound"""
6
+
7
+ # Scale value and maximum relative to zero to enable finding fractional value by straightforward division
8
+ zero_scaled_value: Decimal = value - minimum
9
+ zero_scaled_maximum: Decimal = maximum - minimum
10
+
11
+ # Divide scaled values
12
+ normalized_value: Decimal = zero_scaled_value / zero_scaled_maximum
13
+
14
+ return normalized_value
15
+
16
+
17
+ def clamp_or_normalize_value(value: Decimal, minimum: Decimal, maximum: Decimal) -> Decimal:
18
+ new_value: Decimal
19
+
20
+ if value < minimum:
21
+ new_value = Decimal("0.0")
22
+ elif value > maximum:
23
+ new_value = Decimal("1.0")
24
+ else:
25
+ new_value = normalize_value(value=value, minimum=minimum, maximum=maximum)
26
+
27
+ return new_value
@@ -0,0 +1,52 @@
1
+ from enum import Enum, auto
2
+ from math import inf
3
+ from random import normalvariate
4
+
5
+ Variability = float
6
+
7
+
8
+ class Rounding(Enum):
9
+ ROUND = auto()
10
+ CEILING = auto()
11
+ FLOOR = auto()
12
+
13
+
14
+ def round_to_nearest_multiple(number, round_to, rounding: Rounding = Rounding.ROUND):
15
+ if round_to <= 0:
16
+ raise ValueError(f"Rounding factor can not be 0 or negative.")
17
+
18
+ remainder = number % round_to
19
+
20
+ if rounding == Rounding.ROUND:
21
+ nearest = number + round_to - remainder if 2 * remainder >= round_to else number - remainder
22
+ elif rounding == Rounding.CEILING:
23
+ nearest = number + round_to - remainder
24
+ elif rounding == Rounding.FLOOR:
25
+ nearest = number - remainder
26
+ else:
27
+ raise ValueError(f"rounding is not a valid Rounding value: '{rounding}")
28
+
29
+ return nearest
30
+
31
+
32
+ def get_variability_amount(variability: Variability,
33
+ coloring_image_axis_size: int) -> float:
34
+ if variability == 0.0:
35
+ variability_amount: float = variability
36
+ else:
37
+ # TODO: get scaled or truncated value rather than retrying until value generated that fits in desired range
38
+ # search term: Truncated normal distribution
39
+ # https://scipy.github.io/devdocs/reference/generated/scipy.stats.truncnorm.html
40
+ # https://github.com/jessemzhang/tn_test/blob/master/truncated_normal/truncated_normal.py
41
+ # package name: truncnorm
42
+ # package name: pydistributions
43
+ variation_value: float = inf
44
+ while variation_value < -1.0 or variation_value > 1.0:
45
+ variation_value: float = normalvariate(mu=0.0, sigma=0.25)
46
+
47
+ # Maximum extent of axis considered around point
48
+ variability_radius: float = variability * coloring_image_axis_size
49
+ # Specific extent selected with normal distribution value
50
+ variability_amount: float = variation_value * variability_radius
51
+
52
+ return variability_amount
@@ -0,0 +1,84 @@
1
+ from decimal import Decimal
2
+ from fractions import Fraction
3
+ from typing import NamedTuple
4
+
5
+ # TODO: use Numeric to make parts of this more generic
6
+ Numeric = int | float | Decimal | Fraction
7
+
8
+ # TODO: Point1Df as Vector1 in Decimal
9
+ Point1Df = float
10
+ Point2Df = tuple[float, float]
11
+ Point1Di = int
12
+ Point2Di = tuple[int, int]
13
+
14
+
15
+ class Range1Df(NamedTuple):
16
+ minimum: float
17
+ maximum: float
18
+
19
+ # TODO: implement as __len__
20
+ def size(self) -> float:
21
+ # Measuring stretch between fence posts
22
+ # TODO: confirm that '1.0' should not be added here, because it is measuring between, not at
23
+ return self.maximum - self.minimum + 1.0
24
+ # return self.maximum - self.minimum
25
+
26
+
27
+ class Range1Di(NamedTuple):
28
+ minimum: int
29
+ maximum: int
30
+
31
+ # TODO: implement as __len__
32
+ def size(self) -> int:
33
+ # Measuring amount of fence posts
34
+ return self.maximum - self.minimum + 1
35
+
36
+
37
+ class Range2Df(NamedTuple):
38
+ x_axis: Range1Df
39
+ y_axis: Range1Df
40
+
41
+ def area(self) -> float:
42
+ return self.x_axis.size() * self.y_axis.size()
43
+
44
+
45
+ class Range2Di(NamedTuple):
46
+ x_axis: Range1Di
47
+ y_axis: Range1Di
48
+
49
+ def area(self) -> float:
50
+ return self.x_axis.size() * self.y_axis.size()
51
+
52
+
53
+ # TODO: improve naming with words specific to bucketed int values and tiny-mini float values
54
+ def clamp_svg_value_to_range(svg_image_point: Point1Df, svg_image_axis: Range1Df) -> Point1Df:
55
+ value: Point1Df
56
+ if svg_image_point < svg_image_axis.minimum:
57
+ value = svg_image_axis.minimum
58
+ elif svg_image_point > svg_image_axis.maximum:
59
+ value = svg_image_axis.maximum
60
+ else:
61
+ value = svg_image_point
62
+ return value
63
+
64
+
65
+ # TODO: improve naming with words specific to bucketed int values and tiny-mini float values
66
+ def clamp_image_value_to_range(coloring_image_point: Point1Di, coloring_image_axis: Range1Di) -> Point1Di:
67
+ value: Point1Di
68
+ if coloring_image_point < coloring_image_axis.minimum:
69
+ value = coloring_image_axis.minimum
70
+ elif coloring_image_point > coloring_image_axis.maximum:
71
+ value = coloring_image_axis.maximum
72
+ else:
73
+ value = coloring_image_point
74
+ return value
75
+
76
+
77
+ # TODO: make naming generic to not focus on
78
+ def get_coloring_image_fraction(svg_image_point: Point1Df,
79
+ svg_axis_range: Range1Df) -> float:
80
+ clamped_svg_image_y_axis_point: Point1Df = clamp_svg_value_to_range(svg_image_point=svg_image_point,
81
+ svg_image_axis=svg_axis_range)
82
+ axis_scaler: float = 1.0 / svg_axis_range.size()
83
+ coloring_image_scaled_y_axis_point: float = clamped_svg_image_y_axis_point * axis_scaler
84
+ return coloring_image_scaled_y_axis_point