Example #1
0
def offset(a, o):
    """ Assumes a linear distance field for bounds calculations!
    """
    if o < 0:
        return Shape('-%sf%g' % (a.math, o), a.bounds.xmin, a.bounds.ymin,
                     a.bounds.zmin, a.bounds.xmax, a.bounds.ymax,
                     a.bounds.zmax)
    else:
        return Shape('-%sf%g' % (a.math, o), a.bounds.xmin - o,
                     a.bounds.ymin - o, a.bounds.zmin - o, a.bounds.xmax + o,
                     a.bounds.ymax + o, a.bounds.zmax + o)
Example #2
0
def polygon_radius(x, y, r, N):
    """ Makes a polygon with a center-to-vertex distance r
        The polygon is oriented so that the bottom is always flat.
    """
    # Find the center-to-edge distance
    r_ = -r * math.cos(math.pi / N)
    # Make an offset half-region shape
    half = Shape('-f%gY' % r_)
    # Take the union of a bunch of rotated half-region shapes
    p = functools.reduce(operator.and_,
                         [rotate(half, 360. / N * i) for i in range(N)])
    # Apply appropriate bounds and return
    return Shape(p.math, -r, -r, r, r)
Example #3
0
def triangle(x0, y0, x1, y1, x2, y2):
    """ Defines a triangle from three points.
    """
    # Find the angles of the points about the center
    xm = (x0 + x1 + x2) / 3.
    ym = (y0 + y1 + y2) / 3.
    angles = [
        math.atan2(y - ym, x - xm) for x, y in [(x0, y0), (x1, y1), (x2, y2)]
    ]

    # Sort the angles so that the smallest one is first
    if angles[1] < angles[0] and angles[1] < angles[2]:
        angles = [angles[1], angles[2], angles[0]]
    elif angles[2] < angles[0] and angles[2] < angles[1]:
        angles = [angles[2], angles[0], angles[1]]

    # Enforce that points must be in clockwise order by swapping if necessary
    if angles[2] > angles[1]:
        x0, y0, x1, y1 = x1, y1, x0, y0

    def edge(x, y, dx, dy):
        # dy*(X-x)-dx*(Y-y)
        return '-*f%(dy)g-Xf%(x)g*f%(dx)g-Yf%(y)g' % locals()

    e0 = edge(x0, y0, x1 - x0, y1 - y0)
    e1 = edge(x1, y1, x2 - x1, y2 - y1)
    e2 = edge(x2, y2, x0 - x2, y0 - y2)

    # -min(e0, min(e1, e2))
    return Shape('ni%(e0)si%(e1)s%(e2)s' % locals(), min(x0, x1, x2),
                 min(y0, y1, y2), max(x0, x1, x2), max(y0, y1, y2))
Example #4
0
def right_triangle(x, y, w, h):
    # max(max(x-X,y-Y),X-(x*(Y-y)+(x+w)*(y+h-Y))/h)
    ws = math.copysign(1, w)
    hs = math.copysign(1, h)
    return Shape(
        'aa*f%(ws)g-f%(x)gX*f%(hs)g-f%(y)gY*f%(ws)g-X/+*f%(x)g-Yf%(y)g*+f%(x)gf%(w)g-+f%(y)gf%(h)gYf%(h)g'
        % locals(), x, y, x + w, y + h)
Example #5
0
def circle(x0, y0, r):
    # sqrt((X-x0)**2 + (Y-y0)**2) - r
    r = abs(r)
    return Shape(
        '-r+q%sq%sf%g' % (('-Xf%g' % x0) if x0 else 'X',
                          ('-Yf%g' % y0) if y0 else 'Y', r), x0 - r, y0 - r,
        x0 + r, y0 + r)
Example #6
0
def revolve_x(part):
    ''' Revolve a part in the XY plane about the X axis. '''
    #   Y' = sqrt(Y**2 + Z**2)
    p = part.map('', 'r+qYqZ', '', '')
    return Shape(p.math, part.xmin, part.xmax,
                 min(-abs(part.ymin), -abs(part.ymax)),
                 max(abs(part.ymin), abs(part.ymax)), part.ymin, part.ymax)
