]> git.mar77i.info Git - zenbook_gui/commitdiff
split up vectors module too
authormar77i <mar77i@protonmail.ch>
Wed, 5 Feb 2025 00:11:36 +0000 (01:11 +0100)
committermar77i <mar77i@protonmail.ch>
Wed, 5 Feb 2025 00:11:36 +0000 (01:11 +0100)
14 files changed:
vectors/__init__.py
vectors/base.py [new file with mode: 0644]
vectors/circle.py [new file with mode: 0644]
vectors/ellipse.py [new file with mode: 0644]
vectors/polygon.py [new file with mode: 0644]
vectors/rect.py [new file with mode: 0644]
vectors/stroke_circle.py [new file with mode: 0644]
vectors/stroke_circle_segment.py [new file with mode: 0644]
vectors/stroke_path.py [new file with mode: 0644]
vectors/stroke_round_line.py [new file with mode: 0644]
vectors/stroke_square_line.py [new file with mode: 0644]
vectors/vectors.py [deleted file]
zenbook_conf/shapes.py
zenbook_conf/zenbook_conf.py

index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3d850b7b3b62ef57a7f11298254232a54c7f5d5f 100644 (file)
@@ -0,0 +1,10 @@
+from .base import Shape, Shapes
+from .circle import Circle
+from .ellipse import Ellipse
+from .polygon import Polygon
+from .rect import Rect
+from .stroke_circle import StrokeCircle
+from .stroke_circle_segment import StrokeCircleSegment
+from .stroke_path import StrokePath
+from .stroke_round_line import StrokeRoundLine
+from .stroke_square_line import StrokeSquareLine
diff --git a/vectors/base.py b/vectors/base.py
new file mode 100644 (file)
index 0000000..5d4ccf8
--- /dev/null
@@ -0,0 +1,20 @@
+class Shape:
+    def fit(self, pos, unit):
+        raise NotImplementedError
+
+    def draw(self, surf, color):
+        pass
+
+
+class Shapes(Shape):
+    def __init__(self, shapes):
+        self.shapes = list(shapes)
+
+    def fit(self, pos, unit):
+        if type(self) != Shapes:
+            raise NotImplementedError
+        return Shapes([s.fit(pos, unit) for s in self.shapes])
+
+    def draw(self, surf, color):
+        for shape in self.shapes:
+            shape.draw(surf, color)
diff --git a/vectors/circle.py b/vectors/circle.py
new file mode 100644 (file)
index 0000000..e04b4a9
--- /dev/null
@@ -0,0 +1,30 @@
+from .base import Shape
+from .ellipse import Ellipse
+
+
+class Circle(Shape):
+    def __init__(self, center, radius):
+        self.center = center
+        self.radius = radius
+
+    def fit(self, pos, unit):
+        if type(self) != Circle:
+            raise NotImplementedError
+        if unit[0] == unit[1]:
+            return Circle(
+                (
+                    pos[0] + self.center[0] * unit[0],
+                    pos[1] + self.center[1] * unit[1],
+                ),
+                self.radius * unit[0],
+            )
+        return Ellipse(
+            (
+                round(pos[0] + (self.center[0] - self.radius) * unit[0]),
+                round(pos[1] + (self.center[1] - self.radius) * unit[1]),
+            ),
+            (round(self.radius * 2 * unit[0]), round(self.radius * 2 * unit[1])),
+        )
+
+    def draw(self, surf, color):
+        pygame.draw.circle(surf, color, self.center, self.radius)
diff --git a/vectors/ellipse.py b/vectors/ellipse.py
new file mode 100644 (file)
index 0000000..74ca1d4
--- /dev/null
@@ -0,0 +1,10 @@
+import pygame
+
+from .rect import Rect
+
+
+class Ellipse(Rect):
+    def draw(self, surf, color):
+        pygame.draw.ellipse(
+            surf, color, pygame.Rect(self.left, self.top, self.width, self.height)
+        )
diff --git a/vectors/polygon.py b/vectors/polygon.py
new file mode 100644 (file)
index 0000000..a4b747b
--- /dev/null
@@ -0,0 +1,21 @@
+import pygame
+
+from .base import Shape
+
+
+class Polygon(Shape):
+    def __init__(self, points):
+        self.points = list(points)
+
+    def fit(self, pos, unit):
+        if type(self) != Polygon:
+            raise NotImplementedError
+        return Polygon(
+            [
+                (round(pos[0] + point[0] * unit[0]), round(pos[1] + point[1] * unit[1]))
+                for point in self.points
+            ]
+        )
+
+    def draw(self, surf, color):
+        pygame.draw.polygon(surf, color, self.points)
diff --git a/vectors/rect.py b/vectors/rect.py
new file mode 100644 (file)
index 0000000..e9011ec
--- /dev/null
@@ -0,0 +1,24 @@
+from itertools import chain
+
+import pygame
+
+from .base import Shape
+
+
+class Rect(Shape):
+    def __init__(self, *args):
+        if len(args) == 2:
+            args = tuple(chain.from_iterable(args))
+        self.left, self.top, self.width, self.height = args
+
+    def fit(self, pos, unit):
+        klass = type(self)
+        return klass(
+            (round(pos[0] + self.left * unit[0]), round(pos[1] + self.top * unit[1])),
+            (round(self.width * unit[0]), round(self.height * unit[1])),
+        )
+
+    def draw(self, surf, color):
+        pygame.draw.rect(
+            surf, color, pygame.Rect(self.left, self.top, self.width, self.height)
+        )
diff --git a/vectors/stroke_circle.py b/vectors/stroke_circle.py
new file mode 100644 (file)
index 0000000..fdb12a9
--- /dev/null
@@ -0,0 +1,31 @@
+from math import cos, sin, tau
+
+from .stroke_path import StrokePath
+from .stroke_round_line import StrokeRoundLine
+
+
+class StrokeCircle(StrokePath):
+    def __init__(self, center, radius, width):
+        self.center = center
+        self.radius = radius
+        super().__init__([], True, width)
+        self.points.extend(self.get_points())
+
+    def get_points(self):
+        num_vertices = StrokeRoundLine.corners_needed_to_appear_round(self.radius)
+        return [
+            (
+                self.center[0] + cos(a) * self.radius,
+                self.center[1] + sin(a) * self.radius,
+            )
+            for a in (tau * i / num_vertices for i in range(num_vertices))
+        ]
+
+    def fit(self, pos, unit):
+        if type(self) != StrokeCircle:
+            raise NotImplementedError
+        return StrokeCircle(
+            (pos[0] + self.center[0] * unit[0], pos[1] + self.center[1] * unit[1]),
+            self.radius * max(unit),
+            self.width * max(unit),
+        )
diff --git a/vectors/stroke_circle_segment.py b/vectors/stroke_circle_segment.py
new file mode 100644 (file)
index 0000000..d3eddd1
--- /dev/null
@@ -0,0 +1,44 @@
+from math import cos, sin, tau
+
+
+from .stroke_circle import StrokeCircle
+from .stroke_round_line import StrokeRoundLine
+
+
+class StrokeCircleSegment(StrokeCircle):
+    def __init__(self, center, radius, start_angle, end_angle, width):
+        self.start_angle = start_angle
+        self.end_angle = end_angle
+        super().__init__(center, radius, width)
+        self.closed = False
+
+    def get_points(self):
+        return [
+            (self.center[0] + cos(a) * self.radius, self.center[1] + sin(a) * self.radius)
+            for a in self.get_angle_segments(
+                self.start_angle,
+                self.end_angle,
+                StrokeRoundLine.corners_needed_to_appear_round((self.radius + self.width / 2)),
+            )
+        ]
+
+    def get_angle_segments(self, start_angle, end_angle, num_vertices):
+        start_angle, end_angle = sorted((start_angle, end_angle))
+        diff_angle = end_angle - start_angle
+        for i in range(num_vertices):
+            a = tau * i / num_vertices
+            if a >= diff_angle:
+                yield end_angle
+                break
+            yield start_angle + a
+
+    def fit(self, pos, unit):
+        if type(self) != StrokeCircleSegment:
+            raise NotImplementedError
+        return StrokeCircleSegment(
+            (pos[0] + self.center[0] * unit[0], pos[1] + self.center[1] * unit[1]),
+            self.radius * max(unit),
+            self.start_angle,
+            self.end_angle,
+            self.width * max(unit),
+        )
diff --git a/vectors/stroke_path.py b/vectors/stroke_path.py
new file mode 100644 (file)
index 0000000..6ea9e80
--- /dev/null
@@ -0,0 +1,39 @@
+from .base import Shapes
+from .stroke_round_line import StrokeRoundLine
+
+
+class StrokePath:
+    def __init__(self, points, closed, width):
+        self.points = list(points)
+        self.closed = bool(closed)
+        self.width = width
+
+    @property
+    def shapes(self):
+        if not self.points:
+            return
+        if self.closed:
+            yield StrokeRoundLine(
+                self.points[-1],
+                self.points[0],
+                self.width,
+            )
+        iter_points = iter(self.points)
+        old = next(iter_points)
+        for new in iter_points:
+            yield StrokeRoundLine(old, new, self.width)
+            old = new
+
+    def fit(self, pos, unit):
+        if type(self) != StrokePath:
+            raise NotImplementedError
+        return StrokePath(
+            [
+                (pos[0] + point[0] * unit[0], pos[1] + point[1] * unit[1])
+                for point in self.points
+            ],
+            self.closed,
+            self.width,
+        )
+
+    draw = Shapes.draw
diff --git a/vectors/stroke_round_line.py b/vectors/stroke_round_line.py
new file mode 100644 (file)
index 0000000..df3e40a
--- /dev/null
@@ -0,0 +1,65 @@
+from math import acos, atan2, ceil, cos, floor, pi, sin, sqrt, tau
+
+from .polygon import Polygon
+
+
+class StrokeRoundLine(Polygon):
+    """
+    Enclose a rectangle fitted between two points with a regular, non-rotated n-gon
+    that should be visually indistinguishable with a half circle
+    """
+    def __init__(self, p1, p2, width):
+        self.p1 = p1
+        self.p2 = p2
+        self.width = width
+        super().__init__(self.get_points())
+
+    def get_points(self):
+        radius = self.width / 2
+        num_vertices = self.corners_needed_to_appear_round(radius)
+        delta = (self.p1[0] - self.p2[0], self.p1[1] - self.p2[1])
+        distance = sqrt(delta[0] * delta[0] + delta[1] * delta[1])
+        points = []
+        if distance == 0:
+            initial_corner = opposing_corner = num_vertices
+            back = (0, 0)
+        else:
+            initial_corner = ceil(
+                atan2(-delta[0], delta[1]) * num_vertices / tau
+            )
+            opposing_corner = (
+                floor(atan2(delta[0], -delta[1]) * num_vertices / tau) - initial_corner
+            ) % num_vertices
+            back = (delta[0] * radius / distance, delta[1] * radius / distance)
+            points.extend(
+                (
+                    (self.p2[0] + back[1], self.p2[1] - back[0]),
+                    (self.p1[0] + back[1], self.p1[1] - back[0]),
+                )
+            )
+        p = self.p1
+        for i in range(num_vertices):
+            angle = (i + initial_corner) * tau / num_vertices
+            points.append((p[0] + cos(angle) * radius, p[1] + sin(angle) * radius))
+            if i == opposing_corner:
+                points.extend(
+                    (
+                        (self.p1[0] - back[1], self.p1[1] + back[0]),
+                        (self.p2[0] - back[1], self.p2[1] + back[0]),
+                    )
+                )
+                p = self.p2
+        return points
+
+    @staticmethod
+    def corners_needed_to_appear_round(radius, threshold=.5):
+        return ceil(pi / acos(1 - threshold / radius))
+
+    def fit(self, pos, unit):
+        if type(self) != StrokeRoundLine:
+            raise NotImplementedError
+        return StrokeRoundLine(
+            (pos[0] + self.p1[0] * unit[0], pos[1] + self.p1[1] * unit[1]),
+            (pos[0] + self.p2[0] * unit[0], pos[1] + self.p2[1] * unit[1]),
+            self.width * max(unit),
+        )
diff --git a/vectors/stroke_square_line.py b/vectors/stroke_square_line.py
new file mode 100644 (file)
index 0000000..975f0b8
--- /dev/null
@@ -0,0 +1,43 @@
+from math import sqrt
+
+from .polygon import Polygon
+
+
+class StrokeSquareLine(Polygon):
+    """
+    Rotate a rectangle along the direction in which we're drawing.
+    """
+    def __init__(self, p1, p2, width):
+        self.p1 = p1
+        self.p2 = p2
+        self.width = width
+        super().__init__(self.get_points())
+
+    def get_points(self):
+        p_rel = (self.p1[0] - self.p2[0], self.p1[1] - self.p2[1])
+        twice_distance = 2 * sqrt(p_rel[0] * p_rel[0] + p_rel[1] * p_rel[1])
+        if twice_distance:
+            back = (
+                p_rel[0] * self.width / twice_distance,
+                p_rel[1] * self.width / twice_distance,
+            )
+            back_sum, back_diff = back[0] + back[1], back[0] - back[1]
+        else:
+            back_sum, back_diff = -self.width / 2, self.width / 2
+        # left is aka: (back[1], -back[0])
+        # right is aka: (-back[1], back[0])
+        return [
+            (self.p1[0] + back_sum, self.p1[1] - back_diff),
+            (self.p1[0] + back_diff, self.p1[1] + back_sum),
+            (self.p2[0] - back_sum, self.p2[1] + back_diff),
+            (self.p2[0] - back_diff, self.p2[1] - back_sum),
+        ]
+
+    def fit(self, pos, unit):
+        if type(self) != StrokeSquareLine:
+            raise NotImplementedError
+        return StrokeSquareLine(
+            (pos[0] + self.p1[0] * unit[0], pos[1] + self.p1[1] * unit[1]),
+            (pos[0] + self.p2[0] * unit[0], pos[1] + self.p2[1] * unit[1]),
+            self.width * max(unit),
+        )
diff --git a/vectors/vectors.py b/vectors/vectors.py
deleted file mode 100644 (file)
index b3bf98f..0000000
+++ /dev/null
@@ -1,305 +0,0 @@
-from itertools import chain
-from math import acos, atan2, ceil, cos, floor, pi, sin, sqrt, tau
-
-import pygame
-
-
-class Shape:
-    def fit(self, pos, unit):
-        raise NotImplementedError
-
-    def draw(self, surf, color):
-        pass
-
-
-class Rect(Shape):
-    def __init__(self, *args):
-        if len(args) == 2:
-            args = tuple(chain.from_iterable(args))
-        self.left, self.top, self.width, self.height = args
-
-    def fit(self, pos, unit):
-        klass = type(self)
-        if klass not in (Rect, Ellipse):
-            raise NotImplementedError
-        return klass(
-            (round(pos[0] + self.left * unit[0]), round(pos[1] + self.top * unit[1])),
-            (round(self.width * unit[0]), round(self.height * unit[1])),
-        )
-
-    def draw(self, surf, color):
-        pygame.draw.rect(
-            surf, color, pygame.Rect(self.left, self.top, self.width, self.height)
-        )
-
-
-class Ellipse(Rect):
-    def draw(self, surf, color):
-        pygame.draw.ellipse(
-            surf, color, pygame.Rect(self.left, self.top, self.width, self.height)
-        )
-
-
-class Polygon(Shape):
-    def __init__(self, points):
-        self.points = list(points)
-
-    def fit(self, pos, unit):
-        if type(self) != Polygon:
-            raise NotImplementedError
-        return Polygon(
-            [
-                (round(pos[0] + point[0] * unit[0]), round(pos[1] + point[1] * unit[1]))
-                for point in self.points
-            ]
-        )
-
-    def draw(self, surf, color):
-        pygame.draw.polygon(surf, color, self.points)
-
-
-class Circle(Shape):
-    def __init__(self, center, radius):
-        self.center = center
-        self.radius = radius
-
-    def fit(self, pos, unit):
-        if type(self) != Circle:
-            raise NotImplementedError
-        if unit[0] == unit[1]:
-            return Circle(
-                (
-                    pos[0] + self.center[0] * unit[0],
-                    pos[1] + self.center[1] * unit[1],
-                ),
-                self.radius * unit[0],
-            )
-        return Ellipse(
-            (
-                round(pos[0] + (self.center[0] - self.radius) * unit[0]),
-                round(pos[1] + (self.center[1] - self.radius) * unit[1]),
-            ),
-            (round(self.radius * 2 * unit[0]), round(self.radius * 2 * unit[1])),
-        )
-
-    def draw(self, surf, color):
-        pygame.draw.circle(surf, color, self.center, self.radius)
-
-
-class StrokeSquareLine(Polygon):
-    """
-    Rotate a rectangle along the direction in which we're drawing.
-    """
-    def __init__(self, p1, p2, width):
-        self.p1 = p1
-        self.p2 = p2
-        self.width = width
-        super().__init__(self.get_points())
-
-    def get_points(self):
-        p_rel = (self.p1[0] - self.p2[0], self.p1[1] - self.p2[1])
-        twice_distance = 2 * sqrt(p_rel[0] * p_rel[0] + p_rel[1] * p_rel[1])
-        if twice_distance:
-            back = (
-                p_rel[0] * self.width / twice_distance,
-                p_rel[1] * self.width / twice_distance,
-            )
-            back_sum, back_diff = back[0] + back[1], back[0] - back[1]
-        else:
-            back_sum, back_diff = -self.width / 2, self.width / 2
-        # left is aka: (back[1], -back[0])
-        # right is aka: (-back[1], back[0])
-        return [
-            (self.p1[0] + back_sum, self.p1[1] - back_diff),
-            (self.p1[0] + back_diff, self.p1[1] + back_sum),
-            (self.p2[0] - back_sum, self.p2[1] + back_diff),
-            (self.p2[0] - back_diff, self.p2[1] - back_sum),
-        ]
-
-    def fit(self, pos, unit):
-        if type(self) != StrokeSquareLine:
-            raise NotImplementedError
-        return StrokeSquareLine(
-            (pos[0] + self.p1[0] * unit[0], pos[1] + self.p1[1] * unit[1]),
-            (pos[0] + self.p2[0] * unit[0], pos[1] + self.p2[1] * unit[1]),
-            self.width * max(unit),
-        )
-
-
-class StrokeRoundLine(Polygon):
-    """
-    Enclose a rectangle fitted between two points with a regular, non-rotated n-gon
-    that should be visually indistinguishable with a half circle
-    """
-    def __init__(self, p1, p2, width):
-        self.p1 = p1
-        self.p2 = p2
-        self.width = width
-        super().__init__(self.get_points())
-
-    def get_points(self):
-        radius = self.width / 2
-        num_vertices = self.corners_needed_to_appear_round(radius)
-        delta = (self.p1[0] - self.p2[0], self.p1[1] - self.p2[1])
-        distance = sqrt(delta[0] * delta[0] + delta[1] * delta[1])
-        points = []
-        if distance == 0:
-            initial_corner = opposing_corner = num_vertices
-            back = (0, 0)
-        else:
-            initial_corner = ceil(
-                atan2(-delta[0], delta[1]) * num_vertices / tau
-            )
-            opposing_corner = (
-                floor(atan2(delta[0], -delta[1]) * num_vertices / tau) - initial_corner
-            ) % num_vertices
-            back = (delta[0] * radius / distance, delta[1] * radius / distance)
-            points.extend(
-                (
-                    (self.p2[0] + back[1], self.p2[1] - back[0]),
-                    (self.p1[0] + back[1], self.p1[1] - back[0]),
-                )
-            )
-        p = self.p1
-        for i in range(num_vertices):
-            angle = (i + initial_corner) * tau / num_vertices
-            points.append((p[0] + cos(angle) * radius, p[1] + sin(angle) * radius))
-            if i == opposing_corner:
-                points.extend(
-                    (
-                        (self.p1[0] - back[1], self.p1[1] + back[0]),
-                        (self.p2[0] - back[1], self.p2[1] + back[0]),
-                    )
-                )
-                p = self.p2
-        return points
-
-    @staticmethod
-    def corners_needed_to_appear_round(radius, threshold=.5):
-        return ceil(pi / acos(1 - threshold / radius))
-
-    def fit(self, pos, unit):
-        if type(self) != StrokeRoundLine:
-            raise NotImplementedError
-        return StrokeRoundLine(
-            (pos[0] + self.p1[0] * unit[0], pos[1] + self.p1[1] * unit[1]),
-            (pos[0] + self.p2[0] * unit[0], pos[1] + self.p2[1] * unit[1]),
-            self.width * max(unit),
-        )
-
-
-class Shapes(Shape):
-    def __init__(self, shapes):
-        self.shapes = list(shapes)
-
-    def fit(self, pos, unit):
-        if type(self) != Shapes:
-            raise NotImplementedError
-        return Shapes([s.fit(pos, unit) for s in self.shapes])
-
-    def draw(self, surf, color):
-        for shape in self.shapes:
-            shape.draw(surf, color)
-
-
-class StrokePath:
-    def __init__(self, points, closed, width):
-        self.points = list(points)
-        self.closed = bool(closed)
-        self.width = width
-
-    @property
-    def shapes(self):
-        if not self.points:
-            return
-        if self.closed:
-            yield StrokeRoundLine(
-                self.points[-1],
-                self.points[0],
-                self.width,
-            )
-        iter_points = iter(self.points)
-        old = next(iter_points)
-        for new in iter_points:
-            yield StrokeRoundLine(old, new, self.width)
-            old = new
-
-    def fit(self, pos, unit):
-        if type(self) != StrokePath:
-            raise NotImplementedError
-        return StrokePath(
-            [
-                (pos[0] + point[0] * unit[0], pos[1] + point[1] * unit[1])
-                for point in self.points
-            ],
-            self.closed,
-            self.width,
-        )
-
-    draw = Shapes.draw
-
-
-class StrokeCircle(StrokePath):
-    def __init__(self, center, radius, width):
-        self.center = center
-        self.radius = radius
-        super().__init__([], True, width)
-        self.points.extend(self.get_points())
-
-    def get_points(self):
-        num_vertices = StrokeRoundLine.corners_needed_to_appear_round(self.radius)
-        return [
-            (
-                self.center[0] + cos(a) * self.radius,
-                self.center[1] + sin(a) * self.radius,
-            )
-            for a in (tau * i / num_vertices for i in range(num_vertices))
-        ]
-
-    def fit(self, pos, unit):
-        if type(self) != StrokeCircle:
-            raise NotImplementedError
-        return StrokeCircle(
-            (pos[0] + self.center[0] * unit[0], pos[1] + self.center[1] * unit[1]),
-            self.radius * max(unit),
-            self.width * max(unit),
-        )
-
-
-class StrokeCircleSegment(StrokeCircle):
-    def __init__(self, center, radius, start_angle, end_angle, width):
-        self.start_angle = start_angle
-        self.end_angle = end_angle
-        super().__init__(center, radius, width)
-        self.closed = False
-
-    def get_points(self):
-        return [
-            (self.center[0] + cos(a) * self.radius, self.center[1] + sin(a) * self.radius)
-            for a in self.get_angle_segments(
-                self.start_angle,
-                self.end_angle,
-                StrokeRoundLine.corners_needed_to_appear_round((self.radius + self.width / 2)),
-            )
-        ]
-
-    def get_angle_segments(self, start_angle, end_angle, num_vertices):
-        start_angle, end_angle = sorted((start_angle, end_angle))
-        diff_angle = end_angle - start_angle
-        for i in range(num_vertices):
-            a = tau * i / num_vertices
-            if a >= diff_angle:
-                yield end_angle
-                break
-            yield start_angle + a
-
-    def fit(self, pos, unit):
-        if type(self) != StrokeCircleSegment:
-            raise NotImplementedError
-        return StrokeCircleSegment(
-            (pos[0] + self.center[0] * unit[0], pos[1] + self.center[1] * unit[1]),
-            self.radius * max(unit),
-            self.start_angle,
-            self.end_angle,
-            self.width * max(unit),
-        )
index a9c7c6ddc80f2ab4cdee5393a2718d0550b4df3a..4d7be4b01d9292e26d546adb96ada221d1ca3cb1 100644 (file)
@@ -1,6 +1,6 @@
 from math import cos, pi, sin, tau
 
-from vectors.vectors import (
+from vectors import (
     Polygon, Rect, Shapes, StrokeCircleSegment, StrokeRoundLine, StrokeSquareLine
 )
 
index ff672925c0013e9389b4f68989e912a029ed1a79..b9500631ce41be035bdac83eebc33587f864dbf2 100644 (file)
@@ -3,7 +3,7 @@ from functools import partial
 import pygame
 
 from .bluetooth import BluetoothConf
-from ui.ui import Button, FPSWidget, Icon, IconButton, Root, Switch
+from ui import Button, FPSWidget, Icon, IconButton, Root, Switch
 from .shapes import (
     bluetooth,
     laptop_double,