#! /usr/bin/env python2
# vim:fileencoding=utf-8
#
# Copyright © 2012-2014 R.F. Smith <rsmith@xs4all.nl>. All rights reserved.
# $Date: 2014-06-15 17:12:40 +0200 $
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.

"""Program for converting an STL file into a POV-ray mesh or mesh2."""

import argparse
import sys
import time
from stltools import stl, utils

__version__ = '$Revision: 3.2 $'[11:-2]


def mesh1(name, vertices):
    """Creates a POV-ray mesh description from facet data.

    :name: The name of the object.
    :vertices: An (N,3) numpy array containing the vertex data.
    :returns: a string representation of a POV-ray mesh object.
    """
    facets = vertices.reshape((-1, 3, 3))
    lines = ["# declare m_{} = mesh {{".format(name.replace(' ', '_'))]
    sot = "  triangle {"
    # The indices sequence 1, 0, 2 is used because of the difference between
    # the STL coordinate system and that used in POV-ray.
    fc = "    <{1}, {0}, {2}>,"
    for (a, b, c) in facets:
        lines += [sot, fc.format(*a), fc.format(*b),
                  fc.format(*c)[:-1], "  }"]
    lines += ['}']
    return '\n'.join(lines)


def mesh2(name, vertices):
    """Creates a POV-ray mesh2 object from facet data.

    :name: The name of the object.
    :vertices: An (N,3) numpy array containing the vertex data.
    :returns: a string representation of a POV-ray mesh2 object.
    """
    ifacets, points = stl.toindexed(vertices)
    lines = ["# declare m_{} = mesh2 {{".format(name),
             '  vertex_vectors {', '    {},'.format(len(points))]
    # The indices sequence 1, 0, 2 is used because of the difference between
    # the STL coordinate system and that used in POV-ray
    lines += ['    <{1}, {0}, {2}>,'.format(*p) for p in points]
    lines[-1] = lines[-1][:-1]
    lines += ['  face_indices {', '    {},'.format(len(ifacets))]
    lines += ['    <{}, {}, {}>,'.format(*f) for f in ifacets]
    lines[-1] = lines[-1][:-1]
    lines += ['  }', '}']
    return '\n'.join(lines)


def main(argv):
    """Main program.

    :argv: command line arguments (without program name!)
    """
    msg = utils.Msg()
    parser = argparse.ArgumentParser(description=__doc__)
    argtxt = 'generate a mesh2 object (slow on big files)'
    parser.add_argument('-2,' '--mesh2', action='store_true',
                        help=argtxt, dest='mesh2')
    parser.add_argument('-v', '--version', action='version',
                        version=__version__)
    parser.add_argument('file', nargs='*', help='one or more file names')
    args = parser.parse_args(argv)
    if not args.file:
        parser.print_help()
        sys.exit(0)
    for fn in args.file:
        msg.say('Starting file "{}"'.format(fn))
        if not fn.lower().endswith('.stl'):
            w = 'The file "{}" is probably not an STL file, skipping.'
            msg.say(w.format(fn))
            continue
        try:
            msg.say('Reading facets')
            vertices, name = stl.readstl(fn)
            outfn = utils.outname(fn, '.inc')
        except Exception as e:  # pylint: disable=W0703
            msg.say('Error;', e)
            continue
        outs = "// Generated by stl2pov {}\n".format(__version__)
        outs = "// on {}.\n".format(time.asctime())
        outs += "// Source file name: '{}'\n".format(fn)
        if args.mesh2:
            msg.say('Generating mesh2 data')
            outs += mesh2(name, vertices)
        else:
            msg.say('Generating mesh data')
            outs += mesh1(name, vertices)
        try:
            with open(outfn, 'w+') as of:
                msg.say('Writing output file "{}"'.format(outfn))
                of.write(outs)
        except:
            msg.say('Cannot write output file "{}"'.format(outfn))
            continue
        msg.say('Done with file "{}"'.format(fn))


if __name__ == '__main__':
    main(sys.argv[1:])
