public static SurfaceComponentGeometry CreateExtrudedPolygonCapGeometry(
        float radius, float height, int segmentP, int segmentH, float topRatio = 1, int surfaceGroup = 0, RenderGeometry.FaceType faceType = RenderGeometry.FaceType.Smooth,
        bool splitBoundary = false)
    {
        if (topRatio == 0)
        {
            return(CreateConeCapGeometry(radius, height, segmentP, segmentH, 0, surfaceGroup, faceType, splitBoundary));
        }
        if (topRatio == 1 && height == 0)
        {
            return(CreateRegularPolygonGeometry(radius, segmentP, surfaceGroup, RenderGeometry.FaceType.Polygonal, true));
        }

        StructureGeometry structure = new StructureGeometry();

        SurfaceComponentGeometry upperCap = CreateRegularPolygonGeometry(radius * topRatio, segmentP, surfaceGroup + 1);
        SurfaceComponentGeometry side     = CreateConeSideGeometry(radius, radius * topRatio, height, segmentP, segmentH, 0, false, surfaceGroup, faceType);

        side.ApplyOffset(Vector3.up * (height / 2));

        Vertex cornerUp   = structure.CreateVertex(new Vector3(radius * topRatio, height, 0));
        Vertex cornerDown = structure.CreateVertex(new Vector3(radius, 0, 0));

        structure.CreateFace(side, false, cornerUp, cornerUp, cornerDown, cornerDown);
        structure.CreateFace(upperCap, true, cornerUp);

        SurfaceComponentGeometry geometry = new SurfaceComponentGeometry(structure.Build());

        geometry.DefineBoundaries(structure.GetBuiltVertex(cornerDown));
        if (splitBoundary)
        {
            geometry.SplitBoundaries();
        }
        return(geometry);
    }
Example #2
0
        private RenderGeometry ReplaceAllFace(RenderGeometry original, Func <Face, SurfaceComponentGeometry> surfaceProvider)
        {
            var structure = new StructureGeometry(original);

            structure.faces.ForEach(f => structure.SetFaceComponent(f, surfaceProvider(f), true));
            return(structure.Build());
        }
Example #3
0
    public static SurfaceComponentGeometry CreateDiamondCenterOctaSplitSquareGeometry(
        float sizeX, float sizeZ, int segmentX, int segmentZ, float diamondRatio = 0.6f, int surfaceGroup = 0, RenderGeometry.FaceType faceType = RenderGeometry.FaceType.Polygonal)
    {
        SurfaceComponentGeometry planeGeometry = SurfaceComponentGeometries.CreatePlaneGeometry(sizeX, sizeZ, segmentX, segmentZ);
        List <Vertex>            corners       = planeGeometry.corners;

        var structure    = new StructureGeometry(planeGeometry);
        var edgesToMerge = new List <Halfedge>();

        structure.faces.ForEach(f => {
            var component = CreateSingleDiamondCenterOctaSplitSquareGeometry(1, 1, diamondRatio, surfaceGroup, faceType);
            edgesToMerge.AddRange(component.boundaries.SelectMany(b => b).Select(e => e.opposite));
            structure.SetFaceComponent(f, component, true);
        });
        var geometry = new SurfaceComponentGeometry(structure.Build());

        foreach (Halfedge edge in edgesToMerge)
        {
            if (edge.index >= 0 && !edge.opposite.isBoundary)
            {
                geometry.MergeFaces(edge);
            }
        }
        geometry.DefineBoundaries(corners.Select(structure.GetBuiltVertex).ToArray());

        return(geometry);
    }
    public static RenderGeometry CreateTurningRampGeometry(
        float width, float height, float angle, float extraRadius, int segmentWidth, int segmentLength, bool smoothWidth, bool smoothLength, RampType rampType = RampType.Right, float curvature = 0,
        float baseHeight = 0, float highSideWidth = 0, float lowSideWidth = 0)
    {
        StructureGeometry structure = new StructureGeometry();

        RenderGeometry.FaceType rampFaceType = GetFaceType(smoothWidth, smoothLength);
        RenderGeometry.FaceType sideFaceType = GetFaceType(false, smoothLength);

        return(structure.Build());
    }
    public static RenderGeometry CreateSphereGeometry(float radius, int segmentP, int segmentH, bool smoothH, bool smoothV, float cutTop = 0, float cutBottom = 0)
    {
        if (cutTop + cutBottom > 1)
        {
            return(new RenderGeometry());
        }

        RenderGeometry.FaceType  faceType = GetFaceType(smoothH, smoothV);
        StructureGeometry        structure = new StructureGeometry();
        SurfaceComponentGeometry upperPart, lowerPart, middlePart;

        if (cutTop != 0)
        {
            upperPart = SurfaceComponentGeometries.CreateRegularPolygonGeometry(radius * Mathf.Sqrt(4 * cutTop * (1 - cutTop)), segmentP, 2);
            upperPart.ApplyOffset(radius * (1 - 2 * cutTop) * Vector3.up);
        }
        else
        {
            float angle = cutBottom != 0 ? Mathf.Acos(-1 + cutBottom * 2) : Mathf.PI * (segmentH / 2) / segmentH;
            upperPart = SurfaceComponentGeometries.CreateSphereCapGeometry(radius, segmentP, cutBottom != 0 ? segmentH : segmentH / 2, 2 * angle, 0, 1, faceType);
        }
        if (cutBottom != 0)
        {
            lowerPart = SurfaceComponentGeometries.CreateRegularPolygonGeometry(radius * Mathf.Sqrt(4 * cutBottom * (1 - cutBottom)), segmentP, 2);
            lowerPart.ApplyOffset(radius * (1 - 2 * cutBottom) * Vector3.up);
            lowerPart.ApplyRotation(Quaternion.AngleAxis(180, Vector3.right));
        }
        else
        {
            float angle = cutTop != 0 ? Mathf.Acos(-1 + cutTop * 2) : Mathf.PI * ((segmentH + 1) / 2) / segmentH;
            lowerPart = SurfaceComponentGeometries.CreateSphereCapGeometry(radius, segmentP, cutTop != 0 ? segmentH : (segmentH + 1) / 2, 2 * angle, 0, 1, faceType);
            lowerPart.ApplyRotation(Quaternion.AngleAxis(180, Vector3.right));
        }
        if (cutTop != 0 && cutBottom != 0)
        {
            float angle1 = Mathf.Acos(1 - cutTop * 2);
            float angle2 = Mathf.Acos(-1 + cutBottom * 2);
            middlePart = SurfaceComponentGeometries.CreateSphereSideGeometry(radius, angle1, angle2, segmentP, segmentH, 0, 1, faceType);

            Vertex cornerUp   = structure.CreateVertex();
            Vertex cornerDown = structure.CreateVertex();
            structure.CreateFace(middlePart, false, cornerUp, cornerUp, cornerDown, cornerDown);
            structure.CreateFace(upperPart, false, cornerUp);
            structure.CreateFace(lowerPart, false, cornerDown);
        }
        else
        {
            Vertex corner = structure.CreateVertex();
            structure.CreateFace(upperPart, false, corner);
            structure.CreateFace(lowerPart, false, corner);
        }
        return(structure.Build());
    }
    private static RenderGeometry CreateTetrahedronGeometryInternal(float size, Func <SurfaceComponentGeometry> surfaceGenerator)
    {
        StructureGeometry structure = new StructureGeometry();

        Vertex v1 = structure.CreateVertex(new Vector3(-1, -1, 1) * (size / 2));
        Vertex v2 = structure.CreateVertex(new Vector3(-1, 1, -1) * (size / 2));
        Vertex v3 = structure.CreateVertex(new Vector3(1, -1, -1) * (size / 2));
        Vertex v4 = structure.CreateVertex(new Vector3(1, 1, 1) * (size / 2));

        structure.CreateFace(surfaceGenerator.Invoke(), true, v1, v2, v3);
        structure.CreateFace(surfaceGenerator.Invoke(), true, v1, v4, v2);
        structure.CreateFace(surfaceGenerator.Invoke(), true, v2, v4, v3);
        structure.CreateFace(surfaceGenerator.Invoke(), true, v3, v4, v1);
        return(structure.Build());
    }
