cs110_t3_shapes

  1### IGNORE EVERYTHING THAT STARTS WITH A _
  2from random import randint
  3from math import sqrt, pi, radians, sin, cos
  4
  5__docformat__ = "google"
  6
  7_a_canvas = None
  8
  9def rectangle(top_left=(0, 0), width=25, height=50, color="hotpink", outline="", tag="", **kwargs):
 10    """
 11    A reporter function that draws a rectangle.
 12    Args:
 13        top_left (`tuple`): A coordinate representing the top left-hand corner of the shape.
 14        width (`int`): How wide to draw the shape.
 15        height (`int`): How tall to draw the shape.
 16        color (`str`): What color to draw the shape.
 17        outline (`str`): What color should the border of the shape be.
 18        tag (`str`): The tag to assign to the shape.
 19
 20    Returns:
 21         `Shape`: The rectangle that was created.
 22    """      
 23    point_0 = top_left
 24    point_1 = (top_left[0] + width, top_left[1])
 25    point_2 = (top_left[0] + width, top_left[1] + height)
 26    point_3 = (top_left[0], top_left[1] + height)
 27    return _a_canvas.create_polygon(
 28        point_0, point_1, point_2, point_3, fill=color, tags=tag, **kwargs
 29    )
 30
 31
 32def square(top_left=(0, 0), size=25, color="hotpink", outline="", tag="", **kwargs):
 33    """
 34    A reporter function that draws a square.
 35    Args:
 36        top_left (`tuple`): A coordinate representing the top left-hand corner of the shape.
 37        size (`int`): How big to draw the shape.
 38        color (`str`): What color to draw the shape.
 39        outline (`str`): What color should the border of the shape be.
 40        tag (`str`): The tag to assign to the shape.
 41
 42    Returns:
 43         `Shape`: The square that was created.
 44    """
 45    return rectangle(top_left=top_left, width=size, height=size, color=color, tag=tag, **kwargs)
 46
 47
 48def oval(center=(0, 0), radius_x=25, radius_y=50, color="hotpink", outline="", tag="", **kwargs):
 49    """
 50    A reporter function that draws an oval.
 51    Args:
 52        center (`tuple`): A coordinate representing the center of the shape.
 53        radius_x (`int`): Specifies the oval's radius on the x-axis.
 54        radius_y (`int`): Specifies the oval's radius on the y-axis.
 55        color (`str`): What color to draw the shape.
 56        outline (`str`): What color should the border of the shape be.
 57        tag (`str`): The tag to assign to the shape.
 58
 59    Returns:
 60         `Shape`: The oval that was created.
 61    """
 62    x = center[0]
 63    y = center[1]
 64    x0, y0, x1, y1 = (x - radius_x, y - radius_y, x + radius_x, y + radius_y)
 65    steps = 100
 66    # major and minor axes
 67    a = (x1 - x0) / 2.0
 68    b = (y1 - y0) / 2.0
 69    # center
 70    xc = x0 + a
 71    yc = y0 + b
 72    point_list = []
 73    # create the oval as a list of points
 74    for i in range(steps):
 75        # Calculate the angle for this step
 76        theta = (pi * 2) * (float(i) / steps)
 77        x = a * cos(theta)
 78        y = b * sin(theta)
 79        point_list.append(round(x + xc))
 80        point_list.append(round(y + yc))
 81
 82    return _a_canvas.create_polygon(point_list, fill=color, tags=tag, **kwargs)
 83
 84
 85def circle(center=(0, 0), radius=25, color="hotpink", outline="", tag="", **kwargs):
 86    """
 87    A reporter function that draws a circle.
 88    Args:
 89        center (`tuple`): A coordinate representing the center of the shape.
 90        radius (`int`): Specifies the circle's radius.
 91        color (`str`): What color to draw the shape.
 92        outline (`str`): What color should the border of the shape be.
 93        tag (`str`): The tag to assign to the shape.
 94
 95    Returns:
 96         `Shape`: The circle that was created.
 97    """
 98    return oval(center=center, radius_x=radius, radius_y=radius, color=color, tag=tag, **kwargs)
 99
