from __future__ import absolute_import
import os.path as op
import numpy as nm

from sfepy.base.testing import TestCommon

tolerance = 1e-6

class Test(TestCommon):

    @staticmethod
    def from_conf(conf, options):
        test = Test(conf=conf, options=options)
        return test

    def test_gen_block_mesh(self):
        from sfepy.mesh.mesh_generators import gen_block_mesh

        mesh = gen_block_mesh([1, 2, 3], [4, 3, 5], [2, 1, 0], verbose=False)
        filename = op.join(self.options.out_dir, 'gen_block.mesh')
        mesh.write(filename)
        self.report('block mesh generated')

        csum = nm.sum(mesh.coors - nm.min(mesh.coors, axis=0), axis=0)
        return nm.linalg.norm(csum - nm.array([30, 60, 90])) < tolerance

    def test_gen_cylinder_mesh(self):
        from sfepy.mesh.mesh_generators import gen_cylinder_mesh

        mesh = gen_cylinder_mesh([0.5, 1, 2, 1.5, 3], [5, 4, 3], [0, 2, 1],
                                 axis='z', non_uniform=True, verbose=False)
        filename = op.join(self.options.out_dir, 'gen_cylinder.mesh')
        mesh.write(filename)
        self.report('cylinder mesh generated')

        csum = nm.sum(mesh.coors - nm.min(mesh.coors, axis=0), axis=0)
        return nm.linalg.norm(csum - nm.array([120, 90, 90])) < tolerance

    def test_gen_extended_block_mesh(self):
        from sfepy.mesh.mesh_generators import gen_extended_block_mesh

        mesh = gen_extended_block_mesh([2, 3, 1], [5, 3, 4], [14, 10, 20],
                                       5, [1, 0, 2])
        filename = op.join(self.options.out_dir, 'gen_extended_block.mesh')
        mesh.write(filename)
        self.report('extended block mesh generated')

        csum = nm.sum(mesh.coors - nm.min(mesh.coors, axis=0), axis=0)
        return nm.linalg.norm(csum - nm.array([1932, 1380, 2760])) < tolerance

    def test_gen_tiled_mesh(self):
        from sfepy.mesh.mesh_generators import gen_block_mesh, gen_tiled_mesh

        mesh0 = gen_block_mesh([1, 2, 3], [4, 3, 5], [2, 1, 0], verbose=False)
        mesh = gen_tiled_mesh(mesh0, [3, 1, 5])
        filename = op.join(self.options.out_dir, 'gen_tiled.mesh')
        mesh.write(filename)
        self.report('tiled mesh generated')

        csum = nm.sum(mesh.coors - nm.min(mesh.coors, axis=0), axis=0)
        return nm.linalg.norm(csum - nm.array([945, 630, 4725])) < tolerance

    def test_gen_mesh_from_geom(self):
        from distutils.spawn import find_executable
        from sfepy.mesh.geom_tools import geometry
        from sfepy.mesh.mesh_generators import gen_mesh_from_geom

        nx, ny, nz = 1, 2, 3

        ok = True
        # 2D
        if find_executable('triangle'):
            geo = geometry(2)
            geo.addpoint(0, [0, 0])
            geo.addpoint(1, [nx, 0])
            geo.addpoint(2, [0, ny])

            geo.addline(3, [0, 1])
            geo.addline(4, [1, 2])
            geo.addline(5, [2, 0])

            geo.addsurface(6, [3, 4, 5])
            geo.addphysicalsurface(1, [6])
            mesh = gen_mesh_from_geom(geo, a=0.01, refine=True)
            filename = op.join(self.options.out_dir, 'gen_triangle.mesh')
            mesh.write(filename)
            self.report('mesh generated by "triangle" generator')

            orign = 98
            actn = mesh.coors.shape[0]
            ok = ok and nm.abs((actn - orign) / float(orign)) < 0.05

        # 3D
        if find_executable('tetgen'):
            geo = geometry(3)
            geo.addpoint(0, [0, 0 , 0])
            geo.addpoint(1, [nx, 0, 0])
            geo.addpoint(2, [0, ny, 0])
            geo.addpoint(3, [0, 0, nz])

            geo.addline(4, [0, 1])
            geo.addline(5, [1, 2])
            geo.addline(6, [2, 0])
            geo.addline(7, [0, 3])
            geo.addline(8, [1, 3])
            geo.addline(9, [2, 3])

            geo.addsurface(10, [4, 8, -7])
            geo.addsurface(11, [5, 9, -8])
            geo.addsurface(12, [6, 7, -9])
            geo.addsurface(13, [4, 5, 6])
            #Volume
            geo.addvolume(14, [10, 11, 12, 13])
            geo.addphysicalvolume(1, [14])
            mesh = gen_mesh_from_geom(geo, a=0.001, refine=True)
            filename = op.join(self.options.out_dir, 'gen_tetgen.mesh')
            mesh.write(filename)
            self.report('mesh generated by "tetgen" generator')

            orign = 898
            actn = mesh.coors.shape[0]
            ok = ok and nm.abs((actn - orign) / float(orign)) < 0.05

        return ok

    def test_gen_mesh_from_voxels(self):
        from sfepy.mesh.mesh_generators import gen_mesh_from_voxels

        voxels = nm.array([[[0, 0, 0, 0, 1],
                            [0, 0, 0, 1, 1],
                            [0, 0, 0, 1, 1],
                            [0, 0, 0, 0, 1]],
                           [[0, 0, 0, 1, 1],
                            [0, 1, 1, 1, 1],
                            [0, 1, 1, 1, 1],
                            [0, 0, 0, 1, 1]],
                           [[1, 0, 0, 1, 1],
                            [1, 1, 1, 1, 1],
                            [1, 1, 1, 1, 1],
                            [1, 0, 0, 1, 1]]])
        mesh = gen_mesh_from_voxels(voxels, [0.5, 0.3, 1.])
        filename = op.join(self.options.out_dir, 'gen_voxels.mesh')
        mesh.write(filename)
        self.report('voxel based mesh generated')

        csum = nm.sum(mesh.coors - nm.min(mesh.coors, axis=0), axis=0)
        return nm.linalg.norm(csum - nm.array([90, 48.3, 265])) < tolerance