Example #7
0
    public static SurfaceComponentGeometry CreateDiamondCenterCrossSplitSquareGeometry(
        float sizeX, float sizeZ, int segmentX, int segmentZ, float diamondRatio = 0.6f, int surfaceGroup = 0, RenderGeometry.FaceType faceType = RenderGeometry.FaceType.Polygonal)
    {
        SurfaceComponentGeometry planeGeometry = SurfaceComponentGeometries.CreatePlaneGeometry(sizeX, sizeZ, segmentX, segmentZ);
        List <Vertex>            corners       = planeGeometry.corners;

        var structure = new StructureGeometry(planeGeometry);

        structure.faces.ForEach(f => structure.SetFaceComponent(f, CreateSingleDiamondCenterCrossSplitSquareGeometry(1, 1, diamondRatio, surfaceGroup, faceType), true));
        var geometry = new SurfaceComponentGeometry(structure.Build());

        geometry.DefineBoundaries(corners.Select(structure.GetBuiltVertex).ToArray());

        return(geometry);
    }
Example #8
0
    public static SurfaceComponentGeometry CreateSplitTriangleGeometry(
        float sizeBase, float sizeHeight, float offsetTop, int segment, int surfaceGroup = 0, RenderGeometry.FaceType faceType = RenderGeometry.FaceType.Polygonal)
    {
        SurfaceComponentGeometry triangleGeometry = SurfaceComponentGeometries.CreateTriangleGeometry(sizeBase, sizeHeight, offsetTop, segment, false);
        List <Vertex>            corners          = triangleGeometry.corners;

        var structure = new StructureGeometry(triangleGeometry);

        structure.faces.ForEach(f => structure.SetFaceComponent(f, CreateSingleSplitTriangleGeometry(1, 1, 0, surfaceGroup, faceType), true));
        var geometry = new SurfaceComponentGeometry(structure.Build());

        geometry.DefineBoundaries(corners.Select(structure.GetBuiltVertex).ToArray());

        return(geometry);
    }
    private static RenderGeometry CreateOctahedronGeometryInternal(float size, Func <SurfaceComponentGeometry> surfaceGenerator)
    {
        StructureGeometry structure = new StructureGeometry();

        var corners = new Dictionary <IntVector3, Vertex>();

        foreach (var keyAndPosition in VertexSymmetryGroup("100", Key(1, 0, 0), Vector3.right * (size / 2)))
        {
            corners[keyAndPosition.Key] = structure.CreateVertex(keyAndPosition.Value);
        }
        foreach (IntVector3[] keys in FaceSymmetryGroup("111", Key(1, 0, 0), Key(0, 1, 0), Key(0, 0, 1)))
        {
            structure.CreateFace(surfaceGenerator.Invoke(), true, keys.Select(key => corners[key]).ToArray());
        }
        return(structure.Build());
    }
Example #10
0
    public static SurfaceComponentGeometry CreateTrianglesCombinedRegularPolygonGeometry(float radius, int segmentP, Func <SurfaceComponentGeometry> triangleSurfaceComponentProvider)
    {
        SurfaceComponentGeometry polygonGeometry = SurfaceComponentGeometries.CreateFanCapGeometry(radius, segmentP, 1);

        polygonGeometry.SplitBoundaries();
        List <Vertex> corners = polygonGeometry.corners;

        var structure = new StructureGeometry(polygonGeometry);

        structure.faces.ForEach(f => structure.SetFaceComponent(f, triangleSurfaceComponentProvider(), true));
        var geometry = new SurfaceComponentGeometry(structure.Build());

        geometry.DefineBoundaries(corners.Select(structure.GetBuiltVertex).ToArray());

        return(geometry);
    }
    public static RenderGeometry CreateConeGeometry(float radius, float height, int segmentP, int segmentH, bool smoothH, bool smoothV, float cutTop = 0, float cutAngle = 0)
    {
        if (cutTop == 0)
        {
            StructureGeometry       structure = new StructureGeometry();
            RenderGeometry.FaceType faceType  = GetFaceType(smoothH, smoothV);

            SurfaceComponentGeometry coneCap = SurfaceComponentGeometries.CreateConeCapGeometry(radius, height, segmentP, segmentH, cutAngle, 1, faceType);
            if (cutAngle == 0)
            {
                SurfaceComponentGeometry bottom = SurfaceComponentGeometries.CreateRegularPolygonGeometry(radius, segmentP, 2);
                bottom.ApplyRotation(Quaternion.AngleAxis(180, Vector3.right));

                Vertex corner = structure.CreateVertex();
                structure.CreateFace(coneCap, false, corner);
                structure.CreateFace(bottom, false, corner);
            }
            else
            {
                SurfaceComponentGeometry bottom = SurfaceComponentGeometries.CreateFanCapGeometry(radius, segmentP, 1, cutAngle, 2);
                SurfaceComponentGeometry wall1  = SurfaceComponentGeometries.CreateTriangleGeometry(1, 1, 0, segmentH, true, 3);
                SurfaceComponentGeometry wall2  = SurfaceComponentGeometries.CreateTriangleGeometry(1, 1, 0, segmentH, true, 4);

                Vertex cornerUp    = structure.CreateVertex(new Vector3(0, height, 0));
                Vertex cornerDownC = structure.CreateVertex(Vector3.zero);
                Vertex cornerDown1 = structure.CreateVertex(new Vector3(radius * Mathf.Cos(cutAngle), 0, -radius * Mathf.Sin(cutAngle)));
                Vertex cornerDown2 = structure.CreateVertex(new Vector3(radius, 0, 0));

                structure.CreateFace(coneCap, true, cornerDown1, cornerDown2, cornerUp);
                structure.CreateFace(bottom, true, cornerDown2, cornerDown1, cornerDownC);
                structure.CreateFace(wall1, true, cornerDown1, cornerUp, cornerDownC);
                structure.CreateFace(wall2, true, cornerDownC, cornerUp, cornerDown2);
            }
            return(structure.Build());
        }
        else
        {
            RenderGeometry geometry = CreateCylinderGeometry(radius, height, segmentP, segmentH, smoothH, smoothV, cutAngle);
            geometry.ApplyOffset(Vector3.up * (height / 2));

            float     shrinkCoeff = (1 - cutTop) / height;
            SpaceWarp warp        = new SpaceWarp($"x*(1-y*{shrinkCoeff})", "y", $"z*(1-y*{shrinkCoeff})");
            geometry.ApplySpaceWarp(warp);
            return(geometry);
        }
    }
    private static RenderGeometry CreateCubeGeometryInternal(Vector3 size, Func <int, SurfaceComponentGeometry> surfaceGenerator)
    {
        StructureGeometry structure = new StructureGeometry();

        var corners = new Dictionary <IntVector3, Vertex>();

        foreach (var keyAndPosition in VertexSymmetryGroup("111", Key(1, 1, 1), Vector3.one))
        {
            corners[keyAndPosition.Key] = structure.CreateVertex(keyAndPosition.Value.Times(size / 2));
        }
        foreach (Symmetry symmetry in Symmetry.SymmetryGroup("100"))
        {
            Vertex[] verts = symmetry.Apply(Key(1, -1, -1), Key(1, 1, -1), Key(1, 1, 1), Key(1, -1, 1)).Select(key => corners[key]).ToArray();
            structure.CreateFace(surfaceGenerator.Invoke(symmetry.rotation), true, verts);
        }
        return(structure.Build());
    }
    public static RenderGeometry CreateSpringGeometry(float ringRadius, float barRadius, float heightPerCycle, int segmentPerCycle, int segmentBar, bool smoothH, bool smoothV, float angle = 0, float deltaAngle = 0)
    {
        StructureGeometry structure = new StructureGeometry();

        RenderGeometry.FaceType faceType = GetFaceType(smoothH, smoothV);
        float heightPerRad = heightPerCycle / (2 * Mathf.PI);
        float slope        = heightPerRad / ringRadius;
        float scaleH       = Mathf.Sqrt(1 + slope * slope);
        int   segmentRing  = Mathf.CeilToInt(segmentPerCycle * angle / (2 * Mathf.PI) - 1e-6f);

        SurfaceComponentGeometry face = SurfaceComponentGeometries.CreatePlaneGeometry(1, 1, segmentBar, segmentRing, 1, faceType);

        var warp = new SpaceWarp(
            $" a1=(z+0.5)*{angle}",
            $" a2={deltaAngle}-x*(2*PI)",
            $" r={ringRadius}+{barRadius}*cos(a2)",
            $" X=r*cos(a1)",
            $" Y={scaleH}*{barRadius}*sin(a2)+a1*{heightPerRad}",
            $" Z=r*sin(a1)"
            );

        face.ApplySpaceWarp(warp);

        SurfaceComponentGeometry cap1 = SurfaceComponentGeometries.CreateRegularPolygonGeometry(barRadius, segmentBar, 2);
        SurfaceComponentGeometry cap2 = SurfaceComponentGeometries.CreateRegularPolygonGeometry(barRadius, segmentBar, 2);

        cap1.ApplyLinearTransform(
            Matrix4x4.Translate(Vector3.right * ringRadius) *
            Matrix4x4.Scale(new Vector3(1, scaleH, 1)) *
            Matrix4x4.Rotate(Quaternion.LookRotation(Vector3.down, Vector3.back) * Quaternion.AngleAxis(-deltaAngle * Mathf.Rad2Deg, Vector3.up)));
        cap2.ApplyLinearTransform(
            Matrix4x4.Translate(new Vector3(ringRadius * Mathf.Cos(angle), heightPerRad * angle, ringRadius * Mathf.Sin(angle))) *
            Matrix4x4.Scale(new Vector3(1, scaleH, 1)) *
            Matrix4x4.Rotate(Quaternion.LookRotation(Vector3.up, Quaternion.AngleAxis(angle * Mathf.Rad2Deg, Vector3.down) * Vector3.forward) * Quaternion.AngleAxis(deltaAngle * Mathf.Rad2Deg, Vector3.up)));

        Vertex corner1 = structure.CreateVertex();
        Vertex corner2 = structure.CreateVertex();

        structure.CreateFace(face, false, corner1, corner2, corner2, corner1);
        structure.CreateFace(cap1, false, corner1);
        structure.CreateFace(cap2, false, corner2);
        return(structure.Build());
    }
Example #14
0
    public static SurfaceComponentGeometry CreateXSplitSquareGeometry(
        float sizeX, float sizeZ, int segmentX, int segmentZ, float spikeHeight = 0, int surfaceGroup = 0, RenderGeometry.FaceType faceType = RenderGeometry.FaceType.Polygonal)
    {
        var           planeGeometry = SurfaceComponentGeometries.CreatePlaneGeometry(sizeX, sizeZ, segmentX, segmentZ);
        List <Vertex> corners       = planeGeometry.corners;

        var structure  = new StructureGeometry(planeGeometry);
        var coneHeight = spikeHeight / (sizeZ / segmentZ) * Mathf.Sqrt(2);

        structure.faces.ForEach(f => {
            var component = SurfaceComponentGeometries.CreateConeCapGeometry(1, coneHeight, 4, 1, 0, surfaceGroup, faceType);
            component.SplitBoundaries();
            structure.SetFaceComponent(f, component, true);
        });
        var geometry = new SurfaceComponentGeometry(structure.Build());

        geometry.DefineBoundaries(corners.Select(structure.GetBuiltVertex).ToArray());

        return(geometry);
    }
    public static RenderGeometry CreateTorusGeometry(float ringRadius, float barRadius, int segmentRing, int segmentBar, bool smoothH, bool smoothV, float cutAngle = 0, float deltaAngle = 0)
    {
        StructureGeometry structure = new StructureGeometry();

        RenderGeometry.FaceType faceType = GetFaceType(smoothH, smoothV);

        SurfaceComponentGeometry face = SurfaceComponentGeometries.CreatePlaneGeometry(1, 1, segmentBar, segmentRing, 1, faceType);

        var warp = new SpaceWarp(
            $" a1=(z+0.5)*(2*PI-{cutAngle})",
            $" a2={deltaAngle}-x*(2*PI)",
            $" r={ringRadius}+{barRadius}*cos(a2)",
            $" X=r*cos(a1)",
            $" Y={barRadius}*sin(a2)",
            $" Z=r*sin(a1)"
            );

        face.ApplySpaceWarp(warp);

        if (cutAngle == 0)
        {
            Vertex corner = structure.CreateVertex();
            structure.CreateFace(face, false, corner, corner, corner, corner);
        }
        else
        {
            SurfaceComponentGeometry cap1 = SurfaceComponentGeometries.CreateRegularPolygonGeometry(barRadius, segmentBar, 2);
            SurfaceComponentGeometry cap2 = SurfaceComponentGeometries.CreateRegularPolygonGeometry(barRadius, segmentBar, 2);
            cap1.ApplyRotation(Quaternion.LookRotation(Vector3.down, Vector3.back) * Quaternion.AngleAxis(-deltaAngle, Vector3.up));
            cap1.ApplyOffset(Vector3.right * ringRadius);
            cap2.ApplyRotation(Quaternion.LookRotation(Vector3.up, Quaternion.AngleAxis(cutAngle * Mathf.Rad2Deg, Vector3.up) * Vector3.forward) * Quaternion.AngleAxis(deltaAngle * Mathf.Rad2Deg, Vector3.up));
            cap2.ApplyOffset(new Vector3(ringRadius * Mathf.Cos(cutAngle), 0, -ringRadius * Mathf.Sin(cutAngle)));

            Vertex corner1 = structure.CreateVertex();
            Vertex corner2 = structure.CreateVertex();
            structure.CreateFace(face, false, corner1, corner2, corner2, corner1);
            structure.CreateFace(cap1, false, corner1);
            structure.CreateFace(cap2, false, corner2);
        }
        return(structure.Build());
    }
    public static RenderGeometry CreateCapsuleGeometry(float radius, float height, int segmentP, int segmentH1, int segmentH2, bool smoothH, bool smoothV)
    {
        StructureGeometry structure = new StructureGeometry();

        RenderGeometry.FaceType faceType = GetFaceType(smoothH, smoothV);

        SurfaceComponentGeometry side = SurfaceComponentGeometries.CreateCylinderSideGeometry(radius, height, segmentP, segmentH1, faceType: faceType);

        SurfaceComponentGeometry upperCap = SurfaceComponentGeometries.CreateSphereCapGeometry(radius, segmentP, segmentH2, faceType: faceType);
        SurfaceComponentGeometry lowerCap = SurfaceComponentGeometries.CreateSphereCapGeometry(radius, segmentP, segmentH2, faceType: faceType);

        lowerCap.ApplyRotation(Quaternion.AngleAxis(180, Vector3.right));

        Vertex cornerUp   = structure.CreateVertex(new Vector3(radius, height / 2, 0));
        Vertex cornerDown = structure.CreateVertex(new Vector3(radius, -height / 2, 0));

        structure.CreateFace(side, false, cornerUp, cornerUp, cornerDown, cornerDown);
        structure.CreateFace(upperCap, true, cornerUp);
        structure.CreateFace(lowerCap, true, cornerDown);
        return(structure.Build());
    }
    private static void CreateStraightPlatformPart(
        StructureGeometry structure,
        Vertex cornerTopLeft1, Vertex cornerTopLeft2, Vertex cornerTopRight1, Vertex cornerTopRight2,
        Vertex cornerBottomLeft1, Vertex cornerBottomLeft2, Vertex cornerBottomRight1, Vertex cornerBottomRight2,
        bool addLeftSide, bool addRightSide, int segmentLength, RenderGeometry.FaceType sideFaceType)
    {
        SurfaceComponentGeometry topFace    = SurfaceComponentGeometries.CreatePlaneGeometry(1, 1, 1, segmentLength, 0, sideFaceType);
        SurfaceComponentGeometry bottomFace = SurfaceComponentGeometries.CreatePlaneGeometry(1, 1, 1, segmentLength, 1, sideFaceType);

        if (cornerTopLeft1 == cornerBottomLeft1)
        {
            // Copy vertices since it is a flat face.
            Vertex cornerLeft1  = structure.CreateVertex(cornerBottomLeft1.p);
            Vertex cornerLeft2  = structure.CreateVertex(cornerBottomLeft2.p);
            Vertex cornerRight1 = structure.CreateVertex(cornerBottomRight1.p);
            Vertex cornerRight2 = structure.CreateVertex(cornerBottomRight2.p);
            structure.CreateFace(topFace, true, cornerLeft1, cornerLeft2, cornerRight2, cornerRight1);
            structure.CreateFace(bottomFace, true, cornerRight1, cornerRight2, cornerLeft2, cornerLeft1);
        }
        else
        {
            SurfaceComponentGeometry backFace  = SurfaceComponentGeometries.CreatePlaneGeometry(1, 1, 1, 1, 4, RenderGeometry.FaceType.Polygonal);
            SurfaceComponentGeometry frontFace = SurfaceComponentGeometries.CreatePlaneGeometry(1, 1, 1, 1, 5, RenderGeometry.FaceType.Polygonal);
            structure.CreateFace(topFace, true, cornerTopLeft1, cornerTopLeft2, cornerTopRight2, cornerTopRight1);
            structure.CreateFace(bottomFace, true, cornerBottomRight1, cornerBottomRight2, cornerBottomLeft2, cornerBottomLeft1);
            structure.CreateFace(backFace, true, cornerBottomLeft1, cornerTopLeft1, cornerTopRight1, cornerBottomRight1);
            structure.CreateFace(frontFace, true, cornerBottomRight2, cornerTopRight2, cornerTopLeft2, cornerBottomLeft2);

            if (addLeftSide)
            {
                SurfaceComponentGeometry leftFace = SurfaceComponentGeometries.CreatePlaneGeometry(1, 1, 1, segmentLength, 2, sideFaceType);
                structure.CreateFace(leftFace, true, cornerBottomLeft1, cornerBottomLeft2, cornerTopLeft2, cornerTopLeft1);
            }
            if (addRightSide)
            {
                SurfaceComponentGeometry rightFace = SurfaceComponentGeometries.CreatePlaneGeometry(1, 1, 1, segmentLength, 3, sideFaceType);
                structure.CreateFace(rightFace, true, cornerTopRight1, cornerTopRight2, cornerBottomRight2, cornerBottomRight1);
            }
        }
    }
    private static RenderGeometry CreateIcosahedronGeometryInternal(float size, Func <SurfaceComponentGeometry> surfaceGenerator)
    {
        StructureGeometry structure = new StructureGeometry();

        float goldenRatio = (1 + Mathf.Sqrt(5)) / 2;
        float dL          = size / 2;
        float dS          = dL / goldenRatio;

        var corners = new Dictionary <IntVector3, Vertex>();

        foreach (var keyAndPosition in VertexSymmetryGroup("110", Key(1, 1, 0), Vec(dL, dS, 0)))
        {
            corners[keyAndPosition.Key] = structure.CreateVertex(keyAndPosition.Value);
        }
        foreach (IntVector3[] keys in Combine(
                     FaceSymmetryGroup("101", Key(1, 1, 0), Key(1, 0, 1), Key(1, -1, 0)),
                     FaceSymmetryGroup("111", Key(1, 1, 0), Key(0, 1, 1), Key(1, 0, 1))))
        {
            structure.CreateFace(surfaceGenerator.Invoke(), true, keys.Select(key => corners[key]).ToArray());
        }
        return(structure.Build());
    }
    public static RenderGeometry CreateStraightRampGeometry(
        float width, float height, float length, int segmentWidth, int segmentLength, bool smoothWidth, bool smoothLength, RampType rampType = RampType.Right, float curvature = 0,
        float baseHeight = 0, float highPlatformWidth = 0, float lowPlatformWidth = 0)
    {
        StructureGeometry structure = new StructureGeometry();

        RenderGeometry.FaceType rampFaceType = GetFaceType(smoothWidth, smoothLength);
        RenderGeometry.FaceType sideFaceType = GetFaceType(false, smoothLength);

        float leftPlatformHeight   = (rampType == RampType.Left || rampType == RampType.Peak ? 0 : height) + baseHeight;
        float rightPlatformHeight  = (rampType == RampType.Right || rampType == RampType.Peak ? 0 : height) + baseHeight;
        float middlePlatformHeight = (rampType == RampType.Valley ? 0 : height) + baseHeight;

        float leftPlatformWidth   = ((rampType == RampType.Left || rampType == RampType.Peak) ? lowPlatformWidth : highPlatformWidth);
        float rightPlatformWidth  = ((rampType == RampType.Right || rampType == RampType.Peak) ? lowPlatformWidth : highPlatformWidth);
        float middlePlatformWidth = (rampType == RampType.Valley ? lowPlatformWidth : (rampType == RampType.Peak ? highPlatformWidth : 0));

        float leftX  = -width / 2 - middlePlatformWidth / 2;
        float rightX = width / 2 + middlePlatformWidth / 2;

        bool   isLeftTopAndBottomSameVertex  = (rampType == RampType.Left || rampType == RampType.Peak) && baseHeight == 0;
        bool   isRightTopAndBottomSameVertex = (rampType == RampType.Right || rampType == RampType.Peak) && baseHeight == 0;
        Vertex cornerBottomLeft1             = structure.CreateVertex(new Vector3(leftX, 0, -length / 2));
        Vertex cornerBottomLeft2             = structure.CreateVertex(new Vector3(leftX, 0, length / 2));
        Vertex cornerBottomRight1            = structure.CreateVertex(new Vector3(rightX, 0, -length / 2));
        Vertex cornerBottomRight2            = structure.CreateVertex(new Vector3(rightX, 0, length / 2));
        Vertex cornerTopLeft1  = isLeftTopAndBottomSameVertex ? cornerBottomLeft1 : structure.CreateVertex(new Vector3(leftX, leftPlatformHeight, -length / 2));
        Vertex cornerTopLeft2  = isLeftTopAndBottomSameVertex ? cornerBottomLeft2 : structure.CreateVertex(new Vector3(leftX, leftPlatformHeight, length / 2));
        Vertex cornerTopRight1 = isRightTopAndBottomSameVertex ? cornerBottomRight1 : structure.CreateVertex(new Vector3(rightX, rightPlatformHeight, -length / 2));
        Vertex cornerTopRight2 = isRightTopAndBottomSameVertex ? cornerBottomRight2 : structure.CreateVertex(new Vector3(rightX, rightPlatformHeight, length / 2));

        if (rampType == RampType.Left || rampType == RampType.Right)
        {
            CreateStraightRampPart(
                structure, rampType == RampType.Left,
                cornerTopLeft1, cornerTopLeft2, cornerTopRight1, cornerTopRight2,
                cornerBottomLeft1, cornerBottomLeft2, cornerBottomRight1, cornerBottomRight2,
                leftPlatformWidth == 0, rightPlatformWidth == 0, segmentWidth, segmentLength, curvature, rampFaceType, sideFaceType);
        }
        else
        {
            bool   isMiddleTopAndBottomSameVertex = rampType == RampType.Valley && baseHeight == 0;
            bool   isMiddleLeftAndRightSameVertex = middlePlatformWidth == 0 && !isMiddleTopAndBottomSameVertex;
            Vertex cornerBottomMiddleLeft1        = structure.CreateVertex(new Vector3(-middlePlatformWidth / 2, 0, -length / 2));
            Vertex cornerBottomMiddleLeft2        = structure.CreateVertex(new Vector3(-middlePlatformWidth / 2, 0, length / 2));
            Vertex cornerBottomMiddleRight1       = isMiddleLeftAndRightSameVertex ? cornerBottomMiddleLeft1 : structure.CreateVertex(new Vector3(middlePlatformWidth / 2, 0, -length / 2));
            Vertex cornerBottomMiddleRight2       = isMiddleLeftAndRightSameVertex ? cornerBottomMiddleLeft2 : structure.CreateVertex(new Vector3(middlePlatformWidth / 2, 0, length / 2));
            Vertex cornerTopMiddleLeft1           = isMiddleTopAndBottomSameVertex ? cornerBottomMiddleLeft1 : structure.CreateVertex(new Vector3(-middlePlatformWidth / 2, middlePlatformHeight, -length / 2));
            Vertex cornerTopMiddleLeft2           = isMiddleTopAndBottomSameVertex ? cornerBottomMiddleLeft2 : structure.CreateVertex(new Vector3(-middlePlatformWidth / 2, middlePlatformHeight, length / 2));
            Vertex cornerTopMiddleRight1          = isMiddleTopAndBottomSameVertex ? cornerBottomMiddleRight1 : structure.CreateVertex(new Vector3(middlePlatformWidth / 2, middlePlatformHeight, -length / 2));
            Vertex cornerTopMiddleRight2          = isMiddleTopAndBottomSameVertex ? cornerBottomMiddleRight2 : structure.CreateVertex(new Vector3(middlePlatformWidth / 2, middlePlatformHeight, length / 2));
            CreateStraightRampPart(
                structure, rampType == RampType.Peak,
                cornerTopLeft1, cornerTopLeft2, cornerTopMiddleLeft1, cornerTopMiddleLeft2,
                cornerBottomLeft1, cornerBottomLeft2, cornerBottomMiddleLeft1, cornerBottomMiddleLeft2,
                leftPlatformWidth == 0, false, segmentWidth, segmentLength, curvature, rampFaceType, sideFaceType);
            CreateStraightRampPart(
                structure, rampType == RampType.Valley,
                cornerTopMiddleRight1, cornerTopMiddleRight2, cornerTopRight1, cornerTopRight2,
                cornerBottomMiddleRight1, cornerBottomMiddleRight2, cornerBottomRight1, cornerBottomRight2,
                false, rightPlatformWidth == 0, segmentWidth, segmentLength, curvature, rampFaceType, sideFaceType);
            if (middlePlatformWidth > 0)
            {
                CreateStraightPlatformPart(
                    structure,
                    cornerTopMiddleLeft1, cornerTopMiddleLeft2, cornerTopMiddleRight1, cornerTopMiddleRight2,
                    cornerBottomMiddleLeft1, cornerBottomMiddleLeft2, cornerBottomMiddleRight1, cornerBottomMiddleRight2,
                    false, false, segmentLength, sideFaceType);
            }
        }

        if (leftPlatformWidth > 0)
        {
            Vertex cornerBottomFarLeft1 = structure.CreateVertex(cornerBottomLeft1.p + leftPlatformWidth * Vector3.left);
            Vertex cornerBottomFarLeft2 = structure.CreateVertex(cornerBottomLeft2.p + leftPlatformWidth * Vector3.left);
            Vertex cornerTopFarLeft1    = cornerTopLeft1 == cornerBottomLeft1 ? cornerBottomFarLeft1 : structure.CreateVertex(cornerTopLeft1.p + leftPlatformWidth * Vector3.left);
            Vertex cornerTopFarLeft2    = cornerTopLeft2 == cornerBottomLeft2 ? cornerBottomFarLeft2 : structure.CreateVertex(cornerTopLeft2.p + leftPlatformWidth * Vector3.left);
            CreateStraightPlatformPart(
                structure,
                cornerTopFarLeft1, cornerTopFarLeft2, cornerTopLeft1, cornerTopLeft2,
                cornerBottomFarLeft1, cornerBottomFarLeft2, cornerBottomLeft1, cornerBottomLeft2,
                true, false, segmentLength, sideFaceType);
        }
        if (rightPlatformWidth > 0)
        {
            Vertex cornerBottomFarRight1 = structure.CreateVertex(cornerBottomRight1.p + rightPlatformWidth * Vector3.right);
            Vertex cornerBottomFarRight2 = structure.CreateVertex(cornerBottomRight2.p + rightPlatformWidth * Vector3.right);
            Vertex cornerTopFarRight1    = cornerTopRight1 == cornerBottomRight1 ? cornerBottomFarRight1 : structure.CreateVertex(cornerTopRight1.p + rightPlatformWidth * Vector3.right);
            Vertex cornerTopFarRight2    = cornerTopRight2 == cornerBottomRight2 ? cornerBottomFarRight2 : structure.CreateVertex(cornerTopRight2.p + rightPlatformWidth * Vector3.right);
            CreateStraightPlatformPart(
                structure,
                cornerTopRight1, cornerTopRight2, cornerTopFarRight1, cornerTopFarRight2,
                cornerBottomRight1, cornerBottomRight2, cornerBottomFarRight1, cornerBottomFarRight2,
                false, true, segmentLength, sideFaceType);
        }
        return(structure.Build());
    }
    public static RenderGeometry CreateCylinderGeometry(float radius, float height, int segmentP, int segmentH, bool smoothH, bool smoothV, float cutAngle = 0, float hollowRatio = 0)
    {
        StructureGeometry structure = new StructureGeometry();

        RenderGeometry.FaceType faceType = GetFaceType(smoothH, smoothV);
        float hollowRadius = hollowRatio * radius;

        SurfaceComponentGeometry side      = SurfaceComponentGeometries.CreateCylinderSideGeometry(radius, height, segmentP, segmentH, cutAngle, false, 1, faceType);
        SurfaceComponentGeometry sideInner = null;

        if (hollowRatio > 0)
        {
            sideInner = SurfaceComponentGeometries.CreateCylinderSideGeometry(hollowRadius, height, segmentP, segmentH, cutAngle, true, 1, faceType);
        }
        SurfaceComponentGeometry upperCap, lowerCap;

        if (hollowRatio > 0)
        {
            upperCap = SurfaceComponentGeometries.CreateRingCapGeometry(radius, hollowRadius, segmentP, 1, cutAngle, 2);
            lowerCap = SurfaceComponentGeometries.CreateRingCapGeometry(radius, hollowRadius, segmentP, 1, cutAngle, 2);
        }
        else if (cutAngle == 0)
        {
            upperCap = SurfaceComponentGeometries.CreateRegularPolygonGeometry(radius, segmentP, 2);
            lowerCap = SurfaceComponentGeometries.CreateRegularPolygonGeometry(radius, segmentP, 2);
        }
        else
        {
            upperCap = SurfaceComponentGeometries.CreateFanCapGeometry(radius, segmentP, 1, cutAngle, 2);
            lowerCap = SurfaceComponentGeometries.CreateFanCapGeometry(radius, segmentP, 1, cutAngle, 2);
        }
        lowerCap.ApplyRotation(Quaternion.AngleAxis(cutAngle * Mathf.Rad2Deg, Vector3.up) * Quaternion.AngleAxis(180, Vector3.right));

        if (cutAngle == 0)
        {
            Vertex cornerUp   = structure.CreateVertex(new Vector3(radius, height / 2, 0));
            Vertex cornerDown = structure.CreateVertex(new Vector3(radius, -height / 2, 0));
            if (hollowRatio == 0)
            {
                structure.CreateFace(side, false, cornerUp, cornerUp, cornerDown, cornerDown);
                structure.CreateFace(upperCap, true, cornerUp);
                structure.CreateFace(lowerCap, true, cornerDown);
            }
            else
            {
                Vertex cornerUpInner   = structure.CreateVertex(new Vector3(hollowRadius, height / 2, 0));
                Vertex cornerDownInner = structure.CreateVertex(new Vector3(hollowRadius, -height / 2, 0));
                structure.CreateFace(side, false, cornerUp, cornerUp, cornerDown, cornerDown);
                structure.CreateFace(sideInner, false, cornerDownInner, cornerDownInner, cornerUpInner, cornerUpInner);
                structure.CreateFace(upperCap, true, cornerUpInner, cornerUpInner, cornerUp, cornerUp);
                structure.CreateFace(lowerCap, true, cornerDownInner, cornerDownInner, cornerDown, cornerDown);
            }
        }
        else
        {
            SurfaceComponentGeometry wall1 = SurfaceComponentGeometries.CreatePlaneGeometry(1, 1, 1, segmentH, 3);
            SurfaceComponentGeometry wall2 = SurfaceComponentGeometries.CreatePlaneGeometry(1, 1, 1, segmentH, 4);

            Vertex cornerUp1   = structure.CreateVertex(new Vector3(radius * Mathf.Cos(cutAngle), height / 2, -radius * Mathf.Sin(cutAngle)));
            Vertex cornerUp2   = structure.CreateVertex(new Vector3(radius, height / 2, 0));
            Vertex cornerDown1 = structure.CreateVertex(new Vector3(radius * Mathf.Cos(cutAngle), -height / 2, -radius * Mathf.Sin(cutAngle)));
            Vertex cornerDown2 = structure.CreateVertex(new Vector3(radius, -height / 2, 0));
            if (hollowRatio == 0)
            {
                Vertex cornerUpC   = structure.CreateVertex(new Vector3(0, height / 2, 0));
                Vertex cornerDownC = structure.CreateVertex(new Vector3(0, -height / 2, 0));
                structure.CreateFace(side, false, cornerUp2, cornerUp1, cornerDown1, cornerDown2);
                structure.CreateFace(upperCap, true, cornerUp1, cornerUp2, cornerUpC);
                structure.CreateFace(lowerCap, true, cornerDown2, cornerDown1, cornerDownC);
                structure.CreateFace(wall1, true, cornerUpC, cornerDownC, cornerDown1, cornerUp1);
                structure.CreateFace(wall2, true, cornerDownC, cornerUpC, cornerUp2, cornerDown2);
            }
            else
            {
                Vertex cornerUp1Inner   = structure.CreateVertex(new Vector3(hollowRadius * Mathf.Cos(cutAngle), height / 2, -hollowRadius * Mathf.Sin(cutAngle)));
                Vertex cornerUp2Inner   = structure.CreateVertex(new Vector3(hollowRadius, height / 2, 0));
                Vertex cornerDown1Inner = structure.CreateVertex(new Vector3(hollowRadius * Mathf.Cos(cutAngle), -height / 2, -hollowRadius * Mathf.Sin(cutAngle)));
                Vertex cornerDown2Inner = structure.CreateVertex(new Vector3(hollowRadius, -height / 2, 0));
                structure.CreateFace(side, false, cornerUp2, cornerUp1, cornerDown1, cornerDown2);
                structure.CreateFace(sideInner, false, cornerDown2Inner, cornerDown1Inner, cornerUp1Inner, cornerUp2Inner);
                structure.CreateFace(upperCap, true, cornerUp2Inner, cornerUp1Inner, cornerUp1, cornerUp2);
                structure.CreateFace(lowerCap, true, cornerDown1Inner, cornerDown2Inner, cornerDown2, cornerDown1);
                structure.CreateFace(wall1, true, cornerUp1Inner, cornerDown1Inner, cornerDown1, cornerUp1);
                structure.CreateFace(wall2, true, cornerDown2Inner, cornerUp2Inner, cornerUp2, cornerDown2);
            }
        }
        return(structure.Build());
    }
    private static void CreateStraightRampPart(
        StructureGeometry structure, bool isLeftRamp,
        Vertex cornerTopLeft1, Vertex cornerTopLeft2, Vertex cornerTopRight1, Vertex cornerTopRight2,
        Vertex cornerBottomLeft1, Vertex cornerBottomLeft2, Vertex cornerBottomRight1, Vertex cornerBottomRight2,
        bool addLeftSide, bool addRightSide, int segmentWidth, int segmentLength, float curvature, RenderGeometry.FaceType rampFaceType, RenderGeometry.FaceType sideFaceType)
    {
        bool hasBase = (cornerTopLeft1 != cornerBottomLeft1) && (cornerTopRight1 != cornerBottomRight1);

        SurfaceComponentGeometry rampFace = SurfaceComponentGeometries.CreatePlaneGeometry(1, 1, segmentWidth, segmentLength, 0, rampFaceType);
        SurfaceComponentGeometry rampBottom = SurfaceComponentGeometries.CreatePlaneGeometry(1, 1, 1, segmentLength, 1, sideFaceType);
        SurfaceComponentGeometry rampLeftSide = null, rampRightSide = null;

        if (addLeftSide && (cornerTopLeft1 != cornerBottomLeft1))
        {
            rampLeftSide = SurfaceComponentGeometries.CreatePlaneGeometry(1, 1, 1, segmentLength, 2, sideFaceType);
        }
        if (addRightSide && (cornerTopRight1 != cornerBottomRight1))
        {
            rampRightSide = SurfaceComponentGeometries.CreatePlaneGeometry(1, 1, 1, segmentLength, 3, sideFaceType);
        }

        if (curvature != 0)
        {
            float angle = -curvature * Mathf.PI / 2;
            rampFace.ApplySpaceWarp(new SpaceWarp($"sin(x*{angle})/{angle}", $"(1-cos(x*{angle}))/{angle}", "z"));
        }
        // Fit to a 45 degree ramp, then scale.
        rampFace.ApplyLinearTransform(
            Matrix4x4.Translate(cornerTopLeft1.p) *
            Matrix4x4.Scale(VectorUtil.Abs(cornerTopRight2.p - cornerTopLeft1.p)) *
            MatrixUtil.PointToPointTransform(
                rampFace.corners[0].p, rampFace.corners[3].p, rampFace.corners[1].p,
                Vector3.zero, new Vector3(1, isLeftRamp ? 1 : -1, 0), Vector3.forward));

        structure.CreateFace(rampFace, false, cornerTopLeft1, cornerTopLeft2, cornerTopRight2, cornerTopRight1);
        structure.CreateFace(rampBottom, true, cornerBottomRight1, cornerBottomRight2, cornerBottomLeft2, cornerBottomLeft1);
        if (rampLeftSide != null)
        {
            structure.CreateFace(rampLeftSide, true, cornerBottomLeft1, cornerBottomLeft2, cornerTopLeft2, cornerTopLeft1);
        }
        if (rampRightSide != null)
        {
            structure.CreateFace(rampRightSide, true, cornerTopRight1, cornerTopRight2, cornerBottomRight2, cornerBottomRight1);
        }

        var backVertices = new List <Vector3>();

        backVertices.Add(isLeftRamp ? cornerBottomRight1.p : cornerBottomLeft1.p);
        if (isLeftRamp && hasBase)
        {
            backVertices.Add(cornerBottomLeft1.p);
        }
        backVertices.Add(rampFace.boundaries[3].Last().prev.vertex.p);
        backVertices.AddRange(rampFace.boundaries[3].Select(e => e.vertex.p).Reverse());
        if (!isLeftRamp && hasBase)
        {
            backVertices.Add(cornerBottomRight1.p);
        }
        var movedBackVertices = backVertices.Select(p => p + (cornerTopLeft2.p - cornerTopLeft1.p));
        var frontVertices = movedBackVertices.Take(1).Concat(movedBackVertices.Reverse().Take(backVertices.Count - 1)).ToList();

        SurfaceComponentGeometry backFace  = SurfaceComponentGeometries.CreateStarConvexPolygonGeometry(backVertices, 4, RenderGeometry.FaceType.Smooth);
        SurfaceComponentGeometry frontFace = SurfaceComponentGeometries.CreateStarConvexPolygonGeometry(frontVertices, 5, RenderGeometry.FaceType.Smooth);

        if (hasBase)
        {
            if (isLeftRamp)
            {
                backFace.CombineBoundaries(1, 1, segmentWidth, 1);
                frontFace.CombineBoundaries(1, segmentWidth, 1, 1);
                structure.CreateFace(backFace, false, cornerBottomRight1, cornerBottomLeft1, cornerTopLeft1, cornerTopRight1);
                structure.CreateFace(frontFace, false, cornerBottomRight2, cornerTopRight2, cornerTopLeft2, cornerBottomLeft2);
            }
            else
            {
                backFace.CombineBoundaries(1, segmentWidth, 1, 1);
                frontFace.CombineBoundaries(1, 1, segmentWidth, 1);
                structure.CreateFace(backFace, false, cornerBottomLeft1, cornerTopLeft1, cornerTopRight1, cornerBottomRight1);
                structure.CreateFace(frontFace, false, cornerBottomLeft2, cornerBottomRight2, cornerTopRight2, cornerTopLeft2);
            }
        }
        else
        {
            backFace.CombineBoundaries(1, segmentWidth, 1);
            frontFace.CombineBoundaries(1, segmentWidth, 1);
            structure.CreateFace(backFace, false, isLeftRamp ? cornerBottomRight1 : cornerBottomLeft1, cornerTopLeft1, cornerTopRight1);
            structure.CreateFace(frontFace, false, isLeftRamp ? cornerBottomRight2 : cornerBottomLeft2, cornerTopRight2, cornerTopLeft2);
        }
    }