Example #1
0
 def vertex():
     x, y = float(dx.bycode(e, 10)), float(dx.bycode(e, 20))
     outs = '    VERTEX at ({:.2f}, {:.2f})'.format(x, y)
     if 42 in e:
         v = math.degrees(math.atan(float(dx.bycode(e, 42))) * 4)
         outs += ', curve angle {:.1f}°'.format(v)
     print(outs)
Example #2
0
 def vertex():
     x, y = float(dx.bycode(e, 10)), float(dx.bycode(e, 20))
     outs = '    VERTEX at ({:.2f}, {:.2f})'.format(x, y)
     if 42 in e:
         v = math.degrees(math.atan(float(dx.bycode(e, 42))) * 4)
         outs += ', curve angle {:.1f}°'.format(v)
     print(outs)
Example #3
0
 def arc():
     xc, yc, R = (float(dx.bycode(e, 10)), float(dx.bycode(e, 20)), float(dx.bycode(e, 40)))
     sa, ea = float(dx.bycode(e, 50)), float(dx.bycode(e, 51))
     sar, ear = math.radians(sa), math.radians(ea)
     xs, ys = xc + R * math.cos(sar), yc + R * math.sin(sar)
     xe, ye = xc + R * math.cos(ear), yc + R * math.sin(ear)
     outs = '  ARC from ({:.2f}, {:.2f}) to ({:.2f}, {:.2f})'
     print(outs.format(xs, ys, xe, ye))
     outs = '      centered at ({:.2f}, {:.2f}), ' \
            'radius {:.2f}, from {:.1f}° to {:.1f}°'
     print(outs.format(xc, yc, R, sa, ea))
Example #4
0
 def arc():
     xc, yc, R = (float(dx.bycode(e, 10)), float(dx.bycode(e, 20)),
                  float(dx.bycode(e, 40)))
     sa, ea = float(dx.bycode(e, 50)), float(dx.bycode(e, 51))
     sar, ear = math.radians(sa), math.radians(ea)
     xs, ys = xc + R * math.cos(sar), yc + R * math.sin(sar)
     xe, ye = xc + R * math.cos(ear), yc + R * math.sin(ear)
     outs = '  ARC from ({:.2f}, {:.2f}) to ({:.2f}, {:.2f})'
     print(outs.format(xs, ys, xe, ye))
     outs = '      centered at ({:.2f}, {:.2f}), ' \
            'radius {:.2f}, from {:.1f}° to {:.1f}°'
     print(outs.format(xc, yc, R, sa, ea))
Example #5
0
 def arc(e):
     cx, cy = float(dx.bycode(e, 10)), float(dx.bycode(e, 20))
     R = fr(dx.bycode(e, 40))
     sa, ea = (math.radians(float(dx.bycode(e, 50))), math.radians(float(dx.bycode(e, 51))))
     if ea > sa:
         da = ea - sa
     else:
         da = 2 * math.pi - sa + ea
     if DEVLIM > R:
         cnt = 1
     else:
         maxstep = 2 * math.acos(1 - DEVLIM / R)
         if da < 0:
             maxstep = -maxstep
         cnt = math.ceil(da / maxstep)
     step = da / cnt
     angs = [sa + i * step for i in range(cnt + 1)]
     pnts = [(fr(cx + R * math.cos(a)), fr(cy + R * math.sin(a))) for a in angs]
     return pnts
Example #6
0
 def arc(e):
     cx, cy = float(dx.bycode(e, 10)), float(dx.bycode(e, 20))
     R = fr(dx.bycode(e, 40))
     sa, ea = (math.radians(float(dx.bycode(e, 50))),
               math.radians(float(dx.bycode(e, 51))))
     if ea > sa:
         da = ea - sa
     else:
         da = 2 * math.pi - sa + ea
     if DEVLIM > R:
         cnt = 1
     else:
         maxstep = 2 * math.acos(1 - DEVLIM / R)
         if da < 0:
             maxstep = -maxstep
         cnt = math.ceil(da / maxstep)
     step = da / cnt
     angs = [sa + i * step for i in range(cnt + 1)]
     pnts = [(fr(cx + R * math.cos(a)), fr(cy + R * math.sin(a)))
             for a in angs]
     return pnts
