Skip to content

⬅️ Back to Table of Contents

📄 LDrawUtils.js

📊 Analysis Summary

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

📚 Table of Contents

🛠️ File Location:

📂 examples/jsm/utils/LDrawUtils.js

📦 Imports

Name Source
BufferAttribute three
BufferGeometry three
Group three
LineSegments three
Matrix3 three
Mesh three
mergeGeometries ./BufferGeometryUtils.js

Variables & Constants

Name Type Kind Value Exported
newGeometry any let/var new BufferGeometry()
originalPositions any let/var geometry.getAttribute( 'position' ).array
originalNormals any let/var elementSize === 3 ? geometry.getAttribute( 'normal' ).array : null
vertStart number let/var group.start * 3
vertEnd number let/var ( group.start + numVertsGroup ) * 3
normals any let/var originalNormals !== null ? originalNormals.subarray( vertStart, vertEnd ) : null
geoms any let/var geometries[ mat.uuid ]
verts any let/var attribute.array
offset number let/var 0
x any let/var verts[ offset ]
y any let/var verts[ offset + 1 ]
z any let/var verts[ offset + 2 ]
meshGeometries {} let/var {}
linesGeometries {} let/var {}
condLinesGeometries {} let/var {}
normalMatrix any let/var new Matrix3()
elemSize 2 \| 3 let/var c.isMesh ? 3 : 2
matrixIsInverted boolean let/var c.matrixWorld.determinant() < 0
geometries {} let/var c.isMesh ? meshGeometries : ( c.isConditionalLine ? condLinesGeometries : lin...
group any let/var geometry.groups[ groupIndex ]
mat any let/var c.material[ group.materialIndex ]
mergedObject any let/var new Group()
meshGeometry any let/var meshGeometries[ meshMaterialsId ]
lineGeometry any let/var linesGeometries[ linesMaterialsId ]
condLineGeometry any let/var condLinesGeometries[ condLinesMaterialsId ]
condLines any let/var new LineSegments( mergedGeometry, condLineGeometry.mat )

Functions

LDrawUtils.mergeObject(object: Object3D): Group

JSDoc:

/**
     * Merges geometries in the given object by materials and returns a new group object.
     * Use on not indexed geometries. The object buffers reference the old object ones.
     * Special treatment is done to the conditional lines generated by LDrawLoader.
     *
     * @param {Object3D} object - The object to merge.
     * @returns {Group} The merged object.
     */

Parameters:

  • object Object3D

Returns: Group

Calls:

  • geometry.getAttribute
  • Math.min
  • Math.floor
  • originalPositions.subarray
  • originalNormals.subarray
  • newGeometry.setAttribute
  • geometry.getAttribute( 'control0' ).array.subarray
  • geometry.getAttribute( 'control1' ).array.subarray
  • geometry.getAttribute( 'direction' ).array.subarray
  • geoms.arr.push
  • object.updateMatrixWorld
  • object.traverse
  • c.geometry.clone
  • c.matrixWorld.determinant
  • permuteAttribute
  • geometry.applyMatrix4
  • geometry.attributes.control0.applyMatrix4
  • geometry.attributes.control1.applyMatrix4
  • normalMatrix.getNormalMatrix
  • geometry.attributes.direction.applyNormalMatrix
  • Array.isArray
  • extractGroup
  • addGeometry
  • Object.keys
  • mergeGeometries (from ./BufferGeometryUtils.js)
  • mergedObject.add

Internal Comments:

// Extracts a group from a geometry as a new geometry (with attribute buffers referencing original buffers) (x2)
// Permutes first two vertices of each attribute element
// Traverse the object hierarchy collecting geometries and transforming them to world space (x2)
// Create object with merged geometries (x2)

Code
static mergeObject( object ) {

        function extractGroup( geometry, group, elementSize, isConditionalLine ) {

            // Extracts a group from a geometry as a new geometry (with attribute buffers referencing original buffers)

            const newGeometry = new BufferGeometry();

            const originalPositions = geometry.getAttribute( 'position' ).array;
            const originalNormals = elementSize === 3 ? geometry.getAttribute( 'normal' ).array : null;

            const numVertsGroup = Math.min( group.count, Math.floor( originalPositions.length / 3 ) - group.start );
            const vertStart = group.start * 3;
            const vertEnd = ( group.start + numVertsGroup ) * 3;

            const positions = originalPositions.subarray( vertStart, vertEnd );
            const normals = originalNormals !== null ? originalNormals.subarray( vertStart, vertEnd ) : null;

            newGeometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) );
            if ( normals !== null ) newGeometry.setAttribute( 'normal', new BufferAttribute( normals, 3 ) );

            if ( isConditionalLine ) {

                const controlArray0 = geometry.getAttribute( 'control0' ).array.subarray( vertStart, vertEnd );
                const controlArray1 = geometry.getAttribute( 'control1' ).array.subarray( vertStart, vertEnd );
                const directionArray = geometry.getAttribute( 'direction' ).array.subarray( vertStart, vertEnd );

                newGeometry.setAttribute( 'control0', new BufferAttribute( controlArray0, 3, false ) );
                newGeometry.setAttribute( 'control1', new BufferAttribute( controlArray1, 3, false ) );
                newGeometry.setAttribute( 'direction', new BufferAttribute( directionArray, 3, false ) );

            }

            return newGeometry;

        }

        function addGeometry( mat, geometry, geometries ) {

            const geoms = geometries[ mat.uuid ];
            if ( ! geoms ) {

                geometries[ mat.uuid ] = {
                    mat: mat,
                    arr: [ geometry ]
                };

            } else {

                geoms.arr.push( geometry );

            }

        }

        function permuteAttribute( attribute, elemSize ) {

            // Permutes first two vertices of each attribute element

            if ( ! attribute ) return;

            const verts = attribute.array;
            const numVerts = Math.floor( verts.length / 3 );
            let offset = 0;
            for ( let i = 0; i < numVerts; i ++ ) {

                const x = verts[ offset ];
                const y = verts[ offset + 1 ];
                const z = verts[ offset + 2 ];

                verts[ offset ] = verts[ offset + 3 ];
                verts[ offset + 1 ] = verts[ offset + 4 ];
                verts[ offset + 2 ] = verts[ offset + 5 ];

                verts[ offset + 3 ] = x;
                verts[ offset + 4 ] = y;
                verts[ offset + 5 ] = z;

                offset += elemSize * 3;

            }

        }

        // Traverse the object hierarchy collecting geometries and transforming them to world space

        const meshGeometries = {};
        const linesGeometries = {};
        const condLinesGeometries = {};

        object.updateMatrixWorld( true );
        const normalMatrix = new Matrix3();

        object.traverse( c => {

            if ( c.isMesh | c.isLineSegments ) {

                const elemSize = c.isMesh ? 3 : 2;

                const geometry = c.geometry.clone();
                const matrixIsInverted = c.matrixWorld.determinant() < 0;
                if ( matrixIsInverted ) {

                    permuteAttribute( geometry.attributes.position, elemSize );
                    permuteAttribute( geometry.attributes.normal, elemSize );

                }

                geometry.applyMatrix4( c.matrixWorld );

                if ( c.isConditionalLine ) {

                    geometry.attributes.control0.applyMatrix4( c.matrixWorld );
                    geometry.attributes.control1.applyMatrix4( c.matrixWorld );
                    normalMatrix.getNormalMatrix( c.matrixWorld );
                    geometry.attributes.direction.applyNormalMatrix( normalMatrix );

                }

                const geometries = c.isMesh ? meshGeometries : ( c.isConditionalLine ? condLinesGeometries : linesGeometries );

                if ( Array.isArray( c.material ) ) {

                    for ( const groupIndex in geometry.groups ) {

                        const group = geometry.groups[ groupIndex ];
                        const mat = c.material[ group.materialIndex ];
                        const newGeometry = extractGroup( geometry, group, elemSize, c.isConditionalLine );
                        addGeometry( mat, newGeometry, geometries );

                    }

                } else {

                    addGeometry( c.material, geometry, geometries );

                }

            }

        } );

        // Create object with merged geometries

        const mergedObject = new Group();

        const meshMaterialsIds = Object.keys( meshGeometries );
        for ( const meshMaterialsId of meshMaterialsIds ) {

            const meshGeometry = meshGeometries[ meshMaterialsId ];
            const mergedGeometry = mergeGeometries( meshGeometry.arr );
            mergedObject.add( new Mesh( mergedGeometry, meshGeometry.mat ) );

        }

        const linesMaterialsIds = Object.keys( linesGeometries );
        for ( const linesMaterialsId of linesMaterialsIds ) {

            const lineGeometry = linesGeometries[ linesMaterialsId ];
            const mergedGeometry = mergeGeometries( lineGeometry.arr );
            mergedObject.add( new LineSegments( mergedGeometry, lineGeometry.mat ) );

        }

        const condLinesMaterialsIds = Object.keys( condLinesGeometries );
        for ( const condLinesMaterialsId of condLinesMaterialsIds ) {

            const condLineGeometry = condLinesGeometries[ condLinesMaterialsId ];
            const mergedGeometry = mergeGeometries( condLineGeometry.arr );
            const condLines = new LineSegments( mergedGeometry, condLineGeometry.mat );
            condLines.isConditionalLine = true;
            mergedObject.add( condLines );

        }

        mergedObject.userData.constructionStep = 0;
        mergedObject.userData.numConstructionSteps = 1;

        return mergedObject;

    }