100
101def triangle(
102    bottom_center=(0, 0), width=25, top_shift=0, height=0, color="hotpink", outline="", tag="", **kwargs
103):
104    """
105    A reporter function that draws a triangle.
106    Args:
107        bottom_center (`tuple`): A coordinate representing the bottom center of the shape.
108        width (`int`): Specifies the width of the base of the triangle.
109        top_shift (`int`): Specifies the how far to the left or right to shift the top of 
110            the triangle from the bottom center.
111        height (`int`): Specifies the triangle's height.
112        color (`str`): What color to draw the shape.
113        outline (`str`): What color should the border of the shape be.
114        tag (`str`): The tag to assign to the shape.
115
116    Returns:
117         `Shape`: The triangle that was created.
118    """
119    if height == 0:
120        height = width * sqrt(3) / 2
121    point_0 = (bottom_center[0] - width / 2, bottom_center[1])
122    point_1 = (bottom_center[0] + width / 2, bottom_center[1])
123    point_2 = (bottom_center[0] + top_shift, bottom_center[1] - height)
124
125    return _a_canvas.create_polygon(point_0, point_1, point_2, fill=color, tags=tag, **kwargs)
126
127
128def line(points=[], curvy=False, color="hotpink", tag="", **kwargs):
129    """
130    A reporter function that draws a line given a list of points.
131    Args:
132        points (`list`): The points that define the line; this should be a list of tuples (coordinates).
133        curvy (`bool`): Makes a curvy line instead.
134        color (`str`): What color to make the shape.
135        tag (`str`): The tag to assign to the shape.
136
137    Returns:
138        `Shape`: The line that was created.
139    """
140    return _a_canvas.create_line(points, fill=color, smooth=curvy, tags=tag, **kwargs)
141
142
143def arc(points=[], width=5, color="hotpink", line_steps=15, tag="", **kwargs):
144    """
145    A reporter function that draws an arc ("curve") given a list of points.
146    Args:
147        points (`list`): The points outlining the curve; this should be a list of tuples (coordinates).
148            Make sure to give it at least 3 (x,y) coordinates that aren't a straight line!
149        color (`str`): What color to make the shape.
150        tag (`str`): The tag to assign to the shape.
151
152    Returns:
153        `Shape`: The arc that was created.
154    """
155    return _a_canvas.create_line(
156        points,  
157        width=width,
158        fill=color,
159        splinesteps=line_steps,
160        smooth=True,
161        tags=tag,
162        **kwargs
163    )
164
165
166def star(center=(0, 0), radius=50, color="hotpink", outer_radius=75, points=5, outline="", tag="", **kwargs):
167    """
168    A reporter function that draws a star.
169    Args:
170        center (`tuple`): A coordinate representing the center of the shape.
171        radius (`int`): Specifies the radius of the inside part of the star.
172        color (`str`): Specifies the color of the star.
173        outer_radius (`int`): Specifies the radius of the outside part of the star.
174        points (`int`): Specifies the number of points for the star.
175        outline (`str`): What color should the border of the shape be.
176        tag (`str`): The tag to assign to the shape.
177
178    Returns:
179         `Shape`: The star that was created.
180    """
181    arc_segment = 360 / points
182    vertices = []
183    for i in range(points):
184        inner_point = (
185            radius * cos(radians(arc_segment * i)) + center[0],
186            -1 * radius * sin(radians(arc_segment * i)) + center[1],
187        )
188        vertices.append(inner_point)
189        outer_point = (
190            outer_radius * cos(radians(arc_segment * i + arc_segment / 2)) + center[0],
191            -1 * outer_radius * sin(radians(arc_segment * i + arc_segment / 2))
192            + center[1],
193        )
194        vertices.append(outer_point)
195    return polygon(vertices, color=color, tag=tag, **kwargs)
196
197def polygon(points=[], color="hotpink", outline="", tag="", **kwargs):
198    """
199    A reporter function that draws a polygon given a list of points.
200    Args:
201        points (`list`): The points outlining the polygon; this should be a list of tuples (coordinates).
202            defaults to an empty list.
203        outline (`str`): What color should the border of the shape be.
204        color (`str`): What color to make the shape.
205
206    Returns:
207        `Shape`: The polygon that was created.
208   """
209    return _a_canvas.create_polygon(points, fill=color, tags=tag, **kwargs)
210
211def _polar_to_cartesian(r, theta):
212    return int(r*cos(theta)), int(r*sin(theta))
213
214def spiral(center=(0, 0), width=100, roughness=0.01, start=0, spirals=5, line_width=1, **kwargs):
215    """
216    A reporter function that draws a spiral.
217    Args:
218        center (`tuple`): A coordinate representing the center of the shape.
219        width (`int`): Specifies the total width of the spiral.
220        roughness (`float`): Controls how spiral-y the shape is (lower is less spiral-y)
221        start (`int`): Where on the spiral to start drawing.
222        spirals (`int`): How many loops to draw.
223        line_width (`int`): How wide for the line to be drawn.
224        tag (`str`): The tag to assign to the shape.
225
226    Returns:
227         `Shape`: The spiral that was created.
228    """
229    theta = 0.0
230    r = start
231    all_points = []
232    prev_pos = _polar_to_cartesian(r, theta)
233    distance = width / 4 / pi / spirals 
234    all_points.append((prev_pos[0] + center[0], prev_pos[1] + center[1]))
235    while theta < 2 * spirals * pi:
236        theta += roughness
237        r = start + distance*theta
238        pos = _polar_to_cartesian(r, theta)
239        all_points.append((pos[0] + center[0], pos[1] + center[1]))
240
241    return arc(points=all_points, width=line_width, **kwargs)
242
243def move(shape, x_shift=0, y_shift=0):
244    """
245    Purpose: Move the x and y position of all shapes that have been tagged
246    with the tag argument
247    Args:
248        shape (tag or id): the shape (or shapes) to move
249        x_shift (`int`; optional): amount to move in the x direction
250        y_shift (`int`; optional): amount to move in the y direction
251    """
252    shape_ids = _a_canvas.find_withtag(shape)
253    for id in shape_ids:
254        _a_canvas.move(id,
255                        x_shift,
256                        y_shift)
257
258def put_in_front(shape):
259    """
260    A function that "raises" a shape to the "top" of the screen."
261
262    Args:
263        shape (tag or id): The shape to raise.
264    """
265    _a_canvas.tag_raise(shape)
266
267def put_in_back(shape):
268    """
269    A function that "lowers" a shape to the "bottom" of the screen."
270
271    Args:
272        shape (tag or id): The shape to raise.
273    """
274    _a_canvas.tag_lower(shape)
275
276def overlay(shape1, shape2, offset_x=0, offset_y=0):
277    """
278    A reporter function that overlays shape1 onto shape2. It does this by moving shape 1's center
279    to shape 2's center, and then applying any specified offset.
280    Args:
281        shape1 (tag or id): The first shape to use.
282        shape2 (tag or id): The second shape to use.
283        offset_x (`int`): How much to shift shape 2 in the x-direction after centering it.
284        offset_y (`int`): How much to shift shape 2 in the x-direction after centering it.
285        tag (`str`): The tag to assign to the shape.
286
287    Returns:
288        `Shape`: The modified shape1.
289   """
290    center1 = get_center(shape1)
291    center2 = get_center(shape2)
292    _a_canvas.move(
293        shape1,
294        (center2[0] - center1[0]) + offset_x,
295        (center2[1] - center1[1]) + offset_y,
296    )
297    _a_canvas.tag_raise(shape1, shape2)
298    return shape1
299
300
301def underlay(shape1, shape2, offset_x=0, offset_y=0):
302    """
303    A reporter function that underlays shape1 beneath shape2. It does this by moving shape 1's center
304    to shape 2's center, and then applying any specified offset.
305    Args:
306        shape1 (tag or id): The first shape to use.
307        shape2 (tag or id): The second shape to use.
308        offset_x (`int`): How much to shift shape 2 in the x-direction after centering it.
309        offset_y (`int`): How much to shift shape 2 in the x-direction after centering it.
310
311    Returns:
312        `Shape`: The modified shape1.
313   """
314    center1 = get_center(shape1)
315    center2 = get_center(shape2)
316    _a_canvas.move(
317        shape1,
318        (center2[0] - center1[0]) + offset_x,
319        (center2[1] - center1[1]) + offset_y,
320    )
321    _a_canvas.tag_lower(shape1, shape2)
322    return shape1
323
324
325def above(shape1, shape2, offset_x=0, offset_y=0):
326    """
327    A reporter function that places shape1 above shape2 (vertically). It does this by moving shape 1's center
328    to shape 2's center, moving shape 1 in the y-direction the exact height of shape 2, and then applying any
329    specified offset.
330
331    Args:
332        shape1 (tag or id): The first shape to use.
333        shape2 (tag or id): The second shape to use.
334        offset_x (`int`): How much to shift shape 2 in the x-direction after moving it.
335        offset_y (`int`): How much to shift shape 2 in the x-direction after moving it.
336
337    Returns:
338        `Shape`: The modified shape1.  
339    """
340    overlay(shape1, shape2)
341    _a_canvas.move(
342        shape1,
343        0 + offset_x,
344        -1 * (get_height(shape2) + get_height(shape1)) / 2 + offset_y,
345    )
346    return shape1
347
348
349def beside(shape1, shape2, offset_x=0, offset_y=0):
350    """
351    A reporter function that places shape1 beside shape2 (horizontally). It does this by moving shape 1's center
352    to shape 2's center, moving shape 1 in the x-direction the exact width of shape 2, and then applying any
353    specified offset.
354
355    Args:
356        shape1 (tag or id): The first shape to use.
357        shape2 (tag or id): The second shape to use.
358        offset_x (`int`): How much to shift shape 2 in the x-direction after moving it.
359        offset_y (`int`): How much to shift shape 2 in the x-direction after moving it.
360
361    Returns:
362        `Shape`: The modified shape1.  
363    """
364    overlay(shape1, shape2)
365    _a_canvas.move(
366        shape1,
367        (get_width(shape2) + get_width(shape1)) / 2 + offset_x,
368        0 + offset_y,
369    )
370    return shape1
371
372
373def below(shape1, shape2, offset_x=0, offset_y=0):
374    """
375    A reporter function that places shape1 below shape2 (vertically). It does this by moving shape 1's center
376    to shape 2's center, moving shape 1 in the y-direction the exact height of shape 2, and then applying any
377    specified offset.
378
379    Args:
380        shape1 (tag or id): The first shape to use.
381        shape2 (tag or id): The second shape to use.
382        offset_x (`int`): How much to shift shape 2 in the x-direction after moving it.
383        offset_y (`int`): How much to shift shape 2 in the x-direction after moving it.
384
385    Returns:
386        `Shape`: The modified shape1.  
387    """
388    overlay(shape1, shape2)
389    _a_canvas.move(
390        shape1,
391        0 + offset_x,
392        (get_height(shape2) + get_height(shape1)) / 2 + offset_y,
393    )
394    return shape1
395
396def delete(shape):
397    """
398    A function that deletes a shape from our screen.
399
400    Args:
401        shape (tag or id): The shape to delete.
402    """
403    _a_canvas.delete(shape)
404
405def duplicate(shape, color=None):
406    """
407    A reporter function that perfectly copies a shape and returns that copy.
408
409    Args:
410        shape (tag or id): The shape to duplicate.
411        color (`str`): A new color to use with the duplicated shape.
412
413    Returns:
414        `Shape`: The new duplicated shape.  
415    """
416    shape_type = _a_canvas.type(shape)
417    shape_config = _a_canvas.itemconfig(shape)
418    shape_coords = _a_canvas.coords(shape)
419    the_copy = None
420    if shape_type == "polygon":
421        new_config = {key: shape_config[key][-1] for key in shape_config.keys()}
422        if color != None:
423            new_config["fill"] = color
424        the_copy = _a_canvas.create_polygon(shape_coords, **new_config)
425        return the_copy
426
427def mirror(shape):
428    """
429    A reporter function that takes a shape and flips it across its vertical
430    axis, returning the tag or ID of the modified shape.
431        
432    Args:
433        shape (tag or id): The shape in question.
434
435    Returns:
436        The modified shape.
437    """
438    center = get_center(shape)[0]
439    shape_ids = _a_canvas.find_withtag(shape)
440    for shape_id in shape_ids:
441        flipped_coordinates = []
442        shape_coords = _a_canvas.coords(shape_id)
443        counter = 0
444        for num in shape_coords:
445            if counter % 2 == 0:
446                if num < center:
447                    flipped_coordinates.append(num + 2 * (center - num))
448                elif num > center:
449                    flipped_coordinates.append(num - 2 * (num - center))
450                else:
451                    flipped_coordinates.append(num)
452            else:
453                flipped_coordinates.append(num)
454            counter += 1
455        _a_canvas.coords(shape_id, flipped_coordinates)
456
457def rotate(shape, degrees=5, origin=None):
458    """
459    A reporter function that takes a shape and rotates it by a specified amount around a specified point.
460    It does this by interpolating a polygon around the shape and calculating the shifts of individual
461    points on the edge of the polygon.
462
463    Args:
464        shape (tag or id): The shape to rotate.
465        degrees (`int`): The number of degrees to rotate the shape.
466        origin (`tuple`): An `(x,y)` coordinate about which to perform the rotation. Defaults to the center
467            of the given shape.
468
469    Returns:
470        `Shape`: The modified shape.  
471    """
472    if origin is None:
473        origin = get_center(shape)
474
475    theta = radians(degrees)
476    ox, oy = origin
477
478    all_shapes = _a_canvas.find_withtag(shape)
479
480    for a_shape in all_shapes:
481        coords = _a_canvas.coords(a_shape)
482        # update coordinates:
483        for i in range(0, len(coords), 2):
484            px, py = coords[i], coords[i + 1]
485            qx = cos(theta) * (px - ox) - sin(theta) * (py - oy) + ox
486            qy = sin(theta) * (px - ox) + cos(theta) * (py - oy) + oy
487            coords[i] = qx
488            coords[i + 1] = qy
489        # set the coordinates:
490        _a_canvas.coords(a_shape, coords)
491
492    return shape 
493
494def distance(point1, point2):
495    """
496    A reporter function calculates the distance between two `(x, y)` coordinates.
497          
498    Args:
499        point1 (`tuple`): The first `(x, y)` coordinate.
500        point2 (`tuple`): The second `(x, y)` coordinate.
501
502    Returns:
503         A `float` representing the distance between the two points.
504    """
505    return sqrt(((point1[0] - point2[0]) ** 2) + ((point1[1] - point2[1]) ** 2))
506
507def update_color(shape, color):
508    '''
509    Change the fill color of a tagged object.
510
511    Args:
512        shape (tag or id): The tag of the object to re-fill.
513        color (`str`): A color name or hex code to re-fill with.
514    '''
515    ids = _a_canvas.find_withtag(shape)
516    for id in ids:
517        _a_canvas.itemconfig(id, fill=color)
518
519def interpolate_colors(color1, color2, frac):
520    """
521    A reporter function that generates a new color between two given colors.
522    Args:
523        color1 (`str`): The path of the file to wrap
524        color2 (`str`): The path of the file to wrap
525        frac (`float`): What fraction of each color to take. An input of 0 returns
526            color1, an input of 1 returns color2, an input of 0.5 returns a color
527            perfectly between the two.
528
529    Returns:
530         A color (as a hex `str`) to be used elsewhere
531   """
532    if "#" not in color1:
533        color1 = tuple((c // 256 for c in _a_canvas.winfo_rgb(color1)))
534    else:
535        color1 = _tupelize_color(color1)
536    if "#" not in color2:
537        color2 = tuple((c // 256 for c in _a_canvas.winfo_rgb(color2)))
538    else:
539        color2 = _tupelize_color(color2)
540    return _interpolate_tuple(color1, color2, frac)
541
542def get_center(shape):
543    """
544    A reporter function calculates the a coordinate at the center of some shape.
545        
546    Args:
547        shape (tag or id): The shape in question.
548
549    Returns:
550         A `tuple` representing center of the given shape.
551    """
552    bbox = _safe_bbox(shape)
553
554    if bbox is None:
555        raise Exception(f"We couldn't find the shape with id/tag {shape}. Make sure it exists!")
556
557    return (((bbox[2] + bbox[0]) / 2), ((bbox[1] + bbox[3]) / 2))
558
559
560def get_top(shape):
561    """
562    A reporter function calculates the **minimum** y-value of a given shape (since the y-axis is flipped).
563
564    Args:
565        shape (tag or id): The shape in question.
566
567    Returns:
568         A `int` representing the minimum y-coordinate of the shape.
569    """
570    bbox = _safe_bbox(shape)
571    return bbox[1]
572
573
574def get_bottom(shape):
575    """
576    A reporter function calculates the **maximum** y-value of a given shape (since the y-axis is flipped).
577    
578    Args:
579        shape (tag or id): The shape in question.
580
581    Returns:
582         A `int` representing the maximum y-coordinate of the shape.
583    """
584    bbox = _safe_bbox(shape)
585    return bbox[3]
586
587
588def get_left(shape):
589    """
590    A reporter function calculates the **minimum** x-value of a given shape.
591        
592    Args:
593        shape (tag or id): The shape in question.
594
595    Returns:
596         A `int` representing the minimum x-coordinate of the shape.
597    """
598    bbox = _safe_bbox(shape)
599    return bbox[0]
600
601
602def get_right(shape):
603    """
604    A reporter function calculates the **maximum** x-value of a given shape.
605        
606    Args:
607        shape (tag or id): The shape in question.
608
609    Returns:
610         A `int` representing the maximum x-coordinate of the shape.
611    """ 
612    bbox = _safe_bbox(shape)
613    return bbox[2]
614
615
616def get_height(shape):
617    """
618    A reporter function calculates the height of some given shape.
619        
620    Args:
621        shape (tag or id): The shape in question.
622
623    Returns:
624         A `int` representing the height of the shape.
625    """
626    bbox = _safe_bbox(shape)
627    return bbox[3] - bbox[1] - 1
628
629
630def get_width(shape):
631    """
632    A reporter function calculates the width of some given shape.
633        
634    Args:
635        shape (tag or id): The shape in question.
636
637    Returns:
638         An `int` representing width of the shape.
639    """
640    bbox = _safe_bbox(shape)
641    return bbox[2] - bbox[0] - 1
642
643def make_grid(c, w, h):
644    """
645    Draws a grid on a screen with intervals of 100.
646
647    Args:
648        w (`int`): The width of the grid to draw
649        h (`int`): The height of the grid to draw
650    """
651    interval = 100
652    # Creates all vertical lines at intervals of 100
653    for i in range(0, w, interval):
654        _a_canvas.create_line(i, 0, i, h, tag="grid_line")
655    # Creates all horizontal lines at intervals of 100
656    for i in range(0, h, interval):
657        _a_canvas.create_line(0, i, w, i, tag="grid_line")
658    # Creates axis labels
659    offset = 2
660    for y in range(0, h, interval):
661        for x in range(0, w, interval):
662            _a_canvas.create_oval(
663                x - offset, y - offset, x + offset, y + offset, fill="black"
664            )
665            _a_canvas.create_text(
666                x + offset,
667                y + offset,
668                text="({0}, {1})".format(x, y),
669                anchor="nw",
670                font=("Purisa", 8),
671            )
672
673def _safe_bbox(shape):
674    try:
675        bbox = _a_canvas.bbox(shape)
676        if bbox is None:
677            Exception(f"We couldn't find the shape with tag/id: {shape}. Make sure this shape exists!") 
678        return bbox
679    except:
680        raise Exception(f"We couldn't find the shape with tag/id: {shape}. Make sure this shape exists!") 
681
682def _tupelize_color(color):
683    R = int(color[1:3], 16)
684    G = int(color[3:5], 16)
685    B = int(color[5:7], 16)
686    return R, G, B
687
688
689def _interpolate_tuple(startcolor, goalcolor, frac):
690    R = startcolor[0]
691    G = startcolor[1]
692    B = startcolor[2]
693
694    targetR = goalcolor[0]
695    targetG = goalcolor[1]
696    targetB = goalcolor[2]
697
698    DiffR = targetR - R
699    DiffG = targetG - G
700    DiffB = targetB - B
701
702    iR = int(R + (DiffR * frac))
703    iG = int(G + (DiffG * frac))
704    iB = int(B + (DiffB * frac))
705
706    hR = hex(iR).replace("0x", "")
707    hG = hex(iG).replace("0x", "")
708    hB = hex(iB).replace("0x", "")
709
710    if len(hR) == 1:
711        hR = "0" + hR
712    if len(hB) == 1:
713        hB = "0" + hB
714    if len(hG) == 1:
715        hG = "0" + hG
716
717    color = ("#" + hR + hG + hB).upper()
718
719    return color
720
721def does_tag_exist(shape):
722    '''
723    Returns `True` if a given tag exists otherwise returns `False`.
724
725    Args:
726        shape (tag or id): [Required] The tag of the object to lookup.
727
728    '''
729    result = _a_canvas.find_withtag(shape)
730
731    if result:
732        return True
733    else:
734        return False
735
736def random_color():
737    '''
738    Returns a random color as a `string` to be used with `tkinter`.
739    It does not accept any inputs.
740    '''
741    r = lambda: randint(0,255)
742    return '#%02X%02X%02X' % (r(), r(), r())
743
744from tkinter import Tk, Canvas
745
746def setup_shapes(title, background="white", width=600, height=600):
747    """
748    A static function that sets up the pop-up window. **DO NOT USE THIS FUNCTION**.
749    """
750    global _a_canvas
751    gui = Tk()
752    gui.title(title)
753    _a_canvas = Canvas(gui, background=background, width=width, height=width)
754    _a_canvas.pack()
755    make_grid(_a_canvas, width, height)
756    return _a_canvas
def rectangle( top_left=(0, 0), width=25, height=50, color='hotpink', outline='', tag='', **kwargs):
10def rectangle(top_left=(0, 0), width=25, height=50, color="hotpink", outline="", tag="", **kwargs):
11    """
12    A reporter function that draws a rectangle.
13    Args:
14        top_left (`tuple`): A coordinate representing the top left-hand corner of the shape.
15        width (`int`): How wide to draw the shape.
16        height (`int`): How tall to draw the shape.
17        color (`str`): What color to draw the shape.
18        outline (`str`): What color should the border of the shape be.
19        tag (`str`): The tag to assign to the shape.
20
21    Returns:
22         `Shape`: The rectangle that was created.
23    """      
24    point_0 = top_left
25    point_1 = (top_left[0] + width, top_left[1])
26    point_2 = (top_left[0] + width, top_left[1] + height)
27    point_3 = (top_left[0], top_left[1] + height)
28    return _a_canvas.create_polygon(
29        point_0, point_1, point_2, point_3, fill=color, tags=tag, **kwargs
30    )

A reporter function that draws a rectangle.

Arguments:
  • top_left (tuple): A coordinate representing the top left-hand corner of the shape.
  • width (int): How wide to draw the shape.
  • height (int): How tall to draw the shape.
  • color (str): What color to draw the shape.
  • outline (str): What color should the border of the shape be.
  • tag (str): The tag to assign to the shape.
Returns:

Shape: The rectangle that was created.

def square( top_left=(0, 0), size=25, color='hotpink', outline='', tag='', **kwargs):
33def square(top_left=(0, 0), size=25, color="hotpink", outline="", tag="", **kwargs):
34    """
35    A reporter function that draws a square.
36    Args:
37        top_left (`tuple`): A coordinate representing the top left-hand corner of the shape.
38        size (`int`): How big to draw the shape.
39        color (`str`): What color to draw the shape.
40        outline (`str`): What color should the border of the shape be.
41        tag (`str`): The tag to assign to the shape.
42
43    Returns:
44         `Shape`: The square that was created.
45    """
46    return rectangle(top_left=top_left, width=size, height=size, color=color, tag=tag, **kwargs)

A reporter function that draws a square.

Arguments:
  • top_left (tuple): A coordinate representing the top left-hand corner of the shape.
  • size (int): How big to draw the shape.
  • color (str): What color to draw the shape.
  • outline (str): What color should the border of the shape be.
  • tag (str): The tag to assign to the shape.
Returns:

Shape: The square that was created.

def oval( center=(0, 0), radius_x=25, radius_y=50, color='hotpink', outline='', tag='', **kwargs):
49def oval(center=(0, 0), radius_x=25, radius_y=50, color="hotpink", outline="", tag="", **kwargs):
50    """
51    A reporter function that draws an oval.
52    Args:
53        center (`tuple`): A coordinate representing the center of the shape.
54        radius_x (`int`): Specifies the oval's radius on the x-axis.
55        radius_y (`int`): Specifies the oval's radius on the y-axis.
56        color (`str`): What color to draw the shape.
57        outline (`str`): What color should the border of the shape be.
58        tag (`str`): The tag to assign to the shape.
59
60    Returns:
61         `Shape`: The oval that was created.
62    """
63    x = center[0]
64    y = center[1]
65    x0, y0, x1, y1 = (x - radius_x, y - radius_y, x + radius_x, y + radius_y)
66    steps = 100
67    # major and minor axes
68    a = (x1 - x0) / 2.0
69    b = (y1 - y0) / 2.0
70    # center
71    xc = x0 + a
72    yc = y0 + b
73    point_list = []
74    # create the oval as a list of points
75    for i in range(steps):
76        # Calculate the angle for this step
77        theta = (pi * 2) * (float(i) / steps)
78        x = a * cos(theta)
79        y = b * sin(theta)
80        point_list.append(round(x + xc))
81        point_list.append(round(y + yc))
82
83    return _a_canvas.create_polygon(point_list, fill=color, tags=tag, **kwargs)

A reporter function that draws an oval.

Arguments:
  • center (tuple): A coordinate representing the center of the shape.
  • radius_x (int): Specifies the oval's radius on the x-axis.
  • radius_y (int): Specifies the oval's radius on the y-axis.
  • color (str): What color to draw the shape.
  • outline (str): What color should the border of the shape be.
  • tag (str): The tag to assign to the shape.
Returns:

Shape: The oval that was created.

def circle( center=(0, 0), radius=25, color='hotpink', outline='', tag='', **kwargs):
86def circle(center=(0, 0), radius=25, color="hotpink", outline="", tag="", **kwargs):
87    """
88    A reporter function that draws a circle.
89    Args:
90        center (`tuple`): A coordinate representing the center of the shape.
91        radius (`int`): Specifies the circle's radius.
92        color (`str`): What color to draw the shape.
93        outline (`str`): What color should the border of the shape be.
94        tag (`str`): The tag to assign to the shape.
95
96    Returns:
97         `Shape`: The circle that was created.
98    """
99    return oval(center=center, radius_x=radius, radius_y=radius, color=color, tag=tag, **kwargs)

A reporter function that draws a circle.

Arguments:
  • center (tuple): A coordinate representing the center of the shape.
  • radius (int): Specifies the circle's radius.
  • color (str): What color to draw the shape.
  • outline (str): What color should the border of the shape be.
  • tag (str): The tag to assign to the shape.
Returns:

Shape: The circle that was created.

def triangle( bottom_center=(0, 0), width=25, top_shift=0, height=0, color='hotpink', outline='', tag='', **kwargs):
102def triangle(
103    bottom_center=(0, 0), width=25, top_shift=0, height=0, color="hotpink", outline="", tag="", **kwargs
104):
105    """
106    A reporter function that draws a triangle.
107    Args:
108        bottom_center (`tuple`): A coordinate representing the bottom center of the shape.
109        width (`int`): Specifies the width of the base of the triangle.
110        top_shift (`int`): Specifies the how far to the left or right to shift the top of 
111            the triangle from the bottom center.
112        height (`int`): Specifies the triangle's height.
113        color (`str`): What color to draw the shape.
114        outline (`str`): What color should the border of the shape be.
115        tag (`str`): The tag to assign to the shape.
116
117    Returns:
118         `Shape`: The triangle that was created.
119    """
120    if height == 0:
121        height = width * sqrt(3) / 2
122    point_0 = (bottom_center[0] - width / 2, bottom_center[1])
123    point_1 = (bottom_center[0] + width / 2, bottom_center[1])
124    point_2 = (bottom_center[0] + top_shift, bottom_center[1] - height)
125
126    return _a_canvas.create_polygon(point_0, point_1, point_2, fill=color, tags=tag, **kwargs)

A reporter function that draws a triangle.

Arguments:
  • bottom_center (tuple): A coordinate representing the bottom center of the shape.
  • width (int): Specifies the width of the base of the triangle.
  • top_shift (int): Specifies the how far to the left or right to shift the top of the triangle from the bottom center.
  • height (int): Specifies the triangle's height.
  • color (str): What color to draw the shape.
  • outline (str): What color should the border of the shape be.
  • tag (str): The tag to assign to the shape.
Returns:

Shape: The triangle that was created.

def line(points=[], curvy=False, color='hotpink', tag='', **kwargs):
129def line(points=[], curvy=False, color="hotpink", tag="", **kwargs):
130    """
131    A reporter function that draws a line given a list of points.
132    Args:
133        points (`list`): The points that define the line; this should be a list of tuples (coordinates).
134        curvy (`bool`): Makes a curvy line instead.
135        color (`str`): What color to make the shape.
136        tag (`str`): The tag to assign to the shape.
137
138    Returns:
139        `Shape`: The line that was created.
140    """
141    return _a_canvas.create_line(points, fill=color, smooth=curvy, tags=tag, **kwargs)

A reporter function that draws a line given a list of points.

Arguments:
  • points (list): The points that define the line; this should be a list of tuples (coordinates).
  • curvy (bool): Makes a curvy line instead.
  • color (str): What color to make the shape.
  • tag (str): The tag to assign to the shape.
Returns:

Shape: The line that was created.

def arc(points=[], width=5, color='hotpink', line_steps=15, tag='', **kwargs):
144def arc(points=[], width=5, color="hotpink", line_steps=15, tag="", **kwargs):
145    """
146    A reporter function that draws an arc ("curve") given a list of points.
147    Args:
148        points (`list`): The points outlining the curve; this should be a list of tuples (coordinates).
149            Make sure to give it at least 3 (x,y) coordinates that aren't a straight line!
150        color (`str`): What color to make the shape.
151        tag (`str`): The tag to assign to the shape.
152
153    Returns:
154        `Shape`: The arc that was created.
155    """
156    return _a_canvas.create_line(
157        points,  
158        width=width,
159        fill=color,
160        splinesteps=line_steps,
161        smooth=True,
162        tags=tag,
163        **kwargs
164    )

A reporter function that draws an arc ("curve") given a list of points.

Arguments:
  • points (list): The points outlining the curve; this should be a list of tuples (coordinates). Make sure to give it at least 3 (x,y) coordinates that aren't a straight line!
  • color (str): What color to make the shape.
  • tag (str): The tag to assign to the shape.
Returns:

Shape: The arc that was created.

def star( center=(0, 0), radius=50, color='hotpink', outer_radius=75, points=5, outline='', tag='', **kwargs):
167def star(center=(0, 0), radius=50, color="hotpink", outer_radius=75, points=5, outline="", tag="", **kwargs):
168    """
169    A reporter function that draws a star.
170    Args:
171        center (`tuple`): A coordinate representing the center of the shape.
172        radius (`int`): Specifies the radius of the inside part of the star.
173        color (`str`): Specifies the color of the star.
174        outer_radius (`int`): Specifies the radius of the outside part of the star.
175        points (`int`): Specifies the number of points for the star.
176        outline (`str`): What color should the border of the shape be.
177        tag (`str`): The tag to assign to the shape.
178
179    Returns:
180         `Shape`: The star that was created.
181    """
182    arc_segment = 360 / points
183    vertices = []
184    for i in range(points):
185        inner_point = (
186            radius * cos(radians(arc_segment * i)) + center[0],
187            -1 * radius * sin(radians(arc_segment * i)) + center[1],
188        )
189        vertices.append(inner_point)
190        outer_point = (
191            outer_radius * cos(radians(arc_segment * i + arc_segment / 2)) + center[0],
192            -1 * outer_radius * sin(radians(arc_segment * i + arc_segment / 2))
193            + center[1],
194        )
195        vertices.append(outer_point)
196    return polygon(vertices, color=color, tag=tag, **kwargs)

A reporter function that draws a star.

Arguments:
  • center (tuple): A coordinate representing the center of the shape.
  • radius (int): Specifies the radius of the inside part of the star.
  • color (str): Specifies the color of the star.
  • outer_radius (int): Specifies the radius of the outside part of the star.
  • points (int): Specifies the number of points for the star.
  • outline (str): What color should the border of the shape be.
  • tag (str): The tag to assign to the shape.
Returns:

Shape: The star that was created.

def polygon(points=[], color='hotpink', outline='', tag='', **kwargs):
198def polygon(points=[], color="hotpink", outline="", tag="", **kwargs):
199    """
200    A reporter function that draws a polygon given a list of points.
201    Args:
202        points (`list`): The points outlining the polygon; this should be a list of tuples (coordinates).
203            defaults to an empty list.
204        outline (`str`): What color should the border of the shape be.
205        color (`str`): What color to make the shape.
206
207    Returns:
208        `Shape`: The polygon that was created.
209   """
210    return _a_canvas.create_polygon(points, fill=color, tags=tag, **kwargs)

A reporter function that draws a polygon given a list of points.

Arguments:
  • points (list): The points outlining the polygon; this should be a list of tuples (coordinates). defaults to an empty list.
  • outline (str): What color should the border of the shape be.
  • color (str): What color to make the shape.
Returns:

Shape: The polygon that was created.

def spiral( center=(0, 0), width=100, roughness=0.01, start=0, spirals=5, line_width=1, **kwargs):
215def spiral(center=(0, 0), width=100, roughness=0.01, start=0, spirals=5, line_width=1, **kwargs):
216    """
217    A reporter function that draws a spiral.
218    Args:
219        center (`tuple`): A coordinate representing the center of the shape.
220        width (`int`): Specifies the total width of the spiral.
221        roughness (`float`): Controls how spiral-y the shape is (lower is less spiral-y)
222        start (`int`): Where on the spiral to start drawing.
223        spirals (`int`): How many loops to draw.
224        line_width (`int`): How wide for the line to be drawn.
225        tag (`str`): The tag to assign to the shape.
226
227    Returns:
228         `Shape`: The spiral that was created.
229    """
230    theta = 0.0
231    r = start
232    all_points = []
233    prev_pos = _polar_to_cartesian(r, theta)
234    distance = width / 4 / pi / spirals 
235    all_points.append((prev_pos[0] + center[0], prev_pos[1] + center[1]))
236    while theta < 2 * spirals * pi:
237        theta += roughness
238        r = start + distance*theta
239        pos = _polar_to_cartesian(r, theta)
240        all_points.append((pos[0] + center[0], pos[1] + center[1]))
241
242    return arc(points=all_points, width=line_width, **kwargs)

A reporter function that draws a spiral.

Arguments:
  • center (tuple): A coordinate representing the center of the shape.
  • width (int): Specifies the total width of the spiral.
  • roughness (float): Controls how spiral-y the shape is (lower is less spiral-y)
  • start (int): Where on the spiral to start drawing.
  • spirals (int): How many loops to draw.
  • line_width (int): How wide for the line to be drawn.
  • tag (str): The tag to assign to the shape.
Returns:

Shape: The spiral that was created.

def move(shape, x_shift=0, y_shift=0):
244def move(shape, x_shift=0, y_shift=0):
245    """
246    Purpose: Move the x and y position of all shapes that have been tagged
247    with the tag argument
248    Args:
249        shape (tag or id): the shape (or shapes) to move
250        x_shift (`int`; optional): amount to move in the x direction
251        y_shift (`int`; optional): amount to move in the y direction
252    """
253    shape_ids = _a_canvas.find_withtag(shape)
254    for id in shape_ids:
255        _a_canvas.move(id,
256                        x_shift,
257                        y_shift)

Purpose: Move the x and y position of all shapes that have been tagged with the tag argument

Arguments:
  • shape (tag or id): the shape (or shapes) to move
  • x_shift (int; optional): amount to move in the x direction
  • y_shift (int; optional): amount to move in the y direction
def put_in_front(shape):
259def put_in_front(shape):
260    """
261    A function that "raises" a shape to the "top" of the screen."
262
263    Args:
264        shape (tag or id): The shape to raise.
265    """
266    _a_canvas.tag_raise(shape)

A function that "raises" a shape to the "top" of the screen."

Arguments:
  • shape (tag or id): The shape to raise.
def put_in_back(shape):
268def put_in_back(shape):
269    """
270    A function that "lowers" a shape to the "bottom" of the screen."
271
272    Args:
273        shape (tag or id): The shape to raise.
274    """
275    _a_canvas.tag_lower(shape)

A function that "lowers" a shape to the "bottom" of the screen."

Arguments:
  • shape (tag or id): The shape to raise.
def overlay(shape1, shape2, offset_x=0, offset_y=0):
277def overlay(shape1, shape2, offset_x=0, offset_y=0):
278    """
279    A reporter function that overlays shape1 onto shape2. It does this by moving shape 1's center
280    to shape 2's center, and then applying any specified offset.
281    Args:
282        shape1 (tag or id): The first shape to use.
283        shape2 (tag or id): The second shape to use.
284        offset_x (`int`): How much to shift shape 2 in the x-direction after centering it.
285        offset_y (`int`): How much to shift shape 2 in the x-direction after centering it.
286        tag (`str`): The tag to assign to the shape.
287
288    Returns:
289        `Shape`: The modified shape1.
290   """
291    center1 = get_center(shape1)
292    center2 = get_center(shape2)
293    _a_canvas.move(
294        shape1,
295        (center2[0] - center1[0]) + offset_x,
296        (center2[1] - center1[1]) + offset_y,
297    )
298    _a_canvas.tag_raise(shape1, shape2)
299    return shape1

A reporter function that overlays shape1 onto shape2. It does this by moving shape 1's center to shape 2's center, and then applying any specified offset.

Arguments:
  • shape1 (tag or id): The first shape to use.
  • shape2 (tag or id): The second shape to use.
  • offset_x (int): How much to shift shape 2 in the x-direction after centering it.
  • offset_y (int): How much to shift shape 2 in the x-direction after centering it.
  • tag (str): The tag to assign to the shape.
Returns:

Shape: The modified shape1.

def underlay(shape1, shape2, offset_x=0, offset_y=0):
302def underlay(shape1, shape2, offset_x=0, offset_y=0):
303    """
304    A reporter function that underlays shape1 beneath shape2. It does this by moving shape 1's center
305    to shape 2's center, and then applying any specified offset.
306    Args:
307        shape1 (tag or id): The first shape to use.
308        shape2 (tag or id): The second shape to use.
309        offset_x (`int`): How much to shift shape 2 in the x-direction after centering it.
310        offset_y (`int`): How much to shift shape 2 in the x-direction after centering it.
311
312    Returns:
313        `Shape`: The modified shape1.
314   """
315    center1 = get_center(shape1)
316    center2 = get_center(shape2)
317    _a_canvas.move(
318        shape1,
319        (center2[0] - center1[0]) + offset_x,
320        (center2[1] - center1[1]) + offset_y,
321    )
322    _a_canvas.tag_lower(shape1, shape2)
323    return shape1

A reporter function that underlays shape1 beneath shape2. It does this by moving shape 1's center to shape 2's center, and then applying any specified offset.

Arguments:
  • shape1 (tag or id): The first shape to use.
  • shape2 (tag or id): The second shape to use.
  • offset_x (int): How much to shift shape 2 in the x-direction after centering it.
  • offset_y (int): How much to shift shape 2 in the x-direction after centering it.
Returns:

Shape: The modified shape1.

def above(shape1, shape2, offset_x=0, offset_y=0):
326def above(shape1, shape2, offset_x=0, offset_y=0):
327    """
328    A reporter function that places shape1 above shape2 (vertically). It does this by moving shape 1's center
329    to shape 2's center, moving shape 1 in the y-direction the exact height of shape 2, and then applying any
330    specified offset.
331
332    Args:
333        shape1 (tag or id): The first shape to use.
334        shape2 (tag or id): The second shape to use.
335        offset_x (`int`): How much to shift shape 2 in the x-direction after moving it.
336        offset_y (`int`): How much to shift shape 2 in the x-direction after moving it.
337
338    Returns:
339        `Shape`: The modified shape1.  
340    """
341    overlay(shape1, shape2)
342    _a_canvas.move(
343        shape1,
344        0 + offset_x,
345        -1 * (get_height(shape2) + get_height(shape1)) / 2 + offset_y,
346    )
347    return shape1

A reporter function that places shape1 above shape2 (vertically). It does this by moving shape 1's center to shape 2's center, moving shape 1 in the y-direction the exact height of shape 2, and then applying any specified offset.

Arguments:
  • shape1 (tag or id): The first shape to use.
  • shape2 (tag or id): The second shape to use.
  • offset_x (int): How much to shift shape 2 in the x-direction after moving it.
  • offset_y (int): How much to shift shape 2 in the x-direction after moving it.
Returns:

Shape: The modified shape1.

def beside(shape1, shape2, offset_x=0, offset_y=0):
350def beside(shape1, shape2, offset_x=0, offset_y=0):
351    """
352    A reporter function that places shape1 beside shape2 (horizontally). It does this by moving shape 1's center
353    to shape 2's center, moving shape 1 in the x-direction the exact width of shape 2, and then applying any
354    specified offset.
355
356    Args:
357        shape1 (tag or id): The first shape to use.
358        shape2 (tag or id): The second shape to use.
359        offset_x (`int`): How much to shift shape 2 in the x-direction after moving it.
360        offset_y (`int`): How much to shift shape 2 in the x-direction after moving it.
361
362    Returns:
363        `Shape`: The modified shape1.  
364    """
365    overlay(shape1, shape2)
366    _a_canvas.move(
367        shape1,
368        (get_width(shape2) + get_width(shape1)) / 2 + offset_x,
369        0 + offset_y,
370    )
371    return shape1

A reporter function that places shape1 beside shape2 (horizontally). It does this by moving shape 1's center to shape 2's center, moving shape 1 in the x-direction the exact width of shape 2, and then applying any specified offset.

Arguments:
  • shape1 (tag or id): The first shape to use.
  • shape2 (tag or id): The second shape to use.
  • offset_x (int): How much to shift shape 2 in the x-direction after moving it.
  • offset_y (int): How much to shift shape 2 in the x-direction after moving it.
Returns:

Shape: The modified shape1.

def below(shape1, shape2, offset_x=0, offset_y=0):
374def below(shape1, shape2, offset_x=0, offset_y=0):
375    """
376    A reporter function that places shape1 below shape2 (vertically). It does this by moving shape 1's center
377    to shape 2's center, moving shape 1 in the y-direction the exact height of shape 2, and then applying any
378    specified offset.
379
380    Args:
381        shape1 (tag or id): The first shape to use.
382        shape2 (tag or id): The second shape to use.
383        offset_x (`int`): How much to shift shape 2 in the x-direction after moving it.
384        offset_y (`int`): How much to shift shape 2 in the x-direction after moving it.
385
386    Returns:
387        `Shape`: The modified shape1.  
388    """
389    overlay(shape1, shape2)
390    _a_canvas.move(
391        shape1,
392        0 + offset_x,
393        (get_height(shape2) + get_height(shape1)) / 2 + offset_y,
394    )
395    return shape1

A reporter function that places shape1 below shape2 (vertically). It does this by moving shape 1's center to shape 2's center, moving shape 1 in the y-direction the exact height of shape 2, and then applying any specified offset.

Arguments:
  • shape1 (tag or id): The first shape to use.
  • shape2 (tag or id): The second shape to use.
  • offset_x (int): How much to shift shape 2 in the x-direction after moving it.
  • offset_y (int): How much to shift shape 2 in the x-direction after moving it.
Returns:

Shape: The modified shape1.

def delete(shape):
397def delete(shape):
398    """
399    A function that deletes a shape from our screen.
400
401    Args:
402        shape (tag or id): The shape to delete.
403    """
404    _a_canvas.delete(shape)

A function that deletes a shape from our screen.

Arguments:
  • shape (tag or id): The shape to delete.
def duplicate(shape, color=None):
406def duplicate(shape, color=None):
407    """
408    A reporter function that perfectly copies a shape and returns that copy.
409
410    Args:
411        shape (tag or id): The shape to duplicate.
412        color (`str`): A new color to use with the duplicated shape.
413
414    Returns:
415        `Shape`: The new duplicated shape.  
416    """
417    shape_type = _a_canvas.type(shape)
418    shape_config = _a_canvas.itemconfig(shape)
419    shape_coords = _a_canvas.coords(shape)
420    the_copy = None
421    if shape_type == "polygon":
422        new_config = {key: shape_config[key][-1] for key in shape_config.keys()}
423        if color != None:
424            new_config["fill"] = color
425        the_copy = _a_canvas.create_polygon(shape_coords, **new_config)
426        return the_copy

A reporter function that perfectly copies a shape and returns that copy.

Arguments:
  • shape (tag or id): The shape to duplicate.
  • color (str): A new color to use with the duplicated shape.
Returns:

Shape: The new duplicated shape.

def mirror(shape):
428def mirror(shape):
429    """
430    A reporter function that takes a shape and flips it across its vertical
431    axis, returning the tag or ID of the modified shape.
432        
433    Args:
434        shape (tag or id): The shape in question.
435
436    Returns:
437        The modified shape.
438    """
439    center = get_center(shape)[0]
440    shape_ids = _a_canvas.find_withtag(shape)
441    for shape_id in shape_ids:
442        flipped_coordinates = []
443        shape_coords = _a_canvas.coords(shape_id)
444        counter = 0
445        for num in shape_coords:
446            if counter % 2 == 0:
447                if num < center:
448                    flipped_coordinates.append(num + 2 * (center - num))
449                elif num > center:
450                    flipped_coordinates.append(num - 2 * (num - center))
451                else:
452                    flipped_coordinates.append(num)
453            else:
454                flipped_coordinates.append(num)
455            counter += 1
456        _a_canvas.coords(shape_id, flipped_coordinates)

A reporter function that takes a shape and flips it across its vertical axis, returning the tag or ID of the modified shape.

Arguments:
  • shape (tag or id): The shape in question.
Returns:

The modified shape.

def rotate(shape, degrees=5, origin=None):
458def rotate(shape, degrees=5, origin=None):
459    """
460    A reporter function that takes a shape and rotates it by a specified amount around a specified point.
461    It does this by interpolating a polygon around the shape and calculating the shifts of individual
462    points on the edge of the polygon.
463
464    Args:
465        shape (tag or id): The shape to rotate.
466        degrees (`int`): The number of degrees to rotate the shape.
467        origin (`tuple`): An `(x,y)` coordinate about which to perform the rotation. Defaults to the center
468            of the given shape.
469
470    Returns:
471        `Shape`: The modified shape.  
472    """
473    if origin is None:
474        origin = get_center(shape)
475
476    theta = radians(degrees)
477    ox, oy = origin
478
479    all_shapes = _a_canvas.find_withtag(shape)
480
481    for a_shape in all_shapes:
482        coords = _a_canvas.coords(a_shape)
483        # update coordinates:
484        for i in range(0, len(coords), 2):
485            px, py = coords[i], coords[i + 1]
486            qx = cos(theta) * (px - ox) - sin(theta) * (py - oy) + ox
487            qy = sin(theta) * (px - ox) + cos(theta) * (py - oy) + oy
488            coords[i] = qx
489            coords[i + 1] = qy
490        # set the coordinates:
491        _a_canvas.coords(a_shape, coords)
492
493    return shape 

A reporter function that takes a shape and rotates it by a specified amount around a specified point. It does this by interpolating a polygon around the shape and calculating the shifts of individual points on the edge of the polygon.

Arguments:
  • shape (tag or id): The shape to rotate.
  • degrees (int): The number of degrees to rotate the shape.
  • origin (tuple): An (x,y) coordinate about which to perform the rotation. Defaults to the center of the given shape.
Returns:

Shape: The modified shape.

def distance(point1, point2):
495def distance(point1, point2):
496    """
497    A reporter function calculates the distance between two `(x, y)` coordinates.
498          
499    Args:
500        point1 (`tuple`): The first `(x, y)` coordinate.
501        point2 (`tuple`): The second `(x, y)` coordinate.
502
503    Returns:
504         A `float` representing the distance between the two points.
505    """
506    return sqrt(((point1[0] - point2[0]) ** 2) + ((point1[1] - point2[1]) ** 2))

A reporter function calculates the distance between two (x, y) coordinates.

Arguments:
  • point1 (tuple): The first (x, y) coordinate.
  • point2 (tuple): The second (x, y) coordinate.
Returns:

A float representing the distance between the two points.

def update_color(shape, color):
508def update_color(shape, color):
509    '''
510    Change the fill color of a tagged object.
511
512    Args:
513        shape (tag or id): The tag of the object to re-fill.
514        color (`str`): A color name or hex code to re-fill with.
515    '''
516    ids = _a_canvas.find_withtag(shape)
517    for id in ids:
518        _a_canvas.itemconfig(id, fill=color)

Change the fill color of a tagged object.

Arguments:
  • shape (tag or id): The tag of the object to re-fill.
  • color (str): A color name or hex code to re-fill with.
def interpolate_colors(color1, color2, frac):
520def interpolate_colors(color1, color2, frac):
521    """
522    A reporter function that generates a new color between two given colors.
523    Args:
524        color1 (`str`): The path of the file to wrap
525        color2 (`str`): The path of the file to wrap
526        frac (`float`): What fraction of each color to take. An input of 0 returns
527            color1, an input of 1 returns color2, an input of 0.5 returns a color
528            perfectly between the two.
529
530    Returns:
531         A color (as a hex `str`) to be used elsewhere
532   """
533    if "#" not in color1:
534        color1 = tuple((c // 256 for c in _a_canvas.winfo_rgb(color1)))
535    else:
536        color1 = _tupelize_color(color1)
537    if "#" not in color2:
538        color2 = tuple((c // 256 for c in _a_canvas.winfo_rgb(color2)))
539    else:
540        color2 = _tupelize_color(color2)
541    return _interpolate_tuple(color1, color2, frac)

A reporter function that generates a new color between two given colors.

Arguments:
  • color1 (str): The path of the file to wrap
  • color2 (str): The path of the file to wrap
  • frac (float): What fraction of each color to take. An input of 0 returns color1, an input of 1 returns color2, an input of 0.5 returns a color perfectly between the two.
Returns:

A color (as a hex str) to be used elsewhere

def get_center(shape):
543def get_center(shape):
544    """
545    A reporter function calculates the a coordinate at the center of some shape.
546        
547    Args:
548        shape (tag or id): The shape in question.
549
550    Returns:
551         A `tuple` representing center of the given shape.
552    """
553    bbox = _safe_bbox(shape)
554
555    if bbox is None:
556        raise Exception(f"We couldn't find the shape with id/tag {shape}. Make sure it exists!")
557
558    return (((bbox[2] + bbox[0]) / 2), ((bbox[1] + bbox[3]) / 2))

A reporter function calculates the a coordinate at the center of some shape.

Arguments:
  • shape (tag or id): The shape in question.
Returns:

A tuple representing center of the given shape.

def get_top(shape):
561def get_top(shape):
562    """
563    A reporter function calculates the **minimum** y-value of a given shape (since the y-axis is flipped).
564
565    Args:
566        shape (tag or id): The shape in question.
567
568    Returns:
569         A `int` representing the minimum y-coordinate of the shape.
570    """
571    bbox = _safe_bbox(shape)
572    return bbox[1]

A reporter function calculates the minimum y-value of a given shape (since the y-axis is flipped).

Arguments:
  • shape (tag or id): The shape in question.
Returns:

A int representing the minimum y-coordinate of the shape.

def get_bottom(shape):
575def get_bottom(shape):
576    """
577    A reporter function calculates the **maximum** y-value of a given shape (since the y-axis is flipped).
578    
579    Args:
580        shape (tag or id): The shape in question.
581
582    Returns:
583         A `int` representing the maximum y-coordinate of the shape.
584    """
585    bbox = _safe_bbox(shape)
586    return bbox[3]

A reporter function calculates the maximum y-value of a given shape (since the y-axis is flipped).

Arguments:
  • shape (tag or id): The shape in question.
Returns:

A int representing the maximum y-coordinate of the shape.

def get_left(shape):
589def get_left(shape):
590    """
591    A reporter function calculates the **minimum** x-value of a given shape.
592        
593    Args:
594        shape (tag or id): The shape in question.
595
596    Returns:
597         A `int` representing the minimum x-coordinate of the shape.
598    """
599    bbox = _safe_bbox(shape)
600    return bbox[0]

A reporter function calculates the minimum x-value of a given shape.

Arguments:
  • shape (tag or id): The shape in question.
Returns:

A int representing the minimum x-coordinate of the shape.

def get_right(shape):
603def get_right(shape):
604    """
605    A reporter function calculates the **maximum** x-value of a given shape.
606        
607    Args:
608        shape (tag or id): The shape in question.
609
610    Returns:
611         A `int` representing the maximum x-coordinate of the shape.
612    """ 
613    bbox = _safe_bbox(shape)
614    return bbox[2]

A reporter function calculates the maximum x-value of a given shape.

Arguments:
  • shape (tag or id): The shape in question.
Returns:

A int representing the maximum x-coordinate of the shape.

def get_height(shape):
617def get_height(shape):
618    """
619    A reporter function calculates the height of some given shape.
620        
621    Args:
622        shape (tag or id): The shape in question.
623
624    Returns:
625         A `int` representing the height of the shape.
626    """
627    bbox = _safe_bbox(shape)
628    return bbox[3] - bbox[1] - 1

A reporter function calculates the height of some given shape.

Arguments:
  • shape (tag or id): The shape in question.
Returns:

A int representing the height of the shape.

def get_width(shape):
631def get_width(shape):
632    """
633    A reporter function calculates the width of some given shape.
634        
635    Args:
636        shape (tag or id): The shape in question.
637
638    Returns:
639         An `int` representing width of the shape.
640    """
641    bbox = _safe_bbox(shape)
642    return bbox[2] - bbox[0] - 1

A reporter function calculates the width of some given shape.

Arguments:
  • shape (tag or id): The shape in question.
Returns:

An int representing width of the shape.

def make_grid(c, w, h):
644def make_grid(c, w, h):
645    """
646    Draws a grid on a screen with intervals of 100.
647
648    Args:
649        w (`int`): The width of the grid to draw
650        h (`int`): The height of the grid to draw
651    """
652    interval = 100
653    # Creates all vertical lines at intervals of 100
654    for i in range(0, w, interval):
655        _a_canvas.create_line(i, 0, i, h, tag="grid_line")
656    # Creates all horizontal lines at intervals of 100
657    for i in range(0, h, interval):
658        _a_canvas.create_line(0, i, w, i, tag="grid_line")
659    # Creates axis labels
660    offset = 2
661    for y in range(0, h, interval):
662        for x in range(0, w, interval):
663            _a_canvas.create_oval(
664                x - offset, y - offset, x + offset, y + offset, fill="black"
665            )
666            _a_canvas.create_text(
667                x + offset,
668                y + offset,
669                text="({0}, {1})".format(x, y),
670                anchor="nw",
671                font=("Purisa", 8),
672            )

Draws a grid on a screen with intervals of 100.

Arguments:
  • w (int): The width of the grid to draw
  • h (int): The height of the grid to draw
def does_tag_exist(shape):
722def does_tag_exist(shape):
723    '''
724    Returns `True` if a given tag exists otherwise returns `False`.
725
726    Args:
727        shape (tag or id): [Required] The tag of the object to lookup.
728
729    '''
730    result = _a_canvas.find_withtag(shape)
731
732    if result:
733        return True
734    else:
735        return False

Returns True if a given tag exists otherwise returns False.

Arguments:
  • shape (tag or id): [Required] The tag of the object to lookup.
def random_color():
737def random_color():
738    '''
739    Returns a random color as a `string` to be used with `tkinter`.
740    It does not accept any inputs.
741    '''
742    r = lambda: randint(0,255)
743    return '#%02X%02X%02X' % (r(), r(), r())

Returns a random color as a string to be used with tkinter. It does not accept any inputs.

def setup_shapes(title, background='white', width=600, height=600):
747def setup_shapes(title, background="white", width=600, height=600):
748    """
749    A static function that sets up the pop-up window. **DO NOT USE THIS FUNCTION**.
750    """
751    global _a_canvas
752    gui = Tk()
753    gui.title(title)
754    _a_canvas = Canvas(gui, background=background, width=width, height=width)
755    _a_canvas.pack()
756    make_grid(_a_canvas, width, height)
757    return _a_canvas

A static function that sets up the pop-up window. DO NOT USE THIS FUNCTION.