Example #7
0
def printent(e, v):
    """Print a DXF entity"""

    def line():
        xs, ys = float(dx.bycode(e, 10)), float(dx.bycode(e, 20))
        xe, ye = float(dx.bycode(e, 11)), float(dx.bycode(e, 21))
        outs = '  LINE from ({:.2f}, {:.2f}) to ({:.2f}, {:.2f})'
        print(outs.format(xs, ys, xe, ye))

    def arc():
        xc, yc, R = (float(dx.bycode(e, 10)), float(dx.bycode(e, 20)), float(dx.bycode(e, 40)))
        sa, ea = float(dx.bycode(e, 50)), float(dx.bycode(e, 51))
        sar, ear = math.radians(sa), math.radians(ea)
        xs, ys = xc + R * math.cos(sar), yc + R * math.sin(sar)
        xe, ye = xc + R * math.cos(ear), yc + R * math.sin(ear)
        outs = '  ARC from ({:.2f}, {:.2f}) to ({:.2f}, {:.2f})'
        print(outs.format(xs, ys, xe, ye))
        outs = '      centered at ({:.2f}, {:.2f}), ' \
               'radius {:.2f}, from {:.1f}° to {:.1f}°'
        print(outs.format(xc, yc, R, sa, ea))

    def polyline():
        print('  POLYLINE')

    def vertex():
        x, y = float(dx.bycode(e, 10)), float(dx.bycode(e, 20))
        outs = '    VERTEX at ({:.2f}, {:.2f})'.format(x, y)
        if 42 in e:
            v = math.degrees(math.atan(float(dx.bycode(e, 42))) * 4)
            outs += ', curve angle {:.1f}°'.format(v)
        print(outs)

    def endseq():
        print('  ENDSEQ')

    printdict = {
        'LINE': line,
        'ARC': arc,
        'POLYLINE': polyline,
        'VERTEX': vertex,
        'SEQEND': endseq
    }
    k = dx.bycode(e, 0)
    try:
        printdict[k]()
    except KeyError:
        if v:
            print('  {} entity: {}'.format(k, e))
        else:
            print('  {} entity'.format(k))
Example #8
0
def printent(e, v):
    """Print a DXF entity"""
    def line():
        xs, ys = float(dx.bycode(e, 10)), float(dx.bycode(e, 20))
        xe, ye = float(dx.bycode(e, 11)), float(dx.bycode(e, 21))
        outs = '  LINE from ({:.2f}, {:.2f}) to ({:.2f}, {:.2f})'
        print(outs.format(xs, ys, xe, ye))

    def arc():
        xc, yc, R = (float(dx.bycode(e, 10)), float(dx.bycode(e, 20)),
                     float(dx.bycode(e, 40)))
        sa, ea = float(dx.bycode(e, 50)), float(dx.bycode(e, 51))
        sar, ear = math.radians(sa), math.radians(ea)
        xs, ys = xc + R * math.cos(sar), yc + R * math.sin(sar)
        xe, ye = xc + R * math.cos(ear), yc + R * math.sin(ear)
        outs = '  ARC from ({:.2f}, {:.2f}) to ({:.2f}, {:.2f})'
        print(outs.format(xs, ys, xe, ye))
        outs = '      centered at ({:.2f}, {:.2f}), ' \
               'radius {:.2f}, from {:.1f}° to {:.1f}°'
        print(outs.format(xc, yc, R, sa, ea))

    def polyline():
        print('  POLYLINE')

    def vertex():
        x, y = float(dx.bycode(e, 10)), float(dx.bycode(e, 20))
        outs = '    VERTEX at ({:.2f}, {:.2f})'.format(x, y)
        if 42 in e:
            v = math.degrees(math.atan(float(dx.bycode(e, 42))) * 4)
            outs += ', curve angle {:.1f}°'.format(v)
        print(outs)

    def endseq():
        print('  ENDSEQ')

    printdict = {
        'LINE': line,
        'ARC': arc,
        'POLYLINE': polyline,
        'VERTEX': vertex,
        'SEQEND': endseq
    }
    k = dx.bycode(e, 0)
    try:
        printdict[k]()
    except KeyError:
        if v:
            print('  {} entity: {}'.format(k, e))
        else:
            print('  {} entity'.format(k))
