simetri.canvas.draw
Canvas object uses these methods to draw shapes and text.
1"""Canvas object uses these methods to draw shapes and text.""" 2 3from math import cos, sin 4from typing_extensions import Self, Sequence 5 6from ..geometry.geometry import homogenize, ellipse_point, close_points2 7from ..graphics.all_enums import ( 8 Anchor, 9 BackStyle, 10 Drawable, 11 FrameShape, 12 PathOperation, 13 Types, 14 drawable_types, 15 TexLoc, 16) 17from ..colors import colors 18from ..tikz.tikz import scope_code_required 19from ..graphics.sketch import ( 20 ArcSketch, 21 BatchSketch, 22 BezierSketch, 23 CircleSketch, 24 EllipseSketch, 25 LineSketch, 26 PathSketch, 27 PatternSketch, 28 RectSketch, 29 ShapeSketch, 30 TagSketch, 31 TexSketch 32) 33from ..settings.settings import defaults 34from ..canvas.style_map import line_style_map, shape_style_map, group_args 35from ..helpers.illustration import Tag 36from ..graphics.affine import identity_matrix 37from ..graphics.shape import Shape 38from ..graphics.common import Point 39from ..geometry.bezier import bezier_points 40from ..geometry.ellipse import elliptic_arc_points 41from ..graphics.affine import rotation_matrix, translation_matrix 42from ..helpers.utilities import decompose_transformations 43 44 45Color = colors.Color 46 47 48def help_lines( 49 self, 50 pos: Point = None, 51 width: float = None, 52 height: float = None, 53 step_size=None, 54 cs_size: float = None, 55 **kwargs, 56): 57 """ 58 Draw a square grid with the given size. 59 60 Args: 61 pos (Point, optional): Position of the grid. Defaults to None. 62 width (float, optional): Length of the grid along the x-axis. Defaults to None. 63 height (float, optional): Length of the grid along the y-axis. Defaults to None. 64 step_size (optional): Step size for the grid. Defaults to None. 65 cs_size (float, optional): Size of the coordinate system. Defaults to None. 66 **kwargs: Additional keyword arguments. 67 68 Returns: 69 Self: The canvas object. 70 """ 71 self.grid(pos, width, height, step_size, **kwargs) 72 if cs_size > 0: 73 self.draw_CS(cs_size, **kwargs) 74 return self 75 76 77def arc( 78 self, 79 center: Point, 80 radius_x: float, 81 radius_y: float, 82 start_angle: float, 83 span_angle: float, 84 rot_angle: float, 85 n_points: int = None, 86 **kwargs, 87) -> None: 88 """ 89 Draw an arc with the given center, radius, start and end angles in radians. 90 Arc is drawn in counterclockwise direction from start to end. 91 92 Args: 93 center (Point): Center of the arc. 94 radius_x (float): Radius of the arc. 95 radius_y (float): Second radius of the arc. 96 start_angle (float): Start angle of the arc in radians. 97 end_angle (float): End angle of the arc in radians. 98 99 rot_angle (float): Rotation angle of the arc. 100 **kwargs: Additional keyword arguments. 101 """ 102 if radius_y is None: 103 radius_y = radius_x 104 vertices = elliptic_arc_points( 105 center, radius_x, radius_y, start_angle, span_angle, n_points 106 ) 107 if rot_angle != 0: 108 vertices = homogenize(vertices) @ rotation_matrix(rot_angle, center) 109 self._all_vertices.extend(vertices.tolist() + [center]) 110 111 sketch = ArcSketch(vertices=vertices, xform_matrix=self.xform_matrix) 112 for attrib_name in shape_style_map: 113 if hasattr(sketch, attrib_name): 114 attrib_value = self.resolve_property(sketch, attrib_name) 115 else: 116 attrib_value = defaults[attrib_name] 117 setattr(sketch, attrib_name, attrib_value) 118 for k, v in kwargs.items(): 119 setattr(sketch, k, v) 120 self.active_page.sketches.append(sketch) 121 122 return self 123 124 125def bezier(self, control_points, **kwargs): 126 """ 127 Draw a Bezier curve with the given control points. 128 129 Args: 130 control_points: Control points for the Bezier curve. 131 **kwargs: Additional keyword arguments. 132 133 Returns: 134 Self: The canvas object. 135 """ 136 self._all_vertices.extend(control_points) 137 sketch = BezierSketch(control_points, self.xform_matrix) 138 for attrib_name in shape_style_map: 139 if hasattr(sketch, attrib_name): 140 attrib_value = self._resolve_property(sketch, attrib_name) 141 else: 142 attrib_value = defaults[attrib_name] 143 setattr(sketch, attrib_name, attrib_value) 144 self.active_page.sketches.append(sketch) 145 146 for k, v in kwargs.items(): 147 setattr(sketch, k, v) 148 return self 149 150 151def circle(self, center: Point, radius: float, **kwargs) -> None: 152 """ 153 Draw a circle with the given center and radius. 154 155 Args: 156 center (Point): Center of the circle. 157 radius (float): Radius of the circle. 158 **kwargs: Additional keyword arguments. 159 """ 160 x, y = center[:2] 161 p1 = x - radius, y - radius 162 p2 = x + radius, y + radius 163 p3 = x - radius, y + radius 164 p4 = x + radius, y - radius 165 self._all_vertices.extend([p1, p2, p3, p4]) 166 sketch = CircleSketch(center, radius, self.xform_matrix) 167 for attrib_name in shape_style_map: 168 if hasattr(sketch, attrib_name): 169 attrib_value = self.resolve_property(sketch, attrib_name) 170 else: 171 attrib_value = defaults[attrib_name] 172 setattr(sketch, attrib_name, attrib_value) 173 for k, v in kwargs.items(): 174 setattr(sketch, k, v) 175 self.active_page.sketches.append(sketch) 176 177 return self 178 179 180def ellipse(self, center: Point, width: float, height, angle, **kwargs) -> None: 181 """ 182 Draw an ellipse with the given center and x_radius and y_radius. 183 184 Args: 185 center (Point): Center of the ellipse. 186 width (float): Width of the ellipse. 187 height: Height of the ellipse. 188 angle: Angle of the ellipse. 189 **kwargs: Additional keyword arguments. 190 """ 191 x, y = center[:2] 192 x_radius = width / 2 193 y_radius = height / 2 194 p1 = x - x_radius, y - y_radius 195 p2 = x + x_radius, y + y_radius 196 p3 = x - x_radius, y + y_radius 197 p4 = x + x_radius, y - y_radius 198 self._all_vertices.extend([p1, p2, p3, p4]) 199 sketch = EllipseSketch(center, x_radius, y_radius, angle, self.xform_matrix) 200 for attrib_name in shape_style_map: 201 if hasattr(sketch, attrib_name): 202 attrib_value = self.resolve_property(sketch, attrib_name) 203 else: 204 attrib_value = defaults[attrib_name] 205 setattr(sketch, attrib_name, attrib_value) 206 for k, v in kwargs.items(): 207 setattr(sketch, k, v) 208 self.active_page.sketches.append(sketch) 209 210 return self 211 212 213def text( 214 self, 215 txt: str, 216 pos: Point, 217 font_family: str = None, 218 font_size: int = None, 219 font_color: Color = None, 220 anchor: Anchor = None, 221 **kwargs, 222) -> None: 223 """ 224 Draw the given text at the given position. 225 226 Args: 227 txt (str): Text to be drawn. 228 pos (Point): Position of the text. 229 font_family (str, optional): Font family of the text. Defaults to None. 230 font_size (int, optional): Font size of the text. Defaults to None. 231 font_color (Color, optional): Font color of the text. Defaults to None. 232 anchor (Anchor, optional): Anchor of the text. Defaults to None. 233 **kwargs: Additional keyword arguments. 234 """ 235 # first create a Tag object 236 tag_obj = Tag( 237 txt, 238 pos, 239 font_family=font_family, 240 font_size=font_size, 241 font_color=font_color, 242 anchor=anchor, 243 **kwargs, 244 ) 245 tag_obj.draw_frame = False 246 # then call get_tag_sketch to create a TagSketch object 247 sketch = create_sketch(tag_obj, self, **kwargs) 248 self.active_page.sketches.append(sketch) 249 250 return self 251 252 253def line(self, start, end, **kwargs): 254 """ 255 Draw a line segment from start to end. 256 257 Args: 258 start: Starting point of the line. 259 end: Ending point of the line. 260 **kwargs: Additional keyword arguments. 261 262 Returns: 263 Self: The canvas object. 264 """ 265 self._sketch_xform_matrix = self.xform_matrix 266 line_shape = Shape([start, end], closed=False, **kwargs) 267 line_sketch = create_sketch(line_shape, self, **kwargs) 268 self.active_page.sketches.append(line_sketch) 269 self._sketch_xform_matrix = identity_matrix() 270 return self 271 272 273def rectangle(self, center: Point, width: float, height: float, angle: float, **kwargs): 274 """ 275 Draw a rectangle with the given center, width, height and angle. 276 277 Args: 278 center (Point): Center of the rectangle. 279 width (float): Width of the rectangle. 280 height (float): Height of the rectangle. 281 angle (float): Angle of the rectangle. 282 **kwargs: Additional keyword arguments. 283 284 Returns: 285 Self: The canvas object. 286 """ 287 w2 = width / 2 288 h2 = height / 2 289 p1 = center[0] - w2, center[1] + h2 290 p2 = center[0] - w2, center[1] - h2 291 p3 = center[0] + w2, center[1] - h2 292 p4 = center[0] + w2, center[1] + h2 293 points = homogenize([p1, p2, p3, p4]) @ rotation_matrix(angle, center) 294 rect_shape = Shape(points.tolist(), closed=True, **kwargs) 295 rect_sketch = create_sketch(rect_shape, self, **kwargs) 296 self.active_page.sketches.append(rect_sketch) 297 298 return self 299 300 301def draw_CS(self, size: float = None, **kwargs): 302 """ 303 Draw a coordinate system with the given size. 304 305 Args: 306 size (float, optional): Size of the coordinate system. Defaults to None. 307 **kwargs: Additional keyword arguments. 308 309 Returns: 310 Self: The canvas object. 311 """ 312 if size is None: 313 size = defaults["CS_size"] 314 if "colors" in kwargs: 315 x_color, y_color = kwargs["colors"] 316 del kwargs["colors"] 317 else: 318 x_color = defaults["CS_x_color"] 319 y_color = defaults["CS_y_color"] 320 if "line_width" not in kwargs: 321 kwargs["line_width"] = defaults["CS_line_width"] 322 self.line((0, 0), (size, 0), line_color=x_color, **kwargs) 323 self.line((0, 0), (0, size), line_color=y_color, **kwargs) 324 if "line_color" not in kwargs: 325 kwargs["line_color"] = defaults["CS_origin_color"] 326 self.circle((0, 0), radius=defaults["CS_origin_size"], **kwargs) 327 328 return self 329 330 331def lines(self, points, **kwargs): 332 """ 333 Draw connected line segments. 334 335 Args: 336 points: Points to be connected. 337 **kwargs: Additional keyword arguments. 338 339 Returns: 340 Self: The canvas object. 341 """ 342 self._all_vertices.extend(points) 343 sketch = LineSketch(points, self.xform_matrix, **kwargs) 344 for attrib_name in line_style_map: 345 attrib_value = self._resolve_property(sketch, attrib_name) 346 setattr(sketch, attrib_name, attrib_value) 347 self.active_page.sketches.append(sketch) 348 349 return self 350 351def insert_code(self, code: str, location: TexLoc = TexLoc.NONE) -> Self: 352 """ 353 Insert code into the canvas. 354 355 Args: 356 code (str): The code to insert. 357 358 Returns: 359 Self: The canvas object. 360 """ 361 active_sketches = self.active_page.sketches 362 sketch = TexSketch(code, location=location) 363 active_sketches.append(sketch) 364 365 return self 366 367def draw_bbox(self, bbox, **kwargs): 368 """ 369 Draw the bounding box object. 370 371 Args: 372 bbox: Bounding box to be drawn. 373 **kwargs: Additional keyword arguments. 374 375 Returns: 376 Self: The canvas object. 377 """ 378 sketch = create_sketch(bbox, self, **kwargs) 379 self.active_page.sketches.append(sketch) 380 381 return self 382 383 384def draw_pattern(self, pattern, **kwargs): 385 """ 386 Draw the pattern object. 387 388 Args: 389 pattern: Pattern object to be drawn. 390 **kwargs: Additional keyword arguments. 391 392 Returns: 393 Self: The canvas object. 394 """ 395 sketch = create_sketch(pattern, self, **kwargs) 396 self.active_page.sketches.append(sketch) 397 398 return self 399 400 401def draw_hobby( 402 self, 403 points: Sequence[Point], 404 controls: Sequence[Point], 405 cyclic: bool = False, 406 **kwargs, 407): 408 """Draw a Hobby curve through the given points using the control points. 409 410 Args: 411 points (Sequence[Point]): Points through which the curve passes. 412 controls (Sequence[Point]): Control points for the curve. 413 cyclic (bool, optional): Whether the curve is cyclic. Defaults to False. 414 **kwargs: Additional keyword arguments. 415 """ 416 n = len(points) 417 if cyclic: 418 for i in range(n): 419 ind = i * 2 420 bezier_pnts = bezier_points( 421 points[i], *controls[ind : ind + 2], points[(i + 1) % n], 20 422 ) 423 bezier_ = Shape(bezier_pnts) 424 self.draw(bezier_, **kwargs) 425 else: 426 for i in range(len(points) - 1): 427 ind = i * 2 428 bezier_pnts = bezier_points( 429 points[i], *controls[ind : ind + 2], points[i + 1], 20 430 ) 431 bezier_ = Shape(bezier_pnts) 432 self.draw(bezier_, **kwargs) 433 434 435def draw_lace(self, lace, **kwargs): 436 """Draw the lace object. 437 438 Args: 439 lace: Lace object to be drawn. 440 **kwargs: Additional keyword arguments. 441 442 Returns: 443 Self: The canvas object. 444 """ 445 keys = list(lace.fragment_groups.keys()) 446 keys.sort() 447 if lace.swatch is not None: 448 n_colors = len(lace.swatch) 449 for i, key in enumerate(keys): 450 if lace.swatch is not None: 451 fill_color = colors.Color(*lace.swatch[i % n_colors]) 452 kwargs["fill_color"] = fill_color 453 for fragment in lace.fragment_groups[key]: 454 self.active_page.sketches.append(create_sketch(fragment, self, **kwargs)) 455 for plait in lace.plaits: 456 if lace.swatch is not None: 457 fill_color = colors.white 458 kwargs["fill_color"] = fill_color 459 else: 460 kwargs["fill_color"] = None 461 self.active_page.sketches.append(create_sketch(plait, self, **kwargs)) 462 self._all_vertices.extend(plait.corners) 463 464 return self 465 466 467def draw_dimension(self, item, **kwargs): 468 """Draw the dimension object. 469 470 Args: 471 item: Dimension object to be drawn. 472 **kwargs: Additional keyword arguments. 473 474 Returns: 475 Self: The canvas object. 476 """ 477 for shape in item.all_shapes: 478 self._all_vertices.extend(shape.corners) 479 for ext in [item.ext1, item.ext2, item.ext3]: 480 if ext: 481 ext_sketch = create_sketch(ext, self, **kwargs) 482 self.active_page.sketches.append(ext_sketch) 483 if item.dim_line: 484 dim_sketch = create_sketch(item.dim_line, self, **kwargs) 485 self.active_page.sketches.extend(dim_sketch) 486 if item.arrow1: 487 arrow_sketch = create_sketch(item.arrow1, self, **kwargs) 488 self.active_page.sketches.extend(arrow_sketch) 489 self.active_page.sketches.append(create_sketch(item.mid_line, self)) 490 if item.arrow2: 491 arrow_sketch = create_sketch(item.arrow2, self, **kwargs) 492 self.active_page.sketches.extend(arrow_sketch) 493 x, y = item.text_pos[:2] 494 495 tag = Tag(item.text, (x, y), font_size=item.font_size, **kwargs) 496 tag_sketch = create_sketch(tag, self, **kwargs) 497 tag_sketch.draw_frame = True 498 tag_sketch.frame_shape = FrameShape.CIRCLE 499 tag_sketch.fill = True 500 tag_sketch.font_color = colors.black 501 tag_sketch.frame_back_style = BackStyle.COLOR 502 tag_sketch.back_style = BackStyle.COLOR 503 tag_sketch.frame_back_color = colors.white 504 tag_sketch.back_color = colors.white 505 tag_sketch.stroke = False 506 self.active_page.sketches.append(tag_sketch) 507 508 return self 509 510 511def grid( 512 self, 513 pos=(0, 0), 514 width: float = None, 515 height: float = None, 516 step_size=None, 517 **kwargs, 518): 519 """Draw a square grid with the given size. 520 521 Args: 522 pos (tuple, optional): Position of the grid. Defaults to (0, 0). 523 width (float, optional): Length of the grid along the x-axis. Defaults to None. 524 height (float, optional): Length of the grid along the y-axis. Defaults to None. 525 step_size (optional): Step size for the grid. Defaults to None. 526 **kwargs: Additional keyword arguments. 527 528 Returns: 529 Self: The canvas object. 530 """ 531 x, y = pos[:2] 532 if width is None: 533 width = defaults["grid_size"] 534 height = defaults["grid_size"] 535 if "line_width" not in kwargs: 536 kwargs["line_width"] = defaults["grid_line_width"] 537 if "line_color" not in kwargs: 538 kwargs["line_color"] = defaults["grid_line_color"] 539 if "line_dash_array" not in kwargs: 540 kwargs["line_dash_array"] = defaults["grid_line_dash_array"] 541 # draw x-axis 542 # self.line((-size, 0), (size, 0), **kwargs) 543 line_y = Shape([(x, y), (x + width, y)], **kwargs) 544 line_x = Shape([(x, y), (x, y + height)], **kwargs) 545 lines_x = line_y.translate(0, step_size, reps=int(height / step_size)) 546 lines_y = line_x.translate(step_size, 0, reps=int(width / step_size)) 547 self.draw(lines_x) 548 self.draw(lines_y) 549 return self 550 551 552regular_sketch_types = [ 553 Types.ARC, 554 Types.ARC_ARROW, 555 Types.BATCH, 556 Types.BEZIER, 557 Types.CIRCLE, 558 Types.CIRCULAR_GRID, 559 Types.DIVISION, 560 Types.DOT, 561 Types.DOTS, 562 Types.ELLIPSE, 563 Types.FRAGMENT, 564 Types.HEX_GRID, 565 Types.LINPATH, 566 Types.MIXED_GRID, 567 Types.OUTLINE, 568 Types.OVERLAP, 569 Types.PARALLEL_POLYLINE, 570 Types.PLAIT, 571 Types.POLYLINE, 572 Types.Q_BEZIER, 573 Types.RECTANGLE, 574 Types.SECTION, 575 Types.SEGMENT, 576 Types.SHAPE, 577 Types.SINE_WAVE, 578 Types.SQUARE_GRID, 579 Types.STAR, 580 Types.TAG, 581] 582 583 584def extend_vertices(canvas, item): 585 """Extend the list of all vertices with the vertices of the given item. 586 587 Args: 588 canvas: Canvas object. 589 item: Item whose vertices are to be extended. 590 """ 591 all_vertices = canvas._all_vertices 592 if item.subtype == Types.DOTS: 593 vertices = [x.pos for x in item.all_shapes] 594 vertices = [x[:2] for x in homogenize(vertices) @ canvas._sketch_xform_matrix] 595 all_vertices.extend(vertices) 596 elif item.subtype == Types.DOT: 597 vertices = [item.pos] 598 vertices = [x[:2] for x in homogenize(vertices) @ canvas._sketch_xform_matrix] 599 all_vertices.extend(vertices) 600 elif item.subtype == Types.ARROW: 601 for shape in item.all_shapes: 602 all_vertices.extend(shape.corners) 603 elif item.subtype == Types.LACE: 604 for plait in item.plaits: 605 all_vertices.extend(plait.corners) 606 for fragment in item.fragments: 607 all_vertices.extend(fragment.corners) 608 elif item.subtype == Types.PATTERN: 609 all_vertices.extend(item.get_all_vertices()) 610 else: 611 corners = [x[:2] for x in homogenize(item.corners) @ canvas._sketch_xform_matrix] 612 all_vertices.extend(corners) 613 614 615def draw(self, item: Drawable, **kwargs) -> Self: 616 """The item is drawn on the canvas with the given style properties. 617 618 Args: 619 item (Drawable): Item to be drawn. 620 **kwargs: Additional keyword arguments. 621 622 Returns: 623 Self: The canvas object. 624 """ 625 # check if the item has any points 626 if not item: 627 return self 628 629 active_sketches = self.active_page.sketches 630 subtype = item.subtype 631 extend_vertices(self, item) 632 if subtype in regular_sketch_types: 633 sketches = get_sketches(item, self, **kwargs) 634 if sketches: 635 active_sketches.extend(sketches) 636 elif subtype == Types.PATTERN: 637 draw_pattern(self, item, **kwargs) 638 elif subtype == Types.DIMENSION: 639 self.draw_dimension(item, **kwargs) 640 elif subtype == Types.ARROW: 641 for head in item.heads: 642 active_sketches.append(create_sketch(head, self, **kwargs)) 643 active_sketches.append(create_sketch(item.line, self, **kwargs)) 644 elif subtype == Types.LACE: 645 self.draw_lace(item, **kwargs) 646 elif subtype == Types.BOUNDING_BOX: 647 draw_bbox(self, item, **kwargs) 648 return self 649 650 651def get_sketches(item: Drawable, canvas: "Canvas" = None, **kwargs) -> list["Sketch"]: 652 """Create sketches from the given item and return them as a list. 653 654 Args: 655 item (Drawable): Item to be sketched. 656 canvas (Canvas, optional): Canvas object. Defaults to None. 657 **kwargs: Additional keyword arguments. 658 659 Returns: 660 list[Sketch]: List of sketches. 661 """ 662 if not (item.visible and item.active): 663 res = [] 664 elif item.subtype in drawable_types: 665 sketches = create_sketch(item, canvas, **kwargs) 666 if isinstance(sketches, list): 667 res = sketches 668 elif sketches is not None: 669 res = [sketches] 670 else: 671 res = [] 672 else: 673 res = [] 674 return res 675 676 677def set_shape_sketch_style(sketch, item, canvas, linear=False, **kwargs): 678 """Set the style properties of the sketch. 679 680 Args: 681 sketch: Sketch object. 682 item: Item whose style properties are to be set. 683 canvas: Canvas object. 684 linear (bool, optional): Whether the style is linear. Defaults to False. 685 **kwargs: Additional keyword arguments. 686 """ 687 if linear: 688 style_map = line_style_map 689 else: 690 style_map = shape_style_map 691 692 for attrib_name in style_map: 693 attrib_value = canvas._resolve_property(item, attrib_name) 694 setattr(sketch, attrib_name, attrib_value) 695 696 sketch.visible = item.visible 697 sketch.active = item.active 698 sketch.closed = item.closed 699 sketch.fill = item.fill 700 sketch.stroke = item.stroke 701 702 for k, v in kwargs.items(): 703 setattr(sketch, k, v) 704 705def get_verts_in_new_pos(item, **kwargs): 706 """ 707 Get the vertices of the item in a new position. 708 709 Args: 710 item: Item whose vertices are to be obtained. 711 **kwargs: Additional keyword arguments. 712 713 Returns: 714 list: List of vertices in the new position. 715 """ 716 if "pos" in kwargs: 717 x, y = item.midpoint[:2] 718 x1, y1 = kwargs["pos"][:2] 719 dx = x1 - x 720 dy = y1 - y 721 trans_mat = translation_matrix(dx, dy) 722 vertices = item.primary_points.homogen_coords @ trans_mat 723 vertices = vertices[:, :2].tolist() 724 else: 725 vertices = item.vertices 726 727 return vertices 728 729 730def create_sketch(item, canvas, **kwargs): 731 """Create a sketch from the given item. 732 733 Args: 734 item: Item to be sketched. 735 canvas: Canvas object. 736 **kwargs: Additional keyword arguments. 737 738 Returns: 739 Sketch: Created sketch. 740 """ 741 if not (item.visible and item.active): 742 return None 743 744 def get_tag_sketch(item, canvas, **kwargs): 745 """Create a TagSketch from the given item. 746 747 Args: 748 item: Item to be sketched. 749 canvas: Canvas object. 750 **kwargs: Additional keyword arguments. 751 752 Returns: 753 TagSketch: Created TagSketch. 754 """ 755 if "pos" in kwargs: 756 pos = kwargs["pos"] 757 else: 758 pos = item.pos 759 760 sketch = TagSketch(text=item.text, pos=pos, anchor=item.anchor) 761 for attrib_name in item._style_map: 762 if attrib_name == "fill_color": 763 if item.fill_color in [None, colors.black]: 764 setattr(sketch, "frame_back_color", defaults["frame_back_color"]) 765 else: 766 setattr(sketch, "frame_back_color", item.fill_color) 767 continue 768 attrib_value = canvas._resolve_property(item, attrib_name) 769 setattr(sketch, attrib_name, attrib_value) 770 sketch.text_width = item.text_width 771 sketch.visible = item.visible 772 sketch.active = item.active 773 for k, v in kwargs.items(): 774 setattr(sketch, k, v) 775 return sketch 776 777 def get_ellipse_sketch(item, canvas, **kwargs): 778 """Create an EllipseSketch from the given item. 779 780 Args: 781 item: Item to be sketched. 782 canvas: Canvas object. 783 **kwargs: Additional keyword arguments. 784 785 Returns: 786 EllipseSketch: Created EllipseSketch. 787 """ 788 if "pos" in kwargs: 789 center = kwargs["pos"] 790 else: 791 center = item.center 792 793 sketch = EllipseSketch( 794 center, 795 item.a, 796 item.b, 797 item.angle, 798 xform_matrix=canvas.xform_matrix, 799 **kwargs, 800 ) 801 set_shape_sketch_style(sketch, item, canvas, **kwargs) 802 803 return sketch 804 805 def get_pattern_sketch(item, canvas, **kwargs): 806 """Create a PatternSketch from the given item. 807 808 Args: 809 item: Item to be sketched. 810 canvas: Canvas object. 811 **kwargs: Additional keyword arguments. 812 813 Returns: 814 PatternSketch: Created PatternSketch. 815 """ 816 sketch = PatternSketch(item, xform_matrix=canvas.xform_matrix, **kwargs) 817 set_shape_sketch_style(sketch, item, canvas, **kwargs) 818 819 return sketch 820 821 def get_circle_sketch(item, canvas, **kwargs): 822 """Create a CircleSketch from the given item. 823 824 Args: 825 item: Item to be sketched. 826 canvas: Canvas object. 827 **kwargs: Additional keyword arguments. 828 829 Returns: 830 CircleSketch: Created CircleSketch. 831 """ 832 if "pos" in kwargs: 833 center = kwargs["pos"] 834 else: 835 center = item.center 836 sketch = CircleSketch( 837 center, item.radius, xform_matrix=canvas.xform_matrix 838 ) 839 set_shape_sketch_style(sketch, item, canvas, **kwargs) 840 841 return sketch 842 843 def get_dots_sketch(item, canvas, **kwargs): 844 """Create sketches for dots from the given item. 845 846 Args: 847 item: Item to be sketched. 848 canvas: Canvas object. 849 **kwargs: Additional keyword arguments. 850 851 Returns: 852 list: List of created sketches. 853 """ 854 vertices = [x.pos for x in item.all_shapes] 855 fill_color = item[0].fill_color 856 radius = item[0].radius 857 marker_size = item[0].marker_size 858 marker_type = item[0].marker_type 859 item = Shape( 860 vertices, 861 fill_color=fill_color, 862 markers_only=True, 863 draw_markers=True, 864 marker_size=marker_size, 865 marker_radius=radius, 866 marker_type=marker_type, 867 ) 868 sketches = get_sketches(item, canvas, **kwargs) 869 870 return sketches 871 872 def get_arc_sketch(item, canvas, **kwargs): 873 """Create an ArcSketch from the given item. 874 875 Args: 876 item: Item to be sketched. 877 canvas: Canvas object. 878 **kwargs: Additional keyword arguments. 879 880 Returns: 881 ArcSketch: Created ArcSketch. 882 """ 883 884 # vertices = get_verts_in_new_pos(item, **kwargs) 885 sketch = ArcSketch(item.vertices, xform_matrix=canvas._sketch_xform_matrix) 886 set_shape_sketch_style(sketch, item, canvas, **kwargs) 887 888 return sketch 889 890 def get_lace_sketch(item, canvas, **kwargs): 891 """Create sketches for lace from the given item. 892 893 Args: 894 item: Item to be sketched. 895 canvas: Canvas object. 896 **kwargs: Additional keyword arguments. 897 898 Returns: 899 list: List of created sketches. 900 """ 901 sketches = [get_sketch(frag, canvas, **kwargs) for frag in item.fragments] 902 sketches.extend([get_sketch(plait, canvas, **kwargs) for plait in item.plaits]) 903 return sketches 904 905 def get_batch_sketch(item, canvas, **kwargs): 906 """Create a BatchSketch from the given item. 907 908 Args: 909 item: Item to be sketched. 910 canvas: Canvas object. 911 **kwargs: Additional keyword arguments. 912 913 Returns: 914 BatchSketch or list: Created BatchSketch or list of sketches. 915 """ 916 if scope_code_required(item): 917 sketches = [] 918 for element in item.elements: 919 if element.visible and element.active: 920 sketches.extend(get_sketches(element, canvas, **kwargs)) 921 922 sketch = BatchSketch(sketches=sketches) 923 for arg in group_args: 924 setattr(sketch, arg, getattr(item, arg)) 925 926 res = sketch 927 else: 928 sketches = [] 929 for element in item.elements: 930 if hasattr(element, "visible") and hasattr(element, "active"): 931 if element.visible and element.active: 932 sketches.extend(get_sketches(element, canvas, **kwargs)) 933 934 res = sketches 935 936 return res 937 938 def get_path_sketch(item, canvas, **kwargs): 939 """Create sketches for a path from the given item. 940 941 Args: 942 item: Item to be sketched. 943 canvas: Canvas object. 944 **kwargs: Additional keyword arguments. 945 946 Returns: 947 list: List of created sketches. 948 """ 949 950 def extend_verts(obj, vertices): 951 obj_vertices = obj.vertices 952 if obj_vertices: 953 if vertices and close_points2(vertices[-1], obj_vertices[0]): 954 obj_vertices = obj_vertices[1:] 955 vertices.extend(obj_vertices) 956 957 path_op = PathOperation 958 linears = [ 959 path_op.ARC, 960 path_op.ARC_TO, 961 path_op.BLEND_ARC, 962 path_op.BLEND_CUBIC, 963 path_op.BLEND_QUAD, 964 path_op.BLEND_SINE, 965 path_op.CUBIC_TO, 966 path_op.FORWARD, 967 path_op.H_LINE, 968 path_op.HOBBY_TO, 969 path_op.QUAD_TO, 970 path_op.R_LINE, 971 path_op.SEGMENTS, 972 path_op.SINE, 973 path_op.V_LINE, 974 path_op.LINE_TO, 975 ] 976 sketches = [] 977 vertices = [] 978 for i, op in enumerate(item.operations): 979 if op.subtype in linears: 980 obj = item.objects[i] 981 extend_verts(obj, vertices) 982 elif op.subtype in [path_op.MOVE_TO, path_op.R_MOVE]: 983 if i == 0: 984 continue 985 shape = Shape(vertices) 986 sketch = create_sketch(shape, canvas, **kwargs) 987 if sketch: 988 sketch.visible = item.visible 989 sketch.active = item.active 990 sketches.append(sketch) 991 vertices = [] 992 elif op.subtype == path_op.CLOSE: 993 shape = Shape(vertices, closed=True) 994 sketch = create_sketch(shape, canvas, **kwargs) 995 if sketch: 996 sketch.visible = item.visible 997 sketch.active = item.active 998 sketches.append(sketch) 999 vertices = [] 1000 if vertices: 1001 shape = Shape(vertices) 1002 sketch = create_sketch(shape, canvas, **kwargs) 1003 sketches.append(sketch) 1004 1005 if "handles" in kwargs and kwargs["handles"]: 1006 handles = kwargs["handles"] 1007 del kwargs["handles"] 1008 for handle in item.handles: 1009 shape = Shape(handle) 1010 shape.subtype = Types.HANDLE 1011 handle_sketches = create_sketch(shape, canvas, **kwargs) 1012 sketches.extend(handle_sketches) 1013 1014 for sketch in sketches: 1015 item.closed = sketch.closed 1016 set_shape_sketch_style(sketch, item, canvas, **kwargs) 1017 1018 return sketches 1019 1020 def get_bbox_sketch(item, canvas, **kwargs): 1021 """Create a bounding box sketch from the given item. 1022 1023 Args: 1024 item: Item to be sketched. 1025 canvas: Canvas object. 1026 **kwargs: Additional keyword arguments. 1027 1028 Returns: 1029 ShapeSketch: Created bounding box sketch. 1030 """ 1031 nround = defaults["tikz_nround"] 1032 vertices = [(round(x[0], nround), round(x[1], nround)) for x in item.corners] 1033 if not vertices: 1034 return None 1035 1036 sketch = ShapeSketch(vertices, canvas._sketch_xform_matrix) 1037 sketch.subtype = Types.BBOX_SKETCH 1038 sketch.visible = True 1039 sketch.active = True 1040 sketch.closed = True 1041 sketch.fill = False 1042 sketch.stroke = True 1043 sketch.line_color = colors.gray 1044 sketch.line_width = 1 1045 sketch.line_dash_array = [3, 3] 1046 sketch.draw_markers = False 1047 return sketch 1048 1049 def get_handle_sketch(item, canvas, **kwargs): 1050 """Create handle sketches from the given item. 1051 1052 Args: 1053 item: Item to be sketched. 1054 canvas: Canvas object. 1055 **kwargs: Additional keyword arguments. 1056 1057 Returns: 1058 list: List of created handle sketches. 1059 """ 1060 nround = defaults["tikz_nround"] 1061 vertices = [(round(x[0], nround), round(x[1], nround)) for x in item.vertices] 1062 if not vertices: 1063 return None 1064 if 'pos' in kwargs: 1065 x, y = item.midpoint[:2] 1066 x1, y1 = kwargs["pos"][:2] 1067 dx = x1 - x 1068 dy = y1 - y 1069 vertices = [(x+dx, y+dy) for x, y in vertices] 1070 sketches = [] 1071 sketch = ShapeSketch(vertices, canvas._sketch_xform_matrix) 1072 sketch.subtype = Types.HANDLE 1073 sketch.closed = False 1074 set_shape_sketch_style(sketch, item, canvas, **kwargs) 1075 sketches.append(sketch) 1076 temp_item = Shape() 1077 temp_item.closed = True 1078 handle1 = RectSketch(item.vertices[0], 3, 3, canvas._sketch_xform_matrix) 1079 set_shape_sketch_style(handle1, temp_item, canvas, **kwargs) 1080 handle2 = RectSketch(item.vertices[-1], 3, 3, canvas._sketch_xform_matrix) 1081 set_shape_sketch_style(handle2, temp_item, canvas, **kwargs) 1082 sketches.extend([handle1, handle2]) 1083 1084 return sketches 1085 1086 def get_sketch(item, canvas, **kwargs): 1087 """Create a sketch from the given item. 1088 1089 Args: 1090 item: Item to be sketched. 1091 canvas: Canvas object. 1092 **kwargs: Additional keyword arguments. 1093 1094 Returns: 1095 ShapeSketch: Created sketch. 1096 """ 1097 if not item.vertices: 1098 return None 1099 1100 # vertices = get_verts_in_new_pos(item, **kwargs) 1101 nround = defaults["tikz_nround"] 1102 vertices = [ 1103 (round(x[0], nround), round(x[1], nround)) for x in item.vertices 1104 ] 1105 1106 sketch = ShapeSketch(vertices, canvas._sketch_xform_matrix) 1107 set_shape_sketch_style(sketch, item, canvas, **kwargs) 1108 1109 return sketch 1110 1111 d_subtype_sketch = { 1112 Types.ARC: get_arc_sketch, 1113 Types.ARC_ARROW: get_batch_sketch, 1114 Types.ARROW: get_batch_sketch, 1115 Types.ARROW_HEAD: get_sketch, 1116 Types.BATCH: get_batch_sketch, 1117 Types.BEZIER: get_sketch, 1118 Types.BOUNDING_BOX: get_bbox_sketch, 1119 Types.CIRCLE: get_circle_sketch, 1120 Types.CIRCULAR_GRID: get_batch_sketch, 1121 Types.DIVISION: get_sketch, 1122 Types.DOT: get_circle_sketch, 1123 Types.DOTS: get_dots_sketch, 1124 Types.ELLIPSE: get_sketch, 1125 Types.FRAGMENT: get_sketch, 1126 Types.HANDLE: get_handle_sketch, 1127 Types.HEX_GRID: get_batch_sketch, 1128 Types.LACE: get_lace_sketch, 1129 Types.LINPATH: get_path_sketch, 1130 Types.MIXED_GRID: get_batch_sketch, 1131 Types.OVERLAP: get_batch_sketch, 1132 Types.PARALLEL_POLYLINE: get_batch_sketch, 1133 Types.PATTERN: get_pattern_sketch, 1134 Types.PLAIT: get_sketch, 1135 Types.POLYLINE: get_sketch, 1136 Types.Q_BEZIER: get_sketch, 1137 Types.RECTANGLE: get_sketch, 1138 Types.SECTION: get_sketch, 1139 Types.SEGMENT: get_sketch, 1140 Types.SHAPE: get_sketch, 1141 Types.SINE_WAVE: get_sketch, 1142 Types.SQUARE_GRID: get_batch_sketch, 1143 Types.STAR: get_batch_sketch, 1144 Types.TAG: get_tag_sketch, 1145 } 1146 1147 return d_subtype_sketch[item.subtype](item, canvas, **kwargs)
116@dataclass 117class Color: 118 """A class representing an RGB or RGBA color. 119 120 This class represents a color in RGB or RGBA color space. The default values 121 for the components are normalized between 0.0 and 1.0. Values outside this range 122 are automatically converted from the 0-255 range. 123 124 Attributes: 125 red: The red component of the color (0.0 to 1.0). 126 green: The green component of the color (0.0 to 1.0). 127 blue: The blue component of the color (0.0 to 1.0). 128 alpha: The alpha (transparency) component (0.0 to 1.0), default is 1. 129 space: The color space, default is "rgb". 130 131 Examples: 132 >>> red = Color(1.0, 0.0, 0.0) 133 >>> transparent_blue = Color(0.0, 0.0, 1.0, 0.5) 134 >>> rgb255 = Color(255, 0, 128) # Will be automatically normalized 135 """ 136 red: int = 0 137 green: int = 0 138 blue: int = 0 139 alpha: int = 1 140 space: ColorSpace = "rgb" # for future use 141 142 def __post_init__(self): 143 """Post-initialization to ensure color values are in the correct range.""" 144 r, g, b = self.red, self.green, self.blue 145 if r < 0 or r > 1 or g < 0 or g > 1 or b < 0 or b > 1: 146 self.red = r / 255 147 self.green = g / 255 148 self.blue = b / 255 149 if self.alpha < 0 or self.alpha > 1: 150 self.alpha = self.alpha / 255 151 common_properties(self) 152 153 def __str__(self): 154 return f"Color({self.red}, {self.green}, {self.blue})" 155 156 def __repr__(self): 157 return f"Color({self.red}, {self.green}, {self.blue})" 158 159 def copy(self): 160 return Color(self.red, self.green, self.blue, self.alpha) 161 162 @property 163 def __key__(self): 164 return (self.red, self.green, self.blue) 165 166 def __hash__(self): 167 return hash(self.__key__) 168 169 @property 170 def name(self): 171 # search for the color in the named colors 172 pass 173 174 def __eq__(self, other): 175 if isinstance(other, Color): 176 return self.__key__ == other.__key__ 177 else: 178 return False 179 180 @property 181 def rgb(self): 182 return (self.red, self.green, self.blue) 183 184 @property 185 def rgba(self): 186 return (self.red, self.green, self.blue, self.alpha) 187 188 @property 189 def rgb255(self): 190 r, g, b = self.rgb 191 if r > 1 or g > 1 or b > 1: 192 return (r, g, b) 193 return tuple(round(i * 255) for i in self.rgb) 194 195 @property 196 def rgba255(self): 197 return tuple(round(i * 255) for i in self.rgba)
A class representing an RGB or RGBA color.
This class represents a color in RGB or RGBA color space. The default values for the components are normalized between 0.0 and 1.0. Values outside this range are automatically converted from the 0-255 range.
Attributes:
- red: The red component of the color (0.0 to 1.0).
- green: The green component of the color (0.0 to 1.0).
- blue: The blue component of the color (0.0 to 1.0).
- alpha: The alpha (transparency) component (0.0 to 1.0), default is 1.
- space: The color space, default is "rgb".
Examples:
>>> red = Color(1.0, 0.0, 0.0) >>> transparent_blue = Color(0.0, 0.0, 1.0, 0.5) >>> rgb255 = Color(255, 0, 128) # Will be automatically normalized
49def help_lines( 50 self, 51 pos: Point = None, 52 width: float = None, 53 height: float = None, 54 step_size=None, 55 cs_size: float = None, 56 **kwargs, 57): 58 """ 59 Draw a square grid with the given size. 60 61 Args: 62 pos (Point, optional): Position of the grid. Defaults to None. 63 width (float, optional): Length of the grid along the x-axis. Defaults to None. 64 height (float, optional): Length of the grid along the y-axis. Defaults to None. 65 step_size (optional): Step size for the grid. Defaults to None. 66 cs_size (float, optional): Size of the coordinate system. Defaults to None. 67 **kwargs: Additional keyword arguments. 68 69 Returns: 70 Self: The canvas object. 71 """ 72 self.grid(pos, width, height, step_size, **kwargs) 73 if cs_size > 0: 74 self.draw_CS(cs_size, **kwargs) 75 return self
Draw a square grid with the given size.
Arguments:
- pos (Point, optional): Position of the grid. Defaults to None.
- width (float, optional): Length of the grid along the x-axis. Defaults to None.
- height (float, optional): Length of the grid along the y-axis. Defaults to None.
- step_size (optional): Step size for the grid. Defaults to None.
- cs_size (float, optional): Size of the coordinate system. Defaults to None.
- **kwargs: Additional keyword arguments.
Returns:
Self: The canvas object.
78def arc( 79 self, 80 center: Point, 81 radius_x: float, 82 radius_y: float, 83 start_angle: float, 84 span_angle: float, 85 rot_angle: float, 86 n_points: int = None, 87 **kwargs, 88) -> None: 89 """ 90 Draw an arc with the given center, radius, start and end angles in radians. 91 Arc is drawn in counterclockwise direction from start to end. 92 93 Args: 94 center (Point): Center of the arc. 95 radius_x (float): Radius of the arc. 96 radius_y (float): Second radius of the arc. 97 start_angle (float): Start angle of the arc in radians. 98 end_angle (float): End angle of the arc in radians. 99 100 rot_angle (float): Rotation angle of the arc. 101 **kwargs: Additional keyword arguments. 102 """ 103 if radius_y is None: 104 radius_y = radius_x 105 vertices = elliptic_arc_points( 106 center, radius_x, radius_y, start_angle, span_angle, n_points 107 ) 108 if rot_angle != 0: 109 vertices = homogenize(vertices) @ rotation_matrix(rot_angle, center) 110 self._all_vertices.extend(vertices.tolist() + [center]) 111 112 sketch = ArcSketch(vertices=vertices, xform_matrix=self.xform_matrix) 113 for attrib_name in shape_style_map: 114 if hasattr(sketch, attrib_name): 115 attrib_value = self.resolve_property(sketch, attrib_name) 116 else: 117 attrib_value = defaults[attrib_name] 118 setattr(sketch, attrib_name, attrib_value) 119 for k, v in kwargs.items(): 120 setattr(sketch, k, v) 121 self.active_page.sketches.append(sketch) 122 123 return self
Draw an arc with the given center, radius, start and end angles in radians. Arc is drawn in counterclockwise direction from start to end.
Arguments:
- center (Point): Center of the arc.
- radius_x (float): Radius of the arc.
- radius_y (float): Second radius of the arc.
- start_angle (float): Start angle of the arc in radians.
- end_angle (float): End angle of the arc in radians.
- rot_angle (float): Rotation angle of the arc.
- **kwargs: Additional keyword arguments.
126def bezier(self, control_points, **kwargs): 127 """ 128 Draw a Bezier curve with the given control points. 129 130 Args: 131 control_points: Control points for the Bezier curve. 132 **kwargs: Additional keyword arguments. 133 134 Returns: 135 Self: The canvas object. 136 """ 137 self._all_vertices.extend(control_points) 138 sketch = BezierSketch(control_points, self.xform_matrix) 139 for attrib_name in shape_style_map: 140 if hasattr(sketch, attrib_name): 141 attrib_value = self._resolve_property(sketch, attrib_name) 142 else: 143 attrib_value = defaults[attrib_name] 144 setattr(sketch, attrib_name, attrib_value) 145 self.active_page.sketches.append(sketch) 146 147 for k, v in kwargs.items(): 148 setattr(sketch, k, v) 149 return self
Draw a Bezier curve with the given control points.
Arguments:
- control_points: Control points for the Bezier curve.
- **kwargs: Additional keyword arguments.
Returns:
Self: The canvas object.
152def circle(self, center: Point, radius: float, **kwargs) -> None: 153 """ 154 Draw a circle with the given center and radius. 155 156 Args: 157 center (Point): Center of the circle. 158 radius (float): Radius of the circle. 159 **kwargs: Additional keyword arguments. 160 """ 161 x, y = center[:2] 162 p1 = x - radius, y - radius 163 p2 = x + radius, y + radius 164 p3 = x - radius, y + radius 165 p4 = x + radius, y - radius 166 self._all_vertices.extend([p1, p2, p3, p4]) 167 sketch = CircleSketch(center, radius, self.xform_matrix) 168 for attrib_name in shape_style_map: 169 if hasattr(sketch, attrib_name): 170 attrib_value = self.resolve_property(sketch, attrib_name) 171 else: 172 attrib_value = defaults[attrib_name] 173 setattr(sketch, attrib_name, attrib_value) 174 for k, v in kwargs.items(): 175 setattr(sketch, k, v) 176 self.active_page.sketches.append(sketch) 177 178 return self
Draw a circle with the given center and radius.
Arguments:
- center (Point): Center of the circle.
- radius (float): Radius of the circle.
- **kwargs: Additional keyword arguments.
181def ellipse(self, center: Point, width: float, height, angle, **kwargs) -> None: 182 """ 183 Draw an ellipse with the given center and x_radius and y_radius. 184 185 Args: 186 center (Point): Center of the ellipse. 187 width (float): Width of the ellipse. 188 height: Height of the ellipse. 189 angle: Angle of the ellipse. 190 **kwargs: Additional keyword arguments. 191 """ 192 x, y = center[:2] 193 x_radius = width / 2 194 y_radius = height / 2 195 p1 = x - x_radius, y - y_radius 196 p2 = x + x_radius, y + y_radius 197 p3 = x - x_radius, y + y_radius 198 p4 = x + x_radius, y - y_radius 199 self._all_vertices.extend([p1, p2, p3, p4]) 200 sketch = EllipseSketch(center, x_radius, y_radius, angle, self.xform_matrix) 201 for attrib_name in shape_style_map: 202 if hasattr(sketch, attrib_name): 203 attrib_value = self.resolve_property(sketch, attrib_name) 204 else: 205 attrib_value = defaults[attrib_name] 206 setattr(sketch, attrib_name, attrib_value) 207 for k, v in kwargs.items(): 208 setattr(sketch, k, v) 209 self.active_page.sketches.append(sketch) 210 211 return self
Draw an ellipse with the given center and x_radius and y_radius.
Arguments:
- center (Point): Center of the ellipse.
- width (float): Width of the ellipse.
- height: Height of the ellipse.
- angle: Angle of the ellipse.
- **kwargs: Additional keyword arguments.
214def text( 215 self, 216 txt: str, 217 pos: Point, 218 font_family: str = None, 219 font_size: int = None, 220 font_color: Color = None, 221 anchor: Anchor = None, 222 **kwargs, 223) -> None: 224 """ 225 Draw the given text at the given position. 226 227 Args: 228 txt (str): Text to be drawn. 229 pos (Point): Position of the text. 230 font_family (str, optional): Font family of the text. Defaults to None. 231 font_size (int, optional): Font size of the text. Defaults to None. 232 font_color (Color, optional): Font color of the text. Defaults to None. 233 anchor (Anchor, optional): Anchor of the text. Defaults to None. 234 **kwargs: Additional keyword arguments. 235 """ 236 # first create a Tag object 237 tag_obj = Tag( 238 txt, 239 pos, 240 font_family=font_family, 241 font_size=font_size, 242 font_color=font_color, 243 anchor=anchor, 244 **kwargs, 245 ) 246 tag_obj.draw_frame = False 247 # then call get_tag_sketch to create a TagSketch object 248 sketch = create_sketch(tag_obj, self, **kwargs) 249 self.active_page.sketches.append(sketch) 250 251 return self
Draw the given text at the given position.
Arguments:
- txt (str): Text to be drawn.
- pos (Point): Position of the text.
- font_family (str, optional): Font family of the text. Defaults to None.
- font_size (int, optional): Font size of the text. Defaults to None.
- font_color (Color, optional): Font color of the text. Defaults to None.
- anchor (Anchor, optional): Anchor of the text. Defaults to None.
- **kwargs: Additional keyword arguments.
254def line(self, start, end, **kwargs): 255 """ 256 Draw a line segment from start to end. 257 258 Args: 259 start: Starting point of the line. 260 end: Ending point of the line. 261 **kwargs: Additional keyword arguments. 262 263 Returns: 264 Self: The canvas object. 265 """ 266 self._sketch_xform_matrix = self.xform_matrix 267 line_shape = Shape([start, end], closed=False, **kwargs) 268 line_sketch = create_sketch(line_shape, self, **kwargs) 269 self.active_page.sketches.append(line_sketch) 270 self._sketch_xform_matrix = identity_matrix() 271 return self
Draw a line segment from start to end.
Arguments:
- start: Starting point of the line.
- end: Ending point of the line.
- **kwargs: Additional keyword arguments.
Returns:
Self: The canvas object.
274def rectangle(self, center: Point, width: float, height: float, angle: float, **kwargs): 275 """ 276 Draw a rectangle with the given center, width, height and angle. 277 278 Args: 279 center (Point): Center of the rectangle. 280 width (float): Width of the rectangle. 281 height (float): Height of the rectangle. 282 angle (float): Angle of the rectangle. 283 **kwargs: Additional keyword arguments. 284 285 Returns: 286 Self: The canvas object. 287 """ 288 w2 = width / 2 289 h2 = height / 2 290 p1 = center[0] - w2, center[1] + h2 291 p2 = center[0] - w2, center[1] - h2 292 p3 = center[0] + w2, center[1] - h2 293 p4 = center[0] + w2, center[1] + h2 294 points = homogenize([p1, p2, p3, p4]) @ rotation_matrix(angle, center) 295 rect_shape = Shape(points.tolist(), closed=True, **kwargs) 296 rect_sketch = create_sketch(rect_shape, self, **kwargs) 297 self.active_page.sketches.append(rect_sketch) 298 299 return self
Draw a rectangle with the given center, width, height and angle.
Arguments:
- center (Point): Center of the rectangle.
- width (float): Width of the rectangle.
- height (float): Height of the rectangle.
- angle (float): Angle of the rectangle.
- **kwargs: Additional keyword arguments.
Returns:
Self: The canvas object.
302def draw_CS(self, size: float = None, **kwargs): 303 """ 304 Draw a coordinate system with the given size. 305 306 Args: 307 size (float, optional): Size of the coordinate system. Defaults to None. 308 **kwargs: Additional keyword arguments. 309 310 Returns: 311 Self: The canvas object. 312 """ 313 if size is None: 314 size = defaults["CS_size"] 315 if "colors" in kwargs: 316 x_color, y_color = kwargs["colors"] 317 del kwargs["colors"] 318 else: 319 x_color = defaults["CS_x_color"] 320 y_color = defaults["CS_y_color"] 321 if "line_width" not in kwargs: 322 kwargs["line_width"] = defaults["CS_line_width"] 323 self.line((0, 0), (size, 0), line_color=x_color, **kwargs) 324 self.line((0, 0), (0, size), line_color=y_color, **kwargs) 325 if "line_color" not in kwargs: 326 kwargs["line_color"] = defaults["CS_origin_color"] 327 self.circle((0, 0), radius=defaults["CS_origin_size"], **kwargs) 328 329 return self
Draw a coordinate system with the given size.
Arguments:
- size (float, optional): Size of the coordinate system. Defaults to None.
- **kwargs: Additional keyword arguments.
Returns:
Self: The canvas object.
332def lines(self, points, **kwargs): 333 """ 334 Draw connected line segments. 335 336 Args: 337 points: Points to be connected. 338 **kwargs: Additional keyword arguments. 339 340 Returns: 341 Self: The canvas object. 342 """ 343 self._all_vertices.extend(points) 344 sketch = LineSketch(points, self.xform_matrix, **kwargs) 345 for attrib_name in line_style_map: 346 attrib_value = self._resolve_property(sketch, attrib_name) 347 setattr(sketch, attrib_name, attrib_value) 348 self.active_page.sketches.append(sketch) 349 350 return self
Draw connected line segments.
Arguments:
- points: Points to be connected.
- **kwargs: Additional keyword arguments.
Returns:
Self: The canvas object.
352def insert_code(self, code: str, location: TexLoc = TexLoc.NONE) -> Self: 353 """ 354 Insert code into the canvas. 355 356 Args: 357 code (str): The code to insert. 358 359 Returns: 360 Self: The canvas object. 361 """ 362 active_sketches = self.active_page.sketches 363 sketch = TexSketch(code, location=location) 364 active_sketches.append(sketch) 365 366 return self
Insert code into the canvas.
Arguments:
- code (str): The code to insert.
Returns:
Self: The canvas object.
368def draw_bbox(self, bbox, **kwargs): 369 """ 370 Draw the bounding box object. 371 372 Args: 373 bbox: Bounding box to be drawn. 374 **kwargs: Additional keyword arguments. 375 376 Returns: 377 Self: The canvas object. 378 """ 379 sketch = create_sketch(bbox, self, **kwargs) 380 self.active_page.sketches.append(sketch) 381 382 return self
Draw the bounding box object.
Arguments:
- bbox: Bounding box to be drawn.
- **kwargs: Additional keyword arguments.
Returns:
Self: The canvas object.
385def draw_pattern(self, pattern, **kwargs): 386 """ 387 Draw the pattern object. 388 389 Args: 390 pattern: Pattern object to be drawn. 391 **kwargs: Additional keyword arguments. 392 393 Returns: 394 Self: The canvas object. 395 """ 396 sketch = create_sketch(pattern, self, **kwargs) 397 self.active_page.sketches.append(sketch) 398 399 return self
Draw the pattern object.
Arguments:
- pattern: Pattern object to be drawn.
- **kwargs: Additional keyword arguments.
Returns:
Self: The canvas object.
402def draw_hobby( 403 self, 404 points: Sequence[Point], 405 controls: Sequence[Point], 406 cyclic: bool = False, 407 **kwargs, 408): 409 """Draw a Hobby curve through the given points using the control points. 410 411 Args: 412 points (Sequence[Point]): Points through which the curve passes. 413 controls (Sequence[Point]): Control points for the curve. 414 cyclic (bool, optional): Whether the curve is cyclic. Defaults to False. 415 **kwargs: Additional keyword arguments. 416 """ 417 n = len(points) 418 if cyclic: 419 for i in range(n): 420 ind = i * 2 421 bezier_pnts = bezier_points( 422 points[i], *controls[ind : ind + 2], points[(i + 1) % n], 20 423 ) 424 bezier_ = Shape(bezier_pnts) 425 self.draw(bezier_, **kwargs) 426 else: 427 for i in range(len(points) - 1): 428 ind = i * 2 429 bezier_pnts = bezier_points( 430 points[i], *controls[ind : ind + 2], points[i + 1], 20 431 ) 432 bezier_ = Shape(bezier_pnts) 433 self.draw(bezier_, **kwargs)
Draw a Hobby curve through the given points using the control points.
Arguments:
- points (Sequence[Point]): Points through which the curve passes.
- controls (Sequence[Point]): Control points for the curve.
- cyclic (bool, optional): Whether the curve is cyclic. Defaults to False.
- **kwargs: Additional keyword arguments.
436def draw_lace(self, lace, **kwargs): 437 """Draw the lace object. 438 439 Args: 440 lace: Lace object to be drawn. 441 **kwargs: Additional keyword arguments. 442 443 Returns: 444 Self: The canvas object. 445 """ 446 keys = list(lace.fragment_groups.keys()) 447 keys.sort() 448 if lace.swatch is not None: 449 n_colors = len(lace.swatch) 450 for i, key in enumerate(keys): 451 if lace.swatch is not None: 452 fill_color = colors.Color(*lace.swatch[i % n_colors]) 453 kwargs["fill_color"] = fill_color 454 for fragment in lace.fragment_groups[key]: 455 self.active_page.sketches.append(create_sketch(fragment, self, **kwargs)) 456 for plait in lace.plaits: 457 if lace.swatch is not None: 458 fill_color = colors.white 459 kwargs["fill_color"] = fill_color 460 else: 461 kwargs["fill_color"] = None 462 self.active_page.sketches.append(create_sketch(plait, self, **kwargs)) 463 self._all_vertices.extend(plait.corners) 464 465 return self
Draw the lace object.
Arguments:
- lace: Lace object to be drawn.
- **kwargs: Additional keyword arguments.
Returns:
Self: The canvas object.
468def draw_dimension(self, item, **kwargs): 469 """Draw the dimension object. 470 471 Args: 472 item: Dimension object to be drawn. 473 **kwargs: Additional keyword arguments. 474 475 Returns: 476 Self: The canvas object. 477 """ 478 for shape in item.all_shapes: 479 self._all_vertices.extend(shape.corners) 480 for ext in [item.ext1, item.ext2, item.ext3]: 481 if ext: 482 ext_sketch = create_sketch(ext, self, **kwargs) 483 self.active_page.sketches.append(ext_sketch) 484 if item.dim_line: 485 dim_sketch = create_sketch(item.dim_line, self, **kwargs) 486 self.active_page.sketches.extend(dim_sketch) 487 if item.arrow1: 488 arrow_sketch = create_sketch(item.arrow1, self, **kwargs) 489 self.active_page.sketches.extend(arrow_sketch) 490 self.active_page.sketches.append(create_sketch(item.mid_line, self)) 491 if item.arrow2: 492 arrow_sketch = create_sketch(item.arrow2, self, **kwargs) 493 self.active_page.sketches.extend(arrow_sketch) 494 x, y = item.text_pos[:2] 495 496 tag = Tag(item.text, (x, y), font_size=item.font_size, **kwargs) 497 tag_sketch = create_sketch(tag, self, **kwargs) 498 tag_sketch.draw_frame = True 499 tag_sketch.frame_shape = FrameShape.CIRCLE 500 tag_sketch.fill = True 501 tag_sketch.font_color = colors.black 502 tag_sketch.frame_back_style = BackStyle.COLOR 503 tag_sketch.back_style = BackStyle.COLOR 504 tag_sketch.frame_back_color = colors.white 505 tag_sketch.back_color = colors.white 506 tag_sketch.stroke = False 507 self.active_page.sketches.append(tag_sketch) 508 509 return self
Draw the dimension object.
Arguments:
- item: Dimension object to be drawn.
- **kwargs: Additional keyword arguments.
Returns:
Self: The canvas object.
512def grid( 513 self, 514 pos=(0, 0), 515 width: float = None, 516 height: float = None, 517 step_size=None, 518 **kwargs, 519): 520 """Draw a square grid with the given size. 521 522 Args: 523 pos (tuple, optional): Position of the grid. Defaults to (0, 0). 524 width (float, optional): Length of the grid along the x-axis. Defaults to None. 525 height (float, optional): Length of the grid along the y-axis. Defaults to None. 526 step_size (optional): Step size for the grid. Defaults to None. 527 **kwargs: Additional keyword arguments. 528 529 Returns: 530 Self: The canvas object. 531 """ 532 x, y = pos[:2] 533 if width is None: 534 width = defaults["grid_size"] 535 height = defaults["grid_size"] 536 if "line_width" not in kwargs: 537 kwargs["line_width"] = defaults["grid_line_width"] 538 if "line_color" not in kwargs: 539 kwargs["line_color"] = defaults["grid_line_color"] 540 if "line_dash_array" not in kwargs: 541 kwargs["line_dash_array"] = defaults["grid_line_dash_array"] 542 # draw x-axis 543 # self.line((-size, 0), (size, 0), **kwargs) 544 line_y = Shape([(x, y), (x + width, y)], **kwargs) 545 line_x = Shape([(x, y), (x, y + height)], **kwargs) 546 lines_x = line_y.translate(0, step_size, reps=int(height / step_size)) 547 lines_y = line_x.translate(step_size, 0, reps=int(width / step_size)) 548 self.draw(lines_x) 549 self.draw(lines_y) 550 return self
Draw a square grid with the given size.
Arguments:
- pos (tuple, optional): Position of the grid. Defaults to (0, 0).
- width (float, optional): Length of the grid along the x-axis. Defaults to None.
- height (float, optional): Length of the grid along the y-axis. Defaults to None.
- step_size (optional): Step size for the grid. Defaults to None.
- **kwargs: Additional keyword arguments.
Returns:
Self: The canvas object.
585def extend_vertices(canvas, item): 586 """Extend the list of all vertices with the vertices of the given item. 587 588 Args: 589 canvas: Canvas object. 590 item: Item whose vertices are to be extended. 591 """ 592 all_vertices = canvas._all_vertices 593 if item.subtype == Types.DOTS: 594 vertices = [x.pos for x in item.all_shapes] 595 vertices = [x[:2] for x in homogenize(vertices) @ canvas._sketch_xform_matrix] 596 all_vertices.extend(vertices) 597 elif item.subtype == Types.DOT: 598 vertices = [item.pos] 599 vertices = [x[:2] for x in homogenize(vertices) @ canvas._sketch_xform_matrix] 600 all_vertices.extend(vertices) 601 elif item.subtype == Types.ARROW: 602 for shape in item.all_shapes: 603 all_vertices.extend(shape.corners) 604 elif item.subtype == Types.LACE: 605 for plait in item.plaits: 606 all_vertices.extend(plait.corners) 607 for fragment in item.fragments: 608 all_vertices.extend(fragment.corners) 609 elif item.subtype == Types.PATTERN: 610 all_vertices.extend(item.get_all_vertices()) 611 else: 612 corners = [x[:2] for x in homogenize(item.corners) @ canvas._sketch_xform_matrix] 613 all_vertices.extend(corners)
Extend the list of all vertices with the vertices of the given item.
Arguments:
- canvas: Canvas object.
- item: Item whose vertices are to be extended.
616def draw(self, item: Drawable, **kwargs) -> Self: 617 """The item is drawn on the canvas with the given style properties. 618 619 Args: 620 item (Drawable): Item to be drawn. 621 **kwargs: Additional keyword arguments. 622 623 Returns: 624 Self: The canvas object. 625 """ 626 # check if the item has any points 627 if not item: 628 return self 629 630 active_sketches = self.active_page.sketches 631 subtype = item.subtype 632 extend_vertices(self, item) 633 if subtype in regular_sketch_types: 634 sketches = get_sketches(item, self, **kwargs) 635 if sketches: 636 active_sketches.extend(sketches) 637 elif subtype == Types.PATTERN: 638 draw_pattern(self, item, **kwargs) 639 elif subtype == Types.DIMENSION: 640 self.draw_dimension(item, **kwargs) 641 elif subtype == Types.ARROW: 642 for head in item.heads: 643 active_sketches.append(create_sketch(head, self, **kwargs)) 644 active_sketches.append(create_sketch(item.line, self, **kwargs)) 645 elif subtype == Types.LACE: 646 self.draw_lace(item, **kwargs) 647 elif subtype == Types.BOUNDING_BOX: 648 draw_bbox(self, item, **kwargs) 649 return self
The item is drawn on the canvas with the given style properties.
Arguments:
- item (Drawable): Item to be drawn.
- **kwargs: Additional keyword arguments.
Returns:
Self: The canvas object.
652def get_sketches(item: Drawable, canvas: "Canvas" = None, **kwargs) -> list["Sketch"]: 653 """Create sketches from the given item and return them as a list. 654 655 Args: 656 item (Drawable): Item to be sketched. 657 canvas (Canvas, optional): Canvas object. Defaults to None. 658 **kwargs: Additional keyword arguments. 659 660 Returns: 661 list[Sketch]: List of sketches. 662 """ 663 if not (item.visible and item.active): 664 res = [] 665 elif item.subtype in drawable_types: 666 sketches = create_sketch(item, canvas, **kwargs) 667 if isinstance(sketches, list): 668 res = sketches 669 elif sketches is not None: 670 res = [sketches] 671 else: 672 res = [] 673 else: 674 res = [] 675 return res
Create sketches from the given item and return them as a list.
Arguments:
- item (Drawable): Item to be sketched.
- canvas (Canvas, optional): Canvas object. Defaults to None.
- **kwargs: Additional keyword arguments.
Returns:
list[Sketch]: List of sketches.
678def set_shape_sketch_style(sketch, item, canvas, linear=False, **kwargs): 679 """Set the style properties of the sketch. 680 681 Args: 682 sketch: Sketch object. 683 item: Item whose style properties are to be set. 684 canvas: Canvas object. 685 linear (bool, optional): Whether the style is linear. Defaults to False. 686 **kwargs: Additional keyword arguments. 687 """ 688 if linear: 689 style_map = line_style_map 690 else: 691 style_map = shape_style_map 692 693 for attrib_name in style_map: 694 attrib_value = canvas._resolve_property(item, attrib_name) 695 setattr(sketch, attrib_name, attrib_value) 696 697 sketch.visible = item.visible 698 sketch.active = item.active 699 sketch.closed = item.closed 700 sketch.fill = item.fill 701 sketch.stroke = item.stroke 702 703 for k, v in kwargs.items(): 704 setattr(sketch, k, v)
Set the style properties of the sketch.
Arguments:
- sketch: Sketch object.
- item: Item whose style properties are to be set.
- canvas: Canvas object.
- linear (bool, optional): Whether the style is linear. Defaults to False.
- **kwargs: Additional keyword arguments.
706def get_verts_in_new_pos(item, **kwargs): 707 """ 708 Get the vertices of the item in a new position. 709 710 Args: 711 item: Item whose vertices are to be obtained. 712 **kwargs: Additional keyword arguments. 713 714 Returns: 715 list: List of vertices in the new position. 716 """ 717 if "pos" in kwargs: 718 x, y = item.midpoint[:2] 719 x1, y1 = kwargs["pos"][:2] 720 dx = x1 - x 721 dy = y1 - y 722 trans_mat = translation_matrix(dx, dy) 723 vertices = item.primary_points.homogen_coords @ trans_mat 724 vertices = vertices[:, :2].tolist() 725 else: 726 vertices = item.vertices 727 728 return vertices
Get the vertices of the item in a new position.
Arguments:
- item: Item whose vertices are to be obtained.
- **kwargs: Additional keyword arguments.
Returns:
list: List of vertices in the new position.
731def create_sketch(item, canvas, **kwargs): 732 """Create a sketch from the given item. 733 734 Args: 735 item: Item to be sketched. 736 canvas: Canvas object. 737 **kwargs: Additional keyword arguments. 738 739 Returns: 740 Sketch: Created sketch. 741 """ 742 if not (item.visible and item.active): 743 return None 744 745 def get_tag_sketch(item, canvas, **kwargs): 746 """Create a TagSketch from the given item. 747 748 Args: 749 item: Item to be sketched. 750 canvas: Canvas object. 751 **kwargs: Additional keyword arguments. 752 753 Returns: 754 TagSketch: Created TagSketch. 755 """ 756 if "pos" in kwargs: 757 pos = kwargs["pos"] 758 else: 759 pos = item.pos 760 761 sketch = TagSketch(text=item.text, pos=pos, anchor=item.anchor) 762 for attrib_name in item._style_map: 763 if attrib_name == "fill_color": 764 if item.fill_color in [None, colors.black]: 765 setattr(sketch, "frame_back_color", defaults["frame_back_color"]) 766 else: 767 setattr(sketch, "frame_back_color", item.fill_color) 768 continue 769 attrib_value = canvas._resolve_property(item, attrib_name) 770 setattr(sketch, attrib_name, attrib_value) 771 sketch.text_width = item.text_width 772 sketch.visible = item.visible 773 sketch.active = item.active 774 for k, v in kwargs.items(): 775 setattr(sketch, k, v) 776 return sketch 777 778 def get_ellipse_sketch(item, canvas, **kwargs): 779 """Create an EllipseSketch from the given item. 780 781 Args: 782 item: Item to be sketched. 783 canvas: Canvas object. 784 **kwargs: Additional keyword arguments. 785 786 Returns: 787 EllipseSketch: Created EllipseSketch. 788 """ 789 if "pos" in kwargs: 790 center = kwargs["pos"] 791 else: 792 center = item.center 793 794 sketch = EllipseSketch( 795 center, 796 item.a, 797 item.b, 798 item.angle, 799 xform_matrix=canvas.xform_matrix, 800 **kwargs, 801 ) 802 set_shape_sketch_style(sketch, item, canvas, **kwargs) 803 804 return sketch 805 806 def get_pattern_sketch(item, canvas, **kwargs): 807 """Create a PatternSketch from the given item. 808 809 Args: 810 item: Item to be sketched. 811 canvas: Canvas object. 812 **kwargs: Additional keyword arguments. 813 814 Returns: 815 PatternSketch: Created PatternSketch. 816 """ 817 sketch = PatternSketch(item, xform_matrix=canvas.xform_matrix, **kwargs) 818 set_shape_sketch_style(sketch, item, canvas, **kwargs) 819 820 return sketch 821 822 def get_circle_sketch(item, canvas, **kwargs): 823 """Create a CircleSketch from the given item. 824 825 Args: 826 item: Item to be sketched. 827 canvas: Canvas object. 828 **kwargs: Additional keyword arguments. 829 830 Returns: 831 CircleSketch: Created CircleSketch. 832 """ 833 if "pos" in kwargs: 834 center = kwargs["pos"] 835 else: 836 center = item.center 837 sketch = CircleSketch( 838 center, item.radius, xform_matrix=canvas.xform_matrix 839 ) 840 set_shape_sketch_style(sketch, item, canvas, **kwargs) 841 842 return sketch 843 844 def get_dots_sketch(item, canvas, **kwargs): 845 """Create sketches for dots from the given item. 846 847 Args: 848 item: Item to be sketched. 849 canvas: Canvas object. 850 **kwargs: Additional keyword arguments. 851 852 Returns: 853 list: List of created sketches. 854 """ 855 vertices = [x.pos for x in item.all_shapes] 856 fill_color = item[0].fill_color 857 radius = item[0].radius 858 marker_size = item[0].marker_size 859 marker_type = item[0].marker_type 860 item = Shape( 861 vertices, 862 fill_color=fill_color, 863 markers_only=True, 864 draw_markers=True, 865 marker_size=marker_size, 866 marker_radius=radius, 867 marker_type=marker_type, 868 ) 869 sketches = get_sketches(item, canvas, **kwargs) 870 871 return sketches 872 873 def get_arc_sketch(item, canvas, **kwargs): 874 """Create an ArcSketch from the given item. 875 876 Args: 877 item: Item to be sketched. 878 canvas: Canvas object. 879 **kwargs: Additional keyword arguments. 880 881 Returns: 882 ArcSketch: Created ArcSketch. 883 """ 884 885 # vertices = get_verts_in_new_pos(item, **kwargs) 886 sketch = ArcSketch(item.vertices, xform_matrix=canvas._sketch_xform_matrix) 887 set_shape_sketch_style(sketch, item, canvas, **kwargs) 888 889 return sketch 890 891 def get_lace_sketch(item, canvas, **kwargs): 892 """Create sketches for lace from the given item. 893 894 Args: 895 item: Item to be sketched. 896 canvas: Canvas object. 897 **kwargs: Additional keyword arguments. 898 899 Returns: 900 list: List of created sketches. 901 """ 902 sketches = [get_sketch(frag, canvas, **kwargs) for frag in item.fragments] 903 sketches.extend([get_sketch(plait, canvas, **kwargs) for plait in item.plaits]) 904 return sketches 905 906 def get_batch_sketch(item, canvas, **kwargs): 907 """Create a BatchSketch from the given item. 908 909 Args: 910 item: Item to be sketched. 911 canvas: Canvas object. 912 **kwargs: Additional keyword arguments. 913 914 Returns: 915 BatchSketch or list: Created BatchSketch or list of sketches. 916 """ 917 if scope_code_required(item): 918 sketches = [] 919 for element in item.elements: 920 if element.visible and element.active: 921 sketches.extend(get_sketches(element, canvas, **kwargs)) 922 923 sketch = BatchSketch(sketches=sketches) 924 for arg in group_args: 925 setattr(sketch, arg, getattr(item, arg)) 926 927 res = sketch 928 else: 929 sketches = [] 930 for element in item.elements: 931 if hasattr(element, "visible") and hasattr(element, "active"): 932 if element.visible and element.active: 933 sketches.extend(get_sketches(element, canvas, **kwargs)) 934 935 res = sketches 936 937 return res 938 939 def get_path_sketch(item, canvas, **kwargs): 940 """Create sketches for a path from the given item. 941 942 Args: 943 item: Item to be sketched. 944 canvas: Canvas object. 945 **kwargs: Additional keyword arguments. 946 947 Returns: 948 list: List of created sketches. 949 """ 950 951 def extend_verts(obj, vertices): 952 obj_vertices = obj.vertices 953 if obj_vertices: 954 if vertices and close_points2(vertices[-1], obj_vertices[0]): 955 obj_vertices = obj_vertices[1:] 956 vertices.extend(obj_vertices) 957 958 path_op = PathOperation 959 linears = [ 960 path_op.ARC, 961 path_op.ARC_TO, 962 path_op.BLEND_ARC, 963 path_op.BLEND_CUBIC, 964 path_op.BLEND_QUAD, 965 path_op.BLEND_SINE, 966 path_op.CUBIC_TO, 967 path_op.FORWARD, 968 path_op.H_LINE, 969 path_op.HOBBY_TO, 970 path_op.QUAD_TO, 971 path_op.R_LINE, 972 path_op.SEGMENTS, 973 path_op.SINE, 974 path_op.V_LINE, 975 path_op.LINE_TO, 976 ] 977 sketches = [] 978 vertices = [] 979 for i, op in enumerate(item.operations): 980 if op.subtype in linears: 981 obj = item.objects[i] 982 extend_verts(obj, vertices) 983 elif op.subtype in [path_op.MOVE_TO, path_op.R_MOVE]: 984 if i == 0: 985 continue 986 shape = Shape(vertices) 987 sketch = create_sketch(shape, canvas, **kwargs) 988 if sketch: 989 sketch.visible = item.visible 990 sketch.active = item.active 991 sketches.append(sketch) 992 vertices = [] 993 elif op.subtype == path_op.CLOSE: 994 shape = Shape(vertices, closed=True) 995 sketch = create_sketch(shape, canvas, **kwargs) 996 if sketch: 997 sketch.visible = item.visible 998 sketch.active = item.active 999 sketches.append(sketch) 1000 vertices = [] 1001 if vertices: 1002 shape = Shape(vertices) 1003 sketch = create_sketch(shape, canvas, **kwargs) 1004 sketches.append(sketch) 1005 1006 if "handles" in kwargs and kwargs["handles"]: 1007 handles = kwargs["handles"] 1008 del kwargs["handles"] 1009 for handle in item.handles: 1010 shape = Shape(handle) 1011 shape.subtype = Types.HANDLE 1012 handle_sketches = create_sketch(shape, canvas, **kwargs) 1013 sketches.extend(handle_sketches) 1014 1015 for sketch in sketches: 1016 item.closed = sketch.closed 1017 set_shape_sketch_style(sketch, item, canvas, **kwargs) 1018 1019 return sketches 1020 1021 def get_bbox_sketch(item, canvas, **kwargs): 1022 """Create a bounding box sketch from the given item. 1023 1024 Args: 1025 item: Item to be sketched. 1026 canvas: Canvas object. 1027 **kwargs: Additional keyword arguments. 1028 1029 Returns: 1030 ShapeSketch: Created bounding box sketch. 1031 """ 1032 nround = defaults["tikz_nround"] 1033 vertices = [(round(x[0], nround), round(x[1], nround)) for x in item.corners] 1034 if not vertices: 1035 return None 1036 1037 sketch = ShapeSketch(vertices, canvas._sketch_xform_matrix) 1038 sketch.subtype = Types.BBOX_SKETCH 1039 sketch.visible = True 1040 sketch.active = True 1041 sketch.closed = True 1042 sketch.fill = False 1043 sketch.stroke = True 1044 sketch.line_color = colors.gray 1045 sketch.line_width = 1 1046 sketch.line_dash_array = [3, 3] 1047 sketch.draw_markers = False 1048 return sketch 1049 1050 def get_handle_sketch(item, canvas, **kwargs): 1051 """Create handle sketches from the given item. 1052 1053 Args: 1054 item: Item to be sketched. 1055 canvas: Canvas object. 1056 **kwargs: Additional keyword arguments. 1057 1058 Returns: 1059 list: List of created handle sketches. 1060 """ 1061 nround = defaults["tikz_nround"] 1062 vertices = [(round(x[0], nround), round(x[1], nround)) for x in item.vertices] 1063 if not vertices: 1064 return None 1065 if 'pos' in kwargs: 1066 x, y = item.midpoint[:2] 1067 x1, y1 = kwargs["pos"][:2] 1068 dx = x1 - x 1069 dy = y1 - y 1070 vertices = [(x+dx, y+dy) for x, y in vertices] 1071 sketches = [] 1072 sketch = ShapeSketch(vertices, canvas._sketch_xform_matrix) 1073 sketch.subtype = Types.HANDLE 1074 sketch.closed = False 1075 set_shape_sketch_style(sketch, item, canvas, **kwargs) 1076 sketches.append(sketch) 1077 temp_item = Shape() 1078 temp_item.closed = True 1079 handle1 = RectSketch(item.vertices[0], 3, 3, canvas._sketch_xform_matrix) 1080 set_shape_sketch_style(handle1, temp_item, canvas, **kwargs) 1081 handle2 = RectSketch(item.vertices[-1], 3, 3, canvas._sketch_xform_matrix) 1082 set_shape_sketch_style(handle2, temp_item, canvas, **kwargs) 1083 sketches.extend([handle1, handle2]) 1084 1085 return sketches 1086 1087 def get_sketch(item, canvas, **kwargs): 1088 """Create a sketch from the given item. 1089 1090 Args: 1091 item: Item to be sketched. 1092 canvas: Canvas object. 1093 **kwargs: Additional keyword arguments. 1094 1095 Returns: 1096 ShapeSketch: Created sketch. 1097 """ 1098 if not item.vertices: 1099 return None 1100 1101 # vertices = get_verts_in_new_pos(item, **kwargs) 1102 nround = defaults["tikz_nround"] 1103 vertices = [ 1104 (round(x[0], nround), round(x[1], nround)) for x in item.vertices 1105 ] 1106 1107 sketch = ShapeSketch(vertices, canvas._sketch_xform_matrix) 1108 set_shape_sketch_style(sketch, item, canvas, **kwargs) 1109 1110 return sketch 1111 1112 d_subtype_sketch = { 1113 Types.ARC: get_arc_sketch, 1114 Types.ARC_ARROW: get_batch_sketch, 1115 Types.ARROW: get_batch_sketch, 1116 Types.ARROW_HEAD: get_sketch, 1117 Types.BATCH: get_batch_sketch, 1118 Types.BEZIER: get_sketch, 1119 Types.BOUNDING_BOX: get_bbox_sketch, 1120 Types.CIRCLE: get_circle_sketch, 1121 Types.CIRCULAR_GRID: get_batch_sketch, 1122 Types.DIVISION: get_sketch, 1123 Types.DOT: get_circle_sketch, 1124 Types.DOTS: get_dots_sketch, 1125 Types.ELLIPSE: get_sketch, 1126 Types.FRAGMENT: get_sketch, 1127 Types.HANDLE: get_handle_sketch, 1128 Types.HEX_GRID: get_batch_sketch, 1129 Types.LACE: get_lace_sketch, 1130 Types.LINPATH: get_path_sketch, 1131 Types.MIXED_GRID: get_batch_sketch, 1132 Types.OVERLAP: get_batch_sketch, 1133 Types.PARALLEL_POLYLINE: get_batch_sketch, 1134 Types.PATTERN: get_pattern_sketch, 1135 Types.PLAIT: get_sketch, 1136 Types.POLYLINE: get_sketch, 1137 Types.Q_BEZIER: get_sketch, 1138 Types.RECTANGLE: get_sketch, 1139 Types.SECTION: get_sketch, 1140 Types.SEGMENT: get_sketch, 1141 Types.SHAPE: get_sketch, 1142 Types.SINE_WAVE: get_sketch, 1143 Types.SQUARE_GRID: get_batch_sketch, 1144 Types.STAR: get_batch_sketch, 1145 Types.TAG: get_tag_sketch, 1146 } 1147 1148 return d_subtype_sketch[item.subtype](item, canvas, **kwargs)
Create a sketch from the given item.
Arguments:
- item: Item to be sketched.
- canvas: Canvas object.
- **kwargs: Additional keyword arguments.
Returns:
Sketch: Created sketch.