Add relay element

Issue #18 resolved
Daniel Mouritzen created an issue

I couldn’t find a relay element so I created one:

import SchemDraw
import SchemDraw.elements as elm
import copy

def relay(switch=elm.SWITCH_SPST, inductor=elm.INDUCTOR, core=True, box=True, unit=3.0):
    ''' Generate a relay element

        Parameters
        ----------
        switch : dict
            Element to use for switch
        inductor : dict
            Element to use for inductor
        core : bool
            Draw line separating inductor and switch
        box : bool
            Draw box
        unit : float
            Total length of element including leads

        Returns
        -------
        elm : dict
            The relay element definition dictionary
    '''
    switch = copy.deepcopy(switch)
    inductor = copy.deepcopy(inductor)

    if 'base' in switch:
        switch.setdefault('paths', []).extend(switch['base']['paths'])
        switch.setdefault('shapes', []).extend(switch['base']['shapes'])

    element = {'name': 'RELAY',
               'extend': False,
               'paths': [],
               'shapes': []}

    lead_len = max(0, (unit - 1) / 2)
    left = lead_len
    right = lead_len + 1
    sw_scale = 0.75
    sw_left = left + (1 - sw_scale) / 2

    # Adjust for core
    ind_gap = .5
    if core:
        ind_gap += .2

    # Add inductor
    element['paths'].extend(inductor['paths'])
    if 'shapes' in inductor:
        element['shapes'].extend(inductor['shapes'])
    for path in inductor['paths']:
        element['paths'].append([])
        for node in path:
            element['paths'][-1].append([node[0] + left, node[1]])
    for shape in inductor.get('shapes', []):
        c = shape['center']
        shape['center'] = [c[0] + left, c[1]]
        element['shapes'].append(shape)

    anchors = {'in1': [0, 0],
               'in2': [unit, 0]}
    element['paths'].extend([[[left, 0], anchors['in1']],
                             [[right, 0], anchors['in2']]])

    # Add the core
    if core:
        center = ind_gap/2
        element['paths'].append([[left, center], [right, center]])

    # Add switch
    ind_gap -= min(s['center'][1]*sw_scale for s in switch['shapes'])
    for path in switch.get('paths', []):
        element['paths'].append([])
        for node in path:
            element['paths'][-1].append([node[0]*sw_scale + sw_left, node[1]*sw_scale + ind_gap])
    for shape in switch['shapes']:
        c = shape['center']
        shape['center'] = [c[0]*sw_scale + sw_left, c[1]*sw_scale + ind_gap]
        shape['radius'] *= sw_scale
        element['shapes'].append(shape)

    if 'anchors' in switch:
        for key, pos in switch['anchors'].items():
            x = 0 if pos[0] < 0.5 else unit
            pos = [pos[0]*sw_scale + sw_left, pos[1]*sw_scale + ind_gap]
            anchors[key] = [x, pos[1]]
            element['paths'].append([pos, anchors[key]])
    else:
        a = element['paths'][-1][0]
        b = element['paths'][-1][-1]
        anchors['a'] = [0, a[1]]
        anchors['b'] = [unit, b[1]]
        element['paths'].extend([[a, anchors['a']],
                                 [b, anchors['b']]])

    if box:
        margin = 0.255
        top = max(a[1] for a in anchors.values())
        element['shapes'].append({'shape': 'poly',
                                  'xy': [[left - margin, -margin],
                                         [right + margin, -margin],
                                         [right + margin, top + margin],
                                         [left - margin, top + margin]],
                                  'closed': True,
                                  'fill': False})


    element['anchors'] = anchors
    return element


d = SchemDraw.Drawing()
r=d.add(relay(core=True, box=True, unit=2, switch=elm.SWITCH_SPDT2), anchor='in1', d='down')
d.draw()

It supports all the standard switch types. Feel free to modify it or add it to the code base.

A bit of feedback about the API: Why are all the standard elements defined as dicts instead of being subclasses of Element or something? It would be easier to create elements like this if there were some instance methods like bbox() and transform(x, y, theta, scale) etc that you could call on individual elements. Also, there should be a way to define the ‘natural’ direction of the anchors so the automatic lead extending could work for elements with more than two anchors (and if the elements were classes you could pass extend=False when instantiating it to disable this feature when needed).

Comments (2)

  1. cdelker repo owner

    Thanks for the code, I’ll try to get it worked in. Regarding API, I was headed in that direction during my last refactor, but didn’t get a chance to finish. I hope to revisit the idea soon.

  2. Log in to comment