Level Dimensions#

Level Properties#

Show/Hide Level Dimension Attributes
  • im

    PIL image handle, link to the calling program

  • dr

    PIL drawing handle, link to the calling program

  • at

    Coordinates at left tank wall level

  • diam

    Tank diameter, pixels

  • ldrA

    Inclined leader length, default 20

  • ldrB

    Horizontal leader length, default 20

  • ext

    Tuple of length external extender and gap, if an integer then the extender touches the vessel wall, unless it is 0 then the dimension becomes internal, default 0

  • dash

    Tuple giving dash pattern, dash length then gap default (10, 4)

  • text

    Dimension text, default None

  • font

    Font of the text, default None

  • fill

    Dimension colour RGB tuple, default (0,0,0)

  • tri

    Level indicator, equilateral triangle default 8


../_images/level_dim.png

Level dimension inside a tank#

../_images/level_dim_neg.png

Level dimension negative leader#

Contents of a tank are shown with dashed line and dashed leaders. The dashed lines are made using a dashed line created from a function created in the next section, although the plain Bresenham/Zigl algorithm can be used. Apart from the starting position, diameter of tank, the user can choose different dash patterns, the inclined leader length and the indicating triangle size. The dimension lies on the righthand side of the vessel, if a negative value ldrA is used the dimension is on the lefthand side.

If the normal level dimension cannot be used then an outside dimension can be used. This has an extension line outside of the vessel, the indicating triangle sits on the extension line. As the leaders are outside of the vessel they are drawn solidly. The extender ext can be a single integer, in which case the line touches the vessel or as a tuple of two values, the first being the line length, the second the gap length.

../_images/out_level_dim.png

Level dimension outside a tank#

../_images/out_level_dim_neg.png

Outside level dimension negative leader#

Show/Hide Code level_dim.py

from PIL import Image, ImageDraw, ImageFont
from math import sin, pi
from DimLinesPIL import DashedLine, int_up, angled_text


def dim_level(im, dr, at, diam, ext=0, ldrA=20, ldrB=20, dash=(10,4), text=None,
              font=None, fill=(0,0,0), tri=8):
    # at on left tank wall, diam internal tank diameter,
    # triangle on top of level (8,8,8) p0 tip triangle, p1, p2 angles, p2 on at-p4
    # p3 opposite side to at, both drawn to inside tank wall
    # leader (ldr) at 60° up to p4 then horizontal to p5

    # check dash input
    if len(dash)%2 == 0 or len(dash) ==1:
        pass
    else:
        raise Exception('The dash tuple: {} should be one or an equal number '\
                        'of entries'.format(dash))
    
    if isinstance(ext, int) or len(ext) == 1:
        exto = ext if isinstance(ext, int) else ext[0]
    elif len(ext) == 2:
        exto = sum(ext)
    else:
        raise Exception('out_dim_level: The extension tuple ext {} should be one' \
                        ' or two entries'.format(ext))

    font = ImageFont.load_default() if font is None else font

    (wide, ht) = font.getsize(text)

    angle = 0

    # check whether left or right position
    if ldrA > 0:
        if ext == 0:
            p0 = (int_up(at[0] + diam * 0.4), at[1])
            p4 = (int_up(p0[0] + ldrA * 0.5), p0[1] - int_up(ldrA * sin(pi/3)))
            p5 = (at[0] + diam, p4[1]) if ldrB < diam else (at[0] + diam + ldrB,
                                                            p4[1])
        else:
            p0 = (int_up(at[0] + diam + 0.6 * exto), at[1]) # tip triangle
            p4 = (int_up(p0[0] + ldrA * 0.5), p0[1] - int_up(ldrA * sin(pi/3))) # top ldr
            p5 = (p4[0] + ldrB, p4[1]) # end ldr
    else:
        if ext == 0:
            p0 = (int_up(at[0] + diam * 0.6), at[1])
            p4 = (int_up(p0[0] + ldrA * 0.5), p0[1] + int_up(ldrA * sin(pi/3)))
            p5 = (at[0], p4[1])
        else:
            p0 = (int_up(at[0] - 0.6 * exto), at[1])
            p4 = (int_up(p0[0] + ldrA * 0.5), p0[1] + int_up(ldrA * sin(pi/3)))
            p5 = (p4[0] - ldrB, p4[1])
    
    ldr_w = abs(p5[0] - p4[0])
    if ldr_w < wide:
        raise Exception('The leader width is too small: {} should be larger '\
                        'than the text width {}'.format(ldr_w, wide))
    
    p2 = (p0[0] + tri * 0.5, p0[1] - int_up(tri * sin(pi/3)))
    p1 = (p2[0] - tri, p2[1])
    p3 = (at[0] + diam, at[1]) # outer wall

    DashedLine(dr, at, end_pos=p3, dash=dash, width = 1, fill=fill)
    dr.polygon( [p0, p1, p2], outline=fill)

    if ldrA > 0:
        if ext == 0:
            DashedLine(dr, p2, p4, dash=dash, fill=fill, width=1)
        else:
            dr.line([p2, p4], fill=fill, width=1)
            dr.line([p3, (p3[0] + exto, at[1])], width = 1, fill=fill)
    else:
        if ext ==0:
            DashedLine(dr, p1, p4, dash=dash, fill=fill, width=1)
        else:
            dr.line([p1, p4], fill=fill, width=1)
            dr.line([at, (at[0] - exto, at[1])], width = 1, fill=fill)

    if ext == 0:
        DashedLine(dr, p4, p5, dash=dash, fill=fill)
    else:
        dr.line([p4, p5], width = 1, fill=fill)
        
    p6 = (int((p4[0] + p5[0])//2), p4[1] - ht - 5)

    angled_text(im, p6, text, angle, font, fill=fill)

if __name__ == "__main__":
    Font = ImageFont.truetype('consola.ttf', 12)
    #wide, height = font.getsize('(30, 84)')

    w, h = 200, 200
    image = Image.new('RGB', (w,h), '#FFFFDD')

    draw = ImageDraw.Draw(image)

    a=(90,10)
    b=(90,190)
    c=(110,10)
    d=(110,190)

    draw.line([a,b], width=2, fill='blue')
    draw.line([c,d], width=2, fill='blue')

    At=(a[0],100)
    Diam = c[0] - a[0]

    Fill=(0,0,0)

    dim_level(image, draw, At, Diam, ldrA=-20, ldrB=50, dash=(4,4), text='2500 hl',
              fill=Fill, tri=8, font=Font, ext=40)

    image.show()
    #image.save('../figures/level_dim_neg.png') # show()