# Generate Cylinder

## Summary

Below is an example demonstrating the use of the geometry pipeline to generate a geometric cylinder.

## Example

Generate_Cylinder.dsa
```// Define an anonymous function;
// serves as our main loop,
// limits the scope of variables
(function(){

/*********************************************************************/
// Number : A function to convert from meters/yards/feet/inches to centimeters
function convertToCM( nVal, sFromUnit )
{
switch( sFromUnit.lower() ){
case "m":
return nVal * 100;
case "yd":
return nVal * 36.0 * 2.54;
case "ft":
return nVal * 12.0 * 2.54;
case "in":
return nVal * 2.54;
}

return nVal;
};

/*********************************************************************/
// String : A function for finding a unique label in the scene
function getUniqueLabel( sLabel )
{
// Initialize
var sUnqLabel = sLabel;
// If a node by the same label already exists
if( Scene.findNodeByLabel( sUnqLabel ) ){
// Create an array of the label parts
var aLabel = sUnqLabel.split( " " );
// Initialize
var sPreLabel = sUnqLabel;
// Get the last label part
var sLastPart = aLabel[ aLabel.length - 1 ];
// If the last label part is a number enclosed in parens
if( sLastPart.startsWith( "(" ) && sLastPart.endsWith( ")" ) &&
!isNaN( sLastPart.substring( 1, sLastPart.length - 1 ) ) ){
// Get rid of the number
aLabel.pop();
// Reconstruct the Label without the number
sPreLabel = aLabel.join( " " );
}
// Initialize a count
var i = 2;
// Until we cannot find a node with the label
while( Scene.findNodeByLabel( String( "%1 (%2)" ).arg( sPreLabel ).arg( i ) ) ){
// Increment the count
i += 1;
}
// Construct the unique Label
sUnqLabel = String( "%1 (%2)" ).arg( sPreLabel ).arg( i );
}

// Return the unique Label
return sUnqLabel;
};

/*********************************************************************/
// Get the user input
var sOrigin = "Object Center"; // "World Center"
var nSize = 10;
var sSizeUnit = "cm"; // "m", "yd", "ft", "in"
var nDiameter = 10;
var sDiameterUnit = "cm";
var nSegments = 12;
var nSides = 12;

// Convert the input value to centimeters
nSize = convertToCM( nSize, sSizeUnit );
nDiameter = convertToCM( nDiameter, sDiameterUnit );

// Sanity check the input values
if ( nSize <= 0.0 || nDiameter <= 0.0 || nSegments < 1 || nSides < 3 )
{
// We are done...
return;
}

// Let the user know we are busy
setBusyCursor();

// Create new node
var oNode = new DzNode();

// Set the node name;
// use a name that is consistent with the create primitive action
oNode.setName( "Cylinder" );

// Build the label of the node
var sLabel = String( "Cylinder %1x%2 %3%4 %5%6" )
.arg( nSides )
.arg( nSegments )
.arg( nSize )
.arg( sSizeUnit )
.arg( nDiameter )
.arg( sDiameterUnit );
oNode.setLabel( getUniqueLabel( sLabel ) );

// Create a new object
var oObject = new DzObject();

// Set the object name;
// use a name that is consistent with the create primitive action
oObject.name = String( "pCylinder(%1_%2)%3_%4" )
.arg( nSize )
.arg( nDiameter )
.arg( nSides )
.arg( nSegments );

// Create a new polygonal shape
var oFacetShape = new DzFacetShape();

// Set the shape name and label;
// use a name that is consistent with the create primitive action
oFacetShape.name = "Default";
oFacetShape.setLabel( oFacetShape.name );

// Create a new polygonal mesh
var oFacetMesh = new DzFacetMesh();

// Create a new default material
var oMaterial = new DzDefaultMaterial();

// Set the material name and label;
// use a name that is consistent with the create primitive action
oMaterial.name = "Default";
oMaterial.setLabel( oMaterial.name );

// Add the material to the shape

// Begin editing the mesh
oFacetMesh.beginEdit();

// Get the UV map
var oMap = oFacetMesh.getUVs();

// Activate the material; all new geometry will be added to this
oFacetMesh.activateMaterial( oMaterial.name );

// Declare some variables for generating the mesh
var i, j, nNext;
var x, y, z, nAngle, nSinAngle, nCosAngle;
var bAtSeam = false;
var vecUVsA = new DzVec3( 0, 0, 0 );
var vecUVsB = new DzVec3( 0, 0, 0 );

var nVerts = nSegments + 1;
var nRadius = nDiameter / 2;

// Pre-size the vertex array; faster than dynamic resizing
oFacetMesh.preSizeVertexArray( nSides * nVerts + 2 );

// Create the center vertex and UV for the bottom
vecUVsA.x = 0.25;
vecUVsA.y = 0.75;
oMap.appendPnt2Vec( vecUVsA );

// Create the center vertex and UV for the top
vecUVsA.x = 0.75;
//vecUVsA.y = 0.75;
oMap.appendPnt2Vec( vecUVsA );

// Create the vertices and UVs for the sides
for( i = 0; i < nSides; i += 1 ){
nAngle = ((Math.PI * 2) * i) / nSides;
nSinAngle = Math.sin( nAngle );
nCosAngle = Math.cos( nAngle );

// Create an extra UV for the bottom
vecUVsA.x = (nSinAngle * 0.25) + 0.25;
vecUVsA.y = (nCosAngle * 0.25) + 0.75;
oMap.appendPnt2Vec( vecUVsA );

for( j = 0; j < nVerts; j += 1 ){
oFacetMesh.addVertex( x, nSize * j / nSegments, z );

vecUVsB.x = i / nSides;
vecUVsB.y = (j / (nVerts - 1)) * 0.5;
oMap.appendPnt2Vec( vecUVsB );
}

// Create an extra UV for the top
vecUVsA.x += 0.5;
vecUVsA.y = -(vecUVsA.y - 0.75) + 0.75;
oMap.appendPnt2Vec( vecUVsA );
}

// Create UVs for the seam
var nSeam = oMap.getNumValues();
vecUVsB.x = 1;
for( i = 0; i < nVerts; i += 1 ){
vecUVsB.y = (i / (nVerts - 1)) * 0.5;
oMap.appendPnt2Vec( vecUVsB );
}

// Pre-size the facet array; faster than dynamic resizing
oFacetMesh.preSizeFacets( nSides * (nSegments + 2) );

// Create the faces
var nUVs = nVerts + 2;
var aVertexIndices = new Array( 4 );
var aUvIndices = new Array( 4 );
for( i = 0; i < nSides; i += 1 ){
nNext = i + 1;
if( nNext >= nSides ){
bAtSeam = true;
nNext = 0;
}

aVertexIndices[0] = 0;
aUvIndices[0] = 0;

aVertexIndices[1] = nNext * nVerts + 2;
aUvIndices[1] = nNext * nUVs + 2;

aVertexIndices[2] = i * nVerts + 2;
aUvIndices[2] = i * nUVs + 2;

aVertexIndices[3] = -1;
aUvIndices[3] = -1;

for( j = 0; j < nSegments; j += 1 ){
aVertexIndices[0] = i * nVerts + 2 + j;
aUvIndices[0] = i * nUVs + 3 + j;

aVertexIndices[1] = nNext * nVerts + 2 + j;
aUvIndices[1] = bAtSeam ? nSeam + j : ( nNext * nUVs + 3 + j );

aVertexIndices[2] = nNext * nVerts + 3 + j;
aUvIndices[2] = bAtSeam ? nSeam + j + 1 : ( nNext * nUVs + 4 + j );

aVertexIndices[3] = i * nVerts + 3 + j;
aUvIndices[3] = i * nUVs + 4 + j;

}

aVertexIndices[0] = 1;
aUvIndices[0] = 1;

aVertexIndices[1] = ( i + 1 ) * nVerts + 1;
aUvIndices[1] = ( i + 1 ) * nUVs + 1;

aVertexIndices[2] = ( nNext + 1 ) * nVerts + 1;
aUvIndices[2] = ( nNext + 1 ) * nUVs + 1;

aVertexIndices[3] = -1;
aUvIndices[3] = -1;

}

// Finish editing the mesh
oFacetMesh.finishEdit();

// Set the mesh for the shape
oFacetShape.setFacetMesh( oFacetMesh );

// Add the shape to the object

// Add the object to the node
oNode.setObject( oObject );

// Get the local bounding box
var boxLocal = oNode.getLocalBoundingBox();
var vecMax = boxLocal.max;
var vecMin = boxLocal.min;

// If the user chose the object center for the origin
if( sOrigin == "Object Center" ){
// Get the middle of the height of the box
var nMid = (vecMax.y + vecMin.y) * 0.5;

// Set the origin; default and current
var vecOrigin = new DzVec3(0, nMid, 0);
oNode.setOrigin( vecOrigin, true );
oNode.setOrigin( vecOrigin );
}

// If the height of the bounding box is less than
// 1 unit (1cm) tall, set it to be 1 unit tall
if( vecMax.y < 1 ){
vecMax.y = 1;
}

// Set the end point; default and current
var vecEndPoint = new DzVec3( 0, vecMax.y, 0 );
oNode.setEndPoint( vecEndPoint, true );
oNode.setEndPoint( vecEndPoint );

// Get the presentation for the node
var oPresentation = oNode.getPresentation();

// If the node did not have a presentation,
// create one and assign it to the node
if( !oPresentation ){
oPresentation = new DzPresentation();
oNode.setPresentation( oPresentation );
}

// Set the type of node
oPresentation.type = "Prop";

// Add the node to the scene