Example #9
0
def output(ifn, ofn, entities, args):
    opts = []
    if args.contours:
        opts = ['contours']
    if args.markers:
        opts.append('markers')
    sorters = {'xy': utils.bbxykey, 'yx': utils.bbyxkey, 'dist': utils.distkey}
    sortkey = sorters[args.sort]
    if not args.alllayers:
        layers = dxf.numberedlayers(entities)
        entities = [e for e in entities if dxf.bycode(e, 8) in layers]
    else:
        layers = dxf.layernames(entities)
    num = len(entities)
    if num == 0:
        logging.info("no entities found! Skipping file '{}'.".format(ifn))
        return
    logging.info('{} entities found'.format(num))
    allsegments = lines.mksegments(entities)
    bboxes = [lines.bbox(s) for s in allsegments]
    minx, miny, maxx, maxy = lines.merge_bbox(bboxes)
    out, ctx = plot.setup(ofn, minx, miny, maxx, maxy)
    plot.grid(ctx, minx, miny, maxx, maxy)
    for layername in layers:
        thislayer = dxf.fromlayer(entities, layername)
        segments = lines.mksegments(thislayer)
        ls = '{} entities found in layer "{}".'
        logging.info(ls.format(len(thislayer), layername))
        logging.info('plotting the entities')
        if args.contours:
            closedseg, openseg = lines.combine_segments(segments)
            fs = '{} {} segments in layer "{}"'
            for a, b in (('closed', closedseg), ('open', openseg)):
                logging.info(fs.format(len(b), a, layername))
            openseg.sort(key=sortkey)
            plot.lines(ctx, openseg, marks=args.markers)
            closedseg.sort(key=sortkey)
            plot.lines(ctx, closedseg, marks=args.markers)
        else:
            fs = '{} segments in layer "{}"'
            logging.info(fs.format(len(segments), layername))
            plot.lines(ctx, segments, marks=args.markers)
    plot.title(ctx, 'dxf2pdf', ofn, maxy - miny, options=opts)
    out.show_page()
    logging.info('writing output file "{}"'.format(ofn))
    out.finish()
    logging.info('file "{}" done.'.format(ifn))
Example #10
0
def output(ifn, ofn, entities, args):
    opts = []
    if args.contours:
        opts = ['contours']
    if args.markers:
        opts.append('markers')
    sorters = {'xy': utils.bbxykey, 'yx': utils.bbyxkey, 'dist': utils.distkey}
    sortkey = sorters[args.sort]
    if not args.alllayers:
        layers = dxf.numberedlayers(entities)
        entities = [e for e in entities if dxf.bycode(e, 8) in layers]
    else:
        layers = dxf.layernames(entities)
    num = len(entities)
    if num == 0:
        logging.info("no entities found! Skipping file '{}'.".format(ifn))
        return
    logging.info('{} entities found'.format(num))
    allsegments = lines.mksegments(entities)
    bboxes = [lines.bbox(s) for s in allsegments]
    minx, miny, maxx, maxy = lines.merge_bbox(bboxes)
    out, ctx = plot.setup(ofn, minx, miny, maxx, maxy)
    plot.grid(ctx, minx, miny, maxx, maxy)
    for layername in layers:
        thislayer = dxf.fromlayer(entities, layername)
        segments = lines.mksegments(thislayer)
        ls = '{} entities found in layer "{}".'
        logging.info(ls.format(len(thislayer), layername))
        logging.info('plotting the entities')
        if args.contours:
            closedseg, openseg = lines.combine_segments(segments)
            fs = '{} {} segments in layer "{}"'
            for a, b in (('closed', closedseg), ('open', openseg)):
                logging.info(fs.format(len(b), a, layername))
            openseg.sort(key=sortkey)
            plot.lines(ctx, openseg, marks=args.markers)
            closedseg.sort(key=sortkey)
            plot.lines(ctx, closedseg, marks=args.markers)
        else:
            fs = '{} segments in layer "{}"'
            logging.info(fs.format(len(segments), layername))
            plot.lines(ctx, segments, marks=args.markers)
    plot.title(ctx, 'dxf2pdf', ofn, maxy - miny, options=opts)
    out.show_page()
    logging.info('writing output file "{}"'.format(ofn))
    out.finish()
    logging.info('file "{}" done.'.format(ifn))
