All files / app/codeCharta/ui/codeMap/rendering codeMapGeometricDescription.ts

29.41% Statements 10/34
0% Branches 0/3
75% Functions 6/8
27.27% Lines 9/33

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80  20x     20x           47x 47x 47x       130x       109x       1x       7x                                                                                                      
import { CodeMapBuilding } from "./codeMapBuilding"
import { Vector3, Ray, Box3 } from "three"
import { Scaling } from "../../../codeCharta.model"
 
export class CodeMapGeometricDescription {
    private _buildings: CodeMapBuilding[] // todo tk: depending on how many buildings, refactor this to { [node.path]: node } might give `this.getBuildingByPath` a performance boost
    private mapSize: number
    private scales: Vector3
 
    constructor(mapSize: number) {
        this._buildings = new Array<CodeMapBuilding>()
        this.mapSize = mapSize
        this.scales = new Vector3(1, 1, 1)
    }
 
    add(building: CodeMapBuilding) {
        this._buildings.push(building)
    }
 
    get buildings() {
        return this._buildings
    }
 
    setScales(scales: Scaling) {
        this.scales = new Vector3(scales.x, scales.y, scales.z)
    }
 
    getBuildingByPath(path: string) {
        return this.buildings.find(x => x.node.path === path)
    }
 
    intersect(ray: Ray) {
        let intersectedBuilding: CodeMapBuilding
        let leastIntersectedDistance = Number.POSITIVE_INFINITY
 
        const boxTranslation = this.scales
            .clone()
            .multiplyScalar(this.mapSize)
            .multiply(new Vector3(-1, 0, -1))
 
        for (const building of this._buildings) {
            const box: Box3 = building.boundingBox.clone()
            box.min.multiply(this.scales)
            box.max.multiply(this.scales)
            box.translate(boxTranslation)
 
            Iif (this.rayIntersectsAxisAlignedBoundingBox(ray, box)) {
                const intersectionPoint: Vector3 = ray.intersectBox(box, new Vector3())
 
                Iif (intersectionPoint) {
                    const intersectionDistance = intersectionPoint.distanceTo(ray.origin)
 
                    Iif (intersectionDistance < leastIntersectedDistance) {
                        leastIntersectedDistance = intersectionDistance
                        intersectedBuilding = building
                    }
                }
            }
        }
 
        return intersectedBuilding
    }
 
    private rayIntersectsAxisAlignedBoundingBox(ray: Ray, box: Box3) {
        const tx1 = (box.min.x - ray.origin.x) * (1 / ray.direction.x)
        const tx2 = (box.max.x - ray.origin.x) * (1 / ray.direction.x)
 
        let tmin = Math.min(tx1, tx2)
        let tmax = Math.max(tx1, tx2)
 
        const ty1 = (box.min.y - ray.origin.y) * (1 / ray.direction.y)
        const ty2 = (box.max.y - ray.origin.y) * (1 / ray.direction.y)
 
        tmin = Math.max(tmin, Math.min(ty1, ty2))
        tmax = Math.min(tmax, Math.max(ty1, ty2))
 
        return tmax >= tmin
    }
}