Example #7
0
def revolve_y(part):
    ''' Revolve a part in the XY plane about the Y axis. '''
    #   X' = sqrt(X**2 + Z**2)
    p = part.map('r+qXqZ', '', '', '')
    return Shape(p.math, min(-abs(part.xmin), -abs(part.xmax)),
                 max(abs(part.xmin), abs(part.xmax)), part.ymin, part.ymax,
                 part.xmin, part.xmax)
Example #8
0
def revolve_x(a):
    ''' Revolve a part in the XY plane about the X axis. '''
    #   Y' = +/- sqrt(Y**2 + Z**2)
    pos = a.map(Transform('', 'r+qYqZ', '', '', '', ''))
    neg = a.map(Transform('', 'nr+qYqZ', '', '', '', ''))
    m = max(abs(a.bounds.ymin), abs(a.bounds.ymax))
    return Shape((pos | neg).math, a.bounds.xmin, -m, -m, a.bounds.xmax, m, m)
Example #9
0
def circle(x, y, r):
    """ Defines a circle from a center point and radius.
    """
    # sqrt((X-x)**2 + (Y-y)**2) - r
    r = abs(r)
    return Shape(
        '-r+q%sq%sf%g' % (('-Xf%g' % x) if x else 'X',
                          ('-Yf%g' % y) if y else 'Y', r), x - r, y - r, x + r,
        y + r)
Example #10
0
def invert(a):
    """ Inverts a shape within its existing bounds.
    """
    if a.bounds.is_bounded_xyz():
        return cube(a.bounds.xmin, a.bounds.xmax, a.bounds.ymin, a.bounds.zmax,
                    a.bounds.zmin, a.bounds.zmax) & (~a)
    elif a.bounds.is_bounded_xy():
        return rectangle(a.bounds.xmin, a.bounds.xmax, a.bounds.ymin,
                         a.bounds.ymax) & (~a)
    else:
        return Shape()
Example #11
0
def repel(part, x, y, z, r):
    # Shift the part so that it is centered
    part = move(part, -x, -y, -z)

    # exponential fallout value
    # x*(1 - exp(-sqrt(x**2 + y**2 + z**2) / r))
    d = '-f1xn/r++qXqYqZf%g' % r
    p = part.map(Transform('*X' + d, '*Y' + d, '*Z' + d, '', '', ''))

    b = r / math.e
    return move(
        Shape(p.math, part.bounds.xmin - b, part.bounds.ymin - b,
              part.bounds.zmin - b, part.bounds.xmax + b, part.bounds.ymax + b,
              part.bounds.zmax + b), x, y, z)
Example #12
0
def text(text, x, y, height=1, align='LB'):
    if text == '':
        return Shape()
    dx, dy = 0, -1
    text_shape = None

    for line in text.split('\n'):
        line_shape = None

        for c in line:
            if not c in _glyphs.keys():
                print('Warning:  Unknown character "%s"' % c)
            else:
                chr_math = move(_glyphs[c], dx, dy)
                if line_shape is None: line_shape = chr_math
                else: line_shape |= chr_math
                dx += _widths[c] + 0.1
        dx -= 0.1

        if line_shape is not None:
            if align[0] == 'L':
                pass
            elif align[0] == 'C':
                line_shape = move(line_shape, -dx / 2, 0)
            elif align[0] == 'R':
                line_shape = move(line_shape, -dx, 0)

            if text_shape is None: text_shape = line_shape
            else: text_shape |= line_shape

        dy -= 1.55
        dx = 0
    dy += 1.55
    if text_shape is None: return None

    if align[1] == 'T':
        pass
    elif align[1] == 'B':
        text_shape = move(
            text_shape,
            0,
            -dy,
        )
    elif align[1] == 'C':
        text_shape = move(text_shape, 0, -dy / 2)

    if height != 1:
        text_shape = scale_xy(text_shape, 0, 0, height)

    return move(text_shape, x, y)
