Source: swcad-js-calcs/src/transform/index.js

"use strict"

/**
 * ...
 * @memberof calcs
 * @namespace transform
 */

const transformUtils = ({ jscad, swcadJs }) => {
    const { subtract, union } = jscad.booleans
    const { measureDimensions } = jscad.measurements;
    const { cuboid, rectangle } = jscad.primitives
    const { align, mirror, rotate } = jscad.transforms
    const { colorize } = jscad.colors

    const {
        position,
    } = swcadJs.calcs

    /**
     * ...
     * @memberof calcs.transform
     * @param {object} opts 
     * @param {boolean} opts.reverse 
     * @param {object[]} geoms 
     */
    const stack = ({ reverse = false }, geoms) => {
        let stackHeight = 0
        const geomList = reverse ? geoms.reverse() : geoms
        return geomList.map(geom => {
            const alignedGeom = align({ modes: ['center', 'center', 'min'], relativeTo: [0, 0, stackHeight] }, geom)
            stackHeight = stackHeight + measureDimensions(geom)[2]
            return alignedGeom
        })
    }

    /**
     * ...
     * @param {*} inShape 
     * @returns ...
     * @memberof calcs.transform
     */
    const cutQuadrant = (inShape) => {
        const inShapeDims = measureDimensions(inShape)
        const maskDims = [
            inShapeDims[0] + 5,
            inShapeDims[1] + 5,
        ]
        const cornerCutDims = [
            maskDims[0] / 2,
            maskDims[1] / 2,
        ]
        const cornerCutCtr = [cornerCutDims[0] / 2, cornerCutDims[1] / 2, 0]

        const mask = subtract(
            rectangle({
                size: maskDims
            }),
            rectangle({
                size: cornerCutDims,
                center: cornerCutCtr,
            }),
        )

        return subtract(
            position.ctr(inShape),
            mask,
        )
    }

    /**
     * ...
     * @param {*} inShape 
     * @returns ...
     * @memberof calcs.transform
     */
    const cloneQuadrant = (inShape) => {
        const firstMirror = mirror({ normal: [0, 1, 0] }, inShape)
        const firstHalf = union(
            inShape,
            firstMirror,
        )
        const otherHalf = mirror({ normal: [1, 0, 0] }, firstHalf)

        return union(
            firstHalf,
            otherHalf,
        )
    }

    return {
        /**
         * Cuts a given geometry in half.
         * @memberof calcs.transform
         * @instance
         * @param {Object} opts
         * @param {string} opts.axis - Axis direction pointing to the remaining geometry. This could be negative, specified like "x" or "-y"
         * @param {Object} geom - Object we're cutting
         * @returns bisected geometry
         */
        bisect3d: (opts, geom) => {
            const geomDims = measureDimensions(geom);
            const baseCutBox = cuboid({
                size: [
                    geomDims[0] + 3,
                    geomDims[1] + 3,
                    geomDims[2] + 3,
                ]
            });
            let alignedCutBox = null;
            const remAxis = opts.axis || 'z';
            switch (remAxis) {
                case "-x":
                    alignedCutBox = align({ modes: ['min', 'center', 'center'] }, baseCutBox);
                    break;
                case "x":
                    alignedCutBox = align({ modes: ['max', 'center', 'center'] }, baseCutBox);
                    break;
                case "-y":
                    alignedCutBox = align({ modes: ['center', 'min', 'center'] }, baseCutBox);
                    break;
                case "y":
                    alignedCutBox = align({ modes: ['center', 'max', 'center'] }, baseCutBox);
                    break;
                case "-z":
                    alignedCutBox = align({ modes: ['center', 'center', 'min'] }, baseCutBox);
                    break;
                case "z":
                default:
                    alignedCutBox = align({ modes: ['center', 'center', 'max'] }, baseCutBox);
            }

            return subtract(
                geom,
                alignedCutBox
            );
        },
        /**
         * Cuts a slice of an object
         * @memberof calcs.transform
         * @instance
         * @param {Object} opts
         * @param {number} opts.centralAngle
         * @param {Object} geom - Object we're cutting
         * @returns bisected geometry
         */
        cutCircularSlice: (opts, geom) => {
            const geomDims = measureDimensions(geom);
            const baseCutBox = cuboid({
                size: [
                    geomDims[0] + 3,
                    geomDims[1] + 3,
                    geomDims[2] + 3,
                ]
            });

            const cutBox1 = colorize(
                [0.7, 0.7, 0.1, 0.5],
                rotate([0, 0, opts.centralAngle / 2], align({ modes: ['max', 'center', 'center'] }, baseCutBox))
            );
            const cutBox2 = mirror({ normal: [1, 0, 0] }, cutBox1);
            let cutAssembly = subtract(geom, cutBox1);
            cutAssembly = subtract(cutAssembly, cutBox2);

            return cutAssembly
        },
        stack,
        cutQuadrant,
        cloneQuadrant,
    }
}

module.exports = { init: transformUtils };