extractGroup(geometry: any, group: any, elementSize: any, isConditionalLine: any): any

Parameters:

  • geometry any
  • group any
  • elementSize any
  • isConditionalLine any

Returns: any

Calls:

  • geometry.getAttribute
  • Math.min
  • Math.floor
  • originalPositions.subarray
  • originalNormals.subarray
  • newGeometry.setAttribute
  • geometry.getAttribute( 'control0' ).array.subarray
  • geometry.getAttribute( 'control1' ).array.subarray
  • geometry.getAttribute( 'direction' ).array.subarray

Internal Comments:

// Extracts a group from a geometry as a new geometry (with attribute buffers referencing original buffers) (x2)

Code
function extractGroup( geometry, group, elementSize, isConditionalLine ) {

            // Extracts a group from a geometry as a new geometry (with attribute buffers referencing original buffers)

            const newGeometry = new BufferGeometry();

            const originalPositions = geometry.getAttribute( 'position' ).array;
            const originalNormals = elementSize === 3 ? geometry.getAttribute( 'normal' ).array : null;

            const numVertsGroup = Math.min( group.count, Math.floor( originalPositions.length / 3 ) - group.start );
            const vertStart = group.start * 3;
            const vertEnd = ( group.start + numVertsGroup ) * 3;

            const positions = originalPositions.subarray( vertStart, vertEnd );
            const normals = originalNormals !== null ? originalNormals.subarray( vertStart, vertEnd ) : null;

            newGeometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) );
            if ( normals !== null ) newGeometry.setAttribute( 'normal', new BufferAttribute( normals, 3 ) );

            if ( isConditionalLine ) {

                const controlArray0 = geometry.getAttribute( 'control0' ).array.subarray( vertStart, vertEnd );
                const controlArray1 = geometry.getAttribute( 'control1' ).array.subarray( vertStart, vertEnd );
                const directionArray = geometry.getAttribute( 'direction' ).array.subarray( vertStart, vertEnd );

                newGeometry.setAttribute( 'control0', new BufferAttribute( controlArray0, 3, false ) );
                newGeometry.setAttribute( 'control1', new BufferAttribute( controlArray1, 3, false ) );
                newGeometry.setAttribute( 'direction', new BufferAttribute( directionArray, 3, false ) );

            }

            return newGeometry;

        }