Example #13
0
def loft_xy_z(a, b, zmin, zmax):
    """ Creates a blended loft between two shapes.

        Input shapes should be 2D (in the XY plane).
        The resulting loft will be shape a at zmin and b at zmax.
    """
    # ((z-zmin)/(zmax-zmin))*b + ((zmax-z)/(zmax-zmin))*a
    # In the prefix string below, we add caps at zmin and zmax then
    # factor out the division by (zmax - zmin)
    dz = zmax - zmin
    a_, b_ = a.math, b.math
    return Shape(('aa-Zf%(zmax)g-f%(zmin)g' + 'Z/+*-Zf%(zmin)g%(b_)s' +
                  '*-f%(zmax)gZ%(a_)sf%(dz)g') % locals(),
                 min(a.bounds.xmin, b.bounds.xmin),
                 min(a.bounds.ymin, b.bounds.ymin), zmin,
                 max(a.bounds.xmax, b.bounds.xmax),
                 max(a.bounds.ymax, b.bounds.ymax), zmax)
Example #14
0
def sphere(x0, y0, z0, r):
    return Shape(
        '-r++q%sq%sq%sf%g' % (('-Xf%g' % x0) if x0 else 'X',
                              ('-Yf%g' % y0) if y0 else 'Y',
                              ('-Zf%g' % z0) if z0 else 'Z', r), x0 - r,
        y0 - r, z0 - r, x0 + r, y0 + r, z0 + r)
Example #15
0
def torus_z(x, y, z, R, r):
    return move(
        Shape('-r+q-f%(R)gr+qXqYqZf%(r)g' % locals(), -(R + r), -(R + r), -r,
              R + r, R + r, r), x, y, z)
Example #16
0
def torus_y(x, y, z, R, r):
    # sqrt((R - sqrt((X-x)^2+(Z-z)^2))^2 + (Y-y)^2)-r
    return move(
        Shape('-r+q-f%(R)gr+qXqZqYf%(r)g' % locals(), -(R + r), -r, -(R + r),
              R + r, r, R + r), x, y, z)
Example #17
0
def rectangle(x0, x1, y0, y1):
    # max(max(x0 - X, X - x1), max(y0 - Y, Y - y1)
    return Shape('aa-f%(x0)gX-Xf%(x1)ga-f%(y0)gY-Yf%(y1)g' % locals(), x0, y0,
                 x1, y1)
Example #18
0
def sphere(x, y, z, r):
    return Shape(
        '-r++q%sq%sq%sf%g' % (('-Xf%g' % x) if x else 'X',
                              ('-Yf%g' % y) if y else 'Y',
                              ('-Zf%g' % z) if z else 'Z', r), x - r, y - r,
        z - r, x + r, y + r, z + r)
Example #19
0
def cylinder_y(x, ymin, ymax, z, r):
    from fab.types import Shape, Transform
    # max(sqrt((X-x)^2+(Z-z)^2)-r,max(ymin-Y,Y-ymax))
    return Shape(
        'a-r+q-Xf%(x)gq-Zf%(z)gf%(r)ga-f%(ymin)gY-Yf%(ymax)g' % locals(),
        x - r, ymin, z - r, x + r, ymax, z + r)
Example #20
0
def set_color(a, r, g, b):
    """ Applies a given color to an input shape a and returns it.
    """
    q = Shape(a.math, a.bounds)
    q._r, q._g, q._b = r, g, b
    return q
Example #21
0
def morph(a, b, weight):
    """ Morphs between two shapes.
    """
    # shape = weight*a+(1-weight)*b
    s = "+*f%g%s*f%g%s" % (weight, a.math, 1 - weight, b.math)
    return Shape(s, (a | b).bounds)
Example #22
0
def blend(a, b, amount):
    joint = a | b

    # sqrt(abs(a)) + sqrt(abs(b)) - amount
    fillet = Shape('-+rb%srb%sf%g' % (a.math, b.math, amount), joint.bounds)
    return joint | fillet
