Changes to Line Dimension#
Some of the other dimensions just arrows, not necessarily pointing outwards.
Changed Properties Line Dimension#
- ptB
Finishing coordinates used on a line, optional, default None.
- angle
Slope of arrow in degrees used when working just with arrows, optional, default None.
Change Dimension Script#
We can use the line dimension to draw the arrows, we need its position, angle, shape and which way to point, add a default value to ptB. Use the start point (ptA) for its position add an angle option, checking on the arrow part of the script we should have all that is needed:
def dimension(dr, ptA, ptB=None, angle=None, width=1, fill=(0,0,0),
arrowhead=(8, 10, 3), arrow='last'):
# extract entries from tuples
x0, y0 = ptA
if angle is None and ptB:
phi = atan2(y1-y0, x1-x0)
dr.line((ptA,ptB), width=width, fill=fill)
x1, y1 = ptB
phi = radians(angle)
elif ptB is None and isinstance(angle, int):
x1, y1 = ptA
phi = radians(angle)
else:
raise Exception('dimension: Either supply ptB {} or angle {} not both' \
.format(ptB, angle))
....
There are no other changes required to the line dimension.
After all that we should have a script that looks something like
Show/Hide Code test_arrow_line.py
from PIL import Image, ImageDraw
from math import atan2, sin, cos, radians, sqrt
def dimension(dr, ptA, ptB=None, angle=None, width=1, fill=(0,0,0),
arrowhead=(8, 10, 3), arrow='last'):
if isinstance(arrowhead, tuple) and len(arrowhead) == 3:
d1, d2, d3 = arrowhead
else:
raise Exception('dimension: arrowhead {} needs a 3 entry' \
'tuple'.format(arrowhead))
if arrow not in ('first', 'last', 'both'):
raise Exception('dimension: arrow {} can only be the strings "first",' \
'"last", "both"'.format(arrow))
# Get drawing context
ldraw = ImageDraw.Draw(im)
# extract dims from tuples
x0, y0 = ptA
if angle is None and ptB:
x1, y1 = ptB
phi = atan2(y1-y0, x1-x0)
dr.line((ptA,ptB), width=width, fill=fill)
elif ptB is None and angle:
x1,y1 = ptA
phi = radians(angle)
else:
raise Exception('dimension: Either supply ptB {} or angle {} not both' \
.format(ptB, angle))
# perpendicular distance shaft to arrow tip
el = int(sqrt(d2 * d2 - d3 * d3) + 0.5)
if arrow in ('first', 'both'):
cx0 = x0 + d1 * cos(phi)
cy0 = y0 + d1 * sin(phi)
ex0 = x0 + el * cos(phi)
ey0 = y0 + el * sin(phi)
fx0 = ex0 + d3 * sin(phi)
fy0 = ey0 - d3 * cos(phi)
gx0 = ex0 - d3 * sin(phi)
gy0 = ey0 + d3 * cos(phi)
dr.polygon([(x0, y0), (fx0, fy0), (cx0, cy0),
(gx0, gy0)], fill=fill)
if arrow in ('last', 'both'):
cx0 = x1 - d1 * cos(phi)
cy0 = y1 - d1 * sin(phi)
ex0 = x1 - el * cos(phi)
ey0 = y1 - el * sin(phi)
fx0 = ex0 + d3 * sin(phi)
fy0 = ey0 - d3 * cos(phi)
gx0 = ex0 - d3 * sin(phi)
gy0 = ey0 + d3 * cos(phi)
dr.polygon([(x1, y1), (fx0, fy0), (cx0, cy0),
(gx0, gy0)], fill=fill)
if __name__ == '__main__':
w, h = 640, 480
im = Image.new('RGB', (w,h), '#FFFFDD')
dr = ImageDraw.Draw(im)
ptA = (110,110)
ptB = (430,430)
dimension(dr, ptA, ptB, arrow='both', arrowhead=(8, 10, 3))
ptA = (400,50)
ptB = (50,400)
dimension(dr, ptA, ptB, arrow='both', arrowhead=(8, 10, 3))
im.show()
#im.save('../figures/test_dimension.png')
Note
One can test the dimension module DimLinesPIL by importing the relevant dimension directly and running just the main part of the script.