addGeometry(mat: any, geometry: any, geometries: any): void

Parameters:

  • mat any
  • geometry any
  • geometries any

Returns: void

Calls:

  • geoms.arr.push
Code
function addGeometry( mat, geometry, geometries ) {

            const geoms = geometries[ mat.uuid ];
            if ( ! geoms ) {

                geometries[ mat.uuid ] = {
                    mat: mat,
                    arr: [ geometry ]
                };

            } else {

                geoms.arr.push( geometry );

            }

        }

permuteAttribute(attribute: any, elemSize: any): void

Parameters:

  • attribute any
  • elemSize any

Returns: void

Calls:

  • Math.floor

Internal Comments:

// Permutes first two vertices of each attribute element

Code
function permuteAttribute( attribute, elemSize ) {

            // Permutes first two vertices of each attribute element

            if ( ! attribute ) return;

            const verts = attribute.array;
            const numVerts = Math.floor( verts.length / 3 );
            let offset = 0;
            for ( let i = 0; i < numVerts; i ++ ) {

                const x = verts[ offset ];
                const y = verts[ offset + 1 ];
                const z = verts[ offset + 2 ];

                verts[ offset ] = verts[ offset + 3 ];
                verts[ offset + 1 ] = verts[ offset + 4 ];
                verts[ offset + 2 ] = verts[ offset + 5 ];

                verts[ offset + 3 ] = x;
                verts[ offset + 4 ] = y;
                verts[ offset + 5 ] = z;

                offset += elemSize * 3;

            }

        }

