From f3842460ba7694e9c1c9190bd6b08357254c2808 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sun, 16 Sep 2018 21:29:09 +1000 Subject: [PATCH 1/2] Added line joints --- Tests/images/imagedraw_line_joint_curve.png | Bin 0 -> 3535 bytes Tests/test_imagedraw.py | 14 +++++ docs/reference/ImageDraw.rst | 7 ++- src/PIL/ImageDraw.py | 58 +++++++++++++++++++- 4 files changed, 74 insertions(+), 5 deletions(-) create mode 100644 Tests/images/imagedraw_line_joint_curve.png diff --git a/Tests/images/imagedraw_line_joint_curve.png b/Tests/images/imagedraw_line_joint_curve.png new file mode 100644 index 0000000000000000000000000000000000000000..ad729f52858daee4d20e1d3e24d4a1cdf9a2aeb4 GIT binary patch literal 3535 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 4: + for i in range(1, len(xy)-1): + point = xy[i] + angles = [ + math.degrees(math.atan2( + end[0] - start[0], start[1] - end[1] + )) % 360 + for start, end in ((xy[i-1], point), (point, xy[i+1])) + ] + if angles[0] == angles[1]: + # This is a straight line, so no joint is required + continue + + def coord_at_angle(coord, angle): + x, y = coord + angle -= 90 + distance = width/2 - 1 + return tuple([ + p + + (math.floor(p_d) if p_d > 0 else math.ceil(p_d)) + for p, p_d in + ((x, distance * math.cos(math.radians(angle))), + (y, distance * math.sin(math.radians(angle)))) + ]) + flipped = ((angles[1] > angles[0] and + angles[1] - 180 > angles[0]) or + (angles[1] < angles[0] and + angles[1] + 180 > angles[0])) + coords = [ + (point[0] - width/2 + 1, point[1] - width/2 + 1), + (point[0] + width/2 - 1, point[1] + width/2 - 1) + ] + if flipped: + start, end = (angles[1] + 90, angles[0] + 90) + else: + start, end = (angles[0] - 90, angles[1] - 90) + self.pieslice(coords, start - 90, end - 90, fill) + + if width > 8: + # Cover potential gaps between the line and the joint + if flipped: + gapCoords = [ + coord_at_angle(point, angles[0]+90), + point, + coord_at_angle(point, angles[1]+90) + ] + else: + gapCoords = [ + coord_at_angle(point, angles[0]-90), + point, + coord_at_angle(point, angles[1]-90) + ] + self.line(gapCoords, fill, width=3) def shape(self, shape, fill=None, outline=None): """(Experimental) Draw a shape.""" From 53acbfc4d512aab4fce6bc7cb83896f745ddec0c Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sun, 16 Sep 2018 22:30:11 +1000 Subject: [PATCH 2/2] Added versionadded [ci skip] --- docs/reference/ImageDraw.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/reference/ImageDraw.rst b/docs/reference/ImageDraw.rst index 89d0bfa28..c66fb59dd 100644 --- a/docs/reference/ImageDraw.rst +++ b/docs/reference/ImageDraw.rst @@ -186,6 +186,8 @@ Methods :param joint: Joint type between a sequence of lines. It can be "curve", for rounded edges, or None. + .. versionadded:: 5.3.0 + .. py:method:: PIL.ImageDraw.ImageDraw.pieslice(xy, start, end, fill=None, outline=None) Same as arc, but also draws straight lines between the end points and the