Example #11
0
def main():
    """
    Entry point for dxf2nc.py.
    """
    args = process_arguments()
    sorters = {'xy': utils.bbxykey, 'yx': utils.bbyxkey, 'dist': utils.distkey}
    sortkey = sorters[args.sort]
    lines.epsilon = args.dist
    for f in utils.xpand(args.files):
        logging.info('Starting file "{}"'.format(f))
        try:
            ofn = utils.outname(f, extension='.nc')
            data = dx.parse(f)
            entities = dx.entities(data)
        except ValueError as ex:
            logging.info(str(ex))
            fns = "error during processing. Skipping file '{}'."
            logging.error(fns.format(f))
            continue
        except IOError as ex:
            logging.info(str(ex))
            logging.error("i/o error in file '{}'. Skipping it.".format(f))
            continue
        layers = dx.numberedlayers(entities)
        entities = [e for e in entities if dx.bycode(e, 8) in layers]
        num = len(entities)
        if num == 0:
            logging.info("no entities found! Skipping file '{}'.".format(f))
            continue
        logging.info('{} entities found.'.format(num))
        out = gerbernc.Writer(ofn)
        for layername in layers:
            out.newpiece()
            thislayer = dx.fromlayer(entities, layername)
            ls = '{} entities found in layer "{}".'
            logging.info(ls.format(len(thislayer), layername))
            segments = lines.mksegments(thislayer)
            fs = '{} segments in layer "{}"'
            logging.info(fs.format(len(segments), layername))
            if args.contours:
                cut_contours(segments, out, layername, sortkey)
            else:
                segments.sort(key=sortkey)
                cut_segments(segments, out)
        out.write()
Example #12
0
def main():
    """
    Entry point for dxf2nc.py.
    """
    args = process_arguments()
    sorters = {'xy': utils.bbxykey, 'yx': utils.bbyxkey, 'dist': utils.distkey}
    sortkey = sorters[args.sort]
    lines.epsilon = args.dist
    for f in utils.xpand(args.files):
        logging.info('Starting file "{}"'.format(f))
        try:
            ofn = utils.outname(f, extension='.nc')
            data = dx.parse(f)
            entities = dx.entities(data)
        except ValueError as ex:
            logging.info(str(ex))
            fns = "error during processing. Skipping file '{}'."
            logging.error(fns.format(f))
            continue
        except IOError as ex:
            logging.info(str(ex))
            logging.error("i/o error in file '{}'. Skipping it.".format(f))
            continue
        layers = dx.numberedlayers(entities)
        entities = [e for e in entities if dx.bycode(e, 8) in layers]
        num = len(entities)
        if num == 0:
            logging.info("no entities found! Skipping file '{}'.".format(f))
            continue
        logging.info('{} entities found.'.format(num))
        out = gerbernc.Writer(ofn)
        for layername in layers:
            out.newpiece()
            thislayer = dx.fromlayer(entities, layername)
            ls = '{} entities found in layer "{}".'
            logging.info(ls.format(len(thislayer), layername))
            segments = lines.mksegments(thislayer)
            fs = '{} segments in layer "{}"'
            logging.info(fs.format(len(segments), layername))
            if args.contours:
                cut_contours(segments, out, layername, sortkey)
            else:
                segments.sort(key=sortkey)
                cut_segments(segments, out)
        out.write()
Example #13
0
def main():
    """
    Entry point for dxfgerber.py.
    """
    args = process_arguments()
    sorters = {'xy': utils.bbxykey, 'yx': utils.bbyxkey, 'dist': utils.distkey}
    sortkey = sorters[args.sort]
    lines.epsilon = args.dist
    for f in utils.xpand(args.files):
        logging.info('starting file "{}"'.format(f))
        try:
            ofn = utils.outname(f, extension='.dxf', addenum='_mod')
            data = dx.parse(f)
            entities = dx.entities(data)
        except ValueError as ex:
            logging.info(str(ex))
            fns = "error during processing. Skipping file '{}'."
            logging.error(fns.format(f))
            continue
        except IOError as ex:
            logging.info(str(ex))
            logging.error("i/o error in file '{}'. Skipping it.".format(f))
            continue
        layers = dx.numberedlayers(entities)
        entities = [e for e in entities if dx.bycode(e, 8) in layers]
        num = len(entities)
        if num == 0:
            logging.info("no entities found! Skipping file '{}'.".format(f))
            continue
        logging.info('{} entities found.'.format(num))
        with open(ofn, 'w') as out:
            out.write(dxfheader)
            for layername in layers:
                thislayer = dx.fromlayer(entities, layername)
                ls = '{} entities found in layer "{}".'
                logging.info(ls.format(num, layername))
                segments = lines.mksegments(thislayer)
                fs = '{} segments in layer "{}"'
                logging.info(fs.format(len(segments), layername))
                write_allseg(segments, out, layername, sortkey)
            out.write(dxffooter)
