From ca58e873c4645172534bc950ccb22e638032757b Mon Sep 17 00:00:00 2001 From: Margaret <62753112+meg-1@users.noreply.github.com> Date: Fri, 3 Nov 2023 17:36:33 +0200 Subject: [PATCH 01/13] adding a geometry module --- geometry/__init__.py | 0 geometry/angles/__init__.py | 0 geometry/angles/angle.py | 10 +++ geometry/coordinate_plane/__init__.py | 0 geometry/lines/__init__.py | 0 geometry/shapes/__init__.py | 0 geometry/shapes/ellipses/__init__.py | 0 geometry/shapes/ellipses/circle.py | 64 +++++++++++++++++ geometry/shapes/ellipses/ellipse.py | 37 ++++++++++ geometry/shapes/polygon/__init__.py | 0 geometry/shapes/polygon/polygon.py | 68 +++++++++++++++++++ geometry/shapes/polygon/rectangle.py | 42 ++++++++++++ geometry/shapes/polygon/square.py | 35 ++++++++++ geometry/shapes/shape.py | 30 ++++++++ geometry/shapes/shape_types/__init__.py | 0 geometry/shapes/shape_types/closed_shapes.py | 27 ++++++++ .../shape_types/intersecting_self_shapes.py | 27 ++++++++ geometry/shapes/shape_types/open_shapes.py | 19 ++++++ geometry/shapes/side.py | 17 +++++ 19 files changed, 376 insertions(+) create mode 100644 geometry/__init__.py create mode 100644 geometry/angles/__init__.py create mode 100644 geometry/angles/angle.py create mode 100644 geometry/coordinate_plane/__init__.py create mode 100644 geometry/lines/__init__.py create mode 100644 geometry/shapes/__init__.py create mode 100644 geometry/shapes/ellipses/__init__.py create mode 100644 geometry/shapes/ellipses/circle.py create mode 100644 geometry/shapes/ellipses/ellipse.py create mode 100644 geometry/shapes/polygon/__init__.py create mode 100644 geometry/shapes/polygon/polygon.py create mode 100644 geometry/shapes/polygon/rectangle.py create mode 100644 geometry/shapes/polygon/square.py create mode 100644 geometry/shapes/shape.py create mode 100644 geometry/shapes/shape_types/__init__.py create mode 100644 geometry/shapes/shape_types/closed_shapes.py create mode 100644 geometry/shapes/shape_types/intersecting_self_shapes.py create mode 100644 geometry/shapes/shape_types/open_shapes.py create mode 100644 geometry/shapes/side.py diff --git a/geometry/__init__.py b/geometry/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/geometry/angles/__init__.py b/geometry/angles/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/geometry/angles/angle.py b/geometry/angles/angle.py new file mode 100644 index 000000000000..457f273fbbe5 --- /dev/null +++ b/geometry/angles/angle.py @@ -0,0 +1,10 @@ +from dataclasses import dataclass + + +@dataclass +class Angle: + """ + representation of an Angle in degrees (unit of measurement) + """ + + degrees: float diff --git a/geometry/coordinate_plane/__init__.py b/geometry/coordinate_plane/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/geometry/lines/__init__.py b/geometry/lines/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/geometry/shapes/__init__.py b/geometry/shapes/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/geometry/shapes/ellipses/__init__.py b/geometry/shapes/ellipses/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/geometry/shapes/ellipses/circle.py b/geometry/shapes/ellipses/circle.py new file mode 100644 index 000000000000..af27887d67e4 --- /dev/null +++ b/geometry/shapes/ellipses/circle.py @@ -0,0 +1,64 @@ +import math + +from geometry.shapes.shape_types.closed_shapes import ClosedShape + + +class Circle(ClosedShape): + + """ + a structure which represents a + geometrical circle on a 2D surface + + >>> circle_one = Circle(5) + >>> circle_one.get_diameter() + 10 + >>> circle_one.perimeter() + 31.41592653589793 + >>> circle_one.is_similar(None) + Traceback (most recent call last): + NotImplementedError: Not Implemented + >>> circle_one.split() + Traceback (most recent call last): + NotImplementedError: Not Implemented + >>> circle_one.max_parts(54) + 1486.0 + >>> circle_one.max_parts(7) + 29.0 + >>> circle_one.max_parts(22.5) + 265.375 + >>> circle_one.max_parts(-222) + -1 + >>> circle_one.max_parts("-222") + Traceback (most recent call last): + TypeError: num_cuts must be a numeric value. + """ + + def __init__(self, radius): + self.radius = radius + self.origin = 0 + + def get_diameter(self): + return self.radius * 2 + + def perimeter(self): + return 2 * math.pi * self.radius + + def area(self): + return math.pi * (self.radius**2) + + def is_similar(self, compared_shape): + raise NotImplementedError("Not Implemented") + + def split(self): + raise NotImplementedError("Not Implemented") + + def max_parts(self, num_cuts: float) -> float: + """ + returns the maximum amount of + parts a circle can be divided + by if cut 'num_cuts' times + """ + + if not isinstance(num_cuts, (int, float)): + raise TypeError("num_cuts must be a numeric value.") + return ((num_cuts + 2 + num_cuts**2) * 0.5) if num_cuts >= 0 else -1 diff --git a/geometry/shapes/ellipses/ellipse.py b/geometry/shapes/ellipses/ellipse.py new file mode 100644 index 000000000000..17d83bd1d1b0 --- /dev/null +++ b/geometry/shapes/ellipses/ellipse.py @@ -0,0 +1,37 @@ +import math + +from geometry.shapes.shape_types.closed_shapes import ClosedShape + + +class Ellipse(ClosedShape): + + """ + a structure which represents a + geometrical ellipse on a 2D surface + + >>> ellipse_one = Ellipse(5, 10) + >>> ellipse_one.perimeter() + 47.12388980384689 + >>> ellipse_one.is_similar(None) + Traceback (most recent call last): + NotImplementedError: Not Implemented + >>> ellipse_one.split() + Traceback (most recent call last): + NotImplementedError: Not Implemented + """ + + def __init__(self, major_radius, minor_radius): + self.major_radius: float = major_radius + self.minor_radius: float = minor_radius + + def perimeter(self): + return math.pi * (self.major_radius + self.minor_radius) + + def area(self): + return math.pi * self.major_radius * self.minor_radius + + def is_similar(self, compared_shape): + raise NotImplementedError("Not Implemented") + + def split(self): + raise NotImplementedError("Not Implemented") diff --git a/geometry/shapes/polygon/__init__.py b/geometry/shapes/polygon/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/geometry/shapes/polygon/polygon.py b/geometry/shapes/polygon/polygon.py new file mode 100644 index 000000000000..836a573c6f5b --- /dev/null +++ b/geometry/shapes/polygon/polygon.py @@ -0,0 +1,68 @@ +from geometry.shapes.shape_types.closed_shapes import ClosedShape +from geometry.shapes.shape_types.intersecting_self_shapes import IntersectSelfShape +from geometry.shapes.side import Side + + +class Polygon(ClosedShape, IntersectSelfShape): + + """ + an abstract class which represents a + set of polygons on a 2D surface + + >>> from geometry.angles.angle import Angle + >>> polygon_one = Polygon() + >>> side_length = 15 + >>> angle_degrees = 60 + >>> side_one = Side([], Angle(angle_degrees), side_length) + >>> side_two = Side([], Angle(angle_degrees), side_length) + >>> side_three = Side([], Angle(angle_degrees), side_length) + >>> side_one.adjacent_sides.append(side_two) + >>> side_one.adjacent_sides.append(side_three) + >>> side_two.adjacent_sides.append(side_three) + >>> side_two.adjacent_sides.append(side_one) + >>> side_three.adjacent_sides.append(side_one) + >>> side_three.adjacent_sides.append(side_two) + >>> polygon_one.add_side(side_one) + >>> polygon_one.add_side(side_two) + >>> polygon_one.add_side(side_three) + >>> polygon_one.set_side(0, side_one) + >>> polygon_one.set_side(1, side_two) + >>> polygon_one.set_side(2, side_three) + >>> side_one_data = polygon_one.get_side(0) + >>> print(side_one_data.length) + 15 + >>> print(side_one_data.angle.degrees) + 60 + >>> polygon_one.area() + + >>> polygon_one.is_similar(None) + + >>> polygon_one.split() + + >>> polygon_one.perimeter() + + """ + + def __init__(self): + self.sides: list[Side] = [] + + def get_side(self, index): + return self.sides[index] + + def set_side(self, index, side): + self.sides[index] = side + + def add_side(self, side): + self.sides.append(side) + + def area(self): + pass + + def is_similar(self, compared_shape): + pass + + def perimeter(self): + pass + + def split(self): + pass diff --git a/geometry/shapes/polygon/rectangle.py b/geometry/shapes/polygon/rectangle.py new file mode 100644 index 000000000000..d338253c9621 --- /dev/null +++ b/geometry/shapes/polygon/rectangle.py @@ -0,0 +1,42 @@ +from geometry.angles.angle import Angle +from geometry.shapes.side import Side + +from .polygon import Polygon + + +class Rectangle(Polygon): + """ + a structure which represents a + geometrical rectangle on a 2D surface + + >>> rectangle_one = Rectangle(5, 10) + >>> rectangle_one.perimeter() + 30 + >>> rectangle_one.area() + 50 + >>> rectangle_one.is_similar(None) + Traceback (most recent call last): + NotImplementedError: Not Implemented + >>> rectangle_one.split() + Traceback (most recent call last): + NotImplementedError: Not Implemented + """ + + def __init__(self, short_side_length, long_side_length): + super().__init__() + self.short_side = Side([], Angle(90), short_side_length) + self.long_side = Side([], Angle(90), long_side_length) + super().add_side(self.short_side) + super().add_side(self.long_side) + + def perimeter(self): + return (self.short_side.length + self.long_side.length) * 2 + + def area(self): + return self.short_side.length * self.long_side.length + + def is_similar(self, compared_shape): + raise NotImplementedError("Not Implemented") + + def split(self): + raise NotImplementedError("Not Implemented") diff --git a/geometry/shapes/polygon/square.py b/geometry/shapes/polygon/square.py new file mode 100644 index 000000000000..01699ac60f2e --- /dev/null +++ b/geometry/shapes/polygon/square.py @@ -0,0 +1,35 @@ +from .rectangle import Rectangle + + +class Square(Rectangle): + """ + a structure which represents a + geometrical square on a 2D surface + + >>> square_one = Square(5) + >>> square_one.perimeter() + 20 + >>> square_one.area() + 25 + >>> square_one.is_similar(None) + Traceback (most recent call last): + NotImplementedError: Not Implemented + >>> square_one.split() + Traceback (most recent call last): + NotImplementedError: Not Implemented + """ + + def __init__(self, side_length): + super().__init__(side_length, side_length) + + def perimeter(self): + return super().perimeter() + + def area(self): + return super().area() + + def is_similar(self, compared_shape): + raise NotImplementedError("Not Implemented") + + def split(self): + raise NotImplementedError("Not Implemented") diff --git a/geometry/shapes/shape.py b/geometry/shapes/shape.py new file mode 100644 index 000000000000..fde61f8c7ef4 --- /dev/null +++ b/geometry/shapes/shape.py @@ -0,0 +1,30 @@ +from abc import ABC, abstractmethod + + +class Shape(ABC): + + """ + interface which represents a geometrical shape + at a global level + """ + + @abstractmethod + def is_similar(self, compared_shape): + """ + a method for comparing with another shape, + which also implements this interface + """ + + @abstractmethod + def split(self): + """ + a method for splitting a shape + into a certain quantity of pieces, + following a specific algorithm + """ + + """ + to do: create a factory method for creating a specific shape + @abstractmethod + def create_shape(self): + pass""" diff --git a/geometry/shapes/shape_types/__init__.py b/geometry/shapes/shape_types/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/geometry/shapes/shape_types/closed_shapes.py b/geometry/shapes/shape_types/closed_shapes.py new file mode 100644 index 000000000000..aea9633bc76f --- /dev/null +++ b/geometry/shapes/shape_types/closed_shapes.py @@ -0,0 +1,27 @@ +from abc import ABC, abstractmethod + +from geometry.shapes.shape import Shape + + +class ClosedShape(Shape, ABC): + """ + an interface which represents shapes + that start and end at the same point [closed shape] + more info: https://en.wikipedia.org/wiki/Polygon + """ + + @abstractmethod + def perimeter(self): + pass + + @abstractmethod + def area(self): + pass + + @abstractmethod + def is_similar(self, compared_shape): + pass + + @abstractmethod + def split(self): + pass diff --git a/geometry/shapes/shape_types/intersecting_self_shapes.py b/geometry/shapes/shape_types/intersecting_self_shapes.py new file mode 100644 index 000000000000..18ec6715f994 --- /dev/null +++ b/geometry/shapes/shape_types/intersecting_self_shapes.py @@ -0,0 +1,27 @@ +from abc import ABC, abstractmethod + +from geometry.shapes.shape import Shape + + +class IntersectSelfShape(Shape, ABC): + """ + an interface which represents polygons + some of whose edges cross each other [self intersecting shapes] + more info: https://en.wikipedia.org/wiki/Polygon + """ + + @abstractmethod + def perimeter(self): + pass + + @abstractmethod + def area(self): + pass + + @abstractmethod + def is_similar(self, compared_shape): + pass + + @abstractmethod + def split(self): + pass diff --git a/geometry/shapes/shape_types/open_shapes.py b/geometry/shapes/shape_types/open_shapes.py new file mode 100644 index 000000000000..959677182ec5 --- /dev/null +++ b/geometry/shapes/shape_types/open_shapes.py @@ -0,0 +1,19 @@ +from abc import ABC, abstractmethod + +from geometry.shapes.shape import Shape + + +class OpenShape(Shape, ABC): + """ + an interface which represents shapes or figures + with different starting and ending points [open shapes] + more info: https://en.wikipedia.org/wiki/Polygon + """ + + @abstractmethod + def is_similar(self, compared_shape): + pass + + @abstractmethod + def split(self): + pass diff --git a/geometry/shapes/side.py b/geometry/shapes/side.py new file mode 100644 index 000000000000..e09fa21226af --- /dev/null +++ b/geometry/shapes/side.py @@ -0,0 +1,17 @@ +from dataclasses import dataclass + +from geometry.angles.angle import Angle + + +@dataclass +class Side: + + """ + represents a side of a shape [such as polygon, e.t.c.] + adjacent_sides: a list of sides which are adjacent to the current side + angle: the angle between adjacent sides + """ + + adjacent_sides: list[float] + angle: Angle + length: float From e3fba5a15764c4971ce0a4783ef2dff840dd493a Mon Sep 17 00:00:00 2001 From: Margaret <62753112+meg-1@users.noreply.github.com> Date: Wed, 15 Nov 2023 17:54:12 +0200 Subject: [PATCH 02/13] fixing errors and adding type hints --- geometry/angles/angles/__init__.py | 0 geometry/angles/angles/angle.py | 10 ++++++++++ geometry/angles/coordinate_plane/__init__.py | 0 geometry/angles/lines/__init__.py | 0 geometry/shapes/ellipses/circle.py | 12 ++++++------ geometry/shapes/ellipses/ellipse.py | 10 +++++----- geometry/shapes/polygon/polygon.py | 19 +++++++++++-------- geometry/shapes/polygon/rectangle.py | 10 +++++----- geometry/shapes/polygon/square.py | 10 +++++----- geometry/shapes/shape.py | 14 +++++++++++--- geometry/shapes/shape_types/closed_shapes.py | 8 ++++---- .../shape_types/intersecting_self_shapes.py | 8 ++++---- geometry/shapes/shape_types/open_shapes.py | 4 ++-- 13 files changed, 63 insertions(+), 42 deletions(-) create mode 100644 geometry/angles/angles/__init__.py create mode 100644 geometry/angles/angles/angle.py create mode 100644 geometry/angles/coordinate_plane/__init__.py create mode 100644 geometry/angles/lines/__init__.py diff --git a/geometry/angles/angles/__init__.py b/geometry/angles/angles/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/geometry/angles/angles/angle.py b/geometry/angles/angles/angle.py new file mode 100644 index 000000000000..457f273fbbe5 --- /dev/null +++ b/geometry/angles/angles/angle.py @@ -0,0 +1,10 @@ +from dataclasses import dataclass + + +@dataclass +class Angle: + """ + representation of an Angle in degrees (unit of measurement) + """ + + degrees: float diff --git a/geometry/angles/coordinate_plane/__init__.py b/geometry/angles/coordinate_plane/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/geometry/angles/lines/__init__.py b/geometry/angles/lines/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/geometry/shapes/ellipses/circle.py b/geometry/shapes/ellipses/circle.py index af27887d67e4..344d72f06979 100644 --- a/geometry/shapes/ellipses/circle.py +++ b/geometry/shapes/ellipses/circle.py @@ -33,23 +33,23 @@ class Circle(ClosedShape): TypeError: num_cuts must be a numeric value. """ - def __init__(self, radius): + def __init__(self, radius: float) -> None: self.radius = radius self.origin = 0 - def get_diameter(self): + def get_diameter(self) -> float: return self.radius * 2 - def perimeter(self): + def perimeter(self) -> float: return 2 * math.pi * self.radius - def area(self): + def area(self) -> float: return math.pi * (self.radius**2) - def is_similar(self, compared_shape): + def is_similar(self, compared_shape: ClosedShape) -> bool: raise NotImplementedError("Not Implemented") - def split(self): + def split(self) -> float: raise NotImplementedError("Not Implemented") def max_parts(self, num_cuts: float) -> float: diff --git a/geometry/shapes/ellipses/ellipse.py b/geometry/shapes/ellipses/ellipse.py index 17d83bd1d1b0..10dae03f11c1 100644 --- a/geometry/shapes/ellipses/ellipse.py +++ b/geometry/shapes/ellipses/ellipse.py @@ -20,18 +20,18 @@ class Ellipse(ClosedShape): NotImplementedError: Not Implemented """ - def __init__(self, major_radius, minor_radius): + def __init__(self, major_radius: float, minor_radius: float) -> None: self.major_radius: float = major_radius self.minor_radius: float = minor_radius - def perimeter(self): + def perimeter(self) -> float: return math.pi * (self.major_radius + self.minor_radius) - def area(self): + def area(self) -> float: return math.pi * self.major_radius * self.minor_radius - def is_similar(self, compared_shape): + def is_similar(self, compared_shape: ClosedShape) -> bool: raise NotImplementedError("Not Implemented") - def split(self): + def split(self) -> float: raise NotImplementedError("Not Implemented") diff --git a/geometry/shapes/polygon/polygon.py b/geometry/shapes/polygon/polygon.py index 836a573c6f5b..4206f778ffd2 100644 --- a/geometry/shapes/polygon/polygon.py +++ b/geometry/shapes/polygon/polygon.py @@ -1,6 +1,9 @@ from geometry.shapes.shape_types.closed_shapes import ClosedShape from geometry.shapes.shape_types.intersecting_self_shapes import IntersectSelfShape from geometry.shapes.side import Side +from typing import TypeVar + +PolygonType = TypeVar("PolygonType", bound="Polygon") class Polygon(ClosedShape, IntersectSelfShape): @@ -43,26 +46,26 @@ class Polygon(ClosedShape, IntersectSelfShape): """ - def __init__(self): + def __init__(self) -> None: self.sides: list[Side] = [] - def get_side(self, index): + def get_side(self, index: int) -> Side: return self.sides[index] - def set_side(self, index, side): + def set_side(self, index: int, side: Side) -> None: self.sides[index] = side - def add_side(self, side): + def add_side(self, side: Side) -> None: self.sides.append(side) - def area(self): + def area(self) -> float: pass - def is_similar(self, compared_shape): + def is_similar(self, compared_shape: PolygonType) -> bool: pass - def perimeter(self): + def perimeter(self) -> float: pass - def split(self): + def split(self) -> float: pass diff --git a/geometry/shapes/polygon/rectangle.py b/geometry/shapes/polygon/rectangle.py index d338253c9621..7fbd609c50aa 100644 --- a/geometry/shapes/polygon/rectangle.py +++ b/geometry/shapes/polygon/rectangle.py @@ -22,21 +22,21 @@ class Rectangle(Polygon): NotImplementedError: Not Implemented """ - def __init__(self, short_side_length, long_side_length): + def __init__(self, short_side_length: float, long_side_length: float) -> None: super().__init__() self.short_side = Side([], Angle(90), short_side_length) self.long_side = Side([], Angle(90), long_side_length) super().add_side(self.short_side) super().add_side(self.long_side) - def perimeter(self): + def perimeter(self) -> float: return (self.short_side.length + self.long_side.length) * 2 - def area(self): + def area(self) -> float: return self.short_side.length * self.long_side.length - def is_similar(self, compared_shape): + def is_similar(self, compared_shape: Polygon) -> bool: raise NotImplementedError("Not Implemented") - def split(self): + def split(self) -> float: raise NotImplementedError("Not Implemented") diff --git a/geometry/shapes/polygon/square.py b/geometry/shapes/polygon/square.py index 01699ac60f2e..e2444118e477 100644 --- a/geometry/shapes/polygon/square.py +++ b/geometry/shapes/polygon/square.py @@ -19,17 +19,17 @@ class Square(Rectangle): NotImplementedError: Not Implemented """ - def __init__(self, side_length): + def __init__(self, side_length: float) -> None: super().__init__(side_length, side_length) - def perimeter(self): + def perimeter(self) -> float: return super().perimeter() - def area(self): + def area(self) -> float: return super().area() - def is_similar(self, compared_shape): + def is_similar(self, compared_shape: Rectangle) -> bool: raise NotImplementedError("Not Implemented") - def split(self): + def split(self) -> float: raise NotImplementedError("Not Implemented") diff --git a/geometry/shapes/shape.py b/geometry/shapes/shape.py index fde61f8c7ef4..e1d2e5834d77 100644 --- a/geometry/shapes/shape.py +++ b/geometry/shapes/shape.py @@ -1,4 +1,7 @@ from abc import ABC, abstractmethod +from typing import TypeVar + +ShapeType = TypeVar("ShapeType", bound="Shape") class Shape(ABC): @@ -9,18 +12,23 @@ class Shape(ABC): """ @abstractmethod - def is_similar(self, compared_shape): + def is_similar(self, compared_shape: ShapeType) -> bool: """ a method for comparing with another shape, which also implements this interface """ @abstractmethod - def split(self): + def split(self) -> float: """ a method for splitting a shape into a certain quantity of pieces, - following a specific algorithm + following a specific algorithm which returns + the amount of pieces after splitting the shape + + note: in the future, a separate class might be created, + which will represent a certain part of a shape, because of that + the return type of this method might change """ """ diff --git a/geometry/shapes/shape_types/closed_shapes.py b/geometry/shapes/shape_types/closed_shapes.py index aea9633bc76f..808a60ba7741 100644 --- a/geometry/shapes/shape_types/closed_shapes.py +++ b/geometry/shapes/shape_types/closed_shapes.py @@ -11,17 +11,17 @@ class ClosedShape(Shape, ABC): """ @abstractmethod - def perimeter(self): + def perimeter(self) -> float: pass @abstractmethod - def area(self): + def area(self) -> float: pass @abstractmethod - def is_similar(self, compared_shape): + def is_similar(self, compared_shape: Shape) -> bool: pass @abstractmethod - def split(self): + def split(self) -> float: pass diff --git a/geometry/shapes/shape_types/intersecting_self_shapes.py b/geometry/shapes/shape_types/intersecting_self_shapes.py index 18ec6715f994..5701b284425f 100644 --- a/geometry/shapes/shape_types/intersecting_self_shapes.py +++ b/geometry/shapes/shape_types/intersecting_self_shapes.py @@ -11,17 +11,17 @@ class IntersectSelfShape(Shape, ABC): """ @abstractmethod - def perimeter(self): + def perimeter(self) -> float: pass @abstractmethod - def area(self): + def area(self) -> float: pass @abstractmethod - def is_similar(self, compared_shape): + def is_similar(self, compared_shape: Shape) -> bool: pass @abstractmethod - def split(self): + def split(self) -> float: pass diff --git a/geometry/shapes/shape_types/open_shapes.py b/geometry/shapes/shape_types/open_shapes.py index 959677182ec5..5361a404b235 100644 --- a/geometry/shapes/shape_types/open_shapes.py +++ b/geometry/shapes/shape_types/open_shapes.py @@ -11,9 +11,9 @@ class OpenShape(Shape, ABC): """ @abstractmethod - def is_similar(self, compared_shape): + def is_similar(self, compared_shape: Shape) -> bool: pass @abstractmethod - def split(self): + def split(self) -> float: pass From e64240dcc05166a817271461dfab6c97279c67b4 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Thu, 16 Nov 2023 08:26:26 +0600 Subject: [PATCH 03/13] Create code_review_feedback.py --- geometry/code_review_feedback.py | 261 +++++++++++++++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 geometry/code_review_feedback.py diff --git a/geometry/code_review_feedback.py b/geometry/code_review_feedback.py new file mode 100644 index 000000000000..56f10fb4f9ec --- /dev/null +++ b/geometry/code_review_feedback.py @@ -0,0 +1,261 @@ +from __future__ import annotations +import math +from dataclasses import dataclass, field +from types import NoneType +from typing import Self + + +# Building block classes + + +@dataclass +class Angle: + """ + An Angle in degrees (unit of measurement) + + >>> Angle() + Angle(degrees=90) + >>> Angle(45.5) + Angle(degrees=45.5) + >>> Angle(-1) + Traceback (most recent call last): + ... + TypeError: degrees must be a numeric value between 0 and 360. + >>> Angle(361) + Traceback (most recent call last): + ... + TypeError: degrees must be a numeric value between 0 and 360. + """ + degrees: float = 90 + + def __post_init__(self) -> None: + if not isinstance(self.degrees, (int, float)) or not 0 <= self.degrees <= 360: + raise TypeError("degrees must be a numeric value between 0 and 360.") + + +@dataclass +class Side: + """ + A side of a two dimensional Shape such as Polygon, etc. + adjacent_sides: a list of sides which are adjacent to the current side + angle: the angle in degrees between each adjacent side + length: the length of the current side in lightyears + + >>> Side(5) + Side(length=5, angle=Angle(degrees=90), next_side=None) + >>> Side(5, Angle(45.6)) + Side(length=5, angle=Angle(degrees=45.6), next_side=None) + >>> Side(5, Angle(45.6), Side(1, Angle(2))) # doctest: +ELLIPSIS + Side(length=5, angle=Angle(degrees=45.6), next_side=Side(length=1, angle=Angle(d... + """ + length: float + angle: Angle = field(default_factory=Angle) + next_side: Side | None = None + + def __post_init__(self) -> None: + if not isinstance(self.length, (int, float)) or self.length <= 0: + raise TypeError("length must be a positive numeric value.") + if not isinstance(self.angle, Angle): + raise TypeError("angle must be an Angle object.") + if not isinstance(self.next_side, (Side, NoneType)): + raise TypeError("next_side must be a Side or None.") + + +@dataclass +class Ellipse: + """ + A geometric Ellipse on a 2D surface + + >>> Ellipse(5, 10) + Ellipse(major_radius=5, minor_radius=10) + >>> Ellipse(5, 10) is Ellipse(5, 10) + False + >>> Ellipse(5, 10) == Ellipse(5, 10) + True + """ + major_radius: float + minor_radius: float + + @property + def area(self) -> float: + """ + >>> Ellipse(5, 10).area + 157.07963267948966 + """ + return math.pi * self.major_radius * self.minor_radius + + @property + def perimeter(self) -> float: + """ + >>> Ellipse(5, 10).perimeter + 47.12388980384689 + """ + return math.pi * (self.major_radius + self.minor_radius) + + + +class Circle(Ellipse): + """ + A geometric Circle on a 2D surface + + >>> Circle(5) + Circle(radius=5) + >>> Circle(5) is Circle(5) + False + >>> Circle(5) == Circle(5) + True + >>> Circle(5).area + 78.53981633974483 + >>> Circle(5).perimeter + 31.41592653589793 + """ + def __init__(self, radius: float) -> None: + super().__init__(radius, radius) + self.radius = radius + + def __repr__(self) -> str: + return f"Circle(radius={self.radius})" + + @property + def diameter(self) -> float: + """ + >>> Circle(5).diameter + 10 + """ + return self.radius * 2 + + def max_parts(self, num_cuts: float) -> float: + """ + Return the maximum number of parts that circle can be divided into if cut + 'num_cuts' times. + + >>> circle = Circle(5) + >>> circle.max_parts(0) + 1.0 + >>> circle.max_parts(7) + 29.0 + >>> circle.max_parts(54) + 1486.0 + >>> circle.max_parts(22.5) + 265.375 + >>> circle.max_parts(-222) + Traceback (most recent call last): + ... + TypeError: num_cuts must be a positive numeric value. + >>> circle.max_parts("-222") + Traceback (most recent call last): + ... + TypeError: num_cuts must be a positive numeric value. + """ + if not isinstance(num_cuts, (int, float)) or num_cuts < 0: + raise TypeError("num_cuts must be a positive numeric value.") + return (num_cuts + 2 + num_cuts**2) * 0.5 + +@dataclass +class Polygon: + """ + An abstract class which represents Polygon on a 2D surface. + + >>> Polygon() + Polygon(sides=[]) + """ + sides: list[Side] = field(default_factory=list) + + def add_side(self, side: Side) -> Self: + """ + >>> Polygon().add_side(Side(5)) + Polygon(sides=[Side(length=5, angle=Angle(degrees=90), next_side=None)]) + """ + self.sides.append(side) + return self + + def get_side(self, index: int) -> Side: + """ + >>> Polygon().get_side(0) + Traceback (most recent call last): + ... + IndexError: list index out of range + >>> Polygon().add_side(Side(5)).get_side(-1) + Side(length=5, angle=Angle(degrees=90), next_side=None) + """ + return self.sides[index] + + def set_side(self, index: int, side: Side) -> Self: + """ + >>> Polygon().set_side(0, Side(5)) + Traceback (most recent call last): + ... + IndexError: list assignment index out of range + >>> Polygon().add_side(Side(5)).set_side(0, Side(10)) + Polygon(sides=[Side(length=10, angle=Angle(degrees=90), next_side=None)]) + """ + self.sides[index] = side + return self + +class Rectangle(Polygon): + """ + A geometric rectangle on a 2D surface. + + >>> rectangle_one = Rectangle(5, 10) + >>> rectangle_one.perimeter() + 30 + >>> rectangle_one.area() + 50 + """ + def __init__(self, short_side_length: float, long_side_length: float) -> None: + super().__init__() + self.short_side_length = short_side_length + self.long_side_length = long_side_length + self.post_init() + + def post_init(self): + """ + >>> Rectangle(5, 10) # doctest: +NORMALIZE_WHITESPACE + Rectangle(sides=[Side(length=5, angle=Angle(degrees=90), next_side=None), + Side(length=10, angle=Angle(degrees=90), next_side=None)]) + """ + self.short_side = Side(self.short_side_length) + self.long_side = Side(self.long_side_length) + super().add_side(self.short_side) + super().add_side(self.long_side) + + def perimeter(self): + return (self.short_side.length + self.long_side.length) * 2 + + def area(self): + return self.short_side.length * self.long_side.length + +''' +@dataclass +class Square(Rectangle): + """ + a structure which represents a + geometrical square on a 2D surface + >>> square_one = Square(5) + >>> square_one.perimeter() + 20 + >>> square_one.area() + 25 + >>> square_one.is_similar(None) + Traceback (most recent call last): + NotImplementedError: Not Implemented + >>> square_one.split() + Traceback (most recent call last): + NotImplementedError: Not Implemented + """ + + def __init__(self, side_length): + super().__init__(side_length, side_length) + + def perimeter(self): + return super().perimeter() + + def area(self): + return super().area() + + def is_similar(self, compared_shape): + raise NotImplementedError("Not Implemented") + + def split(self): + raise NotImplementedError("Not Implemented") +''' From ed8d79e29658d98a94d1f1b7c8a17ae58f3920b6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 16 Nov 2023 02:27:06 +0000 Subject: [PATCH 04/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- geometry/code_review_feedback.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/geometry/code_review_feedback.py b/geometry/code_review_feedback.py index 56f10fb4f9ec..8b3a37a3ed67 100644 --- a/geometry/code_review_feedback.py +++ b/geometry/code_review_feedback.py @@ -26,6 +26,7 @@ class Angle: ... TypeError: degrees must be a numeric value between 0 and 360. """ + degrees: float = 90 def __post_init__(self) -> None: @@ -48,6 +49,7 @@ class Side: >>> Side(5, Angle(45.6), Side(1, Angle(2))) # doctest: +ELLIPSIS Side(length=5, angle=Angle(degrees=45.6), next_side=Side(length=1, angle=Angle(d... """ + length: float angle: Angle = field(default_factory=Angle) next_side: Side | None = None @@ -73,6 +75,7 @@ class Ellipse: >>> Ellipse(5, 10) == Ellipse(5, 10) True """ + major_radius: float minor_radius: float @@ -93,7 +96,6 @@ def perimeter(self) -> float: return math.pi * (self.major_radius + self.minor_radius) - class Circle(Ellipse): """ A geometric Circle on a 2D surface @@ -109,6 +111,7 @@ class Circle(Ellipse): >>> Circle(5).perimeter 31.41592653589793 """ + def __init__(self, radius: float) -> None: super().__init__(radius, radius) self.radius = radius @@ -151,6 +154,7 @@ def max_parts(self, num_cuts: float) -> float: raise TypeError("num_cuts must be a positive numeric value.") return (num_cuts + 2 + num_cuts**2) * 0.5 + @dataclass class Polygon: """ @@ -159,6 +163,7 @@ class Polygon: >>> Polygon() Polygon(sides=[]) """ + sides: list[Side] = field(default_factory=list) def add_side(self, side: Side) -> Self: @@ -192,6 +197,7 @@ def set_side(self, index: int, side: Side) -> Self: self.sides[index] = side return self + class Rectangle(Polygon): """ A geometric rectangle on a 2D surface. @@ -202,6 +208,7 @@ class Rectangle(Polygon): >>> rectangle_one.area() 50 """ + def __init__(self, short_side_length: float, long_side_length: float) -> None: super().__init__() self.short_side_length = short_side_length @@ -225,6 +232,7 @@ def perimeter(self): def area(self): return self.short_side.length * self.long_side.length + ''' @dataclass class Square(Rectangle): From 0f9720f49058e8d1803405215d8689def68d51e4 Mon Sep 17 00:00:00 2001 From: Margaret <62753112+meg-1@users.noreply.github.com> Date: Fri, 24 Nov 2023 17:26:06 +0200 Subject: [PATCH 05/13] implementing suggestions --- geometry/__init__.py | 0 geometry/angles/__init__.py | 0 geometry/angles/angle.py | 10 - geometry/angles/angles/__init__.py | 0 geometry/angles/angles/angle.py | 10 - geometry/angles/coordinate_plane/__init__.py | 0 geometry/angles/lines/__init__.py | 0 geometry/coordinate_plane/__init__.py | 0 geometry/geometry.py | 259 ++++++++++++++++++ geometry/lines/__init__.py | 0 geometry/shapes/__init__.py | 0 geometry/shapes/ellipses/__init__.py | 0 geometry/shapes/ellipses/circle.py | 64 ----- geometry/shapes/ellipses/ellipse.py | 37 --- geometry/shapes/polygon/__init__.py | 0 geometry/shapes/polygon/polygon.py | 71 ----- geometry/shapes/polygon/rectangle.py | 42 --- geometry/shapes/polygon/square.py | 35 --- geometry/shapes/shape.py | 38 --- geometry/shapes/shape_types/__init__.py | 0 geometry/shapes/shape_types/closed_shapes.py | 27 -- .../shape_types/intersecting_self_shapes.py | 27 -- geometry/shapes/shape_types/open_shapes.py | 19 -- geometry/shapes/side.py | 17 -- 24 files changed, 259 insertions(+), 397 deletions(-) delete mode 100644 geometry/__init__.py delete mode 100644 geometry/angles/__init__.py delete mode 100644 geometry/angles/angle.py delete mode 100644 geometry/angles/angles/__init__.py delete mode 100644 geometry/angles/angles/angle.py delete mode 100644 geometry/angles/coordinate_plane/__init__.py delete mode 100644 geometry/angles/lines/__init__.py delete mode 100644 geometry/coordinate_plane/__init__.py create mode 100644 geometry/geometry.py delete mode 100644 geometry/lines/__init__.py delete mode 100644 geometry/shapes/__init__.py delete mode 100644 geometry/shapes/ellipses/__init__.py delete mode 100644 geometry/shapes/ellipses/circle.py delete mode 100644 geometry/shapes/ellipses/ellipse.py delete mode 100644 geometry/shapes/polygon/__init__.py delete mode 100644 geometry/shapes/polygon/polygon.py delete mode 100644 geometry/shapes/polygon/rectangle.py delete mode 100644 geometry/shapes/polygon/square.py delete mode 100644 geometry/shapes/shape.py delete mode 100644 geometry/shapes/shape_types/__init__.py delete mode 100644 geometry/shapes/shape_types/closed_shapes.py delete mode 100644 geometry/shapes/shape_types/intersecting_self_shapes.py delete mode 100644 geometry/shapes/shape_types/open_shapes.py delete mode 100644 geometry/shapes/side.py diff --git a/geometry/__init__.py b/geometry/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/geometry/angles/__init__.py b/geometry/angles/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/geometry/angles/angle.py b/geometry/angles/angle.py deleted file mode 100644 index 457f273fbbe5..000000000000 --- a/geometry/angles/angle.py +++ /dev/null @@ -1,10 +0,0 @@ -from dataclasses import dataclass - - -@dataclass -class Angle: - """ - representation of an Angle in degrees (unit of measurement) - """ - - degrees: float diff --git a/geometry/angles/angles/__init__.py b/geometry/angles/angles/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/geometry/angles/angles/angle.py b/geometry/angles/angles/angle.py deleted file mode 100644 index 457f273fbbe5..000000000000 --- a/geometry/angles/angles/angle.py +++ /dev/null @@ -1,10 +0,0 @@ -from dataclasses import dataclass - - -@dataclass -class Angle: - """ - representation of an Angle in degrees (unit of measurement) - """ - - degrees: float diff --git a/geometry/angles/coordinate_plane/__init__.py b/geometry/angles/coordinate_plane/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/geometry/angles/lines/__init__.py b/geometry/angles/lines/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/geometry/coordinate_plane/__init__.py b/geometry/coordinate_plane/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/geometry/geometry.py b/geometry/geometry.py new file mode 100644 index 000000000000..6d1790693779 --- /dev/null +++ b/geometry/geometry.py @@ -0,0 +1,259 @@ +from __future__ import annotations +import math +from dataclasses import dataclass, field +from typing_extensions import Self + +NoneType = type(None) + +# Building block classes + + +@dataclass +class Angle: + """ + An Angle in degrees (unit of measurement) + + >>> Angle() + Angle(degrees=90) + >>> Angle(45.5) + Angle(degrees=45.5) + >>> Angle(-1) + Traceback (most recent call last): + ... + TypeError: degrees must be a numeric value between 0 and 360. + >>> Angle(361) + Traceback (most recent call last): + ... + TypeError: degrees must be a numeric value between 0 and 360. + """ + + degrees: float = 90 + + def __post_init__(self) -> None: + if not isinstance(self.degrees, (int, float)) or not 0 <= self.degrees <= 360: + raise TypeError("degrees must be a numeric value between 0 and 360.") + + +@dataclass +class Side: + """ + A side of a two dimensional Shape such as Polygon, etc. + adjacent_sides: a list of sides which are adjacent to the current side + angle: the angle in degrees between each adjacent side + length: the length of the current side in lightyears + + >>> Side(5) + Side(length=5, angle=Angle(degrees=90), next_side=None) + >>> Side(5, Angle(45.6)) + Side(length=5, angle=Angle(degrees=45.6), next_side=None) + >>> Side(5, Angle(45.6), Side(1, Angle(2))) # doctest: +ELLIPSIS + Side(length=5, angle=Angle(degrees=45.6), next_side=Side(length=1, angle=Angle(d... + """ + + length: float + angle: Angle = field(default_factory=Angle) + next_side: Side | None = None + + def __post_init__(self) -> None: + if not isinstance(self.length, (int, float)) or self.length <= 0: + raise TypeError("length must be a positive numeric value.") + if not isinstance(self.angle, Angle): + raise TypeError("angle must be an Angle object.") + if not isinstance(self.next_side, (Side, NoneType)): + raise TypeError("next_side must be a Side or None.") + + +@dataclass +class Ellipse: + """ + A geometric Ellipse on a 2D surface + + >>> Ellipse(5, 10) + Ellipse(major_radius=5, minor_radius=10) + >>> Ellipse(5, 10) is Ellipse(5, 10) + False + >>> Ellipse(5, 10) == Ellipse(5, 10) + True + """ + + major_radius: float + minor_radius: float + + @property + def area(self) -> float: + """ + >>> Ellipse(5, 10).area + 157.07963267948966 + """ + return math.pi * self.major_radius * self.minor_radius + + @property + def perimeter(self) -> float: + """ + >>> Ellipse(5, 10).perimeter + 47.12388980384689 + """ + return math.pi * (self.major_radius + self.minor_radius) + + +class Circle(Ellipse): + """ + A geometric Circle on a 2D surface + + >>> Circle(5) + Circle(radius=5) + >>> Circle(5) is Circle(5) + False + >>> Circle(5) == Circle(5) + True + >>> Circle(5).area + 78.53981633974483 + >>> Circle(5).perimeter + 31.41592653589793 + """ + + def __init__(self, radius: float) -> None: + super().__init__(radius, radius) + self.radius = radius + + def __repr__(self) -> str: + return f"Circle(radius={self.radius})" + + @property + def diameter(self) -> float: + """ + >>> Circle(5).diameter + 10 + """ + return self.radius * 2 + + def max_parts(self, num_cuts: float) -> float: + """ + Return the maximum number of parts that circle can be divided into if cut + 'num_cuts' times. + + >>> circle = Circle(5) + >>> circle.max_parts(0) + 1.0 + >>> circle.max_parts(7) + 29.0 + >>> circle.max_parts(54) + 1486.0 + >>> circle.max_parts(22.5) + 265.375 + >>> circle.max_parts(-222) + Traceback (most recent call last): + ... + TypeError: num_cuts must be a positive numeric value. + >>> circle.max_parts("-222") + Traceback (most recent call last): + ... + TypeError: num_cuts must be a positive numeric value. + """ + if not isinstance(num_cuts, (int, float)) or num_cuts < 0: + raise TypeError("num_cuts must be a positive numeric value.") + return (num_cuts + 2 + num_cuts**2) * 0.5 + + +@dataclass +class Polygon: + """ + An abstract class which represents Polygon on a 2D surface. + + >>> Polygon() + Polygon(sides=[]) + """ + + sides: list[Side] = field(default_factory=list) + + def add_side(self, side: Side) -> Self: + """ + >>> Polygon().add_side(Side(5)) + Polygon(sides=[Side(length=5, angle=Angle(degrees=90), next_side=None)]) + """ + self.sides.append(side) + return self + + def get_side(self, index: int) -> Side: + """ + >>> Polygon().get_side(0) + Traceback (most recent call last): + ... + IndexError: list index out of range + >>> Polygon().add_side(Side(5)).get_side(-1) + Side(length=5, angle=Angle(degrees=90), next_side=None) + """ + return self.sides[index] + + def set_side(self, index: int, side: Side) -> Self: + """ + >>> Polygon().set_side(0, Side(5)) + Traceback (most recent call last): + ... + IndexError: list assignment index out of range + >>> Polygon().add_side(Side(5)).set_side(0, Side(10)) + Polygon(sides=[Side(length=10, angle=Angle(degrees=90), next_side=None)]) + """ + self.sides[index] = side + return self + + +class Rectangle(Polygon): + """ + A geometric rectangle on a 2D surface. + + >>> rectangle_one = Rectangle(5, 10) + >>> rectangle_one.perimeter() + 30 + >>> rectangle_one.area() + 50 + """ + + def __init__(self, short_side_length: float, long_side_length: float) -> None: + super().__init__() + self.short_side_length = short_side_length + self.long_side_length = long_side_length + self.post_init() + + def post_init(self): + """ + >>> Rectangle(5, 10) # doctest: +NORMALIZE_WHITESPACE + Rectangle(sides=[Side(length=5, angle=Angle(degrees=90), next_side=None), + Side(length=10, angle=Angle(degrees=90), next_side=None)]) + """ + self.short_side = Side(self.short_side_length) + self.long_side = Side(self.long_side_length) + super().add_side(self.short_side) + super().add_side(self.long_side) + + def perimeter(self): + return (self.short_side.length + self.long_side.length) * 2 + + def area(self): + return self.short_side.length * self.long_side.length + + +@dataclass +class Square(Rectangle): + """ + a structure which represents a + geometrical square on a 2D surface + >>> square_one = Square(5) + >>> square_one.perimeter() + 20 + >>> square_one.area() + 25 + """ + + def __init__(self, side_length): + super().__init__(side_length, side_length) + + def perimeter(self): + return super().perimeter() + + def area(self): + return super().area() + + +if __name__ == "__main__": + __import__("doctest").testmod() diff --git a/geometry/lines/__init__.py b/geometry/lines/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/geometry/shapes/__init__.py b/geometry/shapes/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/geometry/shapes/ellipses/__init__.py b/geometry/shapes/ellipses/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/geometry/shapes/ellipses/circle.py b/geometry/shapes/ellipses/circle.py deleted file mode 100644 index 344d72f06979..000000000000 --- a/geometry/shapes/ellipses/circle.py +++ /dev/null @@ -1,64 +0,0 @@ -import math - -from geometry.shapes.shape_types.closed_shapes import ClosedShape - - -class Circle(ClosedShape): - - """ - a structure which represents a - geometrical circle on a 2D surface - - >>> circle_one = Circle(5) - >>> circle_one.get_diameter() - 10 - >>> circle_one.perimeter() - 31.41592653589793 - >>> circle_one.is_similar(None) - Traceback (most recent call last): - NotImplementedError: Not Implemented - >>> circle_one.split() - Traceback (most recent call last): - NotImplementedError: Not Implemented - >>> circle_one.max_parts(54) - 1486.0 - >>> circle_one.max_parts(7) - 29.0 - >>> circle_one.max_parts(22.5) - 265.375 - >>> circle_one.max_parts(-222) - -1 - >>> circle_one.max_parts("-222") - Traceback (most recent call last): - TypeError: num_cuts must be a numeric value. - """ - - def __init__(self, radius: float) -> None: - self.radius = radius - self.origin = 0 - - def get_diameter(self) -> float: - return self.radius * 2 - - def perimeter(self) -> float: - return 2 * math.pi * self.radius - - def area(self) -> float: - return math.pi * (self.radius**2) - - def is_similar(self, compared_shape: ClosedShape) -> bool: - raise NotImplementedError("Not Implemented") - - def split(self) -> float: - raise NotImplementedError("Not Implemented") - - def max_parts(self, num_cuts: float) -> float: - """ - returns the maximum amount of - parts a circle can be divided - by if cut 'num_cuts' times - """ - - if not isinstance(num_cuts, (int, float)): - raise TypeError("num_cuts must be a numeric value.") - return ((num_cuts + 2 + num_cuts**2) * 0.5) if num_cuts >= 0 else -1 diff --git a/geometry/shapes/ellipses/ellipse.py b/geometry/shapes/ellipses/ellipse.py deleted file mode 100644 index 10dae03f11c1..000000000000 --- a/geometry/shapes/ellipses/ellipse.py +++ /dev/null @@ -1,37 +0,0 @@ -import math - -from geometry.shapes.shape_types.closed_shapes import ClosedShape - - -class Ellipse(ClosedShape): - - """ - a structure which represents a - geometrical ellipse on a 2D surface - - >>> ellipse_one = Ellipse(5, 10) - >>> ellipse_one.perimeter() - 47.12388980384689 - >>> ellipse_one.is_similar(None) - Traceback (most recent call last): - NotImplementedError: Not Implemented - >>> ellipse_one.split() - Traceback (most recent call last): - NotImplementedError: Not Implemented - """ - - def __init__(self, major_radius: float, minor_radius: float) -> None: - self.major_radius: float = major_radius - self.minor_radius: float = minor_radius - - def perimeter(self) -> float: - return math.pi * (self.major_radius + self.minor_radius) - - def area(self) -> float: - return math.pi * self.major_radius * self.minor_radius - - def is_similar(self, compared_shape: ClosedShape) -> bool: - raise NotImplementedError("Not Implemented") - - def split(self) -> float: - raise NotImplementedError("Not Implemented") diff --git a/geometry/shapes/polygon/__init__.py b/geometry/shapes/polygon/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/geometry/shapes/polygon/polygon.py b/geometry/shapes/polygon/polygon.py deleted file mode 100644 index 4206f778ffd2..000000000000 --- a/geometry/shapes/polygon/polygon.py +++ /dev/null @@ -1,71 +0,0 @@ -from geometry.shapes.shape_types.closed_shapes import ClosedShape -from geometry.shapes.shape_types.intersecting_self_shapes import IntersectSelfShape -from geometry.shapes.side import Side -from typing import TypeVar - -PolygonType = TypeVar("PolygonType", bound="Polygon") - - -class Polygon(ClosedShape, IntersectSelfShape): - - """ - an abstract class which represents a - set of polygons on a 2D surface - - >>> from geometry.angles.angle import Angle - >>> polygon_one = Polygon() - >>> side_length = 15 - >>> angle_degrees = 60 - >>> side_one = Side([], Angle(angle_degrees), side_length) - >>> side_two = Side([], Angle(angle_degrees), side_length) - >>> side_three = Side([], Angle(angle_degrees), side_length) - >>> side_one.adjacent_sides.append(side_two) - >>> side_one.adjacent_sides.append(side_three) - >>> side_two.adjacent_sides.append(side_three) - >>> side_two.adjacent_sides.append(side_one) - >>> side_three.adjacent_sides.append(side_one) - >>> side_three.adjacent_sides.append(side_two) - >>> polygon_one.add_side(side_one) - >>> polygon_one.add_side(side_two) - >>> polygon_one.add_side(side_three) - >>> polygon_one.set_side(0, side_one) - >>> polygon_one.set_side(1, side_two) - >>> polygon_one.set_side(2, side_three) - >>> side_one_data = polygon_one.get_side(0) - >>> print(side_one_data.length) - 15 - >>> print(side_one_data.angle.degrees) - 60 - >>> polygon_one.area() - - >>> polygon_one.is_similar(None) - - >>> polygon_one.split() - - >>> polygon_one.perimeter() - - """ - - def __init__(self) -> None: - self.sides: list[Side] = [] - - def get_side(self, index: int) -> Side: - return self.sides[index] - - def set_side(self, index: int, side: Side) -> None: - self.sides[index] = side - - def add_side(self, side: Side) -> None: - self.sides.append(side) - - def area(self) -> float: - pass - - def is_similar(self, compared_shape: PolygonType) -> bool: - pass - - def perimeter(self) -> float: - pass - - def split(self) -> float: - pass diff --git a/geometry/shapes/polygon/rectangle.py b/geometry/shapes/polygon/rectangle.py deleted file mode 100644 index 7fbd609c50aa..000000000000 --- a/geometry/shapes/polygon/rectangle.py +++ /dev/null @@ -1,42 +0,0 @@ -from geometry.angles.angle import Angle -from geometry.shapes.side import Side - -from .polygon import Polygon - - -class Rectangle(Polygon): - """ - a structure which represents a - geometrical rectangle on a 2D surface - - >>> rectangle_one = Rectangle(5, 10) - >>> rectangle_one.perimeter() - 30 - >>> rectangle_one.area() - 50 - >>> rectangle_one.is_similar(None) - Traceback (most recent call last): - NotImplementedError: Not Implemented - >>> rectangle_one.split() - Traceback (most recent call last): - NotImplementedError: Not Implemented - """ - - def __init__(self, short_side_length: float, long_side_length: float) -> None: - super().__init__() - self.short_side = Side([], Angle(90), short_side_length) - self.long_side = Side([], Angle(90), long_side_length) - super().add_side(self.short_side) - super().add_side(self.long_side) - - def perimeter(self) -> float: - return (self.short_side.length + self.long_side.length) * 2 - - def area(self) -> float: - return self.short_side.length * self.long_side.length - - def is_similar(self, compared_shape: Polygon) -> bool: - raise NotImplementedError("Not Implemented") - - def split(self) -> float: - raise NotImplementedError("Not Implemented") diff --git a/geometry/shapes/polygon/square.py b/geometry/shapes/polygon/square.py deleted file mode 100644 index e2444118e477..000000000000 --- a/geometry/shapes/polygon/square.py +++ /dev/null @@ -1,35 +0,0 @@ -from .rectangle import Rectangle - - -class Square(Rectangle): - """ - a structure which represents a - geometrical square on a 2D surface - - >>> square_one = Square(5) - >>> square_one.perimeter() - 20 - >>> square_one.area() - 25 - >>> square_one.is_similar(None) - Traceback (most recent call last): - NotImplementedError: Not Implemented - >>> square_one.split() - Traceback (most recent call last): - NotImplementedError: Not Implemented - """ - - def __init__(self, side_length: float) -> None: - super().__init__(side_length, side_length) - - def perimeter(self) -> float: - return super().perimeter() - - def area(self) -> float: - return super().area() - - def is_similar(self, compared_shape: Rectangle) -> bool: - raise NotImplementedError("Not Implemented") - - def split(self) -> float: - raise NotImplementedError("Not Implemented") diff --git a/geometry/shapes/shape.py b/geometry/shapes/shape.py deleted file mode 100644 index e1d2e5834d77..000000000000 --- a/geometry/shapes/shape.py +++ /dev/null @@ -1,38 +0,0 @@ -from abc import ABC, abstractmethod -from typing import TypeVar - -ShapeType = TypeVar("ShapeType", bound="Shape") - - -class Shape(ABC): - - """ - interface which represents a geometrical shape - at a global level - """ - - @abstractmethod - def is_similar(self, compared_shape: ShapeType) -> bool: - """ - a method for comparing with another shape, - which also implements this interface - """ - - @abstractmethod - def split(self) -> float: - """ - a method for splitting a shape - into a certain quantity of pieces, - following a specific algorithm which returns - the amount of pieces after splitting the shape - - note: in the future, a separate class might be created, - which will represent a certain part of a shape, because of that - the return type of this method might change - """ - - """ - to do: create a factory method for creating a specific shape - @abstractmethod - def create_shape(self): - pass""" diff --git a/geometry/shapes/shape_types/__init__.py b/geometry/shapes/shape_types/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/geometry/shapes/shape_types/closed_shapes.py b/geometry/shapes/shape_types/closed_shapes.py deleted file mode 100644 index 808a60ba7741..000000000000 --- a/geometry/shapes/shape_types/closed_shapes.py +++ /dev/null @@ -1,27 +0,0 @@ -from abc import ABC, abstractmethod - -from geometry.shapes.shape import Shape - - -class ClosedShape(Shape, ABC): - """ - an interface which represents shapes - that start and end at the same point [closed shape] - more info: https://en.wikipedia.org/wiki/Polygon - """ - - @abstractmethod - def perimeter(self) -> float: - pass - - @abstractmethod - def area(self) -> float: - pass - - @abstractmethod - def is_similar(self, compared_shape: Shape) -> bool: - pass - - @abstractmethod - def split(self) -> float: - pass diff --git a/geometry/shapes/shape_types/intersecting_self_shapes.py b/geometry/shapes/shape_types/intersecting_self_shapes.py deleted file mode 100644 index 5701b284425f..000000000000 --- a/geometry/shapes/shape_types/intersecting_self_shapes.py +++ /dev/null @@ -1,27 +0,0 @@ -from abc import ABC, abstractmethod - -from geometry.shapes.shape import Shape - - -class IntersectSelfShape(Shape, ABC): - """ - an interface which represents polygons - some of whose edges cross each other [self intersecting shapes] - more info: https://en.wikipedia.org/wiki/Polygon - """ - - @abstractmethod - def perimeter(self) -> float: - pass - - @abstractmethod - def area(self) -> float: - pass - - @abstractmethod - def is_similar(self, compared_shape: Shape) -> bool: - pass - - @abstractmethod - def split(self) -> float: - pass diff --git a/geometry/shapes/shape_types/open_shapes.py b/geometry/shapes/shape_types/open_shapes.py deleted file mode 100644 index 5361a404b235..000000000000 --- a/geometry/shapes/shape_types/open_shapes.py +++ /dev/null @@ -1,19 +0,0 @@ -from abc import ABC, abstractmethod - -from geometry.shapes.shape import Shape - - -class OpenShape(Shape, ABC): - """ - an interface which represents shapes or figures - with different starting and ending points [open shapes] - more info: https://en.wikipedia.org/wiki/Polygon - """ - - @abstractmethod - def is_similar(self, compared_shape: Shape) -> bool: - pass - - @abstractmethod - def split(self) -> float: - pass diff --git a/geometry/shapes/side.py b/geometry/shapes/side.py deleted file mode 100644 index e09fa21226af..000000000000 --- a/geometry/shapes/side.py +++ /dev/null @@ -1,17 +0,0 @@ -from dataclasses import dataclass - -from geometry.angles.angle import Angle - - -@dataclass -class Side: - - """ - represents a side of a shape [such as polygon, e.t.c.] - adjacent_sides: a list of sides which are adjacent to the current side - angle: the angle between adjacent sides - """ - - adjacent_sides: list[float] - angle: Angle - length: float From fc95d8db9555833937e32faec61c5db9d46f3f64 Mon Sep 17 00:00:00 2001 From: Margaret <62753112+meg-1@users.noreply.github.com> Date: Fri, 24 Nov 2023 17:33:33 +0200 Subject: [PATCH 06/13] fixing ruff errors --- geometry/geometry.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/geometry/geometry.py b/geometry/geometry.py index 6d1790693779..5b9ef8964b17 100644 --- a/geometry/geometry.py +++ b/geometry/geometry.py @@ -1,9 +1,8 @@ from __future__ import annotations import math from dataclasses import dataclass, field -from typing_extensions import Self - -NoneType = type(None) +from types import NoneType +from typing import Self # Building block classes From 1ddea9c075a2946a285f3c46765bb4f7595efd38 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Fri, 24 Nov 2023 18:28:51 +0100 Subject: [PATCH 07/13] Update geometry/code_review_feedback.py --- geometry/code_review_feedback.py | 1 + 1 file changed, 1 insertion(+) diff --git a/geometry/code_review_feedback.py b/geometry/code_review_feedback.py index 8b3a37a3ed67..de5c03923077 100644 --- a/geometry/code_review_feedback.py +++ b/geometry/code_review_feedback.py @@ -1,4 +1,5 @@ from __future__ import annotations + import math from dataclasses import dataclass, field from types import NoneType From 0b27159e67067783d46a67c8751cb5a4b14cd0fa Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Fri, 24 Nov 2023 18:30:38 +0100 Subject: [PATCH 08/13] Update geometry/code_review_feedback.py --- geometry/code_review_feedback.py | 1 - 1 file changed, 1 deletion(-) diff --git a/geometry/code_review_feedback.py b/geometry/code_review_feedback.py index de5c03923077..c66bab23f6ae 100644 --- a/geometry/code_review_feedback.py +++ b/geometry/code_review_feedback.py @@ -5,7 +5,6 @@ from types import NoneType from typing import Self - # Building block classes From 99ca67666a0d47a95ae9494dd547d026728d46cb Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Fri, 24 Nov 2023 18:32:52 +0100 Subject: [PATCH 09/13] Update geometry/geometry.py --- geometry/geometry.py | 1 + 1 file changed, 1 insertion(+) diff --git a/geometry/geometry.py b/geometry/geometry.py index 5b9ef8964b17..f730f0017af0 100644 --- a/geometry/geometry.py +++ b/geometry/geometry.py @@ -1,4 +1,5 @@ from __future__ import annotations + import math from dataclasses import dataclass, field from types import NoneType From 17df18a3a4c8185e04d570e02553d74a71615f16 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Fri, 24 Nov 2023 18:50:49 +0100 Subject: [PATCH 10/13] Apply suggestions from code review --- geometry/code_review_feedback.py | 6 +++--- geometry/geometry.py | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/geometry/code_review_feedback.py b/geometry/code_review_feedback.py index c66bab23f6ae..50fa8c46260d 100644 --- a/geometry/code_review_feedback.py +++ b/geometry/code_review_feedback.py @@ -215,7 +215,7 @@ def __init__(self, short_side_length: float, long_side_length: float) -> None: self.long_side_length = long_side_length self.post_init() - def post_init(self): + def post_init(self) -> None: """ >>> Rectangle(5, 10) # doctest: +NORMALIZE_WHITESPACE Rectangle(sides=[Side(length=5, angle=Angle(degrees=90), next_side=None), @@ -226,10 +226,10 @@ def post_init(self): super().add_side(self.short_side) super().add_side(self.long_side) - def perimeter(self): + def perimeter(self) -> float: return (self.short_side.length + self.long_side.length) * 2 - def area(self): + def area(self) -> float: return self.short_side.length * self.long_side.length diff --git a/geometry/geometry.py b/geometry/geometry.py index f730f0017af0..26fb2522e97e 100644 --- a/geometry/geometry.py +++ b/geometry/geometry.py @@ -215,7 +215,7 @@ def __init__(self, short_side_length: float, long_side_length: float) -> None: self.long_side_length = long_side_length self.post_init() - def post_init(self): + def post_init(self) -> None: """ >>> Rectangle(5, 10) # doctest: +NORMALIZE_WHITESPACE Rectangle(sides=[Side(length=5, angle=Angle(degrees=90), next_side=None), @@ -226,10 +226,10 @@ def post_init(self): super().add_side(self.short_side) super().add_side(self.long_side) - def perimeter(self): + def perimeter(self) -> float: return (self.short_side.length + self.long_side.length) * 2 - def area(self): + def area(self) -> float: return self.short_side.length * self.long_side.length @@ -245,13 +245,13 @@ class Square(Rectangle): 25 """ - def __init__(self, side_length): + def __init__(self, side_length) -> None: super().__init__(side_length, side_length) - def perimeter(self): + def perimeter(self) -> float: return super().perimeter() - def area(self): + def area(self) -> float: return super().area() From d54617f5a1d8545e1f0194adc460fdbb7f5a6896 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Fri, 24 Nov 2023 18:51:53 +0100 Subject: [PATCH 11/13] Delete geometry/code_review_feedback.py --- geometry/code_review_feedback.py | 269 ------------------------------- 1 file changed, 269 deletions(-) delete mode 100644 geometry/code_review_feedback.py diff --git a/geometry/code_review_feedback.py b/geometry/code_review_feedback.py deleted file mode 100644 index 50fa8c46260d..000000000000 --- a/geometry/code_review_feedback.py +++ /dev/null @@ -1,269 +0,0 @@ -from __future__ import annotations - -import math -from dataclasses import dataclass, field -from types import NoneType -from typing import Self - -# Building block classes - - -@dataclass -class Angle: - """ - An Angle in degrees (unit of measurement) - - >>> Angle() - Angle(degrees=90) - >>> Angle(45.5) - Angle(degrees=45.5) - >>> Angle(-1) - Traceback (most recent call last): - ... - TypeError: degrees must be a numeric value between 0 and 360. - >>> Angle(361) - Traceback (most recent call last): - ... - TypeError: degrees must be a numeric value between 0 and 360. - """ - - degrees: float = 90 - - def __post_init__(self) -> None: - if not isinstance(self.degrees, (int, float)) or not 0 <= self.degrees <= 360: - raise TypeError("degrees must be a numeric value between 0 and 360.") - - -@dataclass -class Side: - """ - A side of a two dimensional Shape such as Polygon, etc. - adjacent_sides: a list of sides which are adjacent to the current side - angle: the angle in degrees between each adjacent side - length: the length of the current side in lightyears - - >>> Side(5) - Side(length=5, angle=Angle(degrees=90), next_side=None) - >>> Side(5, Angle(45.6)) - Side(length=5, angle=Angle(degrees=45.6), next_side=None) - >>> Side(5, Angle(45.6), Side(1, Angle(2))) # doctest: +ELLIPSIS - Side(length=5, angle=Angle(degrees=45.6), next_side=Side(length=1, angle=Angle(d... - """ - - length: float - angle: Angle = field(default_factory=Angle) - next_side: Side | None = None - - def __post_init__(self) -> None: - if not isinstance(self.length, (int, float)) or self.length <= 0: - raise TypeError("length must be a positive numeric value.") - if not isinstance(self.angle, Angle): - raise TypeError("angle must be an Angle object.") - if not isinstance(self.next_side, (Side, NoneType)): - raise TypeError("next_side must be a Side or None.") - - -@dataclass -class Ellipse: - """ - A geometric Ellipse on a 2D surface - - >>> Ellipse(5, 10) - Ellipse(major_radius=5, minor_radius=10) - >>> Ellipse(5, 10) is Ellipse(5, 10) - False - >>> Ellipse(5, 10) == Ellipse(5, 10) - True - """ - - major_radius: float - minor_radius: float - - @property - def area(self) -> float: - """ - >>> Ellipse(5, 10).area - 157.07963267948966 - """ - return math.pi * self.major_radius * self.minor_radius - - @property - def perimeter(self) -> float: - """ - >>> Ellipse(5, 10).perimeter - 47.12388980384689 - """ - return math.pi * (self.major_radius + self.minor_radius) - - -class Circle(Ellipse): - """ - A geometric Circle on a 2D surface - - >>> Circle(5) - Circle(radius=5) - >>> Circle(5) is Circle(5) - False - >>> Circle(5) == Circle(5) - True - >>> Circle(5).area - 78.53981633974483 - >>> Circle(5).perimeter - 31.41592653589793 - """ - - def __init__(self, radius: float) -> None: - super().__init__(radius, radius) - self.radius = radius - - def __repr__(self) -> str: - return f"Circle(radius={self.radius})" - - @property - def diameter(self) -> float: - """ - >>> Circle(5).diameter - 10 - """ - return self.radius * 2 - - def max_parts(self, num_cuts: float) -> float: - """ - Return the maximum number of parts that circle can be divided into if cut - 'num_cuts' times. - - >>> circle = Circle(5) - >>> circle.max_parts(0) - 1.0 - >>> circle.max_parts(7) - 29.0 - >>> circle.max_parts(54) - 1486.0 - >>> circle.max_parts(22.5) - 265.375 - >>> circle.max_parts(-222) - Traceback (most recent call last): - ... - TypeError: num_cuts must be a positive numeric value. - >>> circle.max_parts("-222") - Traceback (most recent call last): - ... - TypeError: num_cuts must be a positive numeric value. - """ - if not isinstance(num_cuts, (int, float)) or num_cuts < 0: - raise TypeError("num_cuts must be a positive numeric value.") - return (num_cuts + 2 + num_cuts**2) * 0.5 - - -@dataclass -class Polygon: - """ - An abstract class which represents Polygon on a 2D surface. - - >>> Polygon() - Polygon(sides=[]) - """ - - sides: list[Side] = field(default_factory=list) - - def add_side(self, side: Side) -> Self: - """ - >>> Polygon().add_side(Side(5)) - Polygon(sides=[Side(length=5, angle=Angle(degrees=90), next_side=None)]) - """ - self.sides.append(side) - return self - - def get_side(self, index: int) -> Side: - """ - >>> Polygon().get_side(0) - Traceback (most recent call last): - ... - IndexError: list index out of range - >>> Polygon().add_side(Side(5)).get_side(-1) - Side(length=5, angle=Angle(degrees=90), next_side=None) - """ - return self.sides[index] - - def set_side(self, index: int, side: Side) -> Self: - """ - >>> Polygon().set_side(0, Side(5)) - Traceback (most recent call last): - ... - IndexError: list assignment index out of range - >>> Polygon().add_side(Side(5)).set_side(0, Side(10)) - Polygon(sides=[Side(length=10, angle=Angle(degrees=90), next_side=None)]) - """ - self.sides[index] = side - return self - - -class Rectangle(Polygon): - """ - A geometric rectangle on a 2D surface. - - >>> rectangle_one = Rectangle(5, 10) - >>> rectangle_one.perimeter() - 30 - >>> rectangle_one.area() - 50 - """ - - def __init__(self, short_side_length: float, long_side_length: float) -> None: - super().__init__() - self.short_side_length = short_side_length - self.long_side_length = long_side_length - self.post_init() - - def post_init(self) -> None: - """ - >>> Rectangle(5, 10) # doctest: +NORMALIZE_WHITESPACE - Rectangle(sides=[Side(length=5, angle=Angle(degrees=90), next_side=None), - Side(length=10, angle=Angle(degrees=90), next_side=None)]) - """ - self.short_side = Side(self.short_side_length) - self.long_side = Side(self.long_side_length) - super().add_side(self.short_side) - super().add_side(self.long_side) - - def perimeter(self) -> float: - return (self.short_side.length + self.long_side.length) * 2 - - def area(self) -> float: - return self.short_side.length * self.long_side.length - - -''' -@dataclass -class Square(Rectangle): - """ - a structure which represents a - geometrical square on a 2D surface - >>> square_one = Square(5) - >>> square_one.perimeter() - 20 - >>> square_one.area() - 25 - >>> square_one.is_similar(None) - Traceback (most recent call last): - NotImplementedError: Not Implemented - >>> square_one.split() - Traceback (most recent call last): - NotImplementedError: Not Implemented - """ - - def __init__(self, side_length): - super().__init__(side_length, side_length) - - def perimeter(self): - return super().perimeter() - - def area(self): - return super().area() - - def is_similar(self, compared_shape): - raise NotImplementedError("Not Implemented") - - def split(self): - raise NotImplementedError("Not Implemented") -''' From b7ec5fd74552e31c2425b0c95efb93620ff59634 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Fri, 24 Nov 2023 18:52:55 +0100 Subject: [PATCH 12/13] Update geometry/geometry.py --- geometry/geometry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geometry/geometry.py b/geometry/geometry.py index 26fb2522e97e..e5b85225a0ff 100644 --- a/geometry/geometry.py +++ b/geometry/geometry.py @@ -245,7 +245,7 @@ class Square(Rectangle): 25 """ - def __init__(self, side_length) -> None: + def __init__(self, side_length: float) -> None: super().__init__(side_length, side_length) def perimeter(self) -> float: From 87d21202283b956410f14f3b6ee331c620854695 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Fri, 24 Nov 2023 18:55:08 +0100 Subject: [PATCH 13/13] Update geometry/geometry.py --- geometry/geometry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geometry/geometry.py b/geometry/geometry.py index e5b85225a0ff..9e353dee17a7 100644 --- a/geometry/geometry.py +++ b/geometry/geometry.py @@ -40,7 +40,7 @@ class Side: A side of a two dimensional Shape such as Polygon, etc. adjacent_sides: a list of sides which are adjacent to the current side angle: the angle in degrees between each adjacent side - length: the length of the current side in lightyears + length: the length of the current side in meters >>> Side(5) Side(length=5, angle=Angle(degrees=90), next_side=None)