Skip to content

⬅️ Back to Table of Contents

📄 TubeGeometry.js

📊 Analysis Summary

Metric Count
🔧 Functions 7
🧱 Classes 1
📦 Imports 4
📊 Variables & Constants 16

📚 Table of Contents

🛠️ File Location:

📂 src/geometries/TubeGeometry.js

📦 Imports

Name Source
BufferGeometry ../core/BufferGeometry.js
Float32BufferAttribute ../core/BufferAttribute.js
Vector2 ../math/Vector2.js
Vector3 ../math/Vector3.js

Variables & Constants

Name Type Kind Value Exported
vertex Vector3 let/var new Vector3()
normal Vector3 let/var new Vector3()
uv Vector2 let/var new Vector2()
P Vector3 let/var new Vector3()
vertices any[] let/var []
normals any[] let/var []
uvs any[] let/var []
indices any[] let/var []
N any let/var frames.normals[ i ]
B any let/var frames.binormals[ i ]
v number let/var j / radialSegments * Math.PI * 2
cos number let/var - Math.cos( v )
a number let/var ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 )
b number let/var ( radialSegments + 1 ) * j + ( i - 1 )
c number let/var ( radialSegments + 1 ) * j + i
d number let/var ( radialSegments + 1 ) * ( j - 1 ) + i

Functions

TubeGeometry.copy(source: any): this

Parameters:

  • source any

Returns: this

Calls:

  • super.copy
  • Object.assign
Code
copy( source ) {

        super.copy( source );

        this.parameters = Object.assign( {}, source.parameters );

        return this;

    }

TubeGeometry.toJSON(): any

Returns: any

Calls:

  • super.toJSON
  • this.parameters.path.toJSON
Code
toJSON() {

        const data = super.toJSON();

        data.path = this.parameters.path.toJSON();

        return data;

    }

TubeGeometry.fromJSON(data: any): TubeGeometry

JSDoc:

/**
     * Factory method for creating an instance of this class from the given
     * JSON object.
     *
     * @param {Object} data - A JSON object representing the serialized geometry.
     * @return {TubeGeometry} A new instance.
     */

Parameters:

  • data any

Returns: TubeGeometry

Calls:

  • new Curves[ data.path.type ]().fromJSON

Internal Comments:

// This only works for built-in curves (e.g. CatmullRomCurve3).
// User defined curves or instances of CurvePath will not be deserialized.

Code
static fromJSON( data ) {

        // This only works for built-in curves (e.g. CatmullRomCurve3).
        // User defined curves or instances of CurvePath will not be deserialized.
        return new TubeGeometry(
            new Curves[ data.path.type ]().fromJSON( data.path ),
            data.tubularSegments,
            data.radius,
            data.radialSegments,
            data.closed
        );

    }

generateBufferData(): void

Returns: void

Calls:

  • generateSegment
  • generateUVs
  • generateIndices

Internal Comments:

// if the geometry is not closed, generate the last row of vertices and normals (x3)
// at the regular position on the given path (x3)
// (x3)
// if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ) (x3)
// uvs are generated in a separate function. (x3)
// this makes it easy compute correct values for closed geometries (x3)
// finally create faces (x3)

Code
function generateBufferData() {

            for ( let i = 0; i < tubularSegments; i ++ ) {

                generateSegment( i );

            }

            // if the geometry is not closed, generate the last row of vertices and normals
            // at the regular position on the given path
            //
            // if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)

            generateSegment( ( closed === false ) ? tubularSegments : 0 );

            // uvs are generated in a separate function.
            // this makes it easy compute correct values for closed geometries

            generateUVs();

            // finally create faces

            generateIndices();

        }

generateSegment(i: any): void

Parameters:

  • i any

Returns: void

Calls:

  • path.getPointAt
  • Math.sin
  • Math.cos
  • normal.normalize
  • normals.push
  • vertices.push

Internal Comments:

