Repository

js/Mobilizing/renderer/3D/three/shape/2D/Arc.js

import * as THREE from 'three';
import Mesh from "../Mesh";
import Vector3 from "../../types/Vector3";
import Vector2 from "../../types/Vector2";
import Transform from "../../scene/Transform";

export default class Arc extends Mesh {
    /**
    * @param {Object} params Parameters object, given by the constructor.
    * @param {Number} [params.radius=1] the arc radius in world unit
    * @param {Number} [params.width=0.2] the arc width (or weight, distance between the exterior segments and the center) in world unit
    * @param {Number} [params.segments=32] the segments number (detail level)
    * @param {Number} [params.startAngle=0] 0 and Math.PI*2 are at 3 o'clock, value is counter clock-wise
    * @param {Number} [params.endAngle=Math.PI*2] 0 and Math.PI*2 are at 3 o'clock, value is counter clock-wise
    * @param {Number} [params.uvScale]
    * @param {Number} [params.center=Vector3.zero]
    */
    constructor({
        width = 0.2,
        radius = 1,
        segments = 32,
        startAngle = 0,
        endAngle = Math.PI * 2,
        uvScale = undefined,
        center = Vector3.zero,
    } = {}) {
        super(...arguments);

        this.width = width;
        this.radius = radius;
        this.segments = segments;
        this.startAngle = startAngle;
        this.endAngle = endAngle;
        this.uvScale = uvScale !== undefined ? uvScale : this.radius * (this.endAngle - this.startAngle) * 1;
        this.center = center;

        //this.geometry = new THREE.BufferGeometry();

        const innerpoints = [];
        const outerpoints = [];
        const interval = (Math.PI * 2) / this.segments;

        let a = 0;

        for (a = this.startAngle; a <= this.endAngle; a += interval) {
            innerpoints.push(new Vector3(Math.cos(a) * (this.radius - this.width / 2), Math.sin(a) * (this.radius - this.width / 2), 0));
            outerpoints.push(new Vector3(Math.cos(a) * (this.radius + this.width / 2), Math.sin(a) * (this.radius + this.width / 2), 0));
        }

        //on termine l'arc si on n'était pas sur un multiple
        if (a !== this.endAngle) {
            innerpoints.push(new Vector3(Math.cos(this.endAngle) * (this.radius - this.width / 2), Math.sin(this.endAngle) * (this.radius - this.width / 2), 0));
            outerpoints.push(new Vector3(Math.cos(this.endAngle) * (this.radius + this.width / 2), Math.sin(this.endAngle) * (this.radius + this.width / 2), 0));
        }

        for (let k = 0; k < innerpoints.length - 1; ++k) {

            const v1 = outerpoints[k];
            const v2 = innerpoints[k];
            const v3 = innerpoints[(k + 1) % innerpoints.length];
            const v4 = outerpoints[(k + 1) % innerpoints.length];

            this.pushQuad(v1, v2, v3, v4);
            
            const uv1 = new Vector2(0, (k + 0) * this.uvScale / (innerpoints.length - 1));
            const uv2 = new Vector2(1, (k + 0) * this.uvScale / (innerpoints.length - 1));
            const uv3 = new Vector2(1, (k + 1) * this.uvScale / (innerpoints.length - 1));
            const uv4 = new Vector2(0, (k + 1) * this.uvScale / (innerpoints.length - 1));

            this.pushUV(uv1);
            this.pushUV(uv2);
            this.pushUV(uv3);
            this.pushUV(uv4);
        }

        //generates the geom normals (lazy!)
        this.computeNormals();

        //manage the material according to the passed params, see the attachMaterial method below
        this.attachMaterial(this.material);

        this._mesh = new THREE.Mesh(this.geometry, this.material._material);
        //console.log(this._mesh);

        this.transform = new Transform(this);
        this.transform.setLocalPosition(this.center);
    }
}