Classes

LDrawUtils

Class Code
class LDrawUtils {

    /**
     * Merges geometries in the given object by materials and returns a new group object.
     * Use on not indexed geometries. The object buffers reference the old object ones.
     * Special treatment is done to the conditional lines generated by LDrawLoader.
     *
     * @param {Object3D} object - The object to merge.
     * @returns {Group} The merged object.
     */
    static mergeObject( object ) {

        function extractGroup( geometry, group, elementSize, isConditionalLine ) {

            // Extracts a group from a geometry as a new geometry (with attribute buffers referencing original buffers)

            const newGeometry = new BufferGeometry();

            const originalPositions = geometry.getAttribute( 'position' ).array;
            const originalNormals = elementSize === 3 ? geometry.getAttribute( 'normal' ).array : null;

            const numVertsGroup = Math.min( group.count, Math.floor( originalPositions.length / 3 ) - group.start );
            const vertStart = group.start * 3;
            const vertEnd = ( group.start + numVertsGroup ) * 3;

            const positions = originalPositions.subarray( vertStart, vertEnd );
            const normals = originalNormals !== null ? originalNormals.subarray( vertStart, vertEnd ) : null;

            newGeometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) );
            if ( normals !== null ) newGeometry.setAttribute( 'normal', new BufferAttribute( normals, 3 ) );

            if ( isConditionalLine ) {

                const controlArray0 = geometry.getAttribute( 'control0' ).array.subarray( vertStart, vertEnd );
                const controlArray1 = geometry.getAttribute( 'control1' ).array.subarray( vertStart, vertEnd );
                const directionArray = geometry.getAttribute( 'direction' ).array.subarray( vertStart, vertEnd );

                newGeometry.setAttribute( 'control0', new BufferAttribute( controlArray0, 3, false ) );
                newGeometry.setAttribute( 'control1', new BufferAttribute( controlArray1, 3, false ) );
                newGeometry.setAttribute( 'direction', new BufferAttribute( directionArray, 3, false ) );

            }

