extrusion geometry
777515
function (shape, curve, path3D, shapePaths, scale, rotation, scaleFunction, rotateFunction, cap, custom) {
                var tangents = path3D.getTangents();
                var normals = path3D.getNormals();
                var binormals = path3D.getBinormals();
                var distances = path3D.getDistances();
                var angle = 0;
                var returnScale = function () { return scale; };
                var returnRotation = function () { return rotation; };
                var rotate = custom ? rotateFunction : returnRotation;
                var scl = custom ? scaleFunction : returnScale;
                var index = (cap === BABYLON.Mesh.NO_CAP || cap === BABYLON.Mesh.CAP_END) ? 0 : 2;
                var rotationMatrix = BABYLON.Tmp.Matrix[0];
                for (var i = 0; i < curve.length; i++) {
                    var shapePath = new Array();
                    var angleStep = rotate(i, distances[i]);
                    var scaleRatio = scl(i, distances[i]);
                    for (var p = 0; p < shape.length; p++) {
                        BABYLON.Matrix.RotationAxisToRef(tangents[i], angle, rotationMatrix);
                        var planed = ((tangents[i].scale(shape[p].z)).add(normals[i].scale(shape[p].x)).add(binormals[i].scale(shape[p].y)));
                        var rotated = shapePath[p] ? shapePath[p] : BABYLON.Vector3.Zero();
                        BABYLON.Vector3.TransformCoordinatesToRef(planed, rotationMatrix, rotated);
                        rotated.scaleInPlace(scaleRatio).addInPlace(curve[i]);
                        shapePath[p] = rotated;
                    }
                    shapePaths[index] = shapePath;
                    angle += angleStep;
                    index++;
                }
                // cap
                var capPath = function (shapePath) {
                    var pointCap = Array();
                    var barycenter = BABYLON.Vector3.Zero();
                    var i;
                    for (i = 0; i < shapePath.length; i++) {
                        barycenter.addInPlace(shapePath[i]);
                    }
                    barycenter.scaleInPlace(1.0 / shapePath.length);
                    for (i = 0; i < shapePath.length; i++) {
                        pointCap.push(barycenter);
                    }
                    return pointCap;
                };
                switch (cap) {
                    case BABYLON.Mesh.NO_CAP:
                        break;
                    case BABYLON.Mesh.CAP_START:
                        shapePaths[0] = capPath(shapePaths[2]);
                        shapePaths[1] = shapePaths[2];
                        break;
                    case BABYLON.Mesh.CAP_END:
                        shapePaths[index] = shapePaths[index - 1];
                        shapePaths[index + 1] = capPath(shapePaths[index - 1]);
                        break;
                    case BABYLON.Mesh.CAP_ALL:
                        shapePaths[0] = capPath(shapePaths[2]);
                        shapePaths[1] = shapePaths[2];
                        shapePaths[index] = shapePaths[index - 1];
                        shapePaths[index + 1] = capPath(shapePaths[index - 1]);
                        break;
                    default:
                        break;
                }
                return shapePaths;
            }
425334
function ( shapes, curveSegments ) {

	BufferGeometry.call( this );

	this.type = '';

	this.parameters = {
		shapes: shapes,
		curveSegments: curveSegments
	};

	curveSegments = curveSegments || 12;

	// buffers

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

	// helper variables

	var groupStart = 0;
	var groupCount = 0;

	// allow single and array values for "shapes" parameter

	if ( Array.isArray( shapes ) === false ) {

		addShape( shapes );

	} else {

		for ( var i = 0; i < shapes.length; i ++ ) {

			addShape( shapes[ i ] );

			this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support

			groupStart += groupCount;
			groupCount = 0;

		}

	}

	// build geometry

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


	// helper functions

	function addShape( shape ) {

		var i, l, shapeHole;

		var indexOffset = vertices.length / 3;
		var points = shape.extractPoints( curveSegments );

		var shapeVertices = points.shape;
		var shapeHoles = points.holes;

		// check direction of vertices

		if ( ShapeUtils.isClockWise( shapeVertices ) === false ) {

			shapeVertices = shapeVertices.reverse();

		}

		for ( i = 0, l = shapeHoles.length; i < l; i ++ ) {

			shapeHole = shapeHoles[ i ];

			if ( ShapeUtils.isClockWise( shapeHole ) === true ) {

				shapeHoles[ i ] = shapeHole.reverse();

			}

		}

		var faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles );

		// join vertices of inner and outer paths to a single array

		for ( i = 0, l = shapeHoles.length; i < l; i ++ ) {

			shapeHole = shapeHoles[ i ];
			shapeVertices = shapeVertices.concat( shapeHole );

		}

		// vertices, normals, uvs

		for ( i = 0, l = shapeVertices.length; i < l; i ++ ) {

			var vertex = shapeVertices[ i ];

			vertices.push( vertex.x, vertex.y, 0 );
			normals.push( 0, 0, 1 );
			uvs.push( vertex.x, vertex.y ); // world uvs

		}

		// incides

		for ( i = 0, l = faces.length; i < l; i ++ ) {

			var face = faces[ i ];

			var a = face[ 0 ] + indexOffset;
			var b = face[ 1 ] + indexOffset;
			var c = face[ 2 ] + indexOffset;

			indices.push( a, b, c );
			groupCount += 3;

		}

	}

}
827351
function ( radius, tube, radialSegments, tubularSegments, arc ) {

	BufferGeometry.call( this );

	this.type = '';

	this.parameters = {
		radius: radius,
		tube: tube,
		radialSegments: radialSegments,
		tubularSegments: tubularSegments,
		arc: arc
	};

	radius = radius || 1;
	tube = tube || 0.4;
	radialSegments = Math.floor( radialSegments ) || 8;
	tubularSegments = Math.floor( tubularSegments ) || 6;
	arc = arc || Math.PI * 2;

	// buffers

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

	// helper variables

	var center = new Vector3();
	var vertex = new Vector3();
	var normal = new Vector3();

	var j, i;

	// generate vertices, normals and uvs

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

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

			var u = i / tubularSegments * arc;
			var v = j / radialSegments * Math.PI * 2;

			// vertex

			vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u );
			vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u );
			vertex.z = tube * Math.sin( v );

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

			// normal

			center.x = radius * Math.cos( u );
			center.y = radius * Math.sin( u );
			normal.subVectors( vertex, center ).normalize();

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

			// uv

			uvs.push( i / tubularSegments );
			uvs.push( j / radialSegments );

		}

	}

	// generate indices

	for ( j = 1; j <= radialSegments; j ++ ) {

		for ( i = 1; i <= tubularSegments; i ++ ) {

			// indices

			var a = ( tubularSegments + 1 ) * j + i - 1;
			var b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1;
			var c = ( tubularSegments + 1 ) * ( j - 1 ) + i;
			var d = ( tubularSegments + 1 ) * j + i;

			// faces

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

		}

	}

	// build geometry

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

}
137483
function ( radius, detail ) {

	var t = ( 1 + Math.sqrt( 5 ) ) / 2;
	var r = 1 / t;

	var vertices = [

		// (±1, ±1, ±1)
		- 1, - 1, - 1,	- 1, - 1, 1,
		- 1, 1, - 1, - 1, 1, 1,
		1, - 1, - 1, 1, - 1, 1,
		1, 1, - 1, 1, 1, 1,

		// (0, ±1/φ, ±φ)
		 0, - r, - t, 0, - r, t,
		 0, r, - t, 0, r, t,

		// (±1/φ, ±φ, 0)
		- r, - t, 0, - r, t, 0,
		 r, - t, 0, r, t, 0,

		// (±φ, 0, ±1/φ)
		- t, 0, - r, t, 0, - r,
		- t, 0, r, t, 0, r
	];

	var indices = [
		3, 11, 7, 	3, 7, 15, 	3, 15, 13,
		7, 19, 17, 	7, 17, 6, 	7, 6, 15,
		17, 4, 8, 	17, 8, 10, 	17, 10, 6,
		8, 0, 16, 	8, 16, 2, 	8, 2, 10,
		0, 12, 1, 	0, 1, 18, 	0, 18, 16,
		6, 10, 2, 	6, 2, 13, 	6, 13, 15,
		2, 16, 18, 	2, 18, 3, 	2, 3, 13,
		18, 1, 9, 	18, 9, 11, 	18, 11, 3,
		4, 14, 12, 	4, 12, 0, 	4, 0, 8,
		11, 9, 5, 	11, 5, 19, 	11, 19, 7,
		19, 5, 14, 	19, 14, 4, 	19, 4, 17,
		1, 12, 14, 	1, 14, 5, 	1, 5, 9
	];

	PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );

	this.type = '';

	this.parameters = {
		radius: radius,
		detail: detail
	};

}
147824
function ( radius, detail ) {

	var vertices = [
		1, 1, 1, 	- 1, - 1, 1, 	- 1, 1, - 1, 	1, - 1, - 1
	];

	var indices = [
		2, 1, 0, 	0, 3, 2,	1, 3, 0,	2, 3, 1
	];

	PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );

	this.type = '';

	this.parameters = {
		radius: radius,
		detail: detail
	};

}
256549
function fillRect(x, y, width, height) {
         if (this.backBufferContext2D.globalAlpha < 1 / 255) {
           // Fast path: don't draw fully transparent
           return;
         }

         this.backBufferContext2D.fillRect(x, y, width, height);
       }
345654
function ( width, height, widthSegments, heightSegments ) {

	BufferGeometry.call( this );

	this.type = '';

	this.parameters = {
		width: width,
		height: height,
		widthSegments: widthSegments,
		heightSegments: heightSegments
	};

	width = width || 1;
	height = height || 1;

	var width_half = width / 2;
	var height_half = height / 2;

	var gridX = Math.floor( widthSegments ) || 1;
	var gridY = Math.floor( heightSegments ) || 1;

	var gridX1 = gridX + 1;
	var gridY1 = gridY + 1;

	var segment_width = width / gridX;
	var segment_height = height / gridY;

	var ix, iy;

	// buffers

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

	// generate vertices, normals and uvs

	for ( iy = 0; iy < gridY1; iy ++ ) {

		var y = iy * segment_height - height_half;

		for ( ix = 0; ix < gridX1; ix ++ ) {

			var x = ix * segment_width - width_half;

			vertices.push( x, - y, 0 );

			normals.push( 0, 0, 1 );

			uvs.push( ix / gridX );
			uvs.push( 1 - ( iy / gridY ) );

		}

	}

	// indices

	for ( iy = 0; iy < gridY; iy ++ ) {

		for ( ix = 0; ix < gridX; ix ++ ) {

			var a = ix + gridX1 * iy;
			var b = ix + gridX1 * ( iy + 1 );
			var c = ( ix + 1 ) + gridX1 * ( iy + 1 );
			var d = ( ix + 1 ) + gridX1 * iy;

			// faces

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

		}

	}

	// build geometry

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

}
1308361
private void drawShape(
            Canvas canvas,
            Paint paint,
            Path path,
            ShapeAppearanceModel shapeAppearanceModel,
            RectF bounds) {
        if (shapeAppearanceModel.isRoundRect()) {
            float cornerSize = shapeAppearanceModel.getTopRightCorner().getCornerSize();
            canvas.drawRoundRect(bounds, cornerSize, cornerSize, paint);
        } else {
            canvas.drawPath(path, paint);
        }
    }
103971
def _rewrite_geometry(geom, new_lines):
    

    new_geom = []
    x = 0
    y = 0
    for line in new_lines:
        moveto, endsat, lineto_cmds = line

        dx = moveto.x - x
        dy = moveto.y - y
        x = endsat.x
        y = endsat.y

        new_geom.append(9)  # move to, run_length = 1
        new_geom.append(zigzag(dx))
        new_geom.append(zigzag(dy))
        new_geom.extend(lineto_cmds)

    # write the lines back out to geom
    del geom[:]
    geom.extend(new_geom)
65604
function ( geometry1, object2 /* mesh | geometry */ ) {

		var matrix, matrixRotation,
		vertexOffset = geometry1.vertices.length,
		uvPosition = geometry1.faceVertexUvs[ 0 ].length,
		geometry2 = object2 instanceof THREE.Mesh ? object2.geometry : object2,
		vertices1 = geometry1.vertices,
		vertices2 = geometry2.vertices,
		faces1 = geometry1.faces,
		faces2 = geometry2.faces,
		uvs1 = geometry1.faceVertexUvs[ 0 ],
		uvs2 = geometry2.faceVertexUvs[ 0 ];

		var geo1MaterialsMap = {};

		for ( var i = 0; i < geometry1.materials.length; i ++ ) {

			var id = geometry1.materials[ i ].id;

			geo1MaterialsMap[ id ] = i;

		}

		if ( object2 instanceof THREE.Mesh ) {

			object2.matrixAutoUpdate && object2.updateMatrix();

			matrix = object2.matrix;
			matrixRotation = new THREE.Matrix4();
			matrixRotation.extractRotation( matrix, object2.scale );

		}

		// vertices

		for ( var i = 0, il = vertices2.length; i < il; i ++ ) {

			var vertex = vertices2[ i ];

			var vertexCopy = vertex.clone();

			if ( matrix ) matrix.multiplyVector3( vertexCopy );

			vertices1.push( vertexCopy );

		}

		// faces

		for ( i = 0, il = faces2.length; i < il; i ++ ) {

			var face = faces2[ i ], faceCopy, normal, color,
			faceVertexNormals = face.vertexNormals,
			faceVertexColors = face.vertexColors;

			if ( face instanceof THREE.Face3 ) {

				faceCopy = new THREE.Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset );

			} else if ( face instanceof THREE.Face4 ) {

				faceCopy = new THREE.Face4( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset, face.d + vertexOffset );

			}

			faceCopy.normal.copy( face.normal );

			if ( matrixRotation ) matrixRotation.multiplyVector3( faceCopy.normal );

			for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) {

				normal = faceVertexNormals[ j ].clone();

				if ( matrixRotation ) matrixRotation.multiplyVector3( normal );

				faceCopy.vertexNormals.push( normal );

			}

			faceCopy.color.copy( face.color );

			for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) {

				color = faceVertexColors[ j ];
				faceCopy.vertexColors.push( color.clone() );

			}

			if ( face.materialIndex !== undefined ) {

				var material2 = geometry2.materials[ face.materialIndex ];
				var materialId2 = material2.id;

				var materialIndex = geo1MaterialsMap[ materialId2 ];

				if ( materialIndex === undefined ) {

					materialIndex = geometry1.materials.length;
					geo1MaterialsMap[ materialId2 ] = materialIndex;

					geometry1.materials.push( material2 );

				}

				faceCopy.materialIndex = materialIndex;

			}

			faceCopy.centroid.copy( face.centroid );
			if ( matrix ) matrix.multiplyVector3( faceCopy.centroid );

			faces1.push( faceCopy );

		}

		// uvs

		for ( i = 0, il = uvs2.length; i < il; i ++ ) {

			var uv = uvs2[ i ], uvCopy = [];

			for ( var j = 0, jl = uv.length; j < jl; j ++ ) {

				uvCopy.push( new THREE.UV( uv[ j ].u, uv[ j ].v ) );

			}

			uvs1.push( uvCopy );

		}

	}
248089
private void buildVertexes()
	{
		vertexes.clear();
		if (controlPoints.size() == 0)
			return;

		double step = 1D / (precision + 1);
		double t = 0;
		vertexes.add(controlPoints.get(0));
		for (int i = 1; i <= precision; i++)
		{
			t = i * step;
			vertexes.add(i, interpolateAll(controlPoints, controlPoints.size() - 1, 0, t));
		}
		vertexes.add(controlPoints.get(controlPoints.size() - 1));

		dirty = false;
	}
631200
def extrude(
        self,
        input_entity,
        translation_axis=None,
        rotation_axis=None,
        point_on_axis=None,
        angle=None,
        num_layers=None,
        recombine=False,
    ):
        
        self._EXTRUDE_ID += 1

        if _is_string(input_entity):
            entity = Dummy(input_entity)
        elif isinstance(input_entity, PointBase):
            entity = Dummy("Point{{{}}}".format(input_entity.id))
        elif isinstance(input_entity, SurfaceBase):
            entity = Dummy("Surface{{{}}}".format(input_entity.id))
        elif hasattr(input_entity, "surface"):
            entity = Dummy("Surface{{{}}}".format(input_entity.surface.id))
        else:
            assert isinstance(input_entity, LineBase), "Illegal extrude entity."
            entity = Dummy("Line{{{}}}".format(input_entity.id))

        extrusion_string = ""

        # out[] = Extrude{0,1,0}{ Line{1}; };
        name = "ex{}".format(self._EXTRUDE_ID)
        if translation_axis is not None:
            if rotation_axis is not None:
                extrusion_string += "{}[] = Extrude{{{{{}}}, {{{}}}, {{{}}}, {}}}{{{};".format(
                    name,
                    ",".join(repr(x) for x in translation_axis),
                    ",".join(repr(x) for x in rotation_axis),
                    ",".join(repr(x) for x in point_on_axis),
                    angle,
                    entity.id,
                )
            else:
                # Only translation
                extrusion_string += "{}[] = Extrude {{{}}} {{{};".format(
                    name, ",".join(repr(x) for x in translation_axis), entity.id
                )
        else:
            assert (
                rotation_axis is not None
            ), "Specify at least translation or rotation."
            # Only rotation
            extrusion_string += "{}[] = Extrude{{{{{}}}, {{{}}}, {}}}{{{};".format(
                name,
                ",".join(repr(x) for x in rotation_axis),
                ",".join(repr(x) for x in point_on_axis),
                angle,
                entity.id,
            )

        if num_layers is not None:
            extrusion_string += " Layers{{{}}}; {}".format(
                num_layers, "Recombine;" if recombine else ""
            )

        # close command
        extrusion_string += "};"
        self._GMSH_CODE.append(extrusion_string)

        # From <https://www.manpagez.com/info/gmsh/gmsh-2.4.0/gmsh_66.php>:
        #
        # > In this last extrusion command we retrieved the volume number
        # > programatically by saving the output of the command into a
        # > list. This list will contain the "top" of the extruded surface (in
        # > out[0]) as well as the newly created volume (in out[1]).
        #
        top = "{}[0]".format(name)
        extruded = "{}[1]".format(name)

        if isinstance(input_entity, LineBase):
            top = LineBase(top)
            # A surface extruded from a single line has always 4 edges
            extruded = SurfaceBase(extruded, 4)
        elif isinstance(input_entity, SurfaceBase):
            top = SurfaceBase(top, input_entity.num_edges)
            extruded = VolumeBase(extruded)
        elif isinstance(input_entity, PointBase):
            top = PointBase(top)
            extruded = LineBase(extruded)
        else:
            top = Dummy(top)
            extruded = Dummy(extruded)

        lat = []
        # lateral surfaces can be deduced only if we start from a SurfaceBase
        if isinstance(input_entity, SurfaceBase):
            # out[0]` is the surface, out[1] the top, and everything after that
            # the sides, cf.
            # <https://gmsh.info/doc/texinfo/gmsh.html#Extrusions>. Each
            # lateral surface has 4 edges: the one from input_entity, the one
            # from top, and the two lines (or splines) connecting their extreme
            # points.
            lat = [
                SurfaceBase("{}[{}]".format(name, i + 2), 4)
                for i in range(input_entity.num_edges)
            ]

        return top, extruded, lat
797286
function Hexagon(diameter, height) {
  var radius = diameter / 2;
  var sqrt3 = Math.sqrt(3) / 2;
  var hex = CAG.fromPoints([
    [radius, 0],
    [radius / 2, radius * sqrt3],
    [-radius / 2, radius * sqrt3],
    [-radius, 0],
    [-radius / 2, -radius * sqrt3],
    [radius / 2, -radius * sqrt3]
  ]);

  return hex.extrude({
    offset: [0, 0, height]
  });
}
405546
def vertices(self):
        
        if self._v_out is None:
            output = qhalf('Fp', self.halfspaces, self.interior_point)
            pts = []
            for l in output[2:]:
                pt = []
                for c in l.split():
                    c = float(c)
                    if c != 10.101 and c != -10.101:
                        pt.append(c)
                    else:
                        pt.append(np.inf)
                pts.append(pt)
            self._v_out = np.array(pts)
        return self._v_out
636671
def diam_floc_vel_term(ConcAl, ConcClay, coag, material,
                       DIM_FRACTAL, VelTerm, Temp):
    """"""
    WaterDensity = pc.density_water(Temp).magnitude
    return (material.Diameter * (((18 * VelTerm * PHI_FLOC
                          * pc.viscosity_kinematic(Temp).magnitude
                          )
                         / (pc.gravity.magnitude * material.Diameter**2)
                         )
                         * (WaterDensity
                            / (dens_floc_init(ConcAl, ConcClay, coag,
                                              material).magnitude
                               - WaterDensity
                               )
                            )
                        ) ** (1 / (DIM_FRACTAL - 1))
            )
798901
public static GeometryCollection extrudeLineStringAsGeometry(LineString lineString, double height){
        Geometry[] geometries = new Geometry[3];        
        GeometryFactory factory = lineString.getFactory();
        //Extract the walls        
        Coordinate[] coords = lineString.getCoordinates();
        Polygon[] walls = new Polygon[coords.length - 1];
        for (int i = 0; i < coords.length - 1; i++) {
            walls[i] = extrudeEdge(coords[i], coords[i + 1], height, factory);
        }
        lineString.apply(new TranslateCoordinateSequenceFilter(0));
        geometries[0]= lineString;
        geometries[1]=  factory.createMultiPolygon(walls);        
        geometries[2]= extractRoof(lineString, height);
        return factory.createGeometryCollection(geometries);
    }
1254479
def writeMesh(self, vertices, faces, normals, values,
                  name='', reshape_faces=True):
        

        # Store properties
        self._hasNormals = normals is not None
        self._hasValues = values is not None
        self._hasFaces = faces is not None

        # Get faces and number of vertices
        if faces is None:
            faces = np.arange(len(vertices))
            reshape_faces = True

        if reshape_faces:
            Nfaces = faces.size // 3
            faces = faces.reshape((Nfaces, 3))
        else:
            is_triangular = np.array([len(f) == 3
                                      for f in faces])
            if not(np.all(is_triangular)):
                logger.warning('''Faces doesn't appear to be triangular,
                be advised the file cannot be read back in vispy''')
        # Number of vertices
        N = vertices.shape[0]

        # Get string with stats
        stats = []
        stats.append('%i vertices' % N)
        if self._hasValues:
            stats.append('%i texcords' % N)
        else:
            stats.append('no texcords')
        if self._hasNormals:
            stats.append('%i normals' % N)
        else:
            stats.append('no normals')
        stats.append('%i faces' % faces.shape[0])

        # Write header
        self.writeLine('# Wavefront OBJ file')
        self.writeLine('# Created by vispy.')
        self.writeLine('#')
        if name:
            self.writeLine('# object %s' % name)
        else:
            self.writeLine('# unnamed object')
        self.writeLine('# %s' % ', '.join(stats))
        self.writeLine('')

        # Write data
        if True:
            for i in range(N):
                self.writeTuple(vertices[i], 'v')
        if self._hasNormals:
            for i in range(N):
                self.writeTuple(normals[i], 'vn')
        if self._hasValues:
            for i in range(N):
                self.writeTuple(values[i], 'vt')
        if True:
            for i in range(faces.shape[0]):
                self.writeFace(faces[i])