// we use getPointAt to sample evenly distributed points from the given path (x3)
// retrieve corresponding normal and binormal (x2)
// generate normals and vertices for the current segment
// normal (x4)
// vertex (x4)

Code
function generateSegment( i ) {

            // we use getPointAt to sample evenly distributed points from the given path

            P = path.getPointAt( i / tubularSegments, P );

            // retrieve corresponding normal and binormal

            const N = frames.normals[ i ];
            const B = frames.binormals[ i ];

            // generate normals and vertices for the current segment

            for ( let j = 0; j <= radialSegments; j ++ ) {

                const v = j / radialSegments * Math.PI * 2;

                const sin = Math.sin( v );
                const cos = - Math.cos( v );

                // normal

                normal.x = ( cos * N.x + sin * B.x );
                normal.y = ( cos * N.y + sin * B.y );
                normal.z = ( cos * N.z + sin * B.z );
                normal.normalize();

                normals.push( normal.x, normal.y, normal.z );

                // vertex

                vertex.x = P.x + radius * normal.x;
                vertex.y = P.y + radius * normal.y;
                vertex.z = P.z + radius * normal.z;

                vertices.push( vertex.x, vertex.y, vertex.z );

            }

        }

generateIndices(): void

Returns: void

Calls:

  • indices.push

Internal Comments:

// faces (x4)

Code
function generateIndices() {

            for ( let j = 1; j <= tubularSegments; j ++ ) {

                for ( let i = 1; i <= radialSegments; i ++ ) {

                    const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
                    const b = ( radialSegments + 1 ) * j + ( i - 1 );
                    const c = ( radialSegments + 1 ) * j + i;
                    const d = ( radialSegments + 1 ) * ( j - 1 ) + i;

                    // faces

                    indices.push( a, b, d );
                    indices.push( b, c, d );

                }

            }

        }

generateUVs(): void

Returns: void

Calls:

  • uvs.push
Code
function generateUVs() {

            for ( let i = 0; i <= tubularSegments; i ++ ) {

                for ( let j = 0; j <= radialSegments; j ++ ) {

                    uv.x = i / tubularSegments;
                    uv.y = j / radialSegments;

                    uvs.push( uv.x, uv.y );

                }

            }

        }

Classes

TubeGeometry

Class Code
class TubeGeometry extends BufferGeometry {

    /**
     * Constructs a new tube geometry.
     *
     * @param {Curve} [path=QuadraticBezierCurve3] - A 3D curve defining the path of the tube.
     * @param {number} [tubularSegments=64] - The number of segments that make up the tube.
     * @param {number} [radius=1] -The radius of the tube.
     * @param {number} [radialSegments=8] - The number of segments that make up the cross-section.
     * @param {boolean} [closed=false] - Whether the tube is closed or not.
     */
    constructor( path = new Curves[ 'QuadraticBezierCurve3' ]( new Vector3( - 1, - 1, 0 ), new Vector3( - 1, 1, 0 ), new Vector3( 1, 1, 0 ) ), tubularSegments = 64, radius = 1, radialSegments = 8, closed = false ) {

        super();

        this.type = 'TubeGeometry';

        /**
         * Holds the constructor parameters that have been
         * used to generate the geometry. Any modification
         * after instantiation does not change the geometry.
         *
         * @type {Object}
         */
        this.parameters = {
            path: path,
            tubularSegments: tubularSegments,
            radius: radius,
            radialSegments: radialSegments,
            closed: closed
        };

        const frames = path.computeFrenetFrames( tubularSegments, closed );

        // expose internals

        this.tangents = frames.tangents;
        this.normals = frames.normals;
        this.binormals = frames.binormals;

        // helper variables

        const vertex = new Vector3();
        const normal = new Vector3();
        const uv = new Vector2();
        let P = new Vector3();

        // buffer

        const vertices = [];
        const normals = [];
        const uvs = [];
        const indices = [];

        // create buffer data

        generateBufferData();

        // build geometry

        this.setIndex( indices );
        this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
        this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
        this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );

        // functions

        function generateBufferData() {

            for ( let i = 0; i < tubularSegments; i ++ ) {

                generateSegment( i );

            }

            // if the geometry is not closed, generate the last row of vertices and normals
            // at the regular position on the given path
            //
            // if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)

            generateSegment( ( closed === false ) ? tubularSegments : 0 );

            // uvs are generated in a separate function.
            // this makes it easy compute correct values for closed geometries

            generateUVs();

            // finally create faces

            generateIndices();

        }

        function generateSegment( i ) {

            // we use getPointAt to sample evenly distributed points from the given path

            P = path.getPointAt( i / tubularSegments, P );

            // retrieve corresponding normal and binormal

            const N = frames.normals[ i ];
            const B = frames.binormals[ i ];

            // generate normals and vertices for the current segment

            for ( let j = 0; j <= radialSegments; j ++ ) {

                const v = j / radialSegments * Math.PI * 2;

                const sin = Math.sin( v );
                const cos = - Math.cos( v );

                // normal

                normal.x = ( cos * N.x + sin * B.x );
                normal.y = ( cos * N.y + sin * B.y );
                normal.z = ( cos * N.z + sin * B.z );
                normal.normalize();

                normals.push( normal.x, normal.y, normal.z );

                // vertex

                vertex.x = P.x + radius * normal.x;
                vertex.y = P.y + radius * normal.y;
                vertex.z = P.z + radius * normal.z;

                vertices.push( vertex.x, vertex.y, vertex.z );

            }

        }

        function generateIndices() {

            for ( let j = 1; j <= tubularSegments; j ++ ) {

                for ( let i = 1; i <= radialSegments; i ++ ) {

                    const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
                    const b = ( radialSegments + 1 ) * j + ( i - 1 );
                    const c = ( radialSegments + 1 ) * j + i;
                    const d = ( radialSegments + 1 ) * ( j - 1 ) + i;

                    // faces

                    indices.push( a, b, d );
                    indices.push( b, c, d );

                }

            }

        }

        function generateUVs() {

            for ( let i = 0; i <= tubularSegments; i ++ ) {

                for ( let j = 0; j <= radialSegments; j ++ ) {

                    uv.x = i / tubularSegments;
                    uv.y = j / radialSegments;

                    uvs.push( uv.x, uv.y );

                }

            }

        }

    }

    copy( source ) {

        super.copy( source );

        this.parameters = Object.assign( {}, source.parameters );

        return this;

    }

    toJSON() {

        const data = super.toJSON();

        data.path = this.parameters.path.toJSON();

        return data;

    }

    /**
     * Factory method for creating an instance of this class from the given
     * JSON object.
     *
     * @param {Object} data - A JSON object representing the serialized geometry.
     * @return {TubeGeometry} A new instance.
     */
    static fromJSON( data ) {

        // This only works for built-in curves (e.g. CatmullRomCurve3).
        // User defined curves or instances of CurvePath will not be deserialized.
        return new TubeGeometry(
            new Curves[ data.path.type ]().fromJSON( data.path ),
            data.tubularSegments,
            data.radius,
            data.radialSegments,
            data.closed
        );

    }

}

Methods

copy(source: any): this
Code
copy( source ) {

        super.copy( source );

        this.parameters = Object.assign( {}, source.parameters );

        return this;

    }
toJSON(): any
Code
toJSON() {

        const data = super.toJSON();

        data.path = this.parameters.path.toJSON();

        return data;

    }
fromJSON(data: any): TubeGeometry
Code
static fromJSON( data ) {

        // This only works for built-in curves (e.g. CatmullRomCurve3).
        // User defined curves or instances of CurvePath will not be deserialized.
        return new TubeGeometry(
            new Curves[ data.path.type ]().fromJSON( data.path ),
            data.tubularSegments,
            data.radius,
            data.radialSegments,
            data.closed
        );

    }