            return newGeometry;

        }

        function addGeometry( mat, geometry, geometries ) {

            const geoms = geometries[ mat.uuid ];
            if ( ! geoms ) {

                geometries[ mat.uuid ] = {
                    mat: mat,
                    arr: [ geometry ]
                };

            } else {

                geoms.arr.push( geometry );

            }

        }

        function permuteAttribute( attribute, elemSize ) {

            // Permutes first two vertices of each attribute element

            if ( ! attribute ) return;

            const verts = attribute.array;
            const numVerts = Math.floor( verts.length / 3 );
            let offset = 0;
            for ( let i = 0; i < numVerts; i ++ ) {

                const x = verts[ offset ];
                const y = verts[ offset + 1 ];
                const z = verts[ offset + 2 ];

                verts[ offset ] = verts[ offset + 3 ];
                verts[ offset + 1 ] = verts[ offset + 4 ];
                verts[ offset + 2 ] = verts[ offset + 5 ];

                verts[ offset + 3 ] = x;
                verts[ offset + 4 ] = y;
                verts[ offset + 5 ] = z;

                offset += elemSize * 3;

            }

        }

        // Traverse the object hierarchy collecting geometries and transforming them to world space

        const meshGeometries = {};
        const linesGeometries = {};
        const condLinesGeometries = {};

        object.updateMatrixWorld( true );
        const normalMatrix = new Matrix3();

        object.traverse( c => {

            if ( c.isMesh | c.isLineSegments ) {

                const elemSize = c.isMesh ? 3 : 2;

                const geometry = c.geometry.clone();
                const matrixIsInverted = c.matrixWorld.determinant() < 0;
                if ( matrixIsInverted ) {

                    permuteAttribute( geometry.attributes.position, elemSize );
                    permuteAttribute( geometry.attributes.normal, elemSize );

                }

                geometry.applyMatrix4( c.matrixWorld );

                if ( c.isConditionalLine ) {

                    geometry.attributes.control0.applyMatrix4( c.matrixWorld );
                    geometry.attributes.control1.applyMatrix4( c.matrixWorld );
                    normalMatrix.getNormalMatrix( c.matrixWorld );
                    geometry.attributes.direction.applyNormalMatrix( normalMatrix );

                }

                const geometries = c.isMesh ? meshGeometries : ( c.isConditionalLine ? condLinesGeometries : linesGeometries );

                if ( Array.isArray( c.material ) ) {

                    for ( const groupIndex in geometry.groups ) {

                        const group = geometry.groups[ groupIndex ];
                        const mat = c.material[ group.materialIndex ];
                        const newGeometry = extractGroup( geometry, group, elemSize, c.isConditionalLine );
                        addGeometry( mat, newGeometry, geometries );

                    }

                } else {

                    addGeometry( c.material, geometry, geometries );

                }

            }

        } );

        // Create object with merged geometries

        const mergedObject = new Group();

        const meshMaterialsIds = Object.keys( meshGeometries );
        for ( const meshMaterialsId of meshMaterialsIds ) {

            const meshGeometry = meshGeometries[ meshMaterialsId ];
            const mergedGeometry = mergeGeometries( meshGeometry.arr );
            mergedObject.add( new Mesh( mergedGeometry, meshGeometry.mat ) );

        }

        const linesMaterialsIds = Object.keys( linesGeometries );
        for ( const linesMaterialsId of linesMaterialsIds ) {

            const lineGeometry = linesGeometries[ linesMaterialsId ];
            const mergedGeometry = mergeGeometries( lineGeometry.arr );
            mergedObject.add( new LineSegments( mergedGeometry, lineGeometry.mat ) );

        }

        const condLinesMaterialsIds = Object.keys( condLinesGeometries );
        for ( const condLinesMaterialsId of condLinesMaterialsIds ) {

            const condLineGeometry = condLinesGeometries[ condLinesMaterialsId ];
            const mergedGeometry = mergeGeometries( condLineGeometry.arr );
            const condLines = new LineSegments( mergedGeometry, condLineGeometry.mat );
            condLines.isConditionalLine = true;
            mergedObject.add( condLines );

        }

        mergedObject.userData.constructionStep = 0;
        mergedObject.userData.numConstructionSteps = 1;

        return mergedObject;

    }

}

Methods

