sketchingpy.shape_struct
Data structures describing shapes.
License:
BSD
1"""Data structures describing shapes. 2 3License: 4 BSD 5""" 6 7import typing 8 9 10class Line: 11 """Data structure describing a segment. 12 13 Data structure describing a segment which can be a straight line but also a curve like a bezier 14 curve. 15 """ 16 17 def get_destination_x(self) -> float: 18 """Get the ending horizontal coordinate of this segment. 19 20 Returns: 21 The x coordinate that this segment ends on. 22 """ 23 raise NotImplementedError('Use implementor.') 24 25 def get_destination_y(self) -> float: 26 """Get the ending vertical coordinate of this segment. 27 28 Returns: 29 The y coordinate that this segment ends on. 30 """ 31 raise NotImplementedError('Use implementor.') 32 33 def get_min_x(self) -> float: 34 """Get the minimum of the x coordinates in this segment. 35 36 Returns: 37 Minimum x coordinate of this segment. 38 """ 39 raise NotImplementedError('Use impelentor.') 40 41 def get_max_x(self) -> float: 42 """Get the maximum of the x coordinates in this segment. 43 44 Returns: 45 Maximum x coordinate of this segment. 46 """ 47 raise NotImplementedError('Use impelentor.') 48 49 def get_min_y(self) -> float: 50 """Get the minimum of the y coordinates in this segment. 51 52 Returns: 53 Minimum y coordinate of this segment. 54 """ 55 raise NotImplementedError('Use impelentor.') 56 57 def get_max_y(self) -> float: 58 """Get the maximum of the y coordinates in this segment. 59 60 Returns: 61 Maximum y coordinate of this segment. 62 """ 63 raise NotImplementedError('Use impelentor.') 64 65 def get_strategy(self) -> str: 66 """Get the type of line that this segment represents. 67 68 Returns: 69 Line strategy like "straight" or "bezier" as a string. 70 """ 71 raise NotImplementedError('Use implementor.') 72 73 def get_control_x1(self): 74 """Get the horizontal coordinate of the first control point. 75 76 Returns: 77 The x coordinate of the first control point. 78 """ 79 raise NotImplementedError('Not supported by strategy.') 80 81 def get_control_y1(self): 82 """Get the vertical coordinate of the first control point. 83 84 Returns: 85 The y coordinate of the first control point. 86 """ 87 raise NotImplementedError('Not supported by strategy.') 88 89 def get_control_x2(self): 90 """Get the horizontal coordinate of the second control point. 91 92 Returns: 93 The x coordinate of the second control point. 94 """ 95 raise NotImplementedError('Not supported by strategy.') 96 97 def get_control_y2(self): 98 """Get the vertical coordinate of the second control point. 99 100 Returns: 101 The y coordinate of the second control point. 102 """ 103 raise NotImplementedError('Not supported by strategy.') 104 105 106class StraightLine(Line): 107 """A segment which is a straight line between two points.""" 108 109 def __init__(self, destination_x: float, destination_y: float): 110 """Create a new straight line segmenet. 111 112 Args: 113 destination_x: The vertical location of the end coordinate. 114 destination_y: The horizontal location of the end coordinate. 115 """ 116 self._destination_x = destination_x 117 self._destination_y = destination_y 118 119 def get_destination_x(self) -> float: 120 return self._destination_x 121 122 def get_destination_y(self) -> float: 123 return self._destination_y 124 125 def get_min_x(self) -> float: 126 return self._destination_x 127 128 def get_max_x(self) -> float: 129 return self._destination_x 130 131 def get_min_y(self) -> float: 132 return self._destination_y 133 134 def get_max_y(self) -> float: 135 return self._destination_y 136 137 def get_strategy(self) -> str: 138 return 'straight' 139 140 141class BezierLine(Line): 142 """A segment which is a bezier curve between two points.""" 143 144 def __init__(self, control_x1: float, control_y1: float, control_x2: float, control_y2: float, 145 destination_x: float, destination_y: float): 146 """Create a new bezier curve. 147 148 Args: 149 control_x1: The horizontal location of the first control point. 150 control_y1: The vertical location of the first control point. 151 control_x2: The horizontal location of the second control point. 152 control_y2: The vertical location of the second control point. 153 destination_x: The vertical location of the end coordinate. 154 destination_y: The horizontal location of the end coordinate. 155 """ 156 self._control_x1 = control_x1 157 self._control_y1 = control_y1 158 self._control_x2 = control_x2 159 self._control_y2 = control_y2 160 self._destination_x = destination_x 161 self._destination_y = destination_y 162 163 def get_control_x1(self): 164 return self._control_x1 165 166 def get_control_y1(self): 167 return self._control_y1 168 169 def get_control_x2(self): 170 return self._control_x2 171 172 def get_control_y2(self): 173 return self._control_y2 174 175 def get_destination_x(self): 176 return self._destination_x 177 178 def get_destination_y(self): 179 return self._destination_y 180 181 def get_min_x(self) -> float: 182 return min([ 183 self._control_x1, 184 self._control_x2, 185 self._destination_x 186 ]) 187 188 def get_max_x(self) -> float: 189 return max([ 190 self._control_x1, 191 self._control_x2, 192 self._destination_x 193 ]) 194 195 def get_min_y(self) -> float: 196 return min([ 197 self._control_y1, 198 self._control_y2, 199 self._destination_y 200 ]) 201 202 def get_max_y(self) -> float: 203 return max([ 204 self._control_y1, 205 self._control_y2, 206 self._destination_y 207 ]) 208 209 def get_strategy(self) -> str: 210 return 'bezier' 211 212 213class Shape: 214 """Structure describing a multi-segement shape.""" 215 216 def __init__(self, start_x: float, start_y: float): 217 """Create a new multi-segment shape. 218 219 Args: 220 start_x: The starting x position of the shape. 221 start_y: The starting y position of the shape. 222 """ 223 self._start_x = start_x 224 self._start_y = start_y 225 self._closed = False 226 self._finished = False 227 self._segments: typing.List[Line] = [] 228 229 def add_line_to(self, x: float, y: float): 230 """Add a straight line to a shape. 231 232 Draw a straight line from the current position to a new destination which is used as the 233 next "current" position. 234 235 Args: 236 x: The x coordinate to which the line should be drawn. 237 y: The y coordinate to which the line should be drawn. 238 """ 239 self._assert_not_finished() 240 self._segments.append(StraightLine(x, y)) 241 242 def add_bezier_to(self, control_x1: float, control_y1: float, control_x2: float, 243 control_y2: float, destination_x: float, destination_y: float): 244 """Add a bezier curve to a shape. 245 246 Draw a bezier curve from the current position to a new destination which is used as the next 247 "current" position. 248 249 Args: 250 control_x1: The horizontal location of the first control point. 251 control_y1: The vertical location of the first control point. 252 control_x2: The horizontal location of the second control point. 253 control_y2: The vertical location of the second control point. 254 destination_x: The vertical location of the end coordinate. 255 destination_y: The horizontal location of the end coordinate. 256 """ 257 self._assert_not_finished() 258 self._segments.append(BezierLine( 259 control_x1, 260 control_y1, 261 control_x2, 262 control_y2, 263 destination_x, 264 destination_y 265 )) 266 267 def get_start_x(self) -> float: 268 """Retrieve the first x coordinate of this shape. 269 270 Get the horizontal coordinate from which the first segment draws. 271 272 Returns: 273 The starting x coordinate. 274 """ 275 return self._start_x 276 277 def get_start_y(self) -> float: 278 """Retrieve the first y coordinate of this shape. 279 280 Get the vertical coordinate from which the first segment draws. 281 282 Returns: 283 The starting y coordinate. 284 """ 285 return self._start_y 286 287 def get_segments(self) -> typing.Iterable[Line]: 288 """Retrieve shape segments. 289 290 Retrieve objects describing each of the segments in a shape. 291 292 Returns: 293 Segements in this shape. 294 """ 295 return self._segments 296 297 def get_is_finished(self) -> bool: 298 """Determine if a shape is finished. 299 300 Determine if the shape is finished so can be drawn. Returns true if finished (can be drawn) 301 and false otherwise (still building). A shape cannot be drawn until it is finished which can 302 be accomplished by either calling end or close. 303 304 Returns: 305 True if finished and false otherwise. 306 """ 307 return self._finished 308 309 def end(self): 310 """Draw a shape. 311 312 Draw a shape which consists of multiple line or curve segments and which can be either open 313 (stroke only) or closed (can be filled). 314 """ 315 self._assert_not_finished() 316 self._finished = True 317 self._closed = False 318 319 def close(self): 320 """Add a straight line to the starting coordinate. 321 322 Add a line in the shape from the current position to the start position, marking the shape 323 as finished and closed which allows it to be filled. 324 """ 325 self._assert_not_finished() 326 self._finished = True 327 self._closed = True 328 329 def get_is_closed(self) -> bool: 330 """Determine if a shape can be filled. 331 332 Determine if the shape is closed so can be filled. Returns true if closed (can be filled) 333 and false otherwise. 334 335 Returns: 336 True if closed and false otherwise. 337 """ 338 self._assert_finished() 339 return self._closed 340 341 def get_min_x(self): 342 """Determine the minimum x coordinate of a shape. 343 344 Determine the minimum x coordinate (relative to start position) that this shape may reach 345 to. This includes bezier control points but does not try to include stroke weight in its 346 calculation. 347 348 Returns: 349 Minimum x coordinate. 350 """ 351 self._assert_finished() 352 return min([self._start_x] + [x.get_min_x() for x in self._segments]) 353 354 def get_max_x(self): 355 """Determine the maximum x coordinate of a shape. 356 357 Determine the maximum x coordinate (relative to start position) that this shape may reach 358 to. This includes bezier control points but does not try to include stroke weight in its 359 calculation. 360 361 Returns: 362 Maximum x coordinate. 363 """ 364 self._assert_finished() 365 return max([self._start_x] + [x.get_max_x() for x in self._segments]) 366 367 def get_min_y(self): 368 """Determine the minimum y coordinate of a shape. 369 370 Determine the minimum y coordinate (relative to start position) that this shape may reach 371 to. This includes bezier control points but does not try to include stroke weight in its 372 calculation. 373 374 Returns: 375 Minimum y coordinate. 376 """ 377 self._assert_finished() 378 return min([self._start_y] + [x.get_min_y() for x in self._segments]) 379 380 def get_max_y(self): 381 """Determine the maximum y coordinate of a shape. 382 383 Determine the maximum y coordinate (relative to start position) that this shape may reach 384 to. This includes bezier control points but does not try to include stroke weight in its 385 calculation. 386 387 Returns: 388 Maximum y coordinate. 389 """ 390 self._assert_finished() 391 return max([self._start_y] + [x.get_max_y() for x in self._segments]) 392 393 def _assert_not_finished(self): 394 if self._finished: 395 raise RuntimeError('Whoops! This shape is already finished.') 396 397 def _assert_finished(self): 398 if not self._finished: 399 raise RuntimeError('Whoops! This shape is not yet finished.')
11class Line: 12 """Data structure describing a segment. 13 14 Data structure describing a segment which can be a straight line but also a curve like a bezier 15 curve. 16 """ 17 18 def get_destination_x(self) -> float: 19 """Get the ending horizontal coordinate of this segment. 20 21 Returns: 22 The x coordinate that this segment ends on. 23 """ 24 raise NotImplementedError('Use implementor.') 25 26 def get_destination_y(self) -> float: 27 """Get the ending vertical coordinate of this segment. 28 29 Returns: 30 The y coordinate that this segment ends on. 31 """ 32 raise NotImplementedError('Use implementor.') 33 34 def get_min_x(self) -> float: 35 """Get the minimum of the x coordinates in this segment. 36 37 Returns: 38 Minimum x coordinate of this segment. 39 """ 40 raise NotImplementedError('Use impelentor.') 41 42 def get_max_x(self) -> float: 43 """Get the maximum of the x coordinates in this segment. 44 45 Returns: 46 Maximum x coordinate of this segment. 47 """ 48 raise NotImplementedError('Use impelentor.') 49 50 def get_min_y(self) -> float: 51 """Get the minimum of the y coordinates in this segment. 52 53 Returns: 54 Minimum y coordinate of this segment. 55 """ 56 raise NotImplementedError('Use impelentor.') 57 58 def get_max_y(self) -> float: 59 """Get the maximum of the y coordinates in this segment. 60 61 Returns: 62 Maximum y coordinate of this segment. 63 """ 64 raise NotImplementedError('Use impelentor.') 65 66 def get_strategy(self) -> str: 67 """Get the type of line that this segment represents. 68 69 Returns: 70 Line strategy like "straight" or "bezier" as a string. 71 """ 72 raise NotImplementedError('Use implementor.') 73 74 def get_control_x1(self): 75 """Get the horizontal coordinate of the first control point. 76 77 Returns: 78 The x coordinate of the first control point. 79 """ 80 raise NotImplementedError('Not supported by strategy.') 81 82 def get_control_y1(self): 83 """Get the vertical coordinate of the first control point. 84 85 Returns: 86 The y coordinate of the first control point. 87 """ 88 raise NotImplementedError('Not supported by strategy.') 89 90 def get_control_x2(self): 91 """Get the horizontal coordinate of the second control point. 92 93 Returns: 94 The x coordinate of the second control point. 95 """ 96 raise NotImplementedError('Not supported by strategy.') 97 98 def get_control_y2(self): 99 """Get the vertical coordinate of the second control point. 100 101 Returns: 102 The y coordinate of the second control point. 103 """ 104 raise NotImplementedError('Not supported by strategy.')
Data structure describing a segment.
Data structure describing a segment which can be a straight line but also a curve like a bezier curve.
18 def get_destination_x(self) -> float: 19 """Get the ending horizontal coordinate of this segment. 20 21 Returns: 22 The x coordinate that this segment ends on. 23 """ 24 raise NotImplementedError('Use implementor.')
Get the ending horizontal coordinate of this segment.
Returns:
The x coordinate that this segment ends on.
26 def get_destination_y(self) -> float: 27 """Get the ending vertical coordinate of this segment. 28 29 Returns: 30 The y coordinate that this segment ends on. 31 """ 32 raise NotImplementedError('Use implementor.')
Get the ending vertical coordinate of this segment.
Returns:
The y coordinate that this segment ends on.
34 def get_min_x(self) -> float: 35 """Get the minimum of the x coordinates in this segment. 36 37 Returns: 38 Minimum x coordinate of this segment. 39 """ 40 raise NotImplementedError('Use impelentor.')
Get the minimum of the x coordinates in this segment.
Returns:
Minimum x coordinate of this segment.
42 def get_max_x(self) -> float: 43 """Get the maximum of the x coordinates in this segment. 44 45 Returns: 46 Maximum x coordinate of this segment. 47 """ 48 raise NotImplementedError('Use impelentor.')
Get the maximum of the x coordinates in this segment.
Returns:
Maximum x coordinate of this segment.
50 def get_min_y(self) -> float: 51 """Get the minimum of the y coordinates in this segment. 52 53 Returns: 54 Minimum y coordinate of this segment. 55 """ 56 raise NotImplementedError('Use impelentor.')
Get the minimum of the y coordinates in this segment.
Returns:
Minimum y coordinate of this segment.
58 def get_max_y(self) -> float: 59 """Get the maximum of the y coordinates in this segment. 60 61 Returns: 62 Maximum y coordinate of this segment. 63 """ 64 raise NotImplementedError('Use impelentor.')
Get the maximum of the y coordinates in this segment.
Returns:
Maximum y coordinate of this segment.
66 def get_strategy(self) -> str: 67 """Get the type of line that this segment represents. 68 69 Returns: 70 Line strategy like "straight" or "bezier" as a string. 71 """ 72 raise NotImplementedError('Use implementor.')
Get the type of line that this segment represents.
Returns:
Line strategy like "straight" or "bezier" as a string.
74 def get_control_x1(self): 75 """Get the horizontal coordinate of the first control point. 76 77 Returns: 78 The x coordinate of the first control point. 79 """ 80 raise NotImplementedError('Not supported by strategy.')
Get the horizontal coordinate of the first control point.
Returns:
The x coordinate of the first control point.
82 def get_control_y1(self): 83 """Get the vertical coordinate of the first control point. 84 85 Returns: 86 The y coordinate of the first control point. 87 """ 88 raise NotImplementedError('Not supported by strategy.')
Get the vertical coordinate of the first control point.
Returns:
The y coordinate of the first control point.
90 def get_control_x2(self): 91 """Get the horizontal coordinate of the second control point. 92 93 Returns: 94 The x coordinate of the second control point. 95 """ 96 raise NotImplementedError('Not supported by strategy.')
Get the horizontal coordinate of the second control point.
Returns:
The x coordinate of the second control point.
98 def get_control_y2(self): 99 """Get the vertical coordinate of the second control point. 100 101 Returns: 102 The y coordinate of the second control point. 103 """ 104 raise NotImplementedError('Not supported by strategy.')
Get the vertical coordinate of the second control point.
Returns:
The y coordinate of the second control point.
107class StraightLine(Line): 108 """A segment which is a straight line between two points.""" 109 110 def __init__(self, destination_x: float, destination_y: float): 111 """Create a new straight line segmenet. 112 113 Args: 114 destination_x: The vertical location of the end coordinate. 115 destination_y: The horizontal location of the end coordinate. 116 """ 117 self._destination_x = destination_x 118 self._destination_y = destination_y 119 120 def get_destination_x(self) -> float: 121 return self._destination_x 122 123 def get_destination_y(self) -> float: 124 return self._destination_y 125 126 def get_min_x(self) -> float: 127 return self._destination_x 128 129 def get_max_x(self) -> float: 130 return self._destination_x 131 132 def get_min_y(self) -> float: 133 return self._destination_y 134 135 def get_max_y(self) -> float: 136 return self._destination_y 137 138 def get_strategy(self) -> str: 139 return 'straight'
A segment which is a straight line between two points.
110 def __init__(self, destination_x: float, destination_y: float): 111 """Create a new straight line segmenet. 112 113 Args: 114 destination_x: The vertical location of the end coordinate. 115 destination_y: The horizontal location of the end coordinate. 116 """ 117 self._destination_x = destination_x 118 self._destination_y = destination_y
Create a new straight line segmenet.
Arguments:
- destination_x: The vertical location of the end coordinate.
- destination_y: The horizontal location of the end coordinate.
Get the ending horizontal coordinate of this segment.
Returns:
The x coordinate that this segment ends on.
Get the ending vertical coordinate of this segment.
Returns:
The y coordinate that this segment ends on.
Get the minimum of the x coordinates in this segment.
Returns:
Minimum x coordinate of this segment.
Get the maximum of the x coordinates in this segment.
Returns:
Maximum x coordinate of this segment.
Get the minimum of the y coordinates in this segment.
Returns:
Minimum y coordinate of this segment.
Get the maximum of the y coordinates in this segment.
Returns:
Maximum y coordinate of this segment.
Get the type of line that this segment represents.
Returns:
Line strategy like "straight" or "bezier" as a string.
Inherited Members
142class BezierLine(Line): 143 """A segment which is a bezier curve between two points.""" 144 145 def __init__(self, control_x1: float, control_y1: float, control_x2: float, control_y2: float, 146 destination_x: float, destination_y: float): 147 """Create a new bezier curve. 148 149 Args: 150 control_x1: The horizontal location of the first control point. 151 control_y1: The vertical location of the first control point. 152 control_x2: The horizontal location of the second control point. 153 control_y2: The vertical location of the second control point. 154 destination_x: The vertical location of the end coordinate. 155 destination_y: The horizontal location of the end coordinate. 156 """ 157 self._control_x1 = control_x1 158 self._control_y1 = control_y1 159 self._control_x2 = control_x2 160 self._control_y2 = control_y2 161 self._destination_x = destination_x 162 self._destination_y = destination_y 163 164 def get_control_x1(self): 165 return self._control_x1 166 167 def get_control_y1(self): 168 return self._control_y1 169 170 def get_control_x2(self): 171 return self._control_x2 172 173 def get_control_y2(self): 174 return self._control_y2 175 176 def get_destination_x(self): 177 return self._destination_x 178 179 def get_destination_y(self): 180 return self._destination_y 181 182 def get_min_x(self) -> float: 183 return min([ 184 self._control_x1, 185 self._control_x2, 186 self._destination_x 187 ]) 188 189 def get_max_x(self) -> float: 190 return max([ 191 self._control_x1, 192 self._control_x2, 193 self._destination_x 194 ]) 195 196 def get_min_y(self) -> float: 197 return min([ 198 self._control_y1, 199 self._control_y2, 200 self._destination_y 201 ]) 202 203 def get_max_y(self) -> float: 204 return max([ 205 self._control_y1, 206 self._control_y2, 207 self._destination_y 208 ]) 209 210 def get_strategy(self) -> str: 211 return 'bezier'
A segment which is a bezier curve between two points.
145 def __init__(self, control_x1: float, control_y1: float, control_x2: float, control_y2: float, 146 destination_x: float, destination_y: float): 147 """Create a new bezier curve. 148 149 Args: 150 control_x1: The horizontal location of the first control point. 151 control_y1: The vertical location of the first control point. 152 control_x2: The horizontal location of the second control point. 153 control_y2: The vertical location of the second control point. 154 destination_x: The vertical location of the end coordinate. 155 destination_y: The horizontal location of the end coordinate. 156 """ 157 self._control_x1 = control_x1 158 self._control_y1 = control_y1 159 self._control_x2 = control_x2 160 self._control_y2 = control_y2 161 self._destination_x = destination_x 162 self._destination_y = destination_y
Create a new bezier curve.
Arguments:
- control_x1: The horizontal location of the first control point.
- control_y1: The vertical location of the first control point.
- control_x2: The horizontal location of the second control point.
- control_y2: The vertical location of the second control point.
- destination_x: The vertical location of the end coordinate.
- destination_y: The horizontal location of the end coordinate.
Get the horizontal coordinate of the first control point.
Returns:
The x coordinate of the first control point.
Get the vertical coordinate of the first control point.
Returns:
The y coordinate of the first control point.
Get the horizontal coordinate of the second control point.
Returns:
The x coordinate of the second control point.
Get the vertical coordinate of the second control point.
Returns:
The y coordinate of the second control point.
Get the ending horizontal coordinate of this segment.
Returns:
The x coordinate that this segment ends on.
Get the ending vertical coordinate of this segment.
Returns:
The y coordinate that this segment ends on.
182 def get_min_x(self) -> float: 183 return min([ 184 self._control_x1, 185 self._control_x2, 186 self._destination_x 187 ])
Get the minimum of the x coordinates in this segment.
Returns:
Minimum x coordinate of this segment.
189 def get_max_x(self) -> float: 190 return max([ 191 self._control_x1, 192 self._control_x2, 193 self._destination_x 194 ])
Get the maximum of the x coordinates in this segment.
Returns:
Maximum x coordinate of this segment.
196 def get_min_y(self) -> float: 197 return min([ 198 self._control_y1, 199 self._control_y2, 200 self._destination_y 201 ])
Get the minimum of the y coordinates in this segment.
Returns:
Minimum y coordinate of this segment.
214class Shape: 215 """Structure describing a multi-segement shape.""" 216 217 def __init__(self, start_x: float, start_y: float): 218 """Create a new multi-segment shape. 219 220 Args: 221 start_x: The starting x position of the shape. 222 start_y: The starting y position of the shape. 223 """ 224 self._start_x = start_x 225 self._start_y = start_y 226 self._closed = False 227 self._finished = False 228 self._segments: typing.List[Line] = [] 229 230 def add_line_to(self, x: float, y: float): 231 """Add a straight line to a shape. 232 233 Draw a straight line from the current position to a new destination which is used as the 234 next "current" position. 235 236 Args: 237 x: The x coordinate to which the line should be drawn. 238 y: The y coordinate to which the line should be drawn. 239 """ 240 self._assert_not_finished() 241 self._segments.append(StraightLine(x, y)) 242 243 def add_bezier_to(self, control_x1: float, control_y1: float, control_x2: float, 244 control_y2: float, destination_x: float, destination_y: float): 245 """Add a bezier curve to a shape. 246 247 Draw a bezier curve from the current position to a new destination which is used as the next 248 "current" position. 249 250 Args: 251 control_x1: The horizontal location of the first control point. 252 control_y1: The vertical location of the first control point. 253 control_x2: The horizontal location of the second control point. 254 control_y2: The vertical location of the second control point. 255 destination_x: The vertical location of the end coordinate. 256 destination_y: The horizontal location of the end coordinate. 257 """ 258 self._assert_not_finished() 259 self._segments.append(BezierLine( 260 control_x1, 261 control_y1, 262 control_x2, 263 control_y2, 264 destination_x, 265 destination_y 266 )) 267 268 def get_start_x(self) -> float: 269 """Retrieve the first x coordinate of this shape. 270 271 Get the horizontal coordinate from which the first segment draws. 272 273 Returns: 274 The starting x coordinate. 275 """ 276 return self._start_x 277 278 def get_start_y(self) -> float: 279 """Retrieve the first y coordinate of this shape. 280 281 Get the vertical coordinate from which the first segment draws. 282 283 Returns: 284 The starting y coordinate. 285 """ 286 return self._start_y 287 288 def get_segments(self) -> typing.Iterable[Line]: 289 """Retrieve shape segments. 290 291 Retrieve objects describing each of the segments in a shape. 292 293 Returns: 294 Segements in this shape. 295 """ 296 return self._segments 297 298 def get_is_finished(self) -> bool: 299 """Determine if a shape is finished. 300 301 Determine if the shape is finished so can be drawn. Returns true if finished (can be drawn) 302 and false otherwise (still building). A shape cannot be drawn until it is finished which can 303 be accomplished by either calling end or close. 304 305 Returns: 306 True if finished and false otherwise. 307 """ 308 return self._finished 309 310 def end(self): 311 """Draw a shape. 312 313 Draw a shape which consists of multiple line or curve segments and which can be either open 314 (stroke only) or closed (can be filled). 315 """ 316 self._assert_not_finished() 317 self._finished = True 318 self._closed = False 319 320 def close(self): 321 """Add a straight line to the starting coordinate. 322 323 Add a line in the shape from the current position to the start position, marking the shape 324 as finished and closed which allows it to be filled. 325 """ 326 self._assert_not_finished() 327 self._finished = True 328 self._closed = True 329 330 def get_is_closed(self) -> bool: 331 """Determine if a shape can be filled. 332 333 Determine if the shape is closed so can be filled. Returns true if closed (can be filled) 334 and false otherwise. 335 336 Returns: 337 True if closed and false otherwise. 338 """ 339 self._assert_finished() 340 return self._closed 341 342 def get_min_x(self): 343 """Determine the minimum x coordinate of a shape. 344 345 Determine the minimum x coordinate (relative to start position) that this shape may reach 346 to. This includes bezier control points but does not try to include stroke weight in its 347 calculation. 348 349 Returns: 350 Minimum x coordinate. 351 """ 352 self._assert_finished() 353 return min([self._start_x] + [x.get_min_x() for x in self._segments]) 354 355 def get_max_x(self): 356 """Determine the maximum x coordinate of a shape. 357 358 Determine the maximum x coordinate (relative to start position) that this shape may reach 359 to. This includes bezier control points but does not try to include stroke weight in its 360 calculation. 361 362 Returns: 363 Maximum x coordinate. 364 """ 365 self._assert_finished() 366 return max([self._start_x] + [x.get_max_x() for x in self._segments]) 367 368 def get_min_y(self): 369 """Determine the minimum y coordinate of a shape. 370 371 Determine the minimum y coordinate (relative to start position) that this shape may reach 372 to. This includes bezier control points but does not try to include stroke weight in its 373 calculation. 374 375 Returns: 376 Minimum y coordinate. 377 """ 378 self._assert_finished() 379 return min([self._start_y] + [x.get_min_y() for x in self._segments]) 380 381 def get_max_y(self): 382 """Determine the maximum y coordinate of a shape. 383 384 Determine the maximum y coordinate (relative to start position) that this shape may reach 385 to. This includes bezier control points but does not try to include stroke weight in its 386 calculation. 387 388 Returns: 389 Maximum y coordinate. 390 """ 391 self._assert_finished() 392 return max([self._start_y] + [x.get_max_y() for x in self._segments]) 393 394 def _assert_not_finished(self): 395 if self._finished: 396 raise RuntimeError('Whoops! This shape is already finished.') 397 398 def _assert_finished(self): 399 if not self._finished: 400 raise RuntimeError('Whoops! This shape is not yet finished.')
Structure describing a multi-segement shape.
217 def __init__(self, start_x: float, start_y: float): 218 """Create a new multi-segment shape. 219 220 Args: 221 start_x: The starting x position of the shape. 222 start_y: The starting y position of the shape. 223 """ 224 self._start_x = start_x 225 self._start_y = start_y 226 self._closed = False 227 self._finished = False 228 self._segments: typing.List[Line] = []
Create a new multi-segment shape.
Arguments:
- start_x: The starting x position of the shape.
- start_y: The starting y position of the shape.
230 def add_line_to(self, x: float, y: float): 231 """Add a straight line to a shape. 232 233 Draw a straight line from the current position to a new destination which is used as the 234 next "current" position. 235 236 Args: 237 x: The x coordinate to which the line should be drawn. 238 y: The y coordinate to which the line should be drawn. 239 """ 240 self._assert_not_finished() 241 self._segments.append(StraightLine(x, y))
Add a straight line to a shape.
Draw a straight line from the current position to a new destination which is used as the next "current" position.
Arguments:
- x: The x coordinate to which the line should be drawn.
- y: The y coordinate to which the line should be drawn.
243 def add_bezier_to(self, control_x1: float, control_y1: float, control_x2: float, 244 control_y2: float, destination_x: float, destination_y: float): 245 """Add a bezier curve to a shape. 246 247 Draw a bezier curve from the current position to a new destination which is used as the next 248 "current" position. 249 250 Args: 251 control_x1: The horizontal location of the first control point. 252 control_y1: The vertical location of the first control point. 253 control_x2: The horizontal location of the second control point. 254 control_y2: The vertical location of the second control point. 255 destination_x: The vertical location of the end coordinate. 256 destination_y: The horizontal location of the end coordinate. 257 """ 258 self._assert_not_finished() 259 self._segments.append(BezierLine( 260 control_x1, 261 control_y1, 262 control_x2, 263 control_y2, 264 destination_x, 265 destination_y 266 ))
Add a bezier curve to a shape.
Draw a bezier curve from the current position to a new destination which is used as the next "current" position.
Arguments:
- control_x1: The horizontal location of the first control point.
- control_y1: The vertical location of the first control point.
- control_x2: The horizontal location of the second control point.
- control_y2: The vertical location of the second control point.
- destination_x: The vertical location of the end coordinate.
- destination_y: The horizontal location of the end coordinate.
268 def get_start_x(self) -> float: 269 """Retrieve the first x coordinate of this shape. 270 271 Get the horizontal coordinate from which the first segment draws. 272 273 Returns: 274 The starting x coordinate. 275 """ 276 return self._start_x
Retrieve the first x coordinate of this shape.
Get the horizontal coordinate from which the first segment draws.
Returns:
The starting x coordinate.
278 def get_start_y(self) -> float: 279 """Retrieve the first y coordinate of this shape. 280 281 Get the vertical coordinate from which the first segment draws. 282 283 Returns: 284 The starting y coordinate. 285 """ 286 return self._start_y
Retrieve the first y coordinate of this shape.
Get the vertical coordinate from which the first segment draws.
Returns:
The starting y coordinate.
288 def get_segments(self) -> typing.Iterable[Line]: 289 """Retrieve shape segments. 290 291 Retrieve objects describing each of the segments in a shape. 292 293 Returns: 294 Segements in this shape. 295 """ 296 return self._segments
Retrieve shape segments.
Retrieve objects describing each of the segments in a shape.
Returns:
Segements in this shape.
298 def get_is_finished(self) -> bool: 299 """Determine if a shape is finished. 300 301 Determine if the shape is finished so can be drawn. Returns true if finished (can be drawn) 302 and false otherwise (still building). A shape cannot be drawn until it is finished which can 303 be accomplished by either calling end or close. 304 305 Returns: 306 True if finished and false otherwise. 307 """ 308 return self._finished
Determine if a shape is finished.
Determine if the shape is finished so can be drawn. Returns true if finished (can be drawn) and false otherwise (still building). A shape cannot be drawn until it is finished which can be accomplished by either calling end or close.
Returns:
True if finished and false otherwise.
310 def end(self): 311 """Draw a shape. 312 313 Draw a shape which consists of multiple line or curve segments and which can be either open 314 (stroke only) or closed (can be filled). 315 """ 316 self._assert_not_finished() 317 self._finished = True 318 self._closed = False
Draw a shape.
Draw a shape which consists of multiple line or curve segments and which can be either open (stroke only) or closed (can be filled).
320 def close(self): 321 """Add a straight line to the starting coordinate. 322 323 Add a line in the shape from the current position to the start position, marking the shape 324 as finished and closed which allows it to be filled. 325 """ 326 self._assert_not_finished() 327 self._finished = True 328 self._closed = True
Add a straight line to the starting coordinate.
Add a line in the shape from the current position to the start position, marking the shape as finished and closed which allows it to be filled.
330 def get_is_closed(self) -> bool: 331 """Determine if a shape can be filled. 332 333 Determine if the shape is closed so can be filled. Returns true if closed (can be filled) 334 and false otherwise. 335 336 Returns: 337 True if closed and false otherwise. 338 """ 339 self._assert_finished() 340 return self._closed
Determine if a shape can be filled.
Determine if the shape is closed so can be filled. Returns true if closed (can be filled) and false otherwise.
Returns:
True if closed and false otherwise.
342 def get_min_x(self): 343 """Determine the minimum x coordinate of a shape. 344 345 Determine the minimum x coordinate (relative to start position) that this shape may reach 346 to. This includes bezier control points but does not try to include stroke weight in its 347 calculation. 348 349 Returns: 350 Minimum x coordinate. 351 """ 352 self._assert_finished() 353 return min([self._start_x] + [x.get_min_x() for x in self._segments])
Determine the minimum x coordinate of a shape.
Determine the minimum x coordinate (relative to start position) that this shape may reach to. This includes bezier control points but does not try to include stroke weight in its calculation.
Returns:
Minimum x coordinate.
355 def get_max_x(self): 356 """Determine the maximum x coordinate of a shape. 357 358 Determine the maximum x coordinate (relative to start position) that this shape may reach 359 to. This includes bezier control points but does not try to include stroke weight in its 360 calculation. 361 362 Returns: 363 Maximum x coordinate. 364 """ 365 self._assert_finished() 366 return max([self._start_x] + [x.get_max_x() for x in self._segments])
Determine the maximum x coordinate of a shape.
Determine the maximum x coordinate (relative to start position) that this shape may reach to. This includes bezier control points but does not try to include stroke weight in its calculation.
Returns:
Maximum x coordinate.
368 def get_min_y(self): 369 """Determine the minimum y coordinate of a shape. 370 371 Determine the minimum y coordinate (relative to start position) that this shape may reach 372 to. This includes bezier control points but does not try to include stroke weight in its 373 calculation. 374 375 Returns: 376 Minimum y coordinate. 377 """ 378 self._assert_finished() 379 return min([self._start_y] + [x.get_min_y() for x in self._segments])
Determine the minimum y coordinate of a shape.
Determine the minimum y coordinate (relative to start position) that this shape may reach to. This includes bezier control points but does not try to include stroke weight in its calculation.
Returns:
Minimum y coordinate.
381 def get_max_y(self): 382 """Determine the maximum y coordinate of a shape. 383 384 Determine the maximum y coordinate (relative to start position) that this shape may reach 385 to. This includes bezier control points but does not try to include stroke weight in its 386 calculation. 387 388 Returns: 389 Maximum y coordinate. 390 """ 391 self._assert_finished() 392 return max([self._start_y] + [x.get_max_y() for x in self._segments])
Determine the maximum y coordinate of a shape.
Determine the maximum y coordinate (relative to start position) that this shape may reach to. This includes bezier control points but does not try to include stroke weight in its calculation.
Returns:
Maximum y coordinate.