simetri.graphics.points
Shape object uses the Points class to store the coordinates of the points that make up the shape. The Points class is a container for coordinates of multiple points. It provides conversion to homogeneous coordinates in nd_arrays. Shape.final_coords is computed by using the Points.homogen_coords property.
1"""Shape object uses the Points class to store the coordinates of the points that make up the shape. 2The Points class is a container for coordinates of multiple points. 3It provides conversion to homogeneous coordinates in nd_arrays. 4Shape.final_coords is computed by using the Points.homogen_coords property.""" 5 6import copy 7from typing import Sequence 8 9from numpy import allclose, ndarray 10from typing_extensions import Self 11 12from ..geometry.geometry import homogenize 13from .common import Point, common_properties 14from .all_enums import * 15from ..settings.settings import defaults 16 17 18class Points: 19 """Container for coordinates of multiple points. They provide conversion to homogeneous 20 coordinates in nd_arrays. Used in Shape objects. 21 """ 22 23 def __init__(self, coords: Sequence[Point] = None) -> None: 24 """Initialize a Points object. 25 26 Args: 27 coords (Sequence[Point], optional): The coordinates of the points. Defaults to None. 28 """ 29 # coords are a list of (x, y) values 30 if coords is None: 31 coords = [] 32 else: 33 coords = [tuple(x) for x in coords] 34 self.coords = coords 35 if self.coords: 36 self.nd_array = homogenize(coords) # homogeneous coordinates 37 self.type = Types.POINTS 38 self.subtype = Types.POINTS 39 self.dist_tol = defaults["dist_tol"] 40 self.dist_tol2 = self.dist_tol**2 41 common_properties(self, False) 42 43 def __str__(self): 44 """Return a string representation of the points. 45 46 Returns: 47 str: The string representation of the points. 48 """ 49 return f"Points({self.coords})" 50 51 def __repr__(self): 52 """Return a string representation of the points. 53 54 Returns: 55 str: The string representation of the points. 56 """ 57 return f"Points({self.coords})" 58 59 def __getitem__(self, subscript): 60 """Get the point(s) at the given subscript. 61 62 Args: 63 subscript (int or slice): The subscript to get the point(s) from. 64 65 Returns: 66 Point or list[Point]: The point(s) at the given subscript. 67 68 Raises: 69 TypeError: If the subscript type is invalid. 70 """ 71 if isinstance(subscript, slice): 72 res = self.coords[subscript.start : subscript.stop : subscript.step] 73 elif isinstance(subscript, int): 74 res = self.coords[subscript] 75 else: 76 raise TypeError("Invalid subscript type") 77 return res 78 79 def _update_coords(self): 80 """Update the homogeneous coordinates of the points.""" 81 self.nd_array = homogenize(self.coords) 82 83 def __setitem__(self, subscript, value): 84 """Set the point(s) at the given subscript. 85 86 Args: 87 subscript (int or slice): The subscript to set the point(s) at. 88 value (Point or list[Point]): The value to set the point(s) to. 89 90 Raises: 91 TypeError: If the subscript type is invalid. 92 """ 93 if isinstance(subscript, slice): 94 self.coords[subscript.start : subscript.stop : subscript.step] = value 95 self._update_coords() 96 elif isinstance(subscript, int): 97 self.coords[subscript] = value 98 self._update_coords() 99 else: 100 raise TypeError("Invalid subscript type") 101 102 def __eq__(self, other): 103 """Check if the points are equal to another Points object. 104 105 Args: 106 other (Points): The other Points object to compare against. 107 108 Returns: 109 bool: True if the points are equal, False otherwise. 110 """ 111 return ( 112 other.type == Types.POINTS 113 and len(self.coords) == len(other.coords) 114 and allclose( 115 self.nd_array, 116 other.nd_array, 117 rtol=defaults["rtol"], 118 atol=defaults["atol"], 119 ) 120 ) 121 122 def append(self, item: Point) -> Self: 123 """Append a point to the points. 124 125 Args: 126 item (Point): The point to append. 127 128 Returns: 129 Self: The updated Points object. 130 """ 131 self.coords.append(item) 132 self._update_coords() 133 return self 134 135 def extend(self, items: Sequence[Point]) -> Self: 136 """Extend the points with a given sequence of points. 137 138 Args: 139 items (Sequence[Point]): The sequence of points to add. 140 141 Returns: 142 Self: The updated Points object. 143 """ 144 self.coords.extend(items) 145 self._update_coords() 146 return self 147 148 def pop(self, index: int = -1) -> Point: 149 """Remove the point at the given index and return it. 150 151 Args: 152 index (int, optional): The index of the point to remove. Defaults to -1. 153 154 Returns: 155 Point: The removed point. 156 """ 157 value = self.coords.pop(index) 158 self._update_coords() 159 return value 160 161 def __delitem__(self, subscript) -> Self: 162 """Delete the point(s) at the given subscript. 163 164 Args: 165 subscript (int or slice): The subscript to delete the point(s) from. 166 167 Raises: 168 TypeError: If the subscript type is invalid. 169 """ 170 coords = self.coords 171 if isinstance(subscript, slice): 172 del coords[subscript.start : subscript.stop : subscript.step] 173 elif isinstance(subscript, int): 174 del coords[subscript] 175 else: 176 raise TypeError("Invalid subscript type") 177 self._update_coords() 178 179 def remove(self, value): 180 """Remove the first occurrence of the given point. 181 182 Args: 183 value (Point): The point value to remove. 184 """ 185 self.coords.remove(value) 186 self._update_coords() 187 188 def insert(self, index, points): 189 """Insert a point at the specified index. 190 191 Args: 192 index (int): The index to insert the point at. 193 points (Point): The point to insert. 194 """ 195 self.coords.insert(index, points) 196 self._update_coords() 197 198 def clear(self): 199 """Clear all points.""" 200 self.coords.clear() 201 self.nd_array = ndarray((0, 3)) 202 203 def reverse(self): 204 """Reverse the order of the points.""" 205 self.coords.reverse() 206 self._update_coords() 207 208 def __iter__(self): 209 """Return an iterator over the points. 210 211 Returns: 212 Iterator[Point]: An iterator over the points. 213 """ 214 return iter(self.coords) 215 216 def __len__(self): 217 """Return the number of points. 218 219 Returns: 220 int: The number of points. 221 """ 222 return len(self.coords) 223 224 def __bool__(self): 225 """Return whether the Points object has any points. 226 227 Returns: 228 bool: True if there are points, False otherwise. 229 """ 230 return bool(self.coords) 231 232 @property 233 def homogen_coords(self): 234 """Return the homogeneous coordinates of the points. 235 236 Returns: 237 ndarray: The homogeneous coordinates. 238 """ 239 return self.nd_array 240 241 def copy(self): 242 """Return a copy of the Points object. 243 244 Returns: 245 Points: A copy of the Points object. 246 """ 247 points = Points(copy.copy(self.coords)) 248 points.nd_array = ndarray.copy(self.nd_array) 249 return points 250 251 @property 252 def pairs(self): 253 """Return a list of consecutive pairs of points. 254 255 Returns: 256 list[tuple[Point, Point]]: A list where each element is a tuple containing two consecutive points. 257 """ 258 return list(zip(self.coords[:-1], self.coords[1:]))
19class Points: 20 """Container for coordinates of multiple points. They provide conversion to homogeneous 21 coordinates in nd_arrays. Used in Shape objects. 22 """ 23 24 def __init__(self, coords: Sequence[Point] = None) -> None: 25 """Initialize a Points object. 26 27 Args: 28 coords (Sequence[Point], optional): The coordinates of the points. Defaults to None. 29 """ 30 # coords are a list of (x, y) values 31 if coords is None: 32 coords = [] 33 else: 34 coords = [tuple(x) for x in coords] 35 self.coords = coords 36 if self.coords: 37 self.nd_array = homogenize(coords) # homogeneous coordinates 38 self.type = Types.POINTS 39 self.subtype = Types.POINTS 40 self.dist_tol = defaults["dist_tol"] 41 self.dist_tol2 = self.dist_tol**2 42 common_properties(self, False) 43 44 def __str__(self): 45 """Return a string representation of the points. 46 47 Returns: 48 str: The string representation of the points. 49 """ 50 return f"Points({self.coords})" 51 52 def __repr__(self): 53 """Return a string representation of the points. 54 55 Returns: 56 str: The string representation of the points. 57 """ 58 return f"Points({self.coords})" 59 60 def __getitem__(self, subscript): 61 """Get the point(s) at the given subscript. 62 63 Args: 64 subscript (int or slice): The subscript to get the point(s) from. 65 66 Returns: 67 Point or list[Point]: The point(s) at the given subscript. 68 69 Raises: 70 TypeError: If the subscript type is invalid. 71 """ 72 if isinstance(subscript, slice): 73 res = self.coords[subscript.start : subscript.stop : subscript.step] 74 elif isinstance(subscript, int): 75 res = self.coords[subscript] 76 else: 77 raise TypeError("Invalid subscript type") 78 return res 79 80 def _update_coords(self): 81 """Update the homogeneous coordinates of the points.""" 82 self.nd_array = homogenize(self.coords) 83 84 def __setitem__(self, subscript, value): 85 """Set the point(s) at the given subscript. 86 87 Args: 88 subscript (int or slice): The subscript to set the point(s) at. 89 value (Point or list[Point]): The value to set the point(s) to. 90 91 Raises: 92 TypeError: If the subscript type is invalid. 93 """ 94 if isinstance(subscript, slice): 95 self.coords[subscript.start : subscript.stop : subscript.step] = value 96 self._update_coords() 97 elif isinstance(subscript, int): 98 self.coords[subscript] = value 99 self._update_coords() 100 else: 101 raise TypeError("Invalid subscript type") 102 103 def __eq__(self, other): 104 """Check if the points are equal to another Points object. 105 106 Args: 107 other (Points): The other Points object to compare against. 108 109 Returns: 110 bool: True if the points are equal, False otherwise. 111 """ 112 return ( 113 other.type == Types.POINTS 114 and len(self.coords) == len(other.coords) 115 and allclose( 116 self.nd_array, 117 other.nd_array, 118 rtol=defaults["rtol"], 119 atol=defaults["atol"], 120 ) 121 ) 122 123 def append(self, item: Point) -> Self: 124 """Append a point to the points. 125 126 Args: 127 item (Point): The point to append. 128 129 Returns: 130 Self: The updated Points object. 131 """ 132 self.coords.append(item) 133 self._update_coords() 134 return self 135 136 def extend(self, items: Sequence[Point]) -> Self: 137 """Extend the points with a given sequence of points. 138 139 Args: 140 items (Sequence[Point]): The sequence of points to add. 141 142 Returns: 143 Self: The updated Points object. 144 """ 145 self.coords.extend(items) 146 self._update_coords() 147 return self 148 149 def pop(self, index: int = -1) -> Point: 150 """Remove the point at the given index and return it. 151 152 Args: 153 index (int, optional): The index of the point to remove. Defaults to -1. 154 155 Returns: 156 Point: The removed point. 157 """ 158 value = self.coords.pop(index) 159 self._update_coords() 160 return value 161 162 def __delitem__(self, subscript) -> Self: 163 """Delete the point(s) at the given subscript. 164 165 Args: 166 subscript (int or slice): The subscript to delete the point(s) from. 167 168 Raises: 169 TypeError: If the subscript type is invalid. 170 """ 171 coords = self.coords 172 if isinstance(subscript, slice): 173 del coords[subscript.start : subscript.stop : subscript.step] 174 elif isinstance(subscript, int): 175 del coords[subscript] 176 else: 177 raise TypeError("Invalid subscript type") 178 self._update_coords() 179 180 def remove(self, value): 181 """Remove the first occurrence of the given point. 182 183 Args: 184 value (Point): The point value to remove. 185 """ 186 self.coords.remove(value) 187 self._update_coords() 188 189 def insert(self, index, points): 190 """Insert a point at the specified index. 191 192 Args: 193 index (int): The index to insert the point at. 194 points (Point): The point to insert. 195 """ 196 self.coords.insert(index, points) 197 self._update_coords() 198 199 def clear(self): 200 """Clear all points.""" 201 self.coords.clear() 202 self.nd_array = ndarray((0, 3)) 203 204 def reverse(self): 205 """Reverse the order of the points.""" 206 self.coords.reverse() 207 self._update_coords() 208 209 def __iter__(self): 210 """Return an iterator over the points. 211 212 Returns: 213 Iterator[Point]: An iterator over the points. 214 """ 215 return iter(self.coords) 216 217 def __len__(self): 218 """Return the number of points. 219 220 Returns: 221 int: The number of points. 222 """ 223 return len(self.coords) 224 225 def __bool__(self): 226 """Return whether the Points object has any points. 227 228 Returns: 229 bool: True if there are points, False otherwise. 230 """ 231 return bool(self.coords) 232 233 @property 234 def homogen_coords(self): 235 """Return the homogeneous coordinates of the points. 236 237 Returns: 238 ndarray: The homogeneous coordinates. 239 """ 240 return self.nd_array 241 242 def copy(self): 243 """Return a copy of the Points object. 244 245 Returns: 246 Points: A copy of the Points object. 247 """ 248 points = Points(copy.copy(self.coords)) 249 points.nd_array = ndarray.copy(self.nd_array) 250 return points 251 252 @property 253 def pairs(self): 254 """Return a list of consecutive pairs of points. 255 256 Returns: 257 list[tuple[Point, Point]]: A list where each element is a tuple containing two consecutive points. 258 """ 259 return list(zip(self.coords[:-1], self.coords[1:]))
Container for coordinates of multiple points. They provide conversion to homogeneous coordinates in nd_arrays. Used in Shape objects.
24 def __init__(self, coords: Sequence[Point] = None) -> None: 25 """Initialize a Points object. 26 27 Args: 28 coords (Sequence[Point], optional): The coordinates of the points. Defaults to None. 29 """ 30 # coords are a list of (x, y) values 31 if coords is None: 32 coords = [] 33 else: 34 coords = [tuple(x) for x in coords] 35 self.coords = coords 36 if self.coords: 37 self.nd_array = homogenize(coords) # homogeneous coordinates 38 self.type = Types.POINTS 39 self.subtype = Types.POINTS 40 self.dist_tol = defaults["dist_tol"] 41 self.dist_tol2 = self.dist_tol**2 42 common_properties(self, False)
Initialize a Points object.
Arguments:
- coords (Sequence[Point], optional): The coordinates of the points. Defaults to None.
123 def append(self, item: Point) -> Self: 124 """Append a point to the points. 125 126 Args: 127 item (Point): The point to append. 128 129 Returns: 130 Self: The updated Points object. 131 """ 132 self.coords.append(item) 133 self._update_coords() 134 return self
Append a point to the points.
Arguments:
- item (Point): The point to append.
Returns:
Self: The updated Points object.
136 def extend(self, items: Sequence[Point]) -> Self: 137 """Extend the points with a given sequence of points. 138 139 Args: 140 items (Sequence[Point]): The sequence of points to add. 141 142 Returns: 143 Self: The updated Points object. 144 """ 145 self.coords.extend(items) 146 self._update_coords() 147 return self
Extend the points with a given sequence of points.
Arguments:
- items (Sequence[Point]): The sequence of points to add.
Returns:
Self: The updated Points object.
149 def pop(self, index: int = -1) -> Point: 150 """Remove the point at the given index and return it. 151 152 Args: 153 index (int, optional): The index of the point to remove. Defaults to -1. 154 155 Returns: 156 Point: The removed point. 157 """ 158 value = self.coords.pop(index) 159 self._update_coords() 160 return value
Remove the point at the given index and return it.
Arguments:
- index (int, optional): The index of the point to remove. Defaults to -1.
Returns:
Point: The removed point.
180 def remove(self, value): 181 """Remove the first occurrence of the given point. 182 183 Args: 184 value (Point): The point value to remove. 185 """ 186 self.coords.remove(value) 187 self._update_coords()
Remove the first occurrence of the given point.
Arguments:
- value (Point): The point value to remove.
189 def insert(self, index, points): 190 """Insert a point at the specified index. 191 192 Args: 193 index (int): The index to insert the point at. 194 points (Point): The point to insert. 195 """ 196 self.coords.insert(index, points) 197 self._update_coords()
Insert a point at the specified index.
Arguments:
- index (int): The index to insert the point at.
- points (Point): The point to insert.
199 def clear(self): 200 """Clear all points.""" 201 self.coords.clear() 202 self.nd_array = ndarray((0, 3))
Clear all points.
204 def reverse(self): 205 """Reverse the order of the points.""" 206 self.coords.reverse() 207 self._update_coords()
Reverse the order of the points.
233 @property 234 def homogen_coords(self): 235 """Return the homogeneous coordinates of the points. 236 237 Returns: 238 ndarray: The homogeneous coordinates. 239 """ 240 return self.nd_array
Return the homogeneous coordinates of the points.
Returns:
ndarray: The homogeneous coordinates.
242 def copy(self): 243 """Return a copy of the Points object. 244 245 Returns: 246 Points: A copy of the Points object. 247 """ 248 points = Points(copy.copy(self.coords)) 249 points.nd_array = ndarray.copy(self.nd_array) 250 return points
Return a copy of the Points object.
Returns:
Points: A copy of the Points object.
252 @property 253 def pairs(self): 254 """Return a list of consecutive pairs of points. 255 256 Returns: 257 list[tuple[Point, Point]]: A list where each element is a tuple containing two consecutive points. 258 """ 259 return list(zip(self.coords[:-1], self.coords[1:]))
Return a list of consecutive pairs of points.
Returns:
list[tuple[Point, Point]]: A list where each element is a tuple containing two consecutive points.