Draws handle and target points with arrow pointing towards the target point. Args: img (PIL.Image.Image): The image to draw on. handle_points (List[Tuple[int, int]]): A list of handle [x,y] points. target_points (List[Tuple[int, int]]): A list of target [x,y] points
(
img: PIL.Image.Image,
handle_points: List[Tuple[int, int]],
target_points: List[Tuple[int, int]],
radius: int = 5)
| 82 | |
| 83 | |
| 84 | def draw_handle_target_points( |
| 85 | img: PIL.Image.Image, |
| 86 | handle_points: List[Tuple[int, int]], |
| 87 | target_points: List[Tuple[int, int]], |
| 88 | radius: int = 5): |
| 89 | """ |
| 90 | Draws handle and target points with arrow pointing towards the target point. |
| 91 | |
| 92 | Args: |
| 93 | img (PIL.Image.Image): The image to draw on. |
| 94 | handle_points (List[Tuple[int, int]]): A list of handle [x,y] points. |
| 95 | target_points (List[Tuple[int, int]]): A list of target [x,y] points. |
| 96 | radius (int): The radius of the handle and target points. |
| 97 | """ |
| 98 | if not isinstance(img, PIL.Image.Image): |
| 99 | img = PIL.Image.fromarray(img) |
| 100 | |
| 101 | if len(handle_points) == len(target_points) + 1: |
| 102 | target_points = copy.deepcopy(target_points) + [None] |
| 103 | |
| 104 | draw = PIL.ImageDraw.Draw(img) |
| 105 | for handle_point, target_point in zip(handle_points, target_points): |
| 106 | handle_point = [handle_point[1], handle_point[0]] |
| 107 | # Draw the handle point |
| 108 | handle_coords = get_ellipse_coords(handle_point, radius) |
| 109 | draw.ellipse(handle_coords, fill="red") |
| 110 | |
| 111 | if target_point is not None: |
| 112 | target_point = [target_point[1], target_point[0]] |
| 113 | # Draw the target point |
| 114 | target_coords = get_ellipse_coords(target_point, radius) |
| 115 | draw.ellipse(target_coords, fill="blue") |
| 116 | |
| 117 | # Draw arrow head |
| 118 | arrow_head_length = 10.0 |
| 119 | |
| 120 | # Compute the direction vector of the line |
| 121 | dx = target_point[0] - handle_point[0] |
| 122 | dy = target_point[1] - handle_point[1] |
| 123 | angle = math.atan2(dy, dx) |
| 124 | |
| 125 | # Shorten the target point by the length of the arrowhead |
| 126 | shortened_target_point = ( |
| 127 | target_point[0] - arrow_head_length * math.cos(angle), |
| 128 | target_point[1] - arrow_head_length * math.sin(angle), |
| 129 | ) |
| 130 | |
| 131 | # Draw the arrow (main line) |
| 132 | draw.line([tuple(handle_point), shortened_target_point], fill='white', width=3) |
| 133 | |
| 134 | # Compute the points for the arrowhead |
| 135 | arrow_point1 = ( |
| 136 | target_point[0] - arrow_head_length * math.cos(angle - math.pi / 6), |
| 137 | target_point[1] - arrow_head_length * math.sin(angle - math.pi / 6), |
| 138 | ) |
| 139 | |
| 140 | arrow_point2 = ( |
| 141 | target_point[0] - arrow_head_length * math.cos(angle + math.pi / 6), |
nothing calls this directly
no test coverage detected