Example #14
0
def main():
    """
    Entry point for dxfgerber.py.
    """
    args = process_arguments()
    sorters = {'xy': utils.bbxykey, 'yx': utils.bbyxkey, 'dist': utils.distkey}
    sortkey = sorters[args.sort]
    lines.epsilon = args.dist
    for f in utils.xpand(args.files):
        logging.info('starting file "{}"'.format(f))
        try:
            ofn = utils.outname(f, extension='.dxf', addenum='_mod')
            data = dx.parse(f)
            entities = dx.entities(data)
        except ValueError as ex:
            logging.info(str(ex))
            fns = "error during processing. Skipping file '{}'."
            logging.error(fns.format(f))
            continue
        except IOError as ex:
            logging.info(str(ex))
            logging.error("i/o error in file '{}'. Skipping it.".format(f))
            continue
        layers = dx.numberedlayers(entities)
        entities = [e for e in entities if dx.bycode(e, 8) in layers]
        num = len(entities)
        if num == 0:
            logging.info("no entities found! Skipping file '{}'.".format(f))
            continue
        logging.info('{} entities found.'.format(num))
        with open(ofn, 'w') as out:
            out.write(dxfheader)
            for layername in layers:
                thislayer = dx.fromlayer(entities, layername)
                ls = '{} entities found in layer "{}".'
                logging.info(ls.format(num, layername))
                segments = lines.mksegments(thislayer)
                fs = '{} segments in layer "{}"'
                logging.info(fs.format(len(segments), layername))
                write_allseg(segments, out, layername, sortkey)
            out.write(dxffooter)
Example #15
0
 def line(e):
     return [(fr(dx.bycode(e, 10)), fr(dx.bycode(e, 20))),
             (fr(dx.bycode(e, 11)), fr(dx.bycode(e, 21)))]
Example #16
0
 def line():
     xs, ys = float(dx.bycode(e, 10)), float(dx.bycode(e, 20))
     xe, ye = float(dx.bycode(e, 11)), float(dx.bycode(e, 21))
     outs = '  LINE from ({:.2f}, {:.2f}) to ({:.2f}, {:.2f})'
     print(outs.format(xs, ys, xe, ye))
Example #17
0
 def line(e):
     return [
         (fr(dx.bycode(e, 10)), fr(dx.bycode(e, 20))),
         (fr(dx.bycode(e, 11)), fr(dx.bycode(e, 21)))
     ]
Example #18
0
def mksegments(entities, ndigits=3):
    """
    Convert an iterable of entities to a list of line segments.

    Arguments:
        entities: An iterable if dictionaries, each containing a DXF entity.
        ndigits: Rounds to ndigits after the decimal point.

    Returns:
        A list of line segments. Line segments are lists of ≥2 (x,y) tuples.
    """

    def fr(n):
        return round(float(n), ndigits)

    def line(e):
        return [
            (fr(dx.bycode(e, 10)), fr(dx.bycode(e, 20))),
            (fr(dx.bycode(e, 11)), fr(dx.bycode(e, 21)))
        ]

    def arc(e):
        cx, cy = float(dx.bycode(e, 10)), float(dx.bycode(e, 20))
        R = fr(dx.bycode(e, 40))
        sa, ea = (math.radians(float(dx.bycode(e, 50))), math.radians(float(dx.bycode(e, 51))))
        if ea > sa:
            da = ea - sa
        else:
            da = 2 * math.pi - sa + ea
        if DEVLIM > R:
            cnt = 1
        else:
            maxstep = 2 * math.acos(1 - DEVLIM / R)
            if da < 0:
                maxstep = -maxstep
            cnt = math.ceil(da / maxstep)
        step = da / cnt
        angs = [sa + i * step for i in range(cnt + 1)]
        pnts = [(fr(cx + R * math.cos(a)), fr(cy + R * math.sin(a))) for a in angs]
        return pnts

    # Convert lines
    lines = [line(e) for e in entities if dx.bycode(e, 0) == 'LINE']
    # Convert arcs
    lines += [arc(e) for e in entities if dx.bycode(e, 0) == 'ARC']
    # Convert polylines
    pi = [n for n, e in enumerate(entities) if dx.bycode(e, 0) == 'POLYLINE']
    se = [n for n, e in enumerate(entities) if dx.bycode(e, 0) == 'SEQEND']
    for start in pi:
        end = [n for n in se if n > start][0]
        poly = entities[start:end]
        points = [(fr(dx.bycode(e, 10)), fr(dx.bycode(e, 20))) for e in poly[1:]]
        angles = [math.atan(float(dx.bycode(e, 42))) * 4 if 42 in e else None for e in poly[1:]]
        if 70 in poly[0] and (int(dx.bycode(poly[0], 70)) & 1):  # closed
            points.append(points[0])
        ends = zip(points, points[1:], angles)
        addition = [points[0]]
        for sp, ep, a in ends:
            if a:
                arcent = _arcdata(sp, ep, a)
                addition += arc(arcent)[1:]
            else:
                addition.append(ep)
        lines += [addition]
    # Convert lwpolylines
    return lines
