draw.js 10.1 KB
import * as THREE from 'three';
import { FontLoader } from 'three/examples/jsm/loaders/FontLoader.js';
import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry.js';
import { Line2 } from 'three/examples/jsm/lines/Line2.js';
import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js';
import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry.js';
import { mergeGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils.js';

export const drawTriangle = (pointa, pointb, pointc, color = 0xffa41e) => {
    const geometry = new THREE.BufferGeometry();
    geometry.setAttribute(
        'position',
        new THREE.Float32BufferAttribute(
            [
                pointa.x,
                pointa.y,
                pointa.z,
                pointb.x,
                pointb.y,
                pointb.z,
                pointc.x,
                pointc.y,
                pointc.z
            ],
            3,
            false
        )
    );
    const material = new THREE.MeshBasicMaterial({
        color,
        side: THREE.DoubleSide
    });
    const mesh = new THREE.Mesh(geometry, material);
    return mesh;
};

export const drawDoubleSideText = (
    group,
    text,
    color,
    size,
    offset,
    path,
    callback
) => {
    const loader = new FontLoader();
    loader.load(path, (font) => {
        const geometry = new TextGeometry(text, {
            font,
            size,
            height: 0.005,
            curveSegments: 12
        });
        geometry.computeBoundingBox();
        geometry.translate(-geometry.boundingBox.max.x * 0.5, offset, 0.005);
        const material = new THREE.MeshBasicMaterial({
            color
        });
        const mesh = new THREE.Mesh(geometry, material);

        const copyText = mesh.clone();
        copyText.rotation.y = Math.PI;

        group.add(copyText);
        group.add(mesh);

        if (callback) callback(group);
    });
};

export const drawTubeLine = (points, color, lineWidth = 0.08) => {
    const fittedCurve = new THREE.CatmullRomCurve3(points);
    const geometry = new THREE.TubeGeometry(fittedCurve, 5, lineWidth, 8);
    const material = new THREE.MeshBasicMaterial({ color });
    const mesh = new THREE.Mesh(geometry, material);
    return mesh;
};

export const drawRectriangle = (
    pointa,
    pointb,
    pointc,
    pointd,
    color = 0x000000,
    lineWidth = 0.08
) => {
    const edgea = drawTubeLine([pointa, pointb], color, lineWidth);
    const edgeb = drawTubeLine([pointb, pointc], color, lineWidth);
    const edgec = drawTubeLine([pointc, pointd], color, lineWidth);
    const edged = drawTubeLine([pointd, pointa], color, lineWidth);
    const group = new THREE.Object3D();
    group.add(edgeb).add(edgea).add(edgec).add(edged);
    return group;
};

export const drawDashLine = (points, color = 0x000000) => {
    const geometry = new THREE.BufferGeometry().setFromPoints(points);
    const material = new THREE.LineDashedMaterial({
        color,
        linewidth: 10,
        scale: 1,
        dashSize: 0.6,
        gapSize: 0.4,
        transparent: true,
        opacity: 0.9
    });
    const line = new THREE.Line(geometry, material);
    line.computeLineDistances();
    return line;
};

/**
 *
 * @param {*[v0,v1,v2,...,]} points
 * @param {*0xXXXXXX} color
 * @returns {new THREE.Line}
 */
export const drawLine = (points, color = 0x000000) => {
    const geometry = new THREE.BufferGeometry().setFromPoints(points);
    const material = new THREE.LineBasicMaterial({
        color,
        linewidth: 20
    });
    const line = new THREE.Line(geometry, material);
    return line;
};

/**
 *
 * @param {*Array [v0.x , v0.y , v0.z , v1.x , v1.y , v1.z]} positions
 * @param {*0xXXXXXX} color
 * @param {*THREE.Vector2} resolution
 * @param {*Number} lineWidth
 * @param {*Number} opacity
 * @param {*Boolean} depthTest
 * @returns
 */
export const drawFatLine = (
    positions,
    resolution,
    color = 0x000000,
    lineWidth = 1,
    opacity = 1,
    depthTest = true
) => {
    const geometry = new LineGeometry();
    geometry.setPositions(positions);
    const matrial = new LineMaterial({
        color,
        resolution,
        dashed: false,
        linewidth: lineWidth,
        transparent: true,
        opacity,
        depthTest
    });
    const line = new Line2(geometry, matrial);
    line.renderOrder = 4;
    line.computeLineDistances();
    return line;
};

export const drawFatDashLine = (positions, color, resolution) => {
    const geometry = new LineGeometry();
    geometry.setPositions(positions);
    const matrial = new LineMaterial({
        color,
        resolution,
        dashed: true,
        linewidth: 1.8,
        transparent: true,
        opacity: 0.95,
        dashSize: 0.7,
        gapSize: 0.6
    });
    const line = new Line2(geometry, matrial);
    line.computeLineDistances();
    return line;
};

export const drawPoints = (points, color = 0x000000, radius = 0.1) => {
    const object = new THREE.Object3D();
    let i = 0;
    while (i < points.length) {
        const point = points[i];
        const geometry = new THREE.SphereGeometry(radius, 32, 16);
        const material = new THREE.MeshBasicMaterial({ color });
        const sphere = new THREE.Mesh(geometry, material);
        sphere.position.set(point.x, point.y, point.z);
        object.add(sphere);
        i += 1;
    }
    return object;
};

export const drawPoint = (point, color = 0x000000, radius = 0.1) => {
    const geometry = new THREE.SphereGeometry(radius, 32, 16);
    const material = new THREE.MeshBasicMaterial({ color });
    const sphere = new THREE.Mesh(geometry, material);
    sphere.position.set(point.x, point.y, point.z);
    return sphere;
};

export const drawCone = (color) => {
    const geometry = new THREE.ConeGeometry(0.3, 0.7, 32, 10, false, 5, 7);
    const material = new THREE.MeshPhongMaterial({
        color
    });
    const matrix = new THREE.Matrix4().makeTranslation(0, -0.3, 0);
    geometry.applyMatrix4(matrix);
    const mesh = new THREE.Mesh(geometry, material);
    return mesh;
};

const CylinderLathe = (
    outerRadius,
    innerRadius,
    height,
    phistart,
    philength
) => {
    const halfH = height * 0.5;
    const points = [
        new THREE.Vector2(innerRadius, -halfH),
        new THREE.Vector2(outerRadius, -halfH),
        new THREE.Vector2(outerRadius, halfH),
        new THREE.Vector2(innerRadius, halfH),
        new THREE.Vector2(innerRadius, -halfH)
    ];
    const geometry = new THREE.LatheGeometry(points, 72, phistart, philength);

    return geometry;
};

export const drawRingMesh = (
    color,
    outerRadius,
    innerRadius,
    height,
    phistart = 0,
    philength = Math.PI * 2
) => {
    const geometry = CylinderLathe(
        outerRadius,
        innerRadius,
        height,
        phistart,
        philength
    );
    const material = new THREE.MeshBasicMaterial({
        color,
        depthTest: false,
        transparent: true,
        opacity: 0.5,
        side: THREE.BackSide
    });
    const mesh = new THREE.Mesh(geometry, material);
    mesh.renderOrder = 4;
    return mesh;
};

export const scaleRingLine = (points) => {
    const scalarGroup = new THREE.Object3D();
    const segment = 360 / 45;
    for (let i = 0; i < segment; i += 1) {
        const contourGeometry = new THREE.BufferGeometry().setFromPoints(
            points
        );
        const cmaterial = new THREE.LineBasicMaterial({
            color: 0xffffff,
            depthTest: false,
            transparent: true
        });
        const contour = new THREE.Line(contourGeometry, cmaterial);
        contour.renderOrder = 4;
        contour.geometry.applyMatrix4(
            new THREE.Matrix4().makeRotationY((Math.PI / 180) * i * 45)
        );
        scalarGroup.add(contour);
    }
    return scalarGroup;
};

export const drawArrow2D = (size, color) => {
    const width = size * 0.3;
    const height = size * 1.2;

    const boxGeometry = new THREE.BoxGeometry(width, height, 0);
    const material = new THREE.MeshBasicMaterial({
        color,
        depthTest: false,
        transparent: true,
        opacity: 0.5
    });

    const TILE_SIZE = 0.27;
    const arrowGeometry = new THREE.CylinderGeometry(
        TILE_SIZE * 3,
        TILE_SIZE * 3,
        0.1,
        3
    );
    arrowGeometry
        .applyMatrix4(new THREE.Matrix4().makeRotationX(-Math.PI * 0.5))
        .applyMatrix4(new THREE.Matrix4().makeTranslation(0, height * 0.67, 0));

    const geometry = mergeGeometries([boxGeometry, arrowGeometry]);
    const mesh = new THREE.Mesh(geometry, material);
    mesh.renderOrder = 4;
    return mesh;
};

export const drawTorusGeometry = (radius, color) => {
    const tube = 0.25;
    const geometry = new THREE.TorusGeometry(
        radius,
        tube,
        3,
        100,
        (Math.PI / 180) * 36
    );
    geometry.applyMatrix4(
        new THREE.Matrix4().makeRotationZ((Math.PI / 180) * 4.5)
    );
    const material = new THREE.MeshBasicMaterial({
        color,
        depthTest: false,
        transparent: true,
        opacity: 0.5
    });
    const torus = new THREE.Mesh(geometry, material);
    return torus;
};

export const drawCircleArrow = (radius, color) => {
    const circleGeometry = drawTorusGeometry(radius, color);
    const size = 1.1;

    const coneGeometry = new THREE.ConeGeometry(size * 0.4, size, 32);
    const material = new THREE.MeshBasicMaterial({
        color,
        depthTest: false,
        transparent: true,
        opacity: 0.8
    });

    let matrix = new THREE.Matrix4()
        .makeTranslation(radius, 0, 0)
        .multiply(new THREE.Matrix4().makeRotationX(Math.PI));
    coneGeometry.applyMatrix4(matrix);

    const coneGeometryleft = new THREE.ConeGeometry(size * 0.4, size, 32);

    matrix = new THREE.Matrix4()
        .makeRotationZ((Math.PI / 180) * 45)
        .multiply(new THREE.Matrix4().makeTranslation(radius, 0, 0));
    coneGeometryleft.applyMatrix4(matrix);

    const geometry = mergeGeometries([
        circleGeometry.geometry,
        coneGeometry,
        coneGeometryleft
    ]);
    const mesh = new THREE.Mesh(geometry, material);
    mesh.renderOrder = 4;
    return mesh;
};