Example #23
0
def set_color(a, r, g, b):
    """ Applies a given color to an input shape a and returns it.
    """
    q = Shape(a.math, a.bounds)
    q._r, q._g, q._b = r, g, b
    return q
Example #24
0
def extrude_z(part, z0, z1):
    # max(part, max(z0-Z, Z-z1))
    return Shape('am  f1%sa-f%gZ-Zf%g' % (part.math, z0, z1), part.bounds.xmin,
                 part.bounds.ymin, z0, part.bounds.xmax, part.bounds.ymax, z1)
Example #25
0
def function_prefix_xyz(fn, xmin, xmax, ymin, ymax, zmin, zmax):
    """ Takes an arbitrary prefix math-string and makes it a function.
        Returns the function intersected with the given bounding cube.
    """
    return Shape(fn) & cube(xmin, xmax, ymin, ymax, zmin, zmax)
Example #26
0
def rectangle(xmin, xmax, ymin, ymax):
    # max(max(xmin - X, X - xmax), max(ymin - Y, Y - ymax)
    return Shape('aa-f%(xmin)gX-Xf%(xmax)ga-f%(ymin)gY-Yf%(ymax)g' % locals(),
                 xmin, ymin, xmax, ymax)
Example #27
0
def blend(p0, p1, amount):
    joint = p0 | p1

    # sqrt(abs(p0)) + sqrt(abs(p1)) - amount
    fillet = Shape('-+rb%srb%sf%g' % (p0.math, p1.math, amount), joint.bounds)
    return joint | fillet
Example #28
0
def cylinder_x(xmin, xmax, y, z, r):
    from fab.types import Shape, Transform
    # max(sqrt((Y-y)^2+(Z-z)^2)-r,max(xmin-X,X-xmax))
    return Shape(
        'a-r+q-Yf%(y)gq-Zf%(z)gf%(r)ga-f%(xmin)gX-Xf%(xmax)g' % locals(), xmin,
        y - r, z - r, xmax, y + r, z + r)
Example #29
0
_widths['y'] = 0.55
_glyphs['y'] = shape

shape = rectangle(0, 0.6, 0, 1)
shape &= ~triangle(0, 0.1, 0, 0.9, 0.45, 0.9)
shape &= ~triangle(0.6, 0.1, 0.15, 0.1, 0.6, 0.9)
_widths['Z'] = 0.6
_glyphs['Z'] = shape

shape = rectangle(0, 0.6, 0, 0.55)
shape &= ~triangle(0, 0.1, 0, 0.45, 0.45, 0.45)
shape &= ~triangle(0.6, 0.1, 0.15, 0.1, 0.6, 0.45)
_widths['z'] = 0.6
_glyphs['z'] = shape

shape = Shape("f1.0", 0, 0.55, 0, 1)
_widths[' '] = 0.55
_glyphs[' '] = shape

shape = circle(0.075, 0.075, 0.075)
shape = scale_y(shape, 0.075, 3)
shape &= rectangle(0.0, 0.15, -0.15, 0.075)
shape &= ~triangle(0.075, 0.075, 0.0, -0.15, -0.5, 0.075)
shape |= circle(0.1, 0.075, 0.075)
_widths[','] = 0.175
_glyphs[','] = shape

shape = circle(0.075, 0.075, 0.075)
_widths['.'] = 0.15
_glyphs['.'] = shape
Example #30
0
def extrude_z(part, zmin, zmax):
    # max(part, max(zmin-Z, Z-zmax))
    return Shape('am__f1%sa-f%gZ-Zf%g' % (part.math, zmin, zmax),
                 part.bounds.xmin, part.bounds.ymin, zmin, part.bounds.xmax,
                 part.bounds.ymax, zmax)
Example #31
0
def right_triangle(x, y, w, h):
    # max(max(x-X,y-Y),X-(x*(Y-y)+(x+w)*(y+h-Y))/h)
    return Shape(
        'aa-f%(x)gX-f%(y)gY-X/+*f%(x)g-Yf%(y)g*+f%(x)gf%(w)g-+f%(y)gf%(h)gYf%(h)g'
        % locals(), x, y, x + w, y + h)