mergeObject(object: Object3D): Group
Code
static mergeObject( object ) {

        function extractGroup( geometry, group, elementSize, isConditionalLine ) {

            // Extracts a group from a geometry as a new geometry (with attribute buffers referencing original buffers)

            const newGeometry = new BufferGeometry();

            const originalPositions = geometry.getAttribute( 'position' ).array;
            const originalNormals = elementSize === 3 ? geometry.getAttribute( 'normal' ).array : null;

            const numVertsGroup = Math.min( group.count, Math.floor( originalPositions.length / 3 ) - group.start );
            const vertStart = group.start * 3;
            const vertEnd = ( group.start + numVertsGroup ) * 3;

            const positions = originalPositions.subarray( vertStart, vertEnd );
            const normals = originalNormals !== null ? originalNormals.subarray( vertStart, vertEnd ) : null;

            newGeometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) );
            if ( normals !== null ) newGeometry.setAttribute( 'normal', new BufferAttribute( normals, 3 ) );

            if ( isConditionalLine ) {

                const controlArray0 = geometry.getAttribute( 'control0' ).array.subarray( vertStart, vertEnd );
                const controlArray1 = geometry.getAttribute( 'control1' ).array.subarray( vertStart, vertEnd );
                const directionArray = geometry.getAttribute( 'direction' ).array.subarray( vertStart, vertEnd );

                newGeometry.setAttribute( 'control0', new BufferAttribute( controlArray0, 3, false ) );
                newGeometry.setAttribute( 'control1', new BufferAttribute( controlArray1, 3, false ) );
                newGeometry.setAttribute( 'direction', new BufferAttribute( directionArray, 3, false ) );

            }

            return newGeometry;

        }

        function addGeometry( mat, geometry, geometries ) {

            const geoms = geometries[ mat.uuid ];
            if ( ! geoms ) {

                geometries[ mat.uuid ] = {
                    mat: mat,
                    arr: [ geometry ]
                };

            } else {

                geoms.arr.push( geometry );

            }

        }

        function permuteAttribute( attribute, elemSize ) {

            // Permutes first two vertices of each attribute element

            if ( ! attribute ) return;

            const verts = attribute.array;
            const numVerts = Math.floor( verts.length / 3 );
            let offset = 0;
            for ( let i = 0; i < numVerts; i ++ ) {

                const x = verts[ offset ];
                const y = verts[ offset + 1 ];
                const z = verts[ offset + 2 ];

                verts[ offset ] = verts[ offset + 3 ];
                verts[ offset + 1 ] = verts[ offset + 4 ];
                verts[ offset + 2 ] = verts[ offset + 5 ];

                verts[ offset + 3 ] = x;
                verts[ offset + 4 ] = y;
                verts[ offset + 5 ] = z;

                offset += elemSize * 3;

            }

        }

        // Traverse the object hierarchy collecting geometries and transforming them to world space

        const meshGeometries = {};
        const linesGeometries = {};
        const condLinesGeometries = {};

        object.updateMatrixWorld( true );
        const normalMatrix = new Matrix3();

        object.traverse( c => {

            if ( c.isMesh | c.isLineSegments ) {

                const elemSize = c.isMesh ? 3 : 2;

                const geometry = c.geometry.clone();
                const matrixIsInverted = c.matrixWorld.determinant() < 0;
                if ( matrixIsInverted ) {

                    permuteAttribute( geometry.attributes.position, elemSize );
                    permuteAttribute( geometry.attributes.normal, elemSize );

                }

                geometry.applyMatrix4( c.matrixWorld );

                if ( c.isConditionalLine ) {

                    geometry.attributes.control0.applyMatrix4( c.matrixWorld );
                    geometry.attributes.control1.applyMatrix4( c.matrixWorld );
                    normalMatrix.getNormalMatrix( c.matrixWorld );
                    geometry.attributes.direction.applyNormalMatrix( normalMatrix );

                }

                const geometries = c.isMesh ? meshGeometries : ( c.isConditionalLine ? condLinesGeometries : linesGeometries );

                if ( Array.isArray( c.material ) ) {

                    for ( const groupIndex in geometry.groups ) {

                        const group = geometry.groups[ groupIndex ];
                        const mat = c.material[ group.materialIndex ];
                        const newGeometry = extractGroup( geometry, group, elemSize, c.isConditionalLine );
                        addGeometry( mat, newGeometry, geometries );

                    }

                } else {

                    addGeometry( c.material, geometry, geometries );

                }

            }

        } );

        // Create object with merged geometries

        const mergedObject = new Group();

        const meshMaterialsIds = Object.keys( meshGeometries );
        for ( const meshMaterialsId of meshMaterialsIds ) {

            const meshGeometry = meshGeometries[ meshMaterialsId ];
            const mergedGeometry = mergeGeometries( meshGeometry.arr );
            mergedObject.add( new Mesh( mergedGeometry, meshGeometry.mat ) );

        }

        const linesMaterialsIds = Object.keys( linesGeometries );
        for ( const linesMaterialsId of linesMaterialsIds ) {

            const lineGeometry = linesGeometries[ linesMaterialsId ];
            const mergedGeometry = mergeGeometries( lineGeometry.arr );
            mergedObject.add( new LineSegments( mergedGeometry, lineGeometry.mat ) );

        }

        const condLinesMaterialsIds = Object.keys( condLinesGeometries );
        for ( const condLinesMaterialsId of condLinesMaterialsIds ) {

            const condLineGeometry = condLinesGeometries[ condLinesMaterialsId ];
            const mergedGeometry = mergeGeometries( condLineGeometry.arr );
            const condLines = new LineSegments( mergedGeometry, condLineGeometry.mat );
            condLines.isConditionalLine = true;
            mergedObject.add( condLines );

        }

        mergedObject.userData.constructionStep = 0;
        mergedObject.userData.numConstructionSteps = 1;

        return mergedObject;

    }