mesh.js


// import { Triangle } from "./triangle"
import { boxForTriangles } from "./box.js"
import { Tree } from "./bvhTree.js"
import { Plane } from "./plane.js"
import { Vector } from "./vector.js"
import { Cube } from "./cube.js"
import { Box } from "./box.js"
import { Matrix, Translate } from "./matrix.js"
import { loadOBJ } from "./obj.js"
import { loadBinaryStl, loadTextSTL } from "./stl.js"
import { Path, Paths } from './path.js'
import { Triangle } from "./triangle.js"

/**
     * 
     * build your own Triangles to place inside, or use a model loader function
     * @see {@link loadOBJ} {@link loadBinaryStl},or {@link loadTextSTL} to load a model or build your own triangles from scratch
     * @param {Triangle} triangles 
     * 
     * 
     */
export class Mesh {

    constructor(triangles) {

        this.box = boxForTriangles(triangles)
        this.triangles = triangles
        this.tree = null
        this.compile()

    }
    compile() {
        if (this.tree == null) {
            let shapes = []
            for (let triangle of this.triangles) {
                shapes.push(triangle)
            }
            this.tree = new Tree(shapes)
        }
    }
    boundingBox() {
        return this.box
    }
    contains() {
        return false
    }
    intersect(ray) {
        // console.log(this, ray)
        if (this.tree == null) {
            this.compile()
        }
        return this.tree.intersect(ray)
    }

    paths() {
        let result = []
        for (let tri of this.triangles) {
            result.push(tri.paths())
        }
        return new Paths(result)
    }
    updateBoundingBox() {
        this.box = boxForTriangles(this.triangles)
    }
    /**
     * Fits mesh inside of cube of size 1
     */
    unitCube() {

        this.fitInside(new Box(new Vector(0, 0, 0), new Vector(1, 1, 1)), new Vector(0, 0, 0))
        this.moveTo(new Vector(0, 0, 0), new Vector(.5, .5, .5))
    }
    /**
     * 
     * @param {Vector} position 
     * @param {Vector} anchor 
     */
    moveTo(position, anchor) {
        let matrix = Translate(position.sub(this.box.anchor(anchor)))
        this.transform(matrix)

    }/**
     * fits inside of given box
     * @param {Box} box 
     * @param {Vector} anchor 
     */
    fitInside(box, anchor) {
        let scale = box.size().div(this.boundingBox().size()).minComponent()

        let extra = box.size().sub(this.boundingBox().size().mulScalar(scale))
        let matrix = new Matrix()

        matrix = matrix.translate(this.boundingBox().min.mulScalar(-1))

        matrix = matrix.scale(new Vector(scale, scale, scale))

        matrix = matrix.translate(box.min.add(extra.mult(anchor)))

        this.transform(matrix)

    }
    /**
     * transforms mesh by given matrix
     * @param {Matrix} matrix 
     */
    transform(matrix) {
        for (let tri of this.triangles) {
            tri.v1 = matrix.mulPosition(tri.v1)
            tri.v2 = matrix.mulPosition(tri.v2)
            tri.v3 = matrix.mulPosition(tri.v3)
            tri.updateBoundingBox()
        }
        this.updateBoundingBox()
        this.tree = null// dirty according to orignal comment
    }

    saveBinarySTL(path) {
        return saveBinaryStl(this)
    }
    /**
     * 
     * @param {Number} size Size of cube example 1/36
     * @returns {Array[Cube]} Array of cubes to be added to scene
     */
    voxelize(size) {
        let m = this
        let z1 = m.box.min.z
        let z2 = m.box.max.z
        let set = new Map()
        for (let z = z1; z <= z2; z += size) {
            let plane = new Plane(new Vector(0, 0, z), new Vector(0, 0, 1))
            let paths = plane.intersectMesh(m)
            for (let path of paths.paths) {
                for (let v of path.verts) {
                    let x = Math.floor(v.x / size + .5) * size
                    let y = Math.floor(v.y / size + 0.5) * size
                    let z = Math.floor(v.z / size + .05) * size
                    set.set(new Vector(x, y, z), true)

                }
            }
        }
        let result = []

        for (let v of set) {
            v = v[0]
            let cube = new Cube(v.subScalar(size / 2), v.addScalar(size / 2))
            result.push(cube)
        }
        return result
    }
}


// terrain plane----
// build square mesh , or x-y rect
// then adjust height of each point by height fucntion