diff --git a/main.py b/main.py index 37ff472..0b38b73 100644 --- a/main.py +++ b/main.py @@ -268,3 +268,7 @@ block_list = ["blue_concrete", "red_concrete", "green_concrete", s = Segment2D(Point2D(0, 0), Point2D(10, 15), 1) print(s) + + +c = Circle(Point2D(0, 0), 5, 10) +print(c.circle_points(10, 10)) diff --git a/networks/geometry/Circle.py b/networks/geometry/Circle.py index 7c480bb..dcd2cfe 100644 --- a/networks/geometry/Circle.py +++ b/networks/geometry/Circle.py @@ -1,17 +1,25 @@ -from typing import Type from networks.geometry.Point2D import Point2D +from math import cos, sin, pi +from typing import List class Circle: def __init__(self, center: Point2D, inner: int, outer: int): self.center = center + self.inner = inner self.outer = outer self.coordinates = [] + self.radius = None # Used with circle_points() + self.spaced_coordinates = [] + self.circle(self.center, self.inner, self.outer) - def circle(self, center: Point2D, inner: int, outer: int): + def __repr__(self): + return f"Circle(center: {self.center}, inner: {self.inner}, outer: {self.outer})" + + def circle(self, center: Point2D, inner: int, outer: int) -> List[Point2D]: """Compute discrete value of a 2d-circle with thickness. https://stackoverflow.com/questions/27755514/circle-with-thickness-drawing-algorithm @@ -21,6 +29,9 @@ class Circle: inner (int): The minimum radius at which the disc is filled (included). outer (int): The maximum radius where disc filling stops (included). + Returns: + list(Point2D): List of 2d-coordinates composing the surface. Note that some coordinates are redondant and are not ordered. + >>> Circle(Point2D(0, 0), 5, 10) """ xo = outer @@ -55,6 +66,33 @@ class Circle: else: xi -= 1 erri += 2 * (y - xi + 1) + return self.coordinates + + def circle_points(self, number: int, radius: int) -> List[Point2D]: + """Get evenly spaced coordinates of the circle. + + https://stackoverflow.com/questions/8487893/generate-all-the-points-on-the-circumference-of-a-circle + + Args: + number (int): Number of coordinates to be returned. + radius (int, optional): Radius of the circle. Defaults to self.inner. + + Returns: + list(Point2D): List of evenly spaced 2d-coordinates forming the circle. + """ + print(self.center.x) + self.spaced_coordinates = [ + Point2D(cos(2 * pi / number * i) * radius, + sin(2 * pi / number * i) * radius) + for i in range(0, number + 1) + ] + + for i in range(len(self.spaced_coordinates)): + self.spaced_coordinates[i] = Point2D( + self.spaced_coordinates[i].x + self.center.x, + self.spaced_coordinates[i].y + self.center.y + ).round() + return self.spaced_coordinates def _x_line(self, x1, x2, y): while x1 <= x2: @@ -65,6 +103,3 @@ class Circle: while y1 <= y2: self.coordinates.append(Point2D(x, y1)) y1 += 1 - - def __repr__(self): - return f"Circle(center: {self.center}, inner: {self.inner}, outer: {self.outer})" diff --git a/networks/geometry/Point2D.py b/networks/geometry/Point2D.py index 1d02ab7..0498f61 100644 --- a/networks/geometry/Point2D.py +++ b/networks/geometry/Point2D.py @@ -75,3 +75,9 @@ class Point2D: angle = math.atan2(np.linalg.det([v0, v1]), np.dot(v0, v1)) return np.degrees(angle) + + def round(self, ndigits: int = None) -> "Point2D": + self.x = round(self.x, ndigits) + self.y = round(self.y, ndigits) + self.coordinate = (self.x, self.y) + return self diff --git a/networks/geometry/Point3D.py b/networks/geometry/Point3D.py index e94598e..d280575 100644 --- a/networks/geometry/Point3D.py +++ b/networks/geometry/Point3D.py @@ -15,3 +15,10 @@ class Point3D: def distance(self, point: "Point3D"): return sqrt((point.x - self.x) ** 2 + (point.y - self.y) ** 2 + (point.z - self.z) ** 2) + + def round(self, ndigits: int = None) -> "Point3D": + self.x = round(self.x, ndigits) + self.y = round(self.y, ndigits) + self.z = round(self.z, ndigits) + self.coordinate = (self.x, self.y, self.z) + return self diff --git a/networks/geometry/Segment2D.py b/networks/geometry/Segment2D.py index 413cfe2..59d3015 100644 --- a/networks/geometry/Segment2D.py +++ b/networks/geometry/Segment2D.py @@ -26,6 +26,8 @@ class Segment2D: start (Point2D): Start point of the segment. end (Point2D): End point of the segment. overlap (LINE_OVERLAP): Overlap draws additional pixel when changing minor direction. For standard bresenham overlap, choose LINE_OVERLAP_NONE. Can also be LINE_OVERLAP_MAJOR or LINE_OVERLAP_MINOR. + + >>> Segment2D(Point2D(0, 0), Point2D(10, 15), 1) """ start = start.copy() end = end.copy() diff --git a/networks/geometry/point_tools.py b/networks/geometry/point_tools.py index 195ca6d..14fc45f 100644 --- a/networks/geometry/point_tools.py +++ b/networks/geometry/point_tools.py @@ -3,23 +3,6 @@ import numpy as np from networks.geometry.segment_tools import discrete_segment, middle_point, parallel -def circle_points(center_point, radius, number=100): - # Works in 2d but supports 3d. - # https://stackoverflow.com/questions/8487893/generate-all-the-points-on-the-circumference-of-a-circle - points = [ - (cos(2 * pi / number * x) * radius, sin(2 * pi / number * x) * radius) - for x in range(0, number + 1) - ] - - for i in range(len(points)): - points[i] = ( - points[i][0] + center_point[0], - points[i][-1] + center_point[-1], - ) - - return points - - def optimized_path(points, start=None): # https://stackoverflow.com/questions/45829155/sort-points-in-order-to-have-a-continuous-curve-using-python if start is None: