Beispiel #1
0
        public IEnumerable <MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals)
        {
            var numSides = (int)_numSides.GetValue();

            if (numSides < 3)
            {
                yield break;
            }

            // This is all very similar to the cylinder brush.
            var width  = box.Width;
            var length = box.Length;
            var major  = width / 2;
            var minor  = length / 2;
            var angle  = 2 * DMath.PI / numSides;

            var points = new Coordinate[numSides];

            for (var i = 0; i < numSides; i++)
            {
                var a    = i * angle;
                var xval = box.Center.X + major * DMath.Cos(a);
                var yval = box.Center.Y + minor * DMath.Sin(a);
                var zval = box.Start.Z;
                points[i] = new Coordinate(xval, yval, zval).Round(roundDecimals);
            }

            var faces = new List <Coordinate[]>();

            var point = new Coordinate(box.Center.X, box.Center.Y, box.End.Z).Round(roundDecimals);

            for (var i = 0; i < numSides; i++)
            {
                var next = (i + 1) % numSides;
                faces.Add(new[] { points[i], point, points[next] });
            }
            faces.Add(points.ToArray());

            var solid = new Solid(generator.GetNextObjectID())
            {
                Colour = Colour.GetRandomBrushColour()
            };

            foreach (var arr in faces)
            {
                var face = new Face(generator.GetNextFaceID())
                {
                    Parent  = solid,
                    Plane   = new Plane(arr[0], arr[1], arr[2]),
                    Colour  = solid.Colour,
                    Texture = { Texture = texture }
                };
                face.Vertices.AddRange(arr.Select(x => new Vertex(x, face)));
                face.UpdateBoundingBox();
                face.AlignTextureToFace();
                solid.Faces.Add(face);
            }
            solid.UpdateBoundingBox();
            yield return(solid);
        }
Beispiel #2
0
        public IEnumerable <MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals)
        {
            var wallWidth = _wallWidth.GetValue();

            if (wallWidth < 1)
            {
                yield break;
            }
            var numSides = (int)_numSides.GetValue();

            if (numSides < 3)
            {
                yield break;
            }

            // Very similar to the cylinder, except we have multiple solids this time
            var width    = box.Width;
            var length   = box.Length;
            var height   = box.Height;
            var majorOut = width / 2;
            var majorIn  = majorOut - wallWidth;
            var minorOut = length / 2;
            var minorIn  = minorOut - wallWidth;
            var angle    = 2 * DMath.PI / numSides;

            // Calculate the X and Y points for the inner and outer ellipses
            var outer = new Coordinate[numSides];
            var inner = new Coordinate[numSides];

            for (var i = 0; i < numSides; i++)
            {
                var a    = i * angle;
                var xval = box.Center.X + majorOut * DMath.Cos(a);
                var yval = box.Center.Y + minorOut * DMath.Sin(a);
                var zval = box.Start.Z;
                outer[i] = new Coordinate(xval, yval, zval).Round(roundDecimals);
                xval     = box.Center.X + majorIn * DMath.Cos(a);
                yval     = box.Center.Y + minorIn * DMath.Sin(a);
                inner[i] = new Coordinate(xval, yval, zval).Round(roundDecimals);
            }

            // Create the solids
            var colour = Colour.GetRandomBrushColour();
            var z      = new Coordinate(0, 0, height).Round(roundDecimals);

            for (var i = 0; i < numSides; i++)
            {
                var faces = new List <Coordinate[]>();
                var next  = (i + 1) % numSides;
                faces.Add(new[] { outer[i], outer[i] + z, outer[next] + z, outer[next] });
                faces.Add(new[] { inner[next], inner[next] + z, inner[i] + z, inner[i] });
                faces.Add(new[] { outer[next], outer[next] + z, inner[next] + z, inner[next] });
                faces.Add(new[] { inner[i], inner[i] + z, outer[i] + z, outer[i] });
                faces.Add(new[] { inner[next] + z, outer[next] + z, outer[i] + z, inner[i] + z });
                faces.Add(new[] { inner[i], outer[i], outer[next], inner[next] });
                yield return(MakeSolid(generator, faces, texture, colour));
            }
        }
Beispiel #3
0
        public IEnumerable <IMapObject> Create(UniqueNumberGenerator generator, Box box, string texture, int roundDecimals)
        {
            var numSides = (int)_numSides.GetValue();

            if (numSides < 3)
            {
                yield break;
            }

            // This is all very similar to the cylinder brush.
            var width  = box.Width;
            var length = box.Length;
            var major  = width / 2;
            var minor  = length / 2;
            var angle  = 2 * Math.PI / numSides;

            var points = new Vector3[numSides];

            for (var i = 0; i < numSides; i++)
            {
                var a    = i * angle;
                var xval = box.Center.X + major * (float)Math.Cos(a);
                var yval = box.Center.Y + minor * (float)Math.Sin(a);
                var zval = box.Start.Z;
                points[i] = new Vector3(xval, yval, zval).Round(roundDecimals);
            }

            var faces = new List <Vector3[]>();

            var point = new Vector3(box.Center.X, box.Center.Y, box.End.Z).Round(roundDecimals);

            for (var i = 0; i < numSides; i++)
            {
                var next = (i + 1) % numSides;
                faces.Add(new[] { points[i], point, points[next] });
            }
            faces.Add(points.ToArray());

            var solid = new Solid(generator.Next("MapObject"));

            solid.Data.Add(new ObjectColor(Colour.GetRandomBrushColour()));
            foreach (var arr in faces)
            {
                var face = new Face(generator.Next("Face"))
                {
                    Plane   = new Plane(arr[0], arr[1], arr[2]),
                    Texture = { Name = texture }
                };
                face.Vertices.AddRange(arr);
                solid.Data.Add(face);
            }
            solid.DescendantsChanged();
            yield return(solid);
        }
Beispiel #4
0
        public IEnumerable <MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals)
        {
            var numSides = (int)_numSides.GetValue();

            if (numSides < 3)
            {
                yield break;
            }
            var wallWidth = _wallWidth.GetValue();

            if (wallWidth < 1)
            {
                yield break;
            }
            var arc = _arc.GetValue();

            if (arc < 1)
            {
                yield break;
            }
            var startAngle = _startAngle.GetValue();

            if (startAngle < 0 || startAngle > 359)
            {
                yield break;
            }
            var addHeight  = _addHeight.GetValue();
            var curvedRamp = _curvedRamp.GetValue();
            var tiltAngle  = curvedRamp ? _tiltAngle.GetValue() : 0;

            if (DMath.Abs(tiltAngle % 180) == 90)
            {
                yield break;
            }
            var tiltInterp = curvedRamp && _tiltInterp.GetValue();

            // Very similar to the pipe brush, except with options for start angle, arc, height and tilt
            var width  = box.Width;
            var length = box.Length;
            var height = box.Height;

            var majorOut = width / 2;
            var majorIn  = majorOut - wallWidth;
            var minorOut = length / 2;
            var minorIn  = minorOut - wallWidth;

            var start = DMath.DegreesToRadians(startAngle);
            var tilt  = DMath.DegreesToRadians(tiltAngle);
            var angle = DMath.DegreesToRadians(arc) / numSides;

            // Calculate the coordinates of the inner and outer ellipses' points
            var outer = new Coordinate[numSides + 1];
            var inner = new Coordinate[numSides + 1];

            for (var i = 0; i < numSides + 1; i++)
            {
                var a          = start + i * angle;
                var h          = i * addHeight;
                var interp     = tiltInterp ? DMath.Cos(DMath.PI / numSides * (i - numSides / 2M)) : 1;
                var tiltHeight = wallWidth / 2 * interp * DMath.Tan(tilt);

                var xval = box.Center.X + majorOut * DMath.Cos(a);
                var yval = box.Center.Y + minorOut * DMath.Sin(a);
                var zval = box.Start.Z + (curvedRamp ? h + tiltHeight : 0);
                outer[i] = new Coordinate(xval, yval, zval).Round(roundDecimals);

                xval     = box.Center.X + majorIn * DMath.Cos(a);
                yval     = box.Center.Y + minorIn * DMath.Sin(a);
                zval     = box.Start.Z + (curvedRamp ? h - tiltHeight : 0);
                inner[i] = new Coordinate(xval, yval, zval).Round(roundDecimals);
            }

            // Create the solids
            var colour = Colour.GetRandomBrushColour();
            var z      = new Coordinate(0, 0, height).Round(roundDecimals);

            for (var i = 0; i < numSides; i++)
            {
                var faces = new List <Coordinate[]>();

                // Since we are triangulating/splitting each arch segment, we need to generate 2 brushes per side
                if (curvedRamp)
                {
                    // The splitting orientation depends on the curving direction of the arch
                    if (addHeight >= 0)
                    {
                        faces.Add(new[] { outer[i], outer[i] + z, outer[i + 1] + z, outer[i + 1] });
                        faces.Add(new[] { outer[i + 1], outer[i + 1] + z, inner[i] + z, inner[i] });
                        faces.Add(new[] { inner[i], inner[i] + z, outer[i] + z, outer[i] });
                        faces.Add(new[] { outer[i] + z, inner[i] + z, outer[i + 1] + z });
                        faces.Add(new[] { outer[i + 1], inner[i], outer[i] });
                    }
                    else
                    {
                        faces.Add(new[] { inner[i + 1], inner[i + 1] + z, inner[i] + z, inner[i] });
                        faces.Add(new[] { outer[i], outer[i] + z, inner[i + 1] + z, inner[i + 1] });
                        faces.Add(new[] { inner[i], inner[i] + z, outer[i] + z, outer[i] });
                        faces.Add(new[] { inner[i + 1] + z, outer[i] + z, inner[i] + z });
                        faces.Add(new[] { inner[i], outer[i], inner[i + 1] });
                    }
                    yield return(MakeSolid(generator, faces, texture, colour));

                    faces.Clear();

                    if (addHeight >= 0)
                    {
                        faces.Add(new[] { inner[i + 1], inner[i + 1] + z, inner[i] + z, inner[i] });
                        faces.Add(new[] { inner[i], inner[i] + z, outer[i + 1] + z, outer[i + 1] });
                        faces.Add(new[] { outer[i + 1], outer[i + 1] + z, inner[i + 1] + z, inner[i + 1] });
                        faces.Add(new[] { inner[i + 1] + z, outer[i + 1] + z, inner[i] + z });
                        faces.Add(new[] { inner[i], outer[i + 1], inner[i + 1] });
                    }
                    else
                    {
                        faces.Add(new[] { outer[i], outer[i] + z, outer[i + 1] + z, outer[i + 1] });
                        faces.Add(new[] { inner[i + 1], inner[i + 1] + z, outer[i] + z, outer[i] });
                        faces.Add(new[] { outer[i + 1], outer[i + 1] + z, inner[i + 1] + z, inner[i + 1] });
                        faces.Add(new[] { outer[i] + z, inner[i + 1] + z, outer[i + 1] + z });
                        faces.Add(new[] { outer[i + 1], inner[i + 1], outer[i] });
                    }
                    yield return(MakeSolid(generator, faces, texture, colour));
                }
                else
                {
                    var h = i * addHeight * Coordinate.UnitZ;
                    faces.Add(new[] { outer[i], outer[i] + z, outer[i + 1] + z, outer[i + 1] }.Select(x => x + h).ToArray());
                    faces.Add(new[] { inner[i + 1], inner[i + 1] + z, inner[i] + z, inner[i] }.Select(x => x + h).ToArray());
                    faces.Add(new[] { outer[i + 1], outer[i + 1] + z, inner[i + 1] + z, inner[i + 1] }.Select(x => x + h).ToArray());
                    faces.Add(new[] { inner[i], inner[i] + z, outer[i] + z, outer[i] }.Select(x => x + h).ToArray());
                    faces.Add(new[] { inner[i + 1] + z, outer[i + 1] + z, outer[i] + z, inner[i] + z }.Select(x => x + h).ToArray());
                    faces.Add(new[] { inner[i], outer[i], outer[i + 1], inner[i + 1] }.Select(x => x + h).ToArray());
                    yield return(MakeSolid(generator, faces, texture, colour));
                }
            }
        }
Beispiel #5
0
        public IEnumerable <MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals)
        {
            var numSides = (int)_numSides.GetValue();

            if (numSides < 3)
            {
                yield break;
            }

            // Cylinders can be elliptical so use both major and minor rather than just the radius
            // NOTE: when a low number (< 10ish) of faces are selected this will cause the cylinder to not touch all the edges of the box.
            var width  = box.Width;
            var length = box.Length;
            var height = box.Height;
            var major  = width / 2;
            var minor  = length / 2;
            var angle  = 2 * DMath.PI / numSides;

            // Calculate the X and Y points for the ellipse
            var points = new Coordinate[numSides];

            for (var i = 0; i < numSides; i++)
            {
                var a    = i * angle;
                var xval = box.Center.X + major * DMath.Cos(a);
                var yval = box.Center.Y + minor * DMath.Sin(a);
                var zval = box.Start.Z;
                points[i] = new Coordinate(xval, yval, zval).Round(roundDecimals);
            }

            var faces = new List <Coordinate[]>();

            // Add the vertical faces
            var z = new Coordinate(0, 0, height).Round(roundDecimals);

            for (var i = 0; i < numSides; i++)
            {
                var next = (i + 1) % numSides;
                faces.Add(new[] { points[i], points[i] + z, points[next] + z, points[next] });
            }
            // Add the elliptical top and bottom faces
            faces.Add(points.ToArray());
            faces.Add(points.Select(x => x + z).Reverse().ToArray());

            // Nothing new here, move along
            var solid = new Solid(generator.GetNextObjectID())
            {
                Colour = Colour.GetRandomBrushColour()
            };

            foreach (var arr in faces)
            {
                var face = new Face(generator.GetNextFaceID())
                {
                    Parent  = solid,
                    Plane   = new Plane(arr[0], arr[1], arr[2]),
                    Colour  = solid.Colour,
                    Texture = { Texture = texture }
                };
                face.Vertices.AddRange(arr.Select(x => new Vertex(x, face)));
                face.UpdateBoundingBox();
                face.AlignTextureToFace();
                solid.Faces.Add(face);
            }
            solid.UpdateBoundingBox();
            yield return(solid);
        }
Beispiel #6
0
        public IEnumerable <MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals)
        {
            var crossSides = (int)_crossSides.GetValue();

            if (crossSides < 3)
            {
                yield break;
            }
            var crossWidth = _crossRadius.GetValue() * 2;

            if (crossWidth < 1)
            {
                yield break;
            }
            var crossMakeHollow = _crossMakeHollow.GetValue();
            var crossArc        = !crossMakeHollow ? 360 : (int)_crossArc.GetValue();

            if (crossArc < 1)
            {
                yield break;
            }
            var crossStartAngle = (int)_crossStartAngle.GetValue();

            if (crossStartAngle < 0 || crossStartAngle > 359)
            {
                yield break;
            }
            var crossWallWidth = _crossWallWidth.GetValue();

            if (crossWallWidth < 1)
            {
                yield break;
            }
            var ringSides = (int)_ringSides.GetValue();

            if (ringSides < 3)
            {
                yield break;
            }
            var ringArc = (int)_ringArc.GetValue();

            if (ringArc < 1)
            {
                yield break;
            }
            var ringStartAngle = (int)_ringStartAngle.GetValue();

            if (ringStartAngle < 0 || ringStartAngle > 359)
            {
                yield break;
            }
            var rotationHeight = _rotationHeight.GetValue();

            // Sort of a combination of cylinder and pipe brushes
            var width               = box.Width;
            var length              = box.Length;
            var height              = box.Height;
            var majorPrimary        = (width - crossWidth) / 2;          // Primary = donut circle
            var minorPrimary        = (length - crossWidth) / 2;
            var majorSecondaryOuter = crossWidth / 2;                    // Secondary = cross section circle
            var minorSecondaryOuter = height / 2;                        // Outer = Outer ring
            var majorSecondaryInner = (crossWidth - crossWallWidth) / 2; // Inner = inner ring (hollow only)
            var minorSecondaryInner = (height - crossWallWidth) / 2;

            var ringStart  = DMath.DegreesToRadians(ringStartAngle);
            var ringAngle  = DMath.DegreesToRadians(ringArc) / ringSides;
            var crossStart = DMath.DegreesToRadians(crossStartAngle);
            var crossAngle = DMath.DegreesToRadians(crossArc) / crossSides;
            var heightAdd  = rotationHeight / ringSides;

            // Rotate around the ring, generating each cross section
            var ringOuterSections = new List <Coordinate[]>();
            var ringInnerSections = new List <Coordinate[]>();

            for (var i = 0; i < ringSides + 1; i++)
            {
                var ring          = ringStart + i * ringAngle;
                var rxval         = box.Center.X + majorPrimary * DMath.Cos(ring);
                var ryval         = box.Center.Y + minorPrimary * DMath.Sin(ring);
                var rzval         = box.Center.Z;
                var crossSecOuter = new Coordinate[crossSides + 1];
                var crossSecInner = new Coordinate[crossSides + 1];
                for (var j = 0; j < crossSides + 1; j++)
                {
                    var cross = crossStart + j * crossAngle;
                    var xval  = majorSecondaryOuter * DMath.Cos(cross) * DMath.Cos(ring);
                    var yval  = majorSecondaryOuter * DMath.Cos(cross) * DMath.Sin(ring);
                    var zval  = minorSecondaryOuter * DMath.Sin(cross);
                    crossSecOuter[j] = new Coordinate(xval + rxval, yval + ryval, zval + rzval).Round(roundDecimals);
                    if (!crossMakeHollow)
                    {
                        continue;
                    }
                    xval             = majorSecondaryInner * DMath.Cos(cross) * DMath.Cos(ring);
                    yval             = majorSecondaryInner * DMath.Cos(cross) * DMath.Sin(ring);
                    zval             = minorSecondaryInner * DMath.Sin(cross);
                    crossSecInner[j] = new Coordinate(xval + rxval, yval + ryval, zval + rzval).Round(roundDecimals);
                }
                ringOuterSections.Add(crossSecOuter);
                ringInnerSections.Add(crossSecInner);
            }

            // Create the solids
            var colour = Colour.GetRandomBrushColour();

            for (var i = 0; i < ringSides; i++)
            {
                var vertical = Coordinate.UnitZ * heightAdd * i;
                var nexti    = i + 1;
                if (crossMakeHollow)
                {
                    // Use pipe cross sections
                    var outerPoints     = ringOuterSections[i];
                    var nextOuterPoints = ringOuterSections[nexti];
                    var innerPoints     = ringInnerSections[i];
                    var nextInnerPoints = ringInnerSections[nexti];
                    for (var j = 0; j < crossSides; j++)
                    {
                        var nextj = j + 1;
                        var faces = new List <Coordinate[]>();
                        faces.Add(new[] { outerPoints[j], outerPoints[nextj], nextOuterPoints[nextj], nextOuterPoints[j] }.Select(x => x + vertical).ToArray());
                        faces.Add(new[] { nextInnerPoints[j], nextInnerPoints[nextj], innerPoints[nextj], innerPoints[j] }.Select(x => x + vertical).ToArray());
                        faces.Add(new[] { innerPoints[nextj], nextInnerPoints[nextj], nextOuterPoints[nextj], outerPoints[nextj] }.Select(x => x + vertical).ToArray());
                        faces.Add(new[] { outerPoints[j], nextOuterPoints[j], nextInnerPoints[j], innerPoints[j] }.Select(x => x + vertical).ToArray());
                        faces.Add(new[] { innerPoints[j], innerPoints[nextj], outerPoints[nextj], outerPoints[j] }.Select(x => x + vertical).ToArray());
                        faces.Add(new[] { nextOuterPoints[j], nextOuterPoints[nextj], nextInnerPoints[nextj], nextInnerPoints[j] }.Select(x => x + vertical).ToArray());
                        yield return(MakeSolid(generator, faces, texture, colour));
                    }
                }
                else
                {
                    // Use cylindrical cross sections
                    var faces      = new List <Coordinate[]>();
                    var points     = ringOuterSections[i];
                    var nextPoints = ringOuterSections[nexti];
                    // Add the outer faces
                    for (var j = 0; j < crossSides; j++)
                    {
                        var nextj = (j + 1) % crossSides;
                        faces.Add(new[] { points[j], points[nextj], nextPoints[nextj], nextPoints[j] }.Select(x => x + vertical).ToArray());
                    }
                    // Add the cross section faces
                    faces.Add(points.Reverse().Select(x => x + vertical).ToArray());
                    faces.Add(nextPoints.Select(x => x + vertical).ToArray());
                    yield return(MakeSolid(generator, faces, texture, colour));
                }
            }
        }
Beispiel #7
0
        public IEnumerable <MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals)
        {
            var numSides = (int)_numSides.GetValue();

            if (numSides < 3)
            {
                yield break;
            }

            var width        = box.Width;
            var length       = box.Length;
            var height       = box.Height;
            var major        = width / 2;
            var minor        = length / 2;
            var heightRadius = height / 2;

            var angleV = DMath.DegreesToRadians(180) / numSides;
            var angleH = DMath.DegreesToRadians(360) / numSides;

            var faces  = new List <Coordinate[]>();
            var bottom = new Coordinate(box.Center.X, box.Center.Y, box.Start.Z).Round(roundDecimals);
            var top    = new Coordinate(box.Center.X, box.Center.Y, box.End.Z).Round(roundDecimals);

            for (var i = 0; i < numSides; i++)
            {
                // Top -> bottom
                var zAngleStart = angleV * i;
                var zAngleEnd   = angleV * (i + 1);
                var zStart      = heightRadius * DMath.Cos(zAngleStart);
                var zEnd        = heightRadius * DMath.Cos(zAngleEnd);
                var zMultStart  = DMath.Sin(zAngleStart);
                var zMultEnd    = DMath.Sin(zAngleEnd);
                for (var j = 0; j < numSides; j++)
                {
                    // Go around the circle in X/Y
                    var xyAngleStart = angleH * j;
                    var xyAngleEnd   = angleH * ((j + 1) % numSides);
                    var xyStartX     = major * DMath.Cos(xyAngleStart);
                    var xyStartY     = minor * DMath.Sin(xyAngleStart);
                    var xyEndX       = major * DMath.Cos(xyAngleEnd);
                    var xyEndY       = minor * DMath.Sin(xyAngleEnd);
                    var one          = (new Coordinate(xyStartX * zMultStart, xyStartY * zMultStart, zStart) + box.Center).Round(roundDecimals);
                    var two          = (new Coordinate(xyEndX * zMultStart, xyEndY * zMultStart, zStart) + box.Center).Round(roundDecimals);
                    var three        = (new Coordinate(xyEndX * zMultEnd, xyEndY * zMultEnd, zEnd) + box.Center).Round(roundDecimals);
                    var four         = (new Coordinate(xyStartX * zMultEnd, xyStartY * zMultEnd, zEnd) + box.Center).Round(roundDecimals);
                    if (i == 0)
                    {
                        // Top faces are triangles
                        faces.Add(new[] { top, three, four });
                    }
                    else if (i == numSides - 1)
                    {
                        // Bottom faces are also triangles
                        faces.Add(new[] { bottom, one, two });
                    }
                    else
                    {
                        // Inner faces are quads
                        faces.Add(new[] { one, two, three, four });
                    }
                }
            }
            yield return(MakeSolid(generator, faces, texture, Colour.GetRandomBrushColour()));
        }
        public IEnumerable <IMapObject> Create(UniqueNumberGenerator generator, Box box, string texture, int roundDecimals)
        {
            var numSides = (int)_numSides.GetValue();

            if (numSides < 3)
            {
                yield break;
            }

            // Cylinders can be elliptical so use both major and minor rather than just the radius
            // NOTE: when a low number (< 10ish) of faces are selected this will cause the cylinder to not touch all the edges of the box.
            var width  = box.Width;
            var length = box.Length;
            var height = box.Height;
            var major  = width / 2;
            var minor  = length / 2;
            var angle  = 2 * (float)Math.PI / numSides;

            // Calculate the X and Y points for the ellipse
            var points = new Vector3[numSides];

            for (var i = 0; i < numSides; i++)
            {
                var a    = i * angle;
                var xval = box.Center.X + major * (float)Math.Cos(a);
                var yval = box.Center.Y + minor * (float)Math.Sin(a);
                var zval = box.Start.Z;
                points[i] = new Vector3(xval, yval, zval).Round(roundDecimals);
            }

            var faces = new List <Vector3[]>();

            // Add the vertical faces
            var z = new Vector3(0, 0, height).Round(roundDecimals);

            for (var i = 0; i < numSides; i++)
            {
                var next = (i + 1) % numSides;
                faces.Add(new[] { points[i], points[i] + z, points[next] + z, points[next] });
            }

            // Add the elliptical top and bottom faces
            faces.Add(points.ToArray());
            faces.Add(points.Select(x => x + z).Reverse().ToArray());

            // Nothing new here, move along
            var solid = new Solid(generator.Next("MapObject"));

            solid.Data.Add(new ObjectColor(Colour.GetRandomBrushColour()));

            foreach (var arr in faces)
            {
                var face = new Face(generator.Next("Face"))
                {
                    Plane   = new Plane(arr[0], arr[1], arr[2]),
                    Texture = { Name = texture }
                };
                face.Vertices.AddRange(arr);
                solid.Data.Add(face);
            }
            solid.DescendantsChanged();
            yield return(solid);
        }