Example #19
0
def mksegments(entities, ndigits=3):
    """
    Convert an iterable of entities to a list of line segments.

    Arguments:
        entities: An iterable if dictionaries, each containing a DXF entity.
        ndigits: Rounds to ndigits after the decimal point.

    Returns:
        A list of line segments. Line segments are lists of ≥2 (x,y) tuples.
    """
    def fr(n):
        return round(float(n), ndigits)

    def line(e):
        return [(fr(dx.bycode(e, 10)), fr(dx.bycode(e, 20))),
                (fr(dx.bycode(e, 11)), fr(dx.bycode(e, 21)))]

    def arc(e):
        cx, cy = float(dx.bycode(e, 10)), float(dx.bycode(e, 20))
        R = fr(dx.bycode(e, 40))
        sa, ea = (math.radians(float(dx.bycode(e, 50))),
                  math.radians(float(dx.bycode(e, 51))))
        if ea > sa:
            da = ea - sa
        else:
            da = 2 * math.pi - sa + ea
        if DEVLIM > R:
            cnt = 1
        else:
            maxstep = 2 * math.acos(1 - DEVLIM / R)
            if da < 0:
                maxstep = -maxstep
            cnt = math.ceil(da / maxstep)
        step = da / cnt
        angs = [sa + i * step for i in range(cnt + 1)]
        pnts = [(fr(cx + R * math.cos(a)), fr(cy + R * math.sin(a)))
                for a in angs]
        return pnts

    # Convert lines
    lines = [line(e) for e in entities if dx.bycode(e, 0) == 'LINE']
    # Convert arcs
    lines += [arc(e) for e in entities if dx.bycode(e, 0) == 'ARC']
    # Convert polylines
    pi = [n for n, e in enumerate(entities) if dx.bycode(e, 0) == 'POLYLINE']
    se = [n for n, e in enumerate(entities) if dx.bycode(e, 0) == 'SEQEND']
    for start in pi:
        end = [n for n in se if n > start][0]
        poly = entities[start:end]
        points = [(fr(dx.bycode(e, 10)), fr(dx.bycode(e, 20)))
                  for e in poly[1:]]
        angles = [
            math.atan(float(dx.bycode(e, 42))) * 4 if 42 in e else None
            for e in poly[1:]
        ]
        if 70 in poly[0] and (int(dx.bycode(poly[0], 70)) & 1):  # closed
            points.append(points[0])
        ends = zip(points, points[1:], angles)
        addition = [points[0]]
        for sp, ep, a in ends:
            if a:
                arcent = _arcdata(sp, ep, a)
                addition += arc(arcent)[1:]
            else:
                addition.append(ep)
        lines += [addition]
    # Convert lwpolylines
    return lines
Example #20
0
 def line():
     xs, ys = float(dx.bycode(e, 10)), float(dx.bycode(e, 20))
     xe, ye = float(dx.bycode(e, 11)), float(dx.bycode(e, 21))
     outs = '  LINE from ({:.2f}, {:.2f}) to ({:.2f}, {:.2f})'
     print(outs.format(xs, ys, xe, ye))