private static void Subdivide(IList <Vector3D> positions, IndicesUnsignedInt indices, TriangleIndicesUnsignedInt triangle, int level)
        {
            if (level > 0)
            {
                positions.Add(((positions[triangle.I0] + positions[triangle.I1]) * 0.5).Normalize());
                positions.Add(((positions[triangle.I1] + positions[triangle.I2]) * 0.5).Normalize());
                positions.Add(((positions[triangle.I2] + positions[triangle.I0]) * 0.5).Normalize());

                int i01 = positions.Count - 3;
                int i12 = positions.Count - 2;
                int i20 = positions.Count - 1;

                //
                // Subdivide input triangle into four triangles
                //
                --level;
                Subdivide(positions, indices, new TriangleIndicesUnsignedInt(triangle.I0, i01, i20), level);
                Subdivide(positions, indices, new TriangleIndicesUnsignedInt(i01, triangle.I1, i12), level);
                Subdivide(positions, indices, new TriangleIndicesUnsignedInt(i01, i12, i20), level);
                Subdivide(positions, indices, new TriangleIndicesUnsignedInt(i20, i12, triangle.I2), level);
            }
            else
            {
                indices.AddTriangle(triangle);
            }
        }
        public void SimpleConcave()
        {
            IList <Vector3D> positions = new List <Vector3D>();

            positions.Add(Ellipsoid.UnitSphere.ToVector3D(Trig.ToRadians(new Geodetic3D(0, 0))));
            positions.Add(Ellipsoid.UnitSphere.ToVector3D(Trig.ToRadians(new Geodetic3D(2, 0))));
            positions.Add(Ellipsoid.UnitSphere.ToVector3D(Trig.ToRadians(new Geodetic3D(2, 2))));
            positions.Add(Ellipsoid.UnitSphere.ToVector3D(Trig.ToRadians(new Geodetic3D(1, 0.25))));
            positions.Add(Ellipsoid.UnitSphere.ToVector3D(Trig.ToRadians(new Geodetic3D(0, 2))));

            IndicesUnsignedInt indices = EarClippingOnEllipsoid.Triangulate(positions);

            Assert.AreEqual(9, indices.Values.Count);
            Assert.AreEqual(1, indices.Values[0]);
            Assert.AreEqual(2, indices.Values[1]);
            Assert.AreEqual(3, indices.Values[2]);

            Assert.AreEqual(3, indices.Values[3]);
            Assert.AreEqual(4, indices.Values[4]);
            Assert.AreEqual(0, indices.Values[5]);

            Assert.AreEqual(0, indices.Values[6]);
            Assert.AreEqual(1, indices.Values[7]);
            Assert.AreEqual(3, indices.Values[8]);
        }
        private static void Subdivide(IList<Vector3D> positions, IndicesUnsignedInt indices, TriangleIndicesUnsignedInt triangle, int level)
        {
            if (level > 0)
            {
                positions.Add(((positions[triangle.I0] + positions[triangle.I1]) * 0.5).Normalize());
                positions.Add(((positions[triangle.I1] + positions[triangle.I2]) * 0.5).Normalize());
                positions.Add(((positions[triangle.I2] + positions[triangle.I0]) * 0.5).Normalize());

                int i01 = positions.Count - 3;
                int i12 = positions.Count - 2;
                int i20 = positions.Count - 1;

                //
                // Subdivide input triangle into four triangles
                //
                --level;
                Subdivide(positions, indices, new TriangleIndicesUnsignedInt(triangle.I0, i01, i20), level);
                Subdivide(positions, indices, new TriangleIndicesUnsignedInt(i01, triangle.I1, i12), level);
                Subdivide(positions, indices, new TriangleIndicesUnsignedInt(i01, i12, i20), level);
                Subdivide(positions, indices, new TriangleIndicesUnsignedInt(i20, i12, triangle.I2), level);
            }
            else
            {
                indices.AddTriangle(triangle);
            }
        }
Example #4
0
        public void TwoTriangles()
        {
            Vector3D[] positions = new Vector3D[]
            {
                Vector3D.Zero,
                new Vector3D(0.5, 0.5, 0),
                new Vector3D(-0.5, 0.5, 0),
                new Vector3D(0, 1, 0)
            };

            IndicesUnsignedInt indices = new IndicesUnsignedInt();

            indices.Values.Add(0);
            indices.Values.Add(1);
            indices.Values.Add(2);
            indices.Values.Add(3);
            indices.Values.Add(2);
            indices.Values.Add(1);

            TriangleMeshSubdivisionResult result = TriangleMeshSubdivision.Compute(positions, indices, Trig.ToRadians(90));

            Assert.AreEqual(0, result.Indices.Values[0]);
            Assert.AreEqual(1, result.Indices.Values[1]);
            Assert.AreEqual(2, result.Indices.Values[2]);

            Assert.AreEqual(3, result.Indices.Values[3]);
            Assert.AreEqual(2, result.Indices.Values[4]);
            Assert.AreEqual(1, result.Indices.Values[5]);
        }
Example #5
0
        public void SimpleConcave()
        {
            IList <Vector2D> positions = new List <Vector2D>();

            positions.Add(new Vector2D(0, 0));
            positions.Add(new Vector2D(2, 0));
            positions.Add(new Vector2D(2, 2));
            positions.Add(new Vector2D(1, 0.25));
            positions.Add(new Vector2D(0, 2));

            IndicesUnsignedInt indices = EarClipping.Triangulate(positions);

            Assert.AreEqual(9, indices.Values.Count);
            Assert.AreEqual(1, indices.Values[0]);
            Assert.AreEqual(2, indices.Values[1]);
            Assert.AreEqual(3, indices.Values[2]);

            Assert.AreEqual(3, indices.Values[3]);
            Assert.AreEqual(4, indices.Values[4]);
            Assert.AreEqual(0, indices.Values[5]);

            Assert.AreEqual(0, indices.Values[6]);
            Assert.AreEqual(1, indices.Values[7]);
            Assert.AreEqual(3, indices.Values[8]);
        }
        public void ArgumentException()
        {
            IndicesUnsignedInt indices = new IndicesUnsignedInt();
            indices.Values.Add(0);
            indices.Values.Add(1);
            indices.Values.Add(2);
            indices.Values.Add(3);

            TriangleMeshSubdivision.Compute(new Vector3D[] { }, indices, Trig.ToRadians(1));
        }
Example #7
0
        public void ArgumentException()
        {
            IndicesUnsignedInt indices = new IndicesUnsignedInt();

            indices.Values.Add(0);
            indices.Values.Add(1);
            indices.Values.Add(2);
            indices.Values.Add(3);

            TriangleMeshSubdivision.Compute(new Vector3D[] { }, indices, Trig.ToRadians(1));
        }
        public void Triangle()
        {
            IList <Vector3D> positions = new List <Vector3D>();

            positions.Add(Ellipsoid.UnitSphere.ToVector3D(Trig.ToRadians(new Geodetic3D(0, 0))));
            positions.Add(Ellipsoid.UnitSphere.ToVector3D(Trig.ToRadians(new Geodetic3D(1, 0))));
            positions.Add(Ellipsoid.UnitSphere.ToVector3D(Trig.ToRadians(new Geodetic3D(1, 1))));

            IndicesUnsignedInt indices = EarClippingOnEllipsoid.Triangulate(positions);

            Assert.AreEqual(3, indices.Values.Count);
            Assert.AreEqual(0, indices.Values[0]);
            Assert.AreEqual(1, indices.Values[1]);
            Assert.AreEqual(2, indices.Values[2]);
        }
Example #9
0
        public void Triangle()
        {
            IList <Vector2D> positions = new List <Vector2D>();

            positions.Add(new Vector2D(0, 0));
            positions.Add(new Vector2D(1, 0));
            positions.Add(new Vector2D(1, 1));

            IndicesUnsignedInt indices = EarClipping.Triangulate(positions);

            Assert.AreEqual(3, indices.Values.Count);
            Assert.AreEqual(0, indices.Values[0]);
            Assert.AreEqual(1, indices.Values[1]);
            Assert.AreEqual(2, indices.Values[2]);
        }
        public void OutOfRangeException2()
        {
            Vector3D[] positions = new Vector3D[]
            {
                Vector3D.Zero,
                new Vector3D(0.5, 0, 0),
                new Vector3D(0.5, 0.5, 0)
            };

            IndicesUnsignedInt indices = new IndicesUnsignedInt();
            indices.Values.Add(0);
            indices.Values.Add(1);
            indices.Values.Add(2);

            TriangleMeshSubdivision.Compute(positions, indices, 0);
        }
Example #11
0
        public void OutOfRangeException2()
        {
            Vector3D[] positions = new Vector3D[]
            {
                Vector3D.Zero,
                new Vector3D(0.5, 0, 0),
                new Vector3D(0.5, 0.5, 0)
            };

            IndicesUnsignedInt indices = new IndicesUnsignedInt();

            indices.Values.Add(0);
            indices.Values.Add(1);
            indices.Values.Add(2);

            TriangleMeshSubdivision.Compute(positions, indices, 0);
        }
Example #12
0
        public void MeshIndices()
        {
            Mesh mesh = new Mesh();

            IndicesUnsignedShort indicesShort = new IndicesUnsignedShort();

            mesh.Indices = indicesShort;
            Assert.AreEqual(IndicesType.UnsignedShort, mesh.Indices.Datatype);

            IndicesUnsignedInt indicesInt = new IndicesUnsignedInt();

            mesh.Indices = indicesInt;
            Assert.AreEqual(IndicesType.UnsignedInt, mesh.Indices.Datatype);

            indicesInt.AddTriangle(new TriangleIndicesUnsignedInt(0, 1, 2));
            Assert.AreEqual(0, indicesInt.Values[0]);
            Assert.AreEqual(1, indicesInt.Values[1]);
            Assert.AreEqual(2, indicesInt.Values[2]);
        }
        public static Mesh Compute(int numberOfSubdivisions)
        {
            if (numberOfSubdivisions < 0)
            {
                throw new ArgumentOutOfRangeException("numberOfSubdivisions");
            }

            Mesh mesh = new Mesh();

            mesh.PrimitiveType         = PrimitiveType.Triangles;
            mesh.FrontFaceWindingOrder = WindingOrder.Counterclockwise;

            VertexAttributeDoubleVector3 positionsAttribute = new VertexAttributeDoubleVector3(
                "position", SubdivisionUtility.NumberOfVertices(numberOfSubdivisions));

            mesh.Attributes.Add(positionsAttribute);

            IndicesUnsignedInt indices = new IndicesUnsignedInt(3 * SubdivisionUtility.NumberOfTriangles(numberOfSubdivisions));

            mesh.Indices = indices;

            //
            // Initial tetrahedron
            //
            double       negativeRootTwoOverThree = -Math.Sqrt(2.0) / 3.0;
            const double negativeOneThird         = -1.0 / 3.0;
            double       rootSixOverThree         = Math.Sqrt(6.0) / 3.0;

            IList <Vector3D> positions = positionsAttribute.Values;

            positions.Add(new Vector3D(0, 0, 1));
            positions.Add(new Vector3D(0, (2.0 * Math.Sqrt(2.0)) / 3.0, negativeOneThird));
            positions.Add(new Vector3D(-rootSixOverThree, negativeRootTwoOverThree, negativeOneThird));
            positions.Add(new Vector3D(rootSixOverThree, negativeRootTwoOverThree, negativeOneThird));

            Subdivide(positions, indices, new TriangleIndicesUnsignedInt(0, 1, 2), numberOfSubdivisions);
            Subdivide(positions, indices, new TriangleIndicesUnsignedInt(0, 2, 3), numberOfSubdivisions);
            Subdivide(positions, indices, new TriangleIndicesUnsignedInt(0, 3, 1), numberOfSubdivisions);
            Subdivide(positions, indices, new TriangleIndicesUnsignedInt(1, 3, 2), numberOfSubdivisions);

            return(mesh);
        }
        public void OneTriangle()
        {
            Vector3D[] positions = new Vector3D[]
            {
                Vector3D.Zero,
                new Vector3D(0.5, 0, 0),
                new Vector3D(0.5, 0.5, 0)
            };

            IndicesUnsignedInt indices = new IndicesUnsignedInt();
            indices.Values.Add(0);
            indices.Values.Add(1);
            indices.Values.Add(2);

            TriangleMeshSubdivisionResult result = TriangleMeshSubdivision.Compute(positions, indices, Trig.ToRadians(1));

            Assert.AreEqual(0, result.Indices.Values[0]);
            Assert.AreEqual(1, result.Indices.Values[1]);
            Assert.AreEqual(2, result.Indices.Values[2]);
        }
        public void ComplexConcave()
        {
            IList <Vector3D> positions = new List <Vector3D>();

            positions.Add(Ellipsoid.UnitSphere.ToVector3D(Trig.ToRadians(new Geodetic3D(0, 0))));
            positions.Add(Ellipsoid.UnitSphere.ToVector3D(Trig.ToRadians(new Geodetic3D(2, 0))));
            positions.Add(Ellipsoid.UnitSphere.ToVector3D(Trig.ToRadians(new Geodetic3D(2, 1))));
            positions.Add(Ellipsoid.UnitSphere.ToVector3D(Trig.ToRadians(new Geodetic3D(0.1, 1.5))));
            positions.Add(Ellipsoid.UnitSphere.ToVector3D(Trig.ToRadians(new Geodetic3D(2, 2))));
            positions.Add(Ellipsoid.UnitSphere.ToVector3D(Trig.ToRadians(new Geodetic3D(0, 2))));
            positions.Add(Ellipsoid.UnitSphere.ToVector3D(Trig.ToRadians(new Geodetic3D(0, 1))));
            positions.Add(Ellipsoid.UnitSphere.ToVector3D(Trig.ToRadians(new Geodetic3D(1.9, 0.5))));

            IndicesUnsignedInt indices = EarClippingOnEllipsoid.Triangulate(positions);

            Assert.AreEqual(18, indices.Values.Count);
            Assert.AreEqual(3, indices.Values[0]);
            Assert.AreEqual(4, indices.Values[1]);
            Assert.AreEqual(5, indices.Values[2]);

            Assert.AreEqual(3, indices.Values[3]);
            Assert.AreEqual(5, indices.Values[4]);
            Assert.AreEqual(6, indices.Values[5]);

            Assert.AreEqual(3, indices.Values[6]);
            Assert.AreEqual(6, indices.Values[7]);
            Assert.AreEqual(7, indices.Values[8]);

            Assert.AreEqual(7, indices.Values[9]);
            Assert.AreEqual(0, indices.Values[10]);
            Assert.AreEqual(1, indices.Values[11]);

            Assert.AreEqual(7, indices.Values[12]);
            Assert.AreEqual(1, indices.Values[13]);
            Assert.AreEqual(2, indices.Values[14]);

            Assert.AreEqual(2, indices.Values[15]);
            Assert.AreEqual(3, indices.Values[16]);
            Assert.AreEqual(7, indices.Values[17]);
        }
Example #16
0
        public void ComplexConcave()
        {
            IList <Vector2D> positions = new List <Vector2D>();

            positions.Add(new Vector2D(0, 0));
            positions.Add(new Vector2D(2, 0));
            positions.Add(new Vector2D(2, 1));
            positions.Add(new Vector2D(0.1, 1.5));
            positions.Add(new Vector2D(2, 2));
            positions.Add(new Vector2D(0, 2));
            positions.Add(new Vector2D(0, 1));
            positions.Add(new Vector2D(1.9, 0.5));

            IndicesUnsignedInt indices = EarClipping.Triangulate(positions);

            Assert.AreEqual(18, indices.Values.Count);
            Assert.AreEqual(3, indices.Values[0]);
            Assert.AreEqual(4, indices.Values[1]);
            Assert.AreEqual(5, indices.Values[2]);

            Assert.AreEqual(3, indices.Values[3]);
            Assert.AreEqual(5, indices.Values[4]);
            Assert.AreEqual(6, indices.Values[5]);

            Assert.AreEqual(3, indices.Values[6]);
            Assert.AreEqual(6, indices.Values[7]);
            Assert.AreEqual(7, indices.Values[8]);

            Assert.AreEqual(7, indices.Values[9]);
            Assert.AreEqual(0, indices.Values[10]);
            Assert.AreEqual(1, indices.Values[11]);

            Assert.AreEqual(7, indices.Values[12]);
            Assert.AreEqual(1, indices.Values[13]);
            Assert.AreEqual(2, indices.Values[14]);

            Assert.AreEqual(2, indices.Values[15]);
            Assert.AreEqual(3, indices.Values[16]);
            Assert.AreEqual(7, indices.Values[17]);
        }
        public static Mesh Compute(int numberOfSubdivisions)
        {
            if (numberOfSubdivisions < 0)
            {
                throw new ArgumentOutOfRangeException("numberOfSubdivisions");
            }

            Mesh mesh = new Mesh();
            mesh.PrimitiveType = PrimitiveType.Triangles;
            mesh.FrontFaceWindingOrder = WindingOrder.Counterclockwise;

            VertexAttributeDoubleVector3 positionsAttribute = new VertexAttributeDoubleVector3(
                "position", SubdivisionUtility.NumberOfVertices(numberOfSubdivisions));
            mesh.Attributes.Add(positionsAttribute);

            IndicesUnsignedInt indices = new IndicesUnsignedInt(3 * SubdivisionUtility.NumberOfTriangles(numberOfSubdivisions));
            mesh.Indices = indices;

            //
            // Initial tetrahedron
            //
            double negativeRootTwoOverThree = -Math.Sqrt(2.0) / 3.0;
            const double negativeOneThird = -1.0 / 3.0;
            double rootSixOverThree = Math.Sqrt(6.0) / 3.0;

            IList<Vector3D> positions = positionsAttribute.Values;
            positions.Add(new Vector3D(0, 0, 1));
            positions.Add(new Vector3D(0, (2.0 * Math.Sqrt(2.0)) / 3.0, negativeOneThird));
            positions.Add(new Vector3D(-rootSixOverThree, negativeRootTwoOverThree, negativeOneThird));
            positions.Add(new Vector3D(rootSixOverThree, negativeRootTwoOverThree, negativeOneThird));

            Subdivide(positions, indices, new TriangleIndicesUnsignedInt(0, 1, 2), numberOfSubdivisions);
            Subdivide(positions, indices, new TriangleIndicesUnsignedInt(0, 2, 3), numberOfSubdivisions);
            Subdivide(positions, indices, new TriangleIndicesUnsignedInt(0, 3, 1), numberOfSubdivisions);
            Subdivide(positions, indices, new TriangleIndicesUnsignedInt(1, 3, 2), numberOfSubdivisions);

            return mesh;
        }
Example #18
0
        public void TwoTriangles3()
        {
            Vector3D[] positions = new Vector3D[]
            {
                Ellipsoid.UnitSphere.ToVector3D(Trig.ToRadians(new Geodetic2D(0, 44))),
                Ellipsoid.UnitSphere.ToVector3D(Trig.ToRadians(new Geodetic2D(1, 45))),
                Ellipsoid.UnitSphere.ToVector3D(Trig.ToRadians(new Geodetic2D(-1, 45))),
                Ellipsoid.UnitSphere.ToVector3D(Trig.ToRadians(new Geodetic2D(0, 46)))
            };

            IndicesUnsignedInt indices = new IndicesUnsignedInt();

            indices.Values.Add(0);
            indices.Values.Add(1);
            indices.Values.Add(2);
            indices.Values.Add(3);
            indices.Values.Add(2);
            indices.Values.Add(1);

            TriangleMeshSubdivisionResult result = TriangleMeshSubdivision.Compute(positions, indices, Trig.ToRadians(1.4));

            Assert.AreEqual(5, result.Positions.Count);
            Assert.AreEqual(12, result.Indices.Values.Count);
        }
        public TriangleMeshTerrainTile(Context context, TerrainTile tile)
        {
            ShaderProgram silhouetteSP = Device.CreateShaderProgram(
                EmbeddedResources.GetText("OpenGlobe.Scene.Terrain.TriangleMeshTerrainTile.SilhouetteVS.glsl"),
                EmbeddedResources.GetText("OpenGlobe.Scene.Terrain.TriangleMeshTerrainTile.SilhouetteGS.glsl"),
                EmbeddedResources.GetText("OpenGlobe.Scene.Terrain.TriangleMeshTerrainTile.SilhouetteFS.glsl"));

            Uniform<float> fillDistance = (Uniform<float>)silhouetteSP.Uniforms["u_fillDistance"];
            fillDistance.Value = 1.5f;
            _silhouetteHeightExaggeration = (Uniform<float>)silhouetteSP.Uniforms["u_heightExaggeration"];

            ShaderProgram sp = Device.CreateShaderProgram(
                EmbeddedResources.GetText("OpenGlobe.Scene.Terrain.TriangleMeshTerrainTile.TerrainVS.glsl"),
                EmbeddedResources.GetText("OpenGlobe.Scene.Terrain.TriangleMeshTerrainTile.TerrainFS.glsl"));

            _tileMinimumHeight = tile.MinimumHeight;
            _tileMaximumHeight = tile.MaximumHeight;

            _heightExaggeration = (Uniform<float>)sp.Uniforms["u_heightExaggeration"];
            _minimumHeight = (Uniform<float>)sp.Uniforms["u_minimumHeight"];
            _maximumHeight = (Uniform<float>)sp.Uniforms["u_maximumHeight"];
            HeightExaggeration = 1;

            ///////////////////////////////////////////////////////////////////

            Mesh mesh = new Mesh();
            mesh.PrimitiveType = PrimitiveType.Triangles;
            mesh.FrontFaceWindingOrder = WindingOrder.Counterclockwise;

            int numberOfPositions = tile.Resolution.X * tile.Resolution.Y;
            VertexAttributeDoubleVector3 positionsAttribute = new VertexAttributeDoubleVector3("position", numberOfPositions);
            IList<Vector3D> positions = positionsAttribute.Values;
            mesh.Attributes.Add(positionsAttribute);

            int numberOfPartitionsX = tile.Resolution.X - 1;
            int numberOfPartitionsY = tile.Resolution.Y - 1;
            int numberOfIndices = (numberOfPartitionsX * numberOfPartitionsY) * 6;
            IndicesUnsignedInt indices = new IndicesUnsignedInt(numberOfIndices);
            mesh.Indices = indices;

            //
            // Positions
            //
            Vector2D lowerLeft = tile.Extent.LowerLeft;
            Vector2D toUpperRight = tile.Extent.UpperRight - lowerLeft;

            int heightIndex = 0;
            for (int y = 0; y <= numberOfPartitionsY; ++y)
            {
                double deltaY = y / (double)numberOfPartitionsY;
                double currentY = lowerLeft.Y + (deltaY * toUpperRight.Y);

                for (int x = 0; x <= numberOfPartitionsX; ++x)
                {
                    double deltaX = x / (double)numberOfPartitionsX;
                    double currentX = lowerLeft.X + (deltaX * toUpperRight.X);
                    positions.Add(new Vector3D(currentX, currentY, tile.Heights[heightIndex++]));
                }
            }

            //
            // Indices
            //
            int rowDelta = numberOfPartitionsX + 1;
            int i = 0;
            for (int y = 0; y < numberOfPartitionsY; ++y)
            {
                for (int x = 0; x < numberOfPartitionsX; ++x)
                {
                    indices.AddTriangle(new TriangleIndicesUnsignedInt(i, i + 1, rowDelta + (i + 1)));
                    indices.AddTriangle(new TriangleIndicesUnsignedInt(i, rowDelta + (i + 1), rowDelta + i));
                    i += 1;
                }
                i += 1;
            }

            _drawState = new DrawState();
            _drawState.RenderState.FacetCulling.FrontFaceWindingOrder = mesh.FrontFaceWindingOrder;
            _drawState.ShaderProgram = sp;
            _drawState.VertexArray = context.CreateVertexArray(mesh, sp.VertexAttributes, BufferHint.StaticDraw);

            _silhouetteDrawState = new DrawState();
            _silhouetteDrawState.RenderState.FacetCulling.Enabled = false;
            _silhouetteDrawState.RenderState.DepthMask = false;
            _silhouetteDrawState.VertexArray = _drawState.VertexArray;
            _silhouetteDrawState.ShaderProgram = silhouetteSP;

            _primitiveType = mesh.PrimitiveType;

            _clearColor = new ClearState();
            _clearColor.Buffers = ClearBuffers.ColorBuffer;
            
            //
            // Only depth needs to be cleared but include stencil for speed.
            //
            _clearDepthStencil = new ClearState();
            _clearDepthStencil.Buffers = ClearBuffers.DepthBuffer | ClearBuffers.StencilBuffer;
        }
Example #20
0
        public static Mesh Compute(Ellipsoid ellipsoid, int numberOfSlicePartitions, int numberOfStackPartitions, GeographicGridEllipsoidVertexAttributes vertexAttributes)
        {
            if (numberOfSlicePartitions < 3)
            {
                throw new ArgumentOutOfRangeException("numberOfSlicePartitions");
            }

            if (numberOfStackPartitions < 2)
            {
                throw new ArgumentOutOfRangeException("numberOfStackPartitions");
            }

            if ((vertexAttributes & GeographicGridEllipsoidVertexAttributes.Position) != GeographicGridEllipsoidVertexAttributes.Position)
            {
                throw new ArgumentException("Positions must be provided.", "vertexAttributes");
            }

            Mesh mesh = new Mesh();

            mesh.PrimitiveType         = PrimitiveType.Triangles;
            mesh.FrontFaceWindingOrder = WindingOrder.Counterclockwise;

            int numberOfVertices = NumberOfVertices(numberOfSlicePartitions, numberOfStackPartitions);
            VertexAttributeDoubleVector3 positionsAttribute = new VertexAttributeDoubleVector3("position", numberOfVertices);

            mesh.Attributes.Add(positionsAttribute);

            IndicesUnsignedInt indices = new IndicesUnsignedInt(3 * NumberOfTriangles(numberOfSlicePartitions, numberOfStackPartitions));

            mesh.Indices = indices;

            IList <Vector3H> normals = null;

            if ((vertexAttributes & GeographicGridEllipsoidVertexAttributes.Normal) == GeographicGridEllipsoidVertexAttributes.Normal)
            {
                VertexAttributeHalfFloatVector3 normalsAttribute = new VertexAttributeHalfFloatVector3("normal", numberOfVertices);
                mesh.Attributes.Add(normalsAttribute);
                normals = normalsAttribute.Values;
            }

            IList <Vector2H> textureCoordinates = null;

            if ((vertexAttributes & GeographicGridEllipsoidVertexAttributes.TextureCoordinate) == GeographicGridEllipsoidVertexAttributes.TextureCoordinate)
            {
                VertexAttributeHalfFloatVector2 textureCoordinateAttribute = new VertexAttributeHalfFloatVector2("textureCoordinate", numberOfVertices);
                mesh.Attributes.Add(textureCoordinateAttribute);
                textureCoordinates = textureCoordinateAttribute.Values;
            }

            //
            // Create lookup table
            //
            double[] cosTheta = new double[numberOfSlicePartitions];
            double[] sinTheta = new double[numberOfSlicePartitions];

            for (int j = 0; j < numberOfSlicePartitions; ++j)
            {
                double theta = Trig.TwoPi * (((double)j) / numberOfSlicePartitions);
                cosTheta[j] = Math.Cos(theta);
                sinTheta[j] = Math.Sin(theta);
            }

            //
            // Create positions
            //
            IList <Vector3D> positions = positionsAttribute.Values;

            positions.Add(new Vector3D(0, 0, ellipsoid.Radii.Z));

            for (int i = 1; i < numberOfStackPartitions; ++i)
            {
                double phi    = Math.PI * (((double)i) / numberOfStackPartitions);
                double sinPhi = Math.Sin(phi);

                double xSinPhi = ellipsoid.Radii.X * sinPhi;
                double ySinPhi = ellipsoid.Radii.Y * sinPhi;
                double zCosPhi = ellipsoid.Radii.Z * Math.Cos(phi);

                for (int j = 0; j < numberOfSlicePartitions; ++j)
                {
                    positions.Add(new Vector3D(cosTheta[j] * xSinPhi, sinTheta[j] * ySinPhi, zCosPhi));
                }
            }
            positions.Add(new Vector3D(0, 0, -ellipsoid.Radii.Z));

            if ((normals != null) || (textureCoordinates != null))
            {
                for (int i = 0; i < positions.Count; ++i)
                {
                    Vector3D deticSurfaceNormal = ellipsoid.GeodeticSurfaceNormal(positions[i]);

                    if (normals != null)
                    {
                        normals.Add(deticSurfaceNormal.ToVector3H());
                    }

                    if (textureCoordinates != null)
                    {
                        textureCoordinates.Add(SubdivisionUtility.ComputeTextureCoordinate(deticSurfaceNormal));
                    }
                }
            }

            //
            // Triangle fan top row
            //
            for (int j = 1; j < numberOfSlicePartitions; ++j)
            {
                indices.AddTriangle(new TriangleIndicesUnsignedInt(0, j, j + 1));
            }
            indices.AddTriangle(new TriangleIndicesUnsignedInt(0, numberOfSlicePartitions, 1));

            //
            // Middle rows are triangle strips
            //
            for (int i = 0; i < numberOfStackPartitions - 2; ++i)
            {
                int topRowOffset    = (i * numberOfSlicePartitions) + 1;
                int bottomRowOffset = ((i + 1) * numberOfSlicePartitions) + 1;

                for (int j = 0; j < numberOfSlicePartitions - 1; ++j)
                {
                    indices.AddTriangle(new TriangleIndicesUnsignedInt(bottomRowOffset + j, bottomRowOffset + j + 1, topRowOffset + j + 1));
                    indices.AddTriangle(new TriangleIndicesUnsignedInt(bottomRowOffset + j, topRowOffset + j + 1, topRowOffset + j));
                }
                indices.AddTriangle(new TriangleIndicesUnsignedInt(bottomRowOffset + numberOfSlicePartitions - 1, bottomRowOffset, topRowOffset));
                indices.AddTriangle(new TriangleIndicesUnsignedInt(bottomRowOffset + numberOfSlicePartitions - 1, topRowOffset, topRowOffset + numberOfSlicePartitions - 1));
            }

            //
            // Triangle fan bottom row
            //
            int lastPosition = positions.Count - 1;

            for (int j = lastPosition - 1; j > lastPosition - numberOfSlicePartitions; --j)
            {
                indices.AddTriangle(new TriangleIndicesUnsignedInt(lastPosition, j, j - 1));
            }
            indices.AddTriangle(new TriangleIndicesUnsignedInt(lastPosition, lastPosition - numberOfSlicePartitions, lastPosition - 1));

            return(mesh);
        }
        public static IndicesUnsignedInt Triangulate(IEnumerable<Vector3D> positions)
        {
            if (positions == null)
            {
                throw new ArgumentNullException("positions");
            }

            //
            // Doubly linked list.  This would be a tad cleaner if it were also circular.
            //
            LinkedList<IndexedVector<Vector3D>> remainingPositions = new LinkedList<IndexedVector<Vector3D>>(); ;

            int index = 0;
            foreach (Vector3D position in positions)
            {
                remainingPositions.AddLast(new IndexedVector<Vector3D>(position, index++));
            }

            if (remainingPositions.Count < 3)
            {
                throw new ArgumentOutOfRangeException("positions", "At least three positions are required.");
            }

            IndicesUnsignedInt indices = new IndicesUnsignedInt(3 * (remainingPositions.Count - 2));

            ///////////////////////////////////////////////////////////////////

            LinkedListNode<IndexedVector<Vector3D>> previousNode = remainingPositions.First;
            LinkedListNode<IndexedVector<Vector3D>> node = previousNode.Next;
            LinkedListNode<IndexedVector<Vector3D>> nextNode = node.Next;

            int bailCount = remainingPositions.Count * remainingPositions.Count;

            while (remainingPositions.Count > 3)
            {
                Vector3D p0 = previousNode.Value.Vector;
                Vector3D p1 = node.Value.Vector;
                Vector3D p2 = nextNode.Value.Vector;

                if (IsTipConvex(p0, p1, p2))
                {
                    bool isEar = true;
                    for (LinkedListNode<IndexedVector<Vector3D>> n = ((nextNode.Next != null) ? nextNode.Next : remainingPositions.First);
                        n != previousNode;
                        n = ((n.Next != null) ? n.Next : remainingPositions.First))
                    {
                        if (ContainmentTests.PointInsideThreeSidedInfinitePyramid(n.Value.Vector, Vector3D.Zero, p0, p1, p2))
                        {
                            isEar = false;
                            break;
                        }
                    }

                    if (isEar)
                    {
                        indices.AddTriangle(new TriangleIndicesUnsignedInt(previousNode.Value.Index, node.Value.Index, nextNode.Value.Index));
                        remainingPositions.Remove(node);

                        node = nextNode;
                        nextNode = (nextNode.Next != null) ? nextNode.Next : remainingPositions.First;
                        continue;
                    }
                }

                previousNode = (previousNode.Next != null) ? previousNode.Next : remainingPositions.First;
                node = (node.Next != null) ? node.Next : remainingPositions.First;
                nextNode = (nextNode.Next != null) ? nextNode.Next : remainingPositions.First;

                if (--bailCount == 0)
                {
                    break;
                }
            }

            LinkedListNode<IndexedVector<Vector3D>> n0 = remainingPositions.First;
            LinkedListNode<IndexedVector<Vector3D>> n1 = n0.Next;
            LinkedListNode<IndexedVector<Vector3D>> n2 = n1.Next;
            indices.AddTriangle(new TriangleIndicesUnsignedInt(n0.Value.Index, n1.Value.Index, n2.Value.Index));

            return indices;
        }
        public static TriangleMeshSubdivisionResult Compute(IEnumerable<Vector3D> positions, IndicesUnsignedInt indices, double granularity)
        {
            if (positions == null)
            {
                throw new ArgumentNullException("positions");
            }

            if (indices == null)
            {
                throw new ArgumentNullException("positions");
            }

            if (indices.Values.Count < 3)
            {
                throw new ArgumentOutOfRangeException("indices", "At least three indices are required.");
            }

            if (indices.Values.Count % 3 != 0)
            {
                throw new ArgumentException("indices", "The number of indices must be divisable by three.");
            }

            if (granularity <= 0.0)
            {
                throw new ArgumentOutOfRangeException("granularity", "Granularity must be greater than zero.");
            }

            //
            // Use two queues:  one for triangles that need (or might need) to be 
            // subdivided and other for triangles that are fully subdivided.
            //
            Queue<TriangleIndicesUnsignedInt> triangles = new Queue<TriangleIndicesUnsignedInt>(indices.Values.Count / 3);
            Queue<TriangleIndicesUnsignedInt> done = new Queue<TriangleIndicesUnsignedInt>(indices.Values.Count / 3);

            IList<uint> indicesValues = indices.Values;
            for (int i = 0; i < indicesValues.Count; i += 3)
            {
                triangles.Enqueue(new TriangleIndicesUnsignedInt(indicesValues[i], indicesValues[i + 1], indicesValues[i + 2]));
            }

            //
            // New positions due to edge splits are appended to the positions list.
            //
            IList<Vector3D> subdividedPositions = CollectionAlgorithms.CopyEnumerableToList(positions);

            //
            // Used to make sure shared edges are not split more than once.
            //
            Dictionary<Edge, int> edges = new Dictionary<Edge, int>();

            //
            // Subdivide triangles until we run out
            //
            while (triangles.Count != 0)
            {
                TriangleIndicesUnsignedInt triangle = triangles.Dequeue();

                Vector3D v0 = subdividedPositions[triangle.I0];
                Vector3D v1 = subdividedPositions[triangle.I1];
                Vector3D v2 = subdividedPositions[triangle.I2];

                double g0 = v0.AngleBetween(v1);
                double g1 = v1.AngleBetween(v2);
                double g2 = v2.AngleBetween(v0);
             
                double max = Math.Max(g0, Math.Max(g1, g2));

                if (max > granularity)
                {
                    if (g0 == max)
                    {
                        Edge edge = new Edge(Math.Min(triangle.I0, triangle.I1), Math.Max(triangle.I0, triangle.I1));
                        int i;
                        if (!edges.TryGetValue(edge, out i))
                        {
                            subdividedPositions.Add((v0 + v1) * 0.5);
                            i = subdividedPositions.Count - 1;
                            edges.Add(edge, i);
                        }

                        triangles.Enqueue(new TriangleIndicesUnsignedInt(triangle.I0, i, triangle.I2));
                        triangles.Enqueue(new TriangleIndicesUnsignedInt(i, triangle.I1, triangle.I2));
                    }
                    else if (g1 == max)
                    {
                        Edge edge = new Edge(Math.Min(triangle.I1, triangle.I2), Math.Max(triangle.I1, triangle.I2));
                        int i;
                        if (!edges.TryGetValue(edge, out i))
                        {
                            subdividedPositions.Add((v1 + v2) * 0.5);
                            i = subdividedPositions.Count - 1;
                            edges.Add(edge, i);
                        }

                        triangles.Enqueue(new TriangleIndicesUnsignedInt(triangle.I1, i, triangle.I0));
                        triangles.Enqueue(new TriangleIndicesUnsignedInt(i, triangle.I2, triangle.I0));
                    }
                    else if (g2 == max)
                    {
                        Edge edge = new Edge(Math.Min(triangle.I2, triangle.I0), Math.Max(triangle.I2, triangle.I0));
                        int i;
                        if (!edges.TryGetValue(edge, out i))
                        {
                            subdividedPositions.Add((v2 + v0) * 0.5);
                            i = subdividedPositions.Count - 1;
                            edges.Add(edge, i);
                        }

                        triangles.Enqueue(new TriangleIndicesUnsignedInt(triangle.I2, i, triangle.I1));
                        triangles.Enqueue(new TriangleIndicesUnsignedInt(i, triangle.I0, triangle.I1));
                    }
                }
                else
                {
                    done.Enqueue(triangle);
                }
            }

            //
            // New indices
            //
            IndicesUnsignedInt subdividedIndices = new IndicesUnsignedInt(done.Count * 3);
            foreach (TriangleIndicesUnsignedInt t in done)
            {
                subdividedIndices.AddTriangle(t);
            }

            return new TriangleMeshSubdivisionResult(subdividedPositions, subdividedIndices);
        }
Example #23
0
        public void MeshIndices()
        {
            Mesh mesh = new Mesh();

            IndicesUnsignedShort indicesShort = new IndicesUnsignedShort();
            mesh.Indices = indicesShort;
            Assert.AreEqual(IndicesType.UnsignedShort, mesh.Indices.Datatype);

            IndicesUnsignedInt indicesInt = new IndicesUnsignedInt();
            mesh.Indices = indicesInt;
            Assert.AreEqual(IndicesType.UnsignedInt, mesh.Indices.Datatype);

            indicesInt.AddTriangle(new TriangleIndicesUnsignedInt(0, 1, 2));
            Assert.AreEqual(0, indicesInt.Values[0]);
            Assert.AreEqual(1, indicesInt.Values[1]);
            Assert.AreEqual(2, indicesInt.Values[2]);
        }
        public static Mesh Compute(Ellipsoid ellipsoid, int numberOfSlicePartitions, int numberOfStackPartitions, GeographicGridEllipsoidVertexAttributes vertexAttributes)
        {
            if (numberOfSlicePartitions < 3)
            {
                throw new ArgumentOutOfRangeException("numberOfSlicePartitions");
            }

            if (numberOfStackPartitions < 2)
            {
                throw new ArgumentOutOfRangeException("numberOfStackPartitions");
            }

            if ((vertexAttributes & GeographicGridEllipsoidVertexAttributes.Position) != GeographicGridEllipsoidVertexAttributes.Position)
            {
                throw new ArgumentException("Positions must be provided.", "vertexAttributes");
            }

            Mesh mesh = new Mesh();
            mesh.PrimitiveType = PrimitiveType.Triangles;
            mesh.FrontFaceWindingOrder = WindingOrder.Counterclockwise;

            int numberOfVertices = NumberOfVertices(numberOfSlicePartitions, numberOfStackPartitions);
            VertexAttributeDoubleVector3 positionsAttribute = new VertexAttributeDoubleVector3("position", numberOfVertices);
            mesh.Attributes.Add(positionsAttribute);

            IndicesUnsignedInt indices = new IndicesUnsignedInt(3 * NumberOfTriangles(numberOfSlicePartitions, numberOfStackPartitions));
            mesh.Indices = indices;

            IList<Vector3H> normals = null;
            if ((vertexAttributes & GeographicGridEllipsoidVertexAttributes.Normal) == GeographicGridEllipsoidVertexAttributes.Normal)
            {
                VertexAttributeHalfFloatVector3 normalsAttribute = new VertexAttributeHalfFloatVector3("normal", numberOfVertices);
                mesh.Attributes.Add(normalsAttribute);
                normals = normalsAttribute.Values;
            }

            IList<Vector2H> textureCoordinates = null;
            if ((vertexAttributes & GeographicGridEllipsoidVertexAttributes.TextureCoordinate) == GeographicGridEllipsoidVertexAttributes.TextureCoordinate)
            {
                VertexAttributeHalfFloatVector2 textureCoordinateAttribute = new VertexAttributeHalfFloatVector2("textureCoordinate", numberOfVertices);
                mesh.Attributes.Add(textureCoordinateAttribute);
                textureCoordinates = textureCoordinateAttribute.Values;
            }

            //
            // Create lookup table
            //
            double[] cosTheta = new double[numberOfSlicePartitions];
            double[] sinTheta = new double[numberOfSlicePartitions];

            for (int j = 0; j < numberOfSlicePartitions; ++j)
            {
                double theta = Trig.TwoPi * (((double)j) / numberOfSlicePartitions);
                cosTheta[j] = Math.Cos(theta);
                sinTheta[j] = Math.Sin(theta);
            }

            //
            // Create positions
            //
            IList<Vector3D> positions = positionsAttribute.Values;
            positions.Add(new Vector3D(0, 0, ellipsoid.Radii.Z));

            for (int i = 1; i < numberOfStackPartitions; ++i)
            {
                double phi = Math.PI * (((double)i) / numberOfStackPartitions);
                double sinPhi = Math.Sin(phi);

                double xSinPhi = ellipsoid.Radii.X * sinPhi;
                double ySinPhi = ellipsoid.Radii.Y * sinPhi;
                double zCosPhi = ellipsoid.Radii.Z * Math.Cos(phi);

                for (int j = 0; j < numberOfSlicePartitions; ++j)
                {
                    positions.Add(new Vector3D(cosTheta[j] * xSinPhi, sinTheta[j] * ySinPhi, zCosPhi));
                }
            }
            positions.Add(new Vector3D(0, 0, -ellipsoid.Radii.Z));

            if ((normals != null) || (textureCoordinates != null))
            {
                for (int i = 0; i < positions.Count; ++i)
                {
                    Vector3D deticSurfaceNormal = ellipsoid.GeodeticSurfaceNormal(positions[i]);

                    if (normals != null)
                    {
                        normals.Add(deticSurfaceNormal.ToVector3H());
                    }

                    if (textureCoordinates != null)
                    {
                        textureCoordinates.Add(SubdivisionUtility.ComputeTextureCoordinate(deticSurfaceNormal));
                    }
                }
            }

            //
            // Triangle fan top row
            //
            for (int j = 1; j < numberOfSlicePartitions; ++j)
            {
                indices.AddTriangle(new TriangleIndicesUnsignedInt(0, j, j + 1));
            }
            indices.AddTriangle(new TriangleIndicesUnsignedInt(0, numberOfSlicePartitions, 1));

            //
            // Middle rows are triangle strips
            //
            for (int i = 0; i < numberOfStackPartitions - 2; ++i)
            {
                int topRowOffset = (i * numberOfSlicePartitions) + 1;
                int bottomRowOffset = ((i + 1) * numberOfSlicePartitions) + 1;

                for (int j = 0; j < numberOfSlicePartitions - 1; ++j)
                {
                    indices.AddTriangle(new TriangleIndicesUnsignedInt(bottomRowOffset + j, bottomRowOffset + j + 1, topRowOffset + j + 1));
                    indices.AddTriangle(new TriangleIndicesUnsignedInt(bottomRowOffset + j, topRowOffset + j + 1, topRowOffset + j));
                }
                indices.AddTriangle(new TriangleIndicesUnsignedInt(bottomRowOffset + numberOfSlicePartitions - 1, bottomRowOffset, topRowOffset));
                indices.AddTriangle(new TriangleIndicesUnsignedInt(bottomRowOffset + numberOfSlicePartitions - 1, topRowOffset, topRowOffset + numberOfSlicePartitions - 1));
            }

            //
            // Triangle fan bottom row
            //
            int lastPosition = positions.Count - 1;
            for (int j = lastPosition - 1; j > lastPosition - numberOfSlicePartitions; --j)
            {
                indices.AddTriangle(new TriangleIndicesUnsignedInt(lastPosition, j, j - 1));
            }
            indices.AddTriangle(new TriangleIndicesUnsignedInt(lastPosition, lastPosition - numberOfSlicePartitions, lastPosition - 1));

            return mesh;
        }
        public static Mesh Compute(Ellipsoid ellipsoid, int numberOfPartitions, CubeMapEllipsoidVertexAttributes vertexAttributes)
        {
            if (numberOfPartitions < 0)
            {
                throw new ArgumentOutOfRangeException("numberOfPartitions");
            }

            if ((vertexAttributes & CubeMapEllipsoidVertexAttributes.Position) != CubeMapEllipsoidVertexAttributes.Position)
            {
                throw new ArgumentException("Positions must be provided.", "vertexAttributes");
            }

            Mesh mesh = new Mesh();

            mesh.PrimitiveType         = PrimitiveType.Triangles;
            mesh.FrontFaceWindingOrder = WindingOrder.Counterclockwise;

            int numberOfVertices = NumberOfVertices(numberOfPartitions);
            VertexAttributeDoubleVector3 positionsAttribute = new VertexAttributeDoubleVector3("position", numberOfVertices);

            mesh.Attributes.Add(positionsAttribute);

            IndicesUnsignedInt indices = new IndicesUnsignedInt(3 * NumberOfTriangles(numberOfPartitions));

            mesh.Indices = indices;

            CubeMapMesh CubeMapMesh = new CubeMapMesh();

            CubeMapMesh.Ellipsoid          = ellipsoid;
            CubeMapMesh.NumberOfPartitions = numberOfPartitions;
            CubeMapMesh.Positions          = positionsAttribute.Values;
            CubeMapMesh.Indices            = indices;

            if ((vertexAttributes & CubeMapEllipsoidVertexAttributes.Normal) == CubeMapEllipsoidVertexAttributes.Normal)
            {
                VertexAttributeHalfFloatVector3 normalsAttribute = new VertexAttributeHalfFloatVector3("normal", numberOfVertices);
                mesh.Attributes.Add(normalsAttribute);
                CubeMapMesh.Normals = normalsAttribute.Values;
            }

            if ((vertexAttributes & CubeMapEllipsoidVertexAttributes.TextureCoordinate) == CubeMapEllipsoidVertexAttributes.TextureCoordinate)
            {
                VertexAttributeHalfFloatVector2 textureCoordinateAttribute = new VertexAttributeHalfFloatVector2("textureCoordinate", numberOfVertices);
                mesh.Attributes.Add(textureCoordinateAttribute);
                CubeMapMesh.TextureCoordinate = textureCoordinateAttribute.Values;
            }

            //
            // Initial cube.  In the plane, z = -1:
            //
            //                   +y
            //                    |
            //             Q2     * p3     Q1
            //                  / | \
            //              p0 *--+--* p2   +x
            //                  \ | /
            //             Q3     * p1     Q4
            //                    |
            //
            // Similarly, p4 to p7 are in the plane z = 1.
            //
            CubeMapMesh.Positions.Add(new Vector3D(-1, 0, -1));
            CubeMapMesh.Positions.Add(new Vector3D(0, -1, -1));
            CubeMapMesh.Positions.Add(new Vector3D(1, 0, -1));
            CubeMapMesh.Positions.Add(new Vector3D(0, 1, -1));
            CubeMapMesh.Positions.Add(new Vector3D(-1, 0, 1));
            CubeMapMesh.Positions.Add(new Vector3D(0, -1, 1));
            CubeMapMesh.Positions.Add(new Vector3D(1, 0, 1));
            CubeMapMesh.Positions.Add(new Vector3D(0, 1, 1));

            //
            // Edges
            //
            // 0 -> 1, 1 -> 2, 2 -> 3, 3 -> 0.  Plane z = -1
            // 4 -> 5, 5 -> 6, 6 -> 7, 7 -> 4.  Plane z = 1
            // 0 -> 4, 1 -> 5, 2 -> 6, 3 -> 7.  From plane z = -1 to plane z - 1
            //
            int[] edge0to1 = AddEdgePositions(0, 1, CubeMapMesh);
            int[] edge1to2 = AddEdgePositions(1, 2, CubeMapMesh);
            int[] edge2to3 = AddEdgePositions(2, 3, CubeMapMesh);
            int[] edge3to0 = AddEdgePositions(3, 0, CubeMapMesh);

            int[] edge4to5 = AddEdgePositions(4, 5, CubeMapMesh);
            int[] edge5to6 = AddEdgePositions(5, 6, CubeMapMesh);
            int[] edge6to7 = AddEdgePositions(6, 7, CubeMapMesh);
            int[] edge7to4 = AddEdgePositions(7, 4, CubeMapMesh);

            int[] edge0to4 = AddEdgePositions(0, 4, CubeMapMesh);
            int[] edge1to5 = AddEdgePositions(1, 5, CubeMapMesh);
            int[] edge2to6 = AddEdgePositions(2, 6, CubeMapMesh);
            int[] edge3to7 = AddEdgePositions(3, 7, CubeMapMesh);

            AddFaceTriangles(edge0to4, edge0to1, edge1to5, edge4to5, CubeMapMesh);                               // Q3 Face
            AddFaceTriangles(edge1to5, edge1to2, edge2to6, edge5to6, CubeMapMesh);                               // Q4 Face
            AddFaceTriangles(edge2to6, edge2to3, edge3to7, edge6to7, CubeMapMesh);                               // Q1 Face
            AddFaceTriangles(edge3to7, edge3to0, edge0to4, edge7to4, CubeMapMesh);                               // Q2 Face
            AddFaceTriangles(ReversedArray(edge7to4), edge4to5, edge5to6, ReversedArray(edge6to7), CubeMapMesh); // Plane z = 1
            AddFaceTriangles(edge1to2, ReversedArray(edge0to1), ReversedArray(edge3to0), edge2to3, CubeMapMesh); // Plane z = -1

            CubeToEllipsoid(CubeMapMesh);
            return(mesh);
        }
        public void TwoTriangles3()
        {
            Vector3D[] positions = new Vector3D[]
            {
                Ellipsoid.UnitSphere.ToVector3D(Trig.ToRadians(new Geodetic2D(0, 44))),
                Ellipsoid.UnitSphere.ToVector3D(Trig.ToRadians(new Geodetic2D(1, 45))),
                Ellipsoid.UnitSphere.ToVector3D(Trig.ToRadians(new Geodetic2D(-1, 45))),
                Ellipsoid.UnitSphere.ToVector3D(Trig.ToRadians(new Geodetic2D(0, 46)))
            };
            
            IndicesUnsignedInt indices = new IndicesUnsignedInt();
            indices.Values.Add(0);
            indices.Values.Add(1);
            indices.Values.Add(2);
            indices.Values.Add(3);
            indices.Values.Add(2);
            indices.Values.Add(1);

            TriangleMeshSubdivisionResult result = TriangleMeshSubdivision.Compute(positions, indices, Trig.ToRadians(1.4));

            Assert.AreEqual(5, result.Positions.Count);
            Assert.AreEqual(12, result.Indices.Values.Count);
        }
Example #27
0
        public PolygonShapefile(
            Shapefile shapefile, 
            Context context, 
            Ellipsoid globeShape,
            ShapefileAppearance appearance)
        {
            Verify.ThrowIfNull(shapefile);
            Verify.ThrowIfNull(context);
            Verify.ThrowIfNull(globeShape);

            _polyline = new OutlinedPolylineTexture();
            _polygons = new List<Polygon>();

            VertexAttributeDoubleVector3 positionAttribute = new VertexAttributeDoubleVector3("position");
            VertexAttributeRGBA colorAttribute = new VertexAttributeRGBA("color");
            VertexAttributeRGBA outlineColorAttribute = new VertexAttributeRGBA("outlineColor");
            IndicesUnsignedInt indices = new IndicesUnsignedInt();

            Random r = new Random(3);
            IList<Vector3D> positions = new List<Vector3D>();

            foreach (Shape shape in shapefile)
            {
                if (shape.ShapeType != ShapeType.Polygon)
                {
                    throw new NotSupportedException("The type of an individual shape does not match the Shapefile type.");
                }

                PolygonShape polygonShape = (PolygonShape)shape;

                for (int j = 0; j < polygonShape.Count; ++j)
                {
                    Color color = Color.FromArgb(127, r.Next(256), r.Next(256), r.Next(256));

                    positions.Clear();

                    ShapePart part = polygonShape[j];

                    for (int i = 0; i < part.Count; ++i)
                    {
                        Vector2D point = part[i];

                        positions.Add(globeShape.ToVector3D(Trig.ToRadians(new Geodetic3D(point.X, point.Y))));

                        //
                        // For polyline
                        //
                        positionAttribute.Values.Add(globeShape.ToVector3D(Trig.ToRadians(new Geodetic3D(point.X, point.Y))));
                        colorAttribute.AddColor(color);
                        outlineColorAttribute.AddColor(Color.Black);

                        if (i != 0)
                        {
                            indices.Values.Add((uint)positionAttribute.Values.Count - 2);
                            indices.Values.Add((uint)positionAttribute.Values.Count - 1);
                        }
                    }

                    try
                    {
                        Polygon p = new Polygon(context, globeShape, positions);
                        p.Color = color;
                        _polygons.Add(p);
                    }
                    catch (ArgumentOutOfRangeException) // Not enough positions after cleaning
                    {
                    }
                }
            }

            Mesh mesh = new Mesh();
            mesh.PrimitiveType = PrimitiveType.Lines;
            mesh.Attributes.Add(positionAttribute);
            mesh.Attributes.Add(colorAttribute);
            mesh.Attributes.Add(outlineColorAttribute);
            mesh.Indices = indices;
            _polyline.Set(context, mesh);
        }
Example #28
0
        public static IndicesUnsignedInt Triangulate(IEnumerable <Vector3D> positions)
        {
            if (positions == null)
            {
                throw new ArgumentNullException("positions");
            }

            //
            // Doubly linked list.  This would be a tad cleaner if it were also circular.
            //
            LinkedList <IndexedVector <Vector3D> > remainingPositions = new LinkedList <IndexedVector <Vector3D> >();;

            int index = 0;

            foreach (Vector3D position in positions)
            {
                remainingPositions.AddLast(new IndexedVector <Vector3D>(position, index++));
            }

            if (remainingPositions.Count < 3)
            {
                throw new ArgumentOutOfRangeException("positions", "At least three positions are required.");
            }

            IndicesUnsignedInt indices = new IndicesUnsignedInt(3 * (remainingPositions.Count - 2));

            ///////////////////////////////////////////////////////////////////

            LinkedListNode <IndexedVector <Vector3D> > previousNode = remainingPositions.First;
            LinkedListNode <IndexedVector <Vector3D> > node         = previousNode.Next;
            LinkedListNode <IndexedVector <Vector3D> > nextNode     = node.Next;

            int bailCount = remainingPositions.Count * remainingPositions.Count;

            while (remainingPositions.Count > 3)
            {
                Vector3D p0 = previousNode.Value.Vector;
                Vector3D p1 = node.Value.Vector;
                Vector3D p2 = nextNode.Value.Vector;

                if (IsTipConvex(p0, p1, p2))
                {
                    bool isEar = true;
                    for (LinkedListNode <IndexedVector <Vector3D> > n = ((nextNode.Next != null) ? nextNode.Next : remainingPositions.First);
                         n != previousNode;
                         n = ((n.Next != null) ? n.Next : remainingPositions.First))
                    {
                        if (ContainmentTests.PointInsideThreeSidedInfinitePyramid(n.Value.Vector, Vector3D.Zero, p0, p1, p2))
                        {
                            isEar = false;
                            break;
                        }
                    }

                    if (isEar)
                    {
                        indices.AddTriangle(new TriangleIndicesUnsignedInt(previousNode.Value.Index, node.Value.Index, nextNode.Value.Index));
                        remainingPositions.Remove(node);

                        node     = nextNode;
                        nextNode = (nextNode.Next != null) ? nextNode.Next : remainingPositions.First;
                        continue;
                    }
                }

                previousNode = (previousNode.Next != null) ? previousNode.Next : remainingPositions.First;
                node         = (node.Next != null) ? node.Next : remainingPositions.First;
                nextNode     = (nextNode.Next != null) ? nextNode.Next : remainingPositions.First;

                if (--bailCount == 0)
                {
                    break;
                }
            }

            LinkedListNode <IndexedVector <Vector3D> > n0 = remainingPositions.First;
            LinkedListNode <IndexedVector <Vector3D> > n1 = n0.Next;
            LinkedListNode <IndexedVector <Vector3D> > n2 = n1.Next;

            indices.AddTriangle(new TriangleIndicesUnsignedInt(n0.Value.Index, n1.Value.Index, n2.Value.Index));

            return(indices);
        }
        public static TriangleMeshSubdivisionResult Compute(IEnumerable <Vector3D> positions, IndicesUnsignedInt indices, double granularity)
        {
            if (positions == null)
            {
                throw new ArgumentNullException("positions");
            }

            if (indices == null)
            {
                throw new ArgumentNullException("positions");
            }

            if (indices.Values.Count < 3)
            {
                throw new ArgumentOutOfRangeException("indices", "At least three indices are required.");
            }

            if (indices.Values.Count % 3 != 0)
            {
                throw new ArgumentException("indices", "The number of indices must be divisable by three.");
            }

            if (granularity <= 0.0)
            {
                throw new ArgumentOutOfRangeException("granularity", "Granularity must be greater than zero.");
            }

            //
            // Use two queues:  one for triangles that need (or might need) to be
            // subdivided and other for triangles that are fully subdivided.
            //
            Queue <TriangleIndicesUnsignedInt> triangles = new Queue <TriangleIndicesUnsignedInt>(indices.Values.Count / 3);
            Queue <TriangleIndicesUnsignedInt> done      = new Queue <TriangleIndicesUnsignedInt>(indices.Values.Count / 3);

            IList <uint> indicesValues = indices.Values;

            for (int i = 0; i < indicesValues.Count; i += 3)
            {
                triangles.Enqueue(new TriangleIndicesUnsignedInt(indicesValues[i], indicesValues[i + 1], indicesValues[i + 2]));
            }

            //
            // New positions due to edge splits are appended to the positions list.
            //
            IList <Vector3D> subdividedPositions = CollectionAlgorithms.CopyEnumerableToList(positions);

            //
            // Used to make sure shared edges are not split more than once.
            //
            Dictionary <Edge, int> edges = new Dictionary <Edge, int>();

            //
            // Subdivide triangles until we run out
            //
            while (triangles.Count != 0)
            {
                TriangleIndicesUnsignedInt triangle = triangles.Dequeue();

                Vector3D v0 = subdividedPositions[triangle.I0];
                Vector3D v1 = subdividedPositions[triangle.I1];
                Vector3D v2 = subdividedPositions[triangle.I2];

                double g0 = v0.AngleBetween(v1);
                double g1 = v1.AngleBetween(v2);
                double g2 = v2.AngleBetween(v0);

                double max = Math.Max(g0, Math.Max(g1, g2));

                if (max > granularity)
                {
                    if (g0 == max)
                    {
                        Edge edge = new Edge(Math.Min(triangle.I0, triangle.I1), Math.Max(triangle.I0, triangle.I1));
                        int  i;
                        if (!edges.TryGetValue(edge, out i))
                        {
                            subdividedPositions.Add((v0 + v1) * 0.5);
                            i = subdividedPositions.Count - 1;
                            edges.Add(edge, i);
                        }

                        triangles.Enqueue(new TriangleIndicesUnsignedInt(triangle.I0, i, triangle.I2));
                        triangles.Enqueue(new TriangleIndicesUnsignedInt(i, triangle.I1, triangle.I2));
                    }
                    else if (g1 == max)
                    {
                        Edge edge = new Edge(Math.Min(triangle.I1, triangle.I2), Math.Max(triangle.I1, triangle.I2));
                        int  i;
                        if (!edges.TryGetValue(edge, out i))
                        {
                            subdividedPositions.Add((v1 + v2) * 0.5);
                            i = subdividedPositions.Count - 1;
                            edges.Add(edge, i);
                        }

                        triangles.Enqueue(new TriangleIndicesUnsignedInt(triangle.I1, i, triangle.I0));
                        triangles.Enqueue(new TriangleIndicesUnsignedInt(i, triangle.I2, triangle.I0));
                    }
                    else if (g2 == max)
                    {
                        Edge edge = new Edge(Math.Min(triangle.I2, triangle.I0), Math.Max(triangle.I2, triangle.I0));
                        int  i;
                        if (!edges.TryGetValue(edge, out i))
                        {
                            subdividedPositions.Add((v2 + v0) * 0.5);
                            i = subdividedPositions.Count - 1;
                            edges.Add(edge, i);
                        }

                        triangles.Enqueue(new TriangleIndicesUnsignedInt(triangle.I2, i, triangle.I1));
                        triangles.Enqueue(new TriangleIndicesUnsignedInt(i, triangle.I0, triangle.I1));
                    }
                }
                else
                {
                    done.Enqueue(triangle);
                }
            }

            //
            // New indices
            //
            IndicesUnsignedInt subdividedIndices = new IndicesUnsignedInt(done.Count * 3);

            foreach (TriangleIndicesUnsignedInt t in done)
            {
                subdividedIndices.AddTriangle(t);
            }

            return(new TriangleMeshSubdivisionResult(subdividedPositions, subdividedIndices));
        }
 internal TriangleMeshSubdivisionResult(ICollection<Vector3D> positions, IndicesUnsignedInt indices)
 {
     _positions = positions;
     _indices = indices;
 }
Example #31
0
 internal TriangleMeshSubdivisionResult(ICollection <Vector3D> positions, IndicesUnsignedInt indices)
 {
     _positions = positions;
     _indices   = indices;
 }
        public static Mesh Compute(RectangleD rectangle, int numberOfPartitionsX, int numberOfPartitionsY)
        {
            if (numberOfPartitionsX < 0)
            {
                throw new ArgumentOutOfRangeException("numberOfPartitionsX");
            }

            if (numberOfPartitionsY < 0)
            {
                throw new ArgumentOutOfRangeException("numberOfPartitionsY");
            }

            Mesh mesh = new Mesh();
            mesh.PrimitiveType = PrimitiveType.Triangles;
            mesh.FrontFaceWindingOrder = WindingOrder.Counterclockwise;

            int numberOfPositions = (numberOfPartitionsX + 1) * (numberOfPartitionsY + 1);
            VertexAttributeFloatVector2 positionsAttribute = new VertexAttributeFloatVector2("position", numberOfPositions);
            IList<Vector2F> positions = positionsAttribute.Values;
            mesh.Attributes.Add(positionsAttribute);

            int numberOfIndices = (numberOfPartitionsX * numberOfPartitionsY) * 6;
            IndicesUnsignedInt indices = new IndicesUnsignedInt(numberOfIndices);
            mesh.Indices = indices;

            //
            // Positions
            //
            Vector2D lowerLeft = rectangle.LowerLeft;
            Vector2D toUpperRight = rectangle.UpperRight - lowerLeft;

            for (int y = 0; y <= numberOfPartitionsY; ++y)
            {
                double deltaY = y / (double)numberOfPartitionsY;
                double currentY = lowerLeft.Y + (deltaY * toUpperRight.Y);

                for (int x = 0; x <= numberOfPartitionsX; ++x)
                {
                    double deltaX = x / (double)numberOfPartitionsX;
                    double currentX = lowerLeft.X + (deltaX * toUpperRight.X);
                    positions.Add(new Vector2D(currentX, currentY).ToVector2F());
                }
            }

            //
            // Indices
            //
            int rowDelta = numberOfPartitionsX + 1;
            int i = 0;
            for (int y = 0; y < numberOfPartitionsY; ++y)
            {
                for (int x = 0; x < numberOfPartitionsX; ++x)
                {
                    indices.AddTriangle(new TriangleIndicesUnsignedInt(i, i + 1, rowDelta + (i + 1)));
                    indices.AddTriangle(new TriangleIndicesUnsignedInt(i, rowDelta + (i + 1), rowDelta + i));
                    i += 1;
                }
                i += 1;
            }

            return mesh;
        }
        public static Mesh Compute(Ellipsoid ellipsoid, int numberOfPartitions, CubeMapEllipsoidVertexAttributes vertexAttributes)
        {
            if (numberOfPartitions < 0)
            {
                throw new ArgumentOutOfRangeException("numberOfPartitions");
            }

            if ((vertexAttributes & CubeMapEllipsoidVertexAttributes.Position) != CubeMapEllipsoidVertexAttributes.Position)
            {
                throw new ArgumentException("Positions must be provided.", "vertexAttributes");
            }

            Mesh mesh = new Mesh();
            mesh.PrimitiveType = PrimitiveType.Triangles;
            mesh.FrontFaceWindingOrder = WindingOrder.Counterclockwise;

            int numberOfVertices = NumberOfVertices(numberOfPartitions);
            VertexAttributeDoubleVector3 positionsAttribute = new VertexAttributeDoubleVector3("position", numberOfVertices);
            mesh.Attributes.Add(positionsAttribute);

            IndicesUnsignedInt indices = new IndicesUnsignedInt(3 * NumberOfTriangles(numberOfPartitions));
            mesh.Indices = indices;

            CubeMapMesh CubeMapMesh = new CubeMapMesh();
            CubeMapMesh.Ellipsoid = ellipsoid;
            CubeMapMesh.NumberOfPartitions = numberOfPartitions;
            CubeMapMesh.Positions = positionsAttribute.Values;
            CubeMapMesh.Indices = indices;

            if ((vertexAttributes & CubeMapEllipsoidVertexAttributes.Normal) == CubeMapEllipsoidVertexAttributes.Normal)
            {
                VertexAttributeHalfFloatVector3 normalsAttribute = new VertexAttributeHalfFloatVector3("normal", numberOfVertices);
                mesh.Attributes.Add(normalsAttribute);
                CubeMapMesh.Normals = normalsAttribute.Values;
            }

            if ((vertexAttributes & CubeMapEllipsoidVertexAttributes.TextureCoordinate) == CubeMapEllipsoidVertexAttributes.TextureCoordinate)
            {
                VertexAttributeHalfFloatVector2 textureCoordinateAttribute = new VertexAttributeHalfFloatVector2("textureCoordinate", numberOfVertices);
                mesh.Attributes.Add(textureCoordinateAttribute);
                CubeMapMesh.TextureCoordinate = textureCoordinateAttribute.Values;
            }

            //
            // Initial cube.  In the plane, z = -1:
            //
            //                   +y
            //                    |
            //             Q2     * p3     Q1
            //                  / | \
            //              p0 *--+--* p2   +x
            //                  \ | /
            //             Q3     * p1     Q4
            //                    |
            //
            // Similarly, p4 to p7 are in the plane z = 1.
            //
            CubeMapMesh.Positions.Add(new Vector3D(-1, 0, -1));
            CubeMapMesh.Positions.Add(new Vector3D(0, -1, -1));
            CubeMapMesh.Positions.Add(new Vector3D(1, 0, -1));
            CubeMapMesh.Positions.Add(new Vector3D(0, 1, -1));
            CubeMapMesh.Positions.Add(new Vector3D(-1, 0, 1));
            CubeMapMesh.Positions.Add(new Vector3D(0, -1, 1));
            CubeMapMesh.Positions.Add(new Vector3D(1, 0, 1));
            CubeMapMesh.Positions.Add(new Vector3D(0, 1, 1));

            //
            // Edges
            //
            // 0 -> 1, 1 -> 2, 2 -> 3, 3 -> 0.  Plane z = -1
            // 4 -> 5, 5 -> 6, 6 -> 7, 7 -> 4.  Plane z = 1
            // 0 -> 4, 1 -> 5, 2 -> 6, 3 -> 7.  From plane z = -1 to plane z - 1
            //
            int[] edge0to1 = AddEdgePositions(0, 1, CubeMapMesh);
            int[] edge1to2 = AddEdgePositions(1, 2, CubeMapMesh);
            int[] edge2to3 = AddEdgePositions(2, 3, CubeMapMesh);
            int[] edge3to0 = AddEdgePositions(3, 0, CubeMapMesh);

            int[] edge4to5 = AddEdgePositions(4, 5, CubeMapMesh);
            int[] edge5to6 = AddEdgePositions(5, 6, CubeMapMesh);
            int[] edge6to7 = AddEdgePositions(6, 7, CubeMapMesh);
            int[] edge7to4 = AddEdgePositions(7, 4, CubeMapMesh);

            int[] edge0to4 = AddEdgePositions(0, 4, CubeMapMesh);
            int[] edge1to5 = AddEdgePositions(1, 5, CubeMapMesh);
            int[] edge2to6 = AddEdgePositions(2, 6, CubeMapMesh);
            int[] edge3to7 = AddEdgePositions(3, 7, CubeMapMesh);

            AddFaceTriangles(edge0to4, edge0to1, edge1to5, edge4to5, CubeMapMesh); // Q3 Face
            AddFaceTriangles(edge1to5, edge1to2, edge2to6, edge5to6, CubeMapMesh); // Q4 Face
            AddFaceTriangles(edge2to6, edge2to3, edge3to7, edge6to7, CubeMapMesh); // Q1 Face
            AddFaceTriangles(edge3to7, edge3to0, edge0to4, edge7to4, CubeMapMesh); // Q2 Face
            AddFaceTriangles(ReversedArray(edge7to4), edge4to5, edge5to6, ReversedArray(edge6to7), CubeMapMesh); // Plane z = 1
            AddFaceTriangles(edge1to2, ReversedArray(edge0to1), ReversedArray(edge3to0), edge2to3, CubeMapMesh); // Plane z = -1

            CubeToEllipsoid(CubeMapMesh);
            return mesh;
        }
Example #34
0
        public static IndicesUnsignedInt Triangulate(IEnumerable <Vector2D> positions)
        {
            //
            // O(n^3)
            //
            // There are several optimization opportunities:
            //   * http://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf
            //   * http://cgm.cs.mcgill.ca/~godfried/publications/triangulation.held.ps.gz
            //   * http://blogs.agi.com/insight3d/index.php/2008/03/20/triangulation-rhymes-with-strangulation/
            //

            if (positions == null)
            {
                throw new ArgumentNullException("positions");
            }

            //
            // Doubly linked list.  This would be a tad cleaner if it were also circular.
            //
            LinkedList <IndexedVector <Vector2D> > remainingPositions = new LinkedList <IndexedVector <Vector2D> >();;

            int index = 0;

            foreach (Vector2D position in positions)
            {
                remainingPositions.AddLast(new IndexedVector <Vector2D>(position, index++));
            }

            if (remainingPositions.Count < 3)
            {
                throw new ArgumentOutOfRangeException("positions", "At least three positions are required.");
            }

            IndicesUnsignedInt indices = new IndicesUnsignedInt(3 * (remainingPositions.Count - 2));

            ///////////////////////////////////////////////////////////////////

            LinkedListNode <IndexedVector <Vector2D> > previousNode = remainingPositions.First;
            LinkedListNode <IndexedVector <Vector2D> > node         = previousNode.Next;
            LinkedListNode <IndexedVector <Vector2D> > nextNode     = node.Next;

            int bailCount = remainingPositions.Count * remainingPositions.Count;

            while (remainingPositions.Count > 3)
            {
                Vector2D p0 = previousNode.Value.Vector;
                Vector2D p1 = node.Value.Vector;
                Vector2D p2 = nextNode.Value.Vector;

                if (IsTipConvex(p0, p1, p2))
                {
                    bool isEar = true;
                    for (LinkedListNode <IndexedVector <Vector2D> > n = ((nextNode.Next != null) ? nextNode.Next : remainingPositions.First);
                         n != previousNode;
                         n = ((n.Next != null) ? n.Next : remainingPositions.First))
                    {
                        if (ContainmentTests.PointInsideTriangle(n.Value.Vector, p0, p1, p2))
                        {
                            isEar = false;
                            break;
                        }
                    }

                    if (isEar)
                    {
                        indices.AddTriangle(new TriangleIndicesUnsignedInt(previousNode.Value.Index, node.Value.Index, nextNode.Value.Index));
                        remainingPositions.Remove(node);

                        node     = nextNode;
                        nextNode = (nextNode.Next != null) ? nextNode.Next : remainingPositions.First;
                        continue;
                    }
                }

                previousNode = (previousNode.Next != null) ? previousNode.Next : remainingPositions.First;
                node         = (node.Next != null) ? node.Next : remainingPositions.First;
                nextNode     = (nextNode.Next != null) ? nextNode.Next : remainingPositions.First;

                if (--bailCount == 0)
                {
                    break;
                }
            }

            LinkedListNode <IndexedVector <Vector2D> > n0 = remainingPositions.First;
            LinkedListNode <IndexedVector <Vector2D> > n1 = n0.Next;
            LinkedListNode <IndexedVector <Vector2D> > n2 = n1.Next;

            indices.AddTriangle(new TriangleIndicesUnsignedInt(n0.Value.Index, n1.Value.Index, n2.Value.Index));

            return(indices);
        }
        private static void AddFaceTriangles(
            int[] leftBottomToTop,
            int[] bottomLeftToRight,
            int[] rightBottomToTop,
            int[] topLeftToRight,
            CubeMapMesh CubeMapMesh)
        {
            IList <Vector3D>   positions = CubeMapMesh.Positions;
            IndicesUnsignedInt indices   = CubeMapMesh.Indices;
            int numberOfPartitions       = CubeMapMesh.NumberOfPartitions;

            Vector3D origin = positions[bottomLeftToRight[0]];
            Vector3D x      = positions[bottomLeftToRight[bottomLeftToRight.Length - 1]] - origin;
            Vector3D y      = positions[topLeftToRight[0]] - origin;

            int[] bottomIndicesBuffer = new int[numberOfPartitions + 1];
            int[] topIndicesBuffer    = new int[numberOfPartitions + 1];

            int[] bottomIndices = bottomLeftToRight;
            int[] topIndices    = topIndicesBuffer;

            for (int j = 1; j <= numberOfPartitions; ++j)
            {
                if (j != numberOfPartitions)
                {
                    if (j != 1)
                    {
                        //
                        // This copy could be avoided by ping ponging buffers.
                        //
                        topIndicesBuffer.CopyTo(bottomIndicesBuffer, 0);
                        bottomIndices = bottomIndicesBuffer;
                    }

                    topIndicesBuffer[0] = leftBottomToTop[j];
                    topIndicesBuffer[numberOfPartitions] = rightBottomToTop[j];

                    double   deltaY  = j / (double)numberOfPartitions;
                    Vector3D offsetY = deltaY * y;

                    for (int i = 1; i < numberOfPartitions; ++i)
                    {
                        double   deltaX  = i / (double)numberOfPartitions;
                        Vector3D offsetX = deltaX * x;

                        topIndicesBuffer[i] = CubeMapMesh.Positions.Count;
                        positions.Add(origin + offsetX + offsetY);
                    }
                }
                else
                {
                    if (j != 1)
                    {
                        bottomIndices = topIndicesBuffer;
                    }
                    topIndices = topLeftToRight;
                }

                for (int i = 0; i < numberOfPartitions; ++i)
                {
                    indices.AddTriangle(new TriangleIndicesUnsignedInt(
                                            bottomIndices[i], bottomIndices[i + 1], topIndices[i + 1]));
                    indices.AddTriangle(new TriangleIndicesUnsignedInt(
                                            bottomIndices[i], topIndices[i + 1], topIndices[i]));
                }
            }
        }
Example #36
0
        public static IndicesUnsignedInt Triangulate(IEnumerable<Vector2D> positions)
        {
            //
            // O(n^3)
            //
            // There are several optimization opportunities:
            //   * http://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf
            //   * http://cgm.cs.mcgill.ca/~godfried/publications/triangulation.held.ps.gz
            //   * http://blogs.agi.com/insight3d/index.php/2008/03/20/triangulation-rhymes-with-strangulation/
            //

            if (positions == null)
            {
                throw new ArgumentNullException("positions");
            }

            //
            // Doubly linked list.  This would be a tad cleaner if it were also circular.
            //
            LinkedList<IndexedVector<Vector2D>> remainingPositions = new LinkedList<IndexedVector<Vector2D>>(); ;

            int index = 0;
            foreach (Vector2D position in positions)
            {
                remainingPositions.AddLast(new IndexedVector<Vector2D>(position, index++));
            }

            if (remainingPositions.Count < 3)
            {
                throw new ArgumentOutOfRangeException("positions", "At least three positions are required.");
            }
            
            IndicesUnsignedInt indices = new IndicesUnsignedInt(3 * (remainingPositions.Count - 2));

            ///////////////////////////////////////////////////////////////////

            LinkedListNode<IndexedVector<Vector2D>> previousNode = remainingPositions.First;
            LinkedListNode<IndexedVector<Vector2D>> node = previousNode.Next;
            LinkedListNode<IndexedVector<Vector2D>> nextNode = node.Next;

            int bailCount = remainingPositions.Count * remainingPositions.Count;

            while (remainingPositions.Count > 3)
            {
                Vector2D p0 = previousNode.Value.Vector;
                Vector2D p1 = node.Value.Vector;
                Vector2D p2 = nextNode.Value.Vector;

                if (IsTipConvex(p0, p1, p2))
                {
                    bool isEar = true;
                    for (LinkedListNode<IndexedVector<Vector2D>> n = ((nextNode.Next != null) ? nextNode.Next : remainingPositions.First);
                        n != previousNode;
                        n = ((n.Next != null) ? n.Next : remainingPositions.First))
                    {
                        if (ContainmentTests.PointInsideTriangle(n.Value.Vector, p0, p1, p2))
                        {
                            isEar = false;
                            break;
                        }
                    }

                    if (isEar)
                    {
                        indices.AddTriangle(new TriangleIndicesUnsignedInt(previousNode.Value.Index, node.Value.Index, nextNode.Value.Index));
                        remainingPositions.Remove(node);

                        node = nextNode;
                        nextNode = (nextNode.Next != null) ? nextNode.Next : remainingPositions.First;
                        continue;
                    }
                }

                previousNode = (previousNode.Next != null) ? previousNode.Next : remainingPositions.First;
                node = (node.Next != null) ? node.Next : remainingPositions.First;
                nextNode = (nextNode.Next != null) ? nextNode.Next : remainingPositions.First;

                if (--bailCount == 0)
                {
                    break;
                }
            }

            LinkedListNode<IndexedVector<Vector2D>> n0 = remainingPositions.First;
            LinkedListNode<IndexedVector<Vector2D>> n1 = n0.Next;
            LinkedListNode<IndexedVector<Vector2D>> n2 = n1.Next;
            indices.AddTriangle(new TriangleIndicesUnsignedInt(n0.Value.Index, n1.Value.Index, n2.Value.Index));

            return indices;
        }
Example #37
0
        public static Mesh Compute(Ellipsoid ellipsoid, int numberOfSubdivisions, SubdivisionEllipsoidVertexAttributes vertexAttributes)
        {
            if (numberOfSubdivisions < 0)
            {
                throw new ArgumentOutOfRangeException("numberOfSubdivisions");
            }

            if ((vertexAttributes & SubdivisionEllipsoidVertexAttributes.Position) != SubdivisionEllipsoidVertexAttributes.Position)
            {
                throw new ArgumentException("Positions must be provided.", "vertexAttributes");
            }

            Mesh mesh = new Mesh();

            mesh.PrimitiveType         = PrimitiveType.Triangles;
            mesh.FrontFaceWindingOrder = WindingOrder.Counterclockwise;

            int numberOfVertices = SubdivisionUtility.NumberOfVertices(numberOfSubdivisions);
            VertexAttributeDoubleVector3 positionsAttribute = new VertexAttributeDoubleVector3("position", numberOfVertices);

            mesh.Attributes.Add(positionsAttribute);

            IndicesUnsignedInt indices = new IndicesUnsignedInt(3 * SubdivisionUtility.NumberOfTriangles(numberOfSubdivisions));

            mesh.Indices = indices;

            SubdivisionMesh subdivisionMesh = new SubdivisionMesh();

            subdivisionMesh.Ellipsoid = ellipsoid;
            subdivisionMesh.Positions = positionsAttribute.Values;
            subdivisionMesh.Indices   = indices;

            if ((vertexAttributes & SubdivisionEllipsoidVertexAttributes.Normal) == SubdivisionEllipsoidVertexAttributes.Normal)
            {
                VertexAttributeHalfFloatVector3 normalsAttribute = new VertexAttributeHalfFloatVector3("normal", numberOfVertices);
                mesh.Attributes.Add(normalsAttribute);
                subdivisionMesh.Normals = normalsAttribute.Values;
            }

            if ((vertexAttributes & SubdivisionEllipsoidVertexAttributes.TextureCoordinate) == SubdivisionEllipsoidVertexAttributes.TextureCoordinate)
            {
                VertexAttributeHalfFloatVector2 textureCoordinateAttribute = new VertexAttributeHalfFloatVector2("textureCoordinate", numberOfVertices);
                mesh.Attributes.Add(textureCoordinateAttribute);
                subdivisionMesh.TextureCoordinate = textureCoordinateAttribute.Values;
            }

            //
            // Initial tetrahedron
            //
            double       negativeRootTwoOverThree = -Math.Sqrt(2.0) / 3.0;
            const double negativeOneThird         = -1.0 / 3.0;
            double       rootSixOverThree         = Math.Sqrt(6.0) / 3.0;

            Vector3D n0 = new Vector3D(0, 0, 1);
            Vector3D n1 = new Vector3D(0, (2.0 * Math.Sqrt(2.0)) / 3.0, negativeOneThird);
            Vector3D n2 = new Vector3D(-rootSixOverThree, negativeRootTwoOverThree, negativeOneThird);
            Vector3D n3 = new Vector3D(rootSixOverThree, negativeRootTwoOverThree, negativeOneThird);

            Vector3D p0 = n0.MultiplyComponents(ellipsoid.Radii);
            Vector3D p1 = n1.MultiplyComponents(ellipsoid.Radii);
            Vector3D p2 = n2.MultiplyComponents(ellipsoid.Radii);
            Vector3D p3 = n3.MultiplyComponents(ellipsoid.Radii);

            subdivisionMesh.Positions.Add(p0);
            subdivisionMesh.Positions.Add(p1);
            subdivisionMesh.Positions.Add(p2);
            subdivisionMesh.Positions.Add(p3);

            if ((subdivisionMesh.Normals != null) || (subdivisionMesh.TextureCoordinate != null))
            {
                Vector3D d0 = ellipsoid.GeodeticSurfaceNormal(p0);
                Vector3D d1 = ellipsoid.GeodeticSurfaceNormal(p1);
                Vector3D d2 = ellipsoid.GeodeticSurfaceNormal(p2);
                Vector3D d3 = ellipsoid.GeodeticSurfaceNormal(p3);

                if (subdivisionMesh.Normals != null)
                {
                    subdivisionMesh.Normals.Add(d0.ToVector3H());
                    subdivisionMesh.Normals.Add(d1.ToVector3H());
                    subdivisionMesh.Normals.Add(d2.ToVector3H());
                    subdivisionMesh.Normals.Add(d3.ToVector3H());
                }

                if (subdivisionMesh.TextureCoordinate != null)
                {
                    subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d0));
                    subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d1));
                    subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d2));
                    subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d3));
                }
            }

            Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(0, 1, 2), numberOfSubdivisions);
            Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(0, 2, 3), numberOfSubdivisions);
            Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(0, 3, 1), numberOfSubdivisions);
            Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(1, 3, 2), numberOfSubdivisions);

            return(mesh);
        }
        public static Mesh Compute(Ellipsoid ellipsoid, int numberOfSubdivisions, SubdivisionEllipsoidVertexAttributes vertexAttributes)
        {
            if (numberOfSubdivisions < 0)
            {
                throw new ArgumentOutOfRangeException("numberOfSubdivisions");
            }

            if ((vertexAttributes & SubdivisionEllipsoidVertexAttributes.Position) != SubdivisionEllipsoidVertexAttributes.Position)
            {
                throw new ArgumentException("Positions must be provided.", "vertexAttributes");
            }

            Mesh mesh = new Mesh();
            mesh.PrimitiveType = PrimitiveType.Triangles;
            mesh.FrontFaceWindingOrder = WindingOrder.Counterclockwise;

            int numberOfVertices = SubdivisionUtility.NumberOfVertices(numberOfSubdivisions);
            VertexAttributeDoubleVector3 positionsAttribute = new VertexAttributeDoubleVector3("position", numberOfVertices);
            mesh.Attributes.Add(positionsAttribute);

            IndicesUnsignedInt indices = new IndicesUnsignedInt(3 * SubdivisionUtility.NumberOfTriangles(numberOfSubdivisions));
            mesh.Indices = indices;

            SubdivisionMesh subdivisionMesh = new SubdivisionMesh();
            subdivisionMesh.Ellipsoid = ellipsoid;
            subdivisionMesh.Positions = positionsAttribute.Values;
            subdivisionMesh.Indices = indices;

            if ((vertexAttributes & SubdivisionEllipsoidVertexAttributes.Normal) == SubdivisionEllipsoidVertexAttributes.Normal)
            {
                VertexAttributeHalfFloatVector3 normalsAttribute = new VertexAttributeHalfFloatVector3("normal", numberOfVertices);
                mesh.Attributes.Add(normalsAttribute);
                subdivisionMesh.Normals = normalsAttribute.Values;
            }

            if ((vertexAttributes & SubdivisionEllipsoidVertexAttributes.TextureCoordinate) == SubdivisionEllipsoidVertexAttributes.TextureCoordinate)
            {
                VertexAttributeHalfFloatVector2 textureCoordinateAttribute = new VertexAttributeHalfFloatVector2("textureCoordinate", numberOfVertices);
                mesh.Attributes.Add(textureCoordinateAttribute);
                subdivisionMesh.TextureCoordinate = textureCoordinateAttribute.Values;
            }

            //
            // Initial tetrahedron
            //
            double negativeRootTwoOverThree = -Math.Sqrt(2.0) / 3.0;
            const double negativeOneThird = -1.0 / 3.0;
            double rootSixOverThree = Math.Sqrt(6.0) / 3.0;

            Vector3D n0 = new Vector3D(0, 0, 1);
            Vector3D n1 = new Vector3D(0, (2.0 * Math.Sqrt(2.0)) / 3.0, negativeOneThird);
            Vector3D n2 = new Vector3D(-rootSixOverThree, negativeRootTwoOverThree, negativeOneThird);
            Vector3D n3 = new Vector3D(rootSixOverThree, negativeRootTwoOverThree, negativeOneThird);

            Vector3D p0 = n0.MultiplyComponents(ellipsoid.Radii);
            Vector3D p1 = n1.MultiplyComponents(ellipsoid.Radii);
            Vector3D p2 = n2.MultiplyComponents(ellipsoid.Radii);
            Vector3D p3 = n3.MultiplyComponents(ellipsoid.Radii);
            
            subdivisionMesh.Positions.Add(p0);
            subdivisionMesh.Positions.Add(p1);
            subdivisionMesh.Positions.Add(p2);
            subdivisionMesh.Positions.Add(p3);

            if ((subdivisionMesh.Normals != null) || (subdivisionMesh.TextureCoordinate != null))
            {
                Vector3D d0 = ellipsoid.GeodeticSurfaceNormal(p0);
                Vector3D d1 = ellipsoid.GeodeticSurfaceNormal(p1);
                Vector3D d2 = ellipsoid.GeodeticSurfaceNormal(p2);
                Vector3D d3 = ellipsoid.GeodeticSurfaceNormal(p3);

                if (subdivisionMesh.Normals != null)
                {
                    subdivisionMesh.Normals.Add(d0.ToVector3H());
                    subdivisionMesh.Normals.Add(d1.ToVector3H());
                    subdivisionMesh.Normals.Add(d2.ToVector3H());
                    subdivisionMesh.Normals.Add(d3.ToVector3H());
                }

                if (subdivisionMesh.TextureCoordinate != null)
                {
                    subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d0));
                    subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d1));
                    subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d2));
                    subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d3));
                }
            }

            Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(0, 1, 2), numberOfSubdivisions);
            Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(0, 2, 3), numberOfSubdivisions);
            Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(0, 3, 1), numberOfSubdivisions);
            Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(1, 3, 2), numberOfSubdivisions);

            return mesh;
        }
Example #39
0
        public static Mesh Compute(RectangleD rectangle, int numberOfPartitionsX, int numberOfPartitionsY)
        {
            if (numberOfPartitionsX < 0)
            {
                throw new ArgumentOutOfRangeException("numberOfPartitionsX");
            }

            if (numberOfPartitionsY < 0)
            {
                throw new ArgumentOutOfRangeException("numberOfPartitionsY");
            }

            Mesh mesh = new Mesh();

            mesh.PrimitiveType         = PrimitiveType.Triangles;
            mesh.FrontFaceWindingOrder = WindingOrder.Counterclockwise;

            int numberOfPositions = (numberOfPartitionsX + 1) * (numberOfPartitionsY + 1);
            VertexAttributeFloatVector2 positionsAttribute = new VertexAttributeFloatVector2("position", numberOfPositions);
            IList <Vector2F>            positions          = positionsAttribute.Values;

            mesh.Attributes.Add(positionsAttribute);

            int numberOfIndices        = (numberOfPartitionsX * numberOfPartitionsY) * 6;
            IndicesUnsignedInt indices = new IndicesUnsignedInt(numberOfIndices);

            mesh.Indices = indices;

            //
            // Positions
            //
            Vector2D lowerLeft    = rectangle.LowerLeft;
            Vector2D toUpperRight = rectangle.UpperRight - lowerLeft;

            for (int y = 0; y <= numberOfPartitionsY; ++y)
            {
                double deltaY   = y / (double)numberOfPartitionsY;
                double currentY = lowerLeft.Y + (deltaY * toUpperRight.Y);

                for (int x = 0; x <= numberOfPartitionsX; ++x)
                {
                    double deltaX   = x / (double)numberOfPartitionsX;
                    double currentX = lowerLeft.X + (deltaX * toUpperRight.X);
                    positions.Add(new Vector2D(currentX, currentY).ToVector2F());
                }
            }

            //
            // Indices
            //
            int rowDelta = numberOfPartitionsX + 1;
            int i        = 0;

            for (int y = 0; y < numberOfPartitionsY; ++y)
            {
                for (int x = 0; x < numberOfPartitionsX; ++x)
                {
                    indices.AddTriangle(new TriangleIndicesUnsignedInt(i, i + 1, rowDelta + (i + 1)));
                    indices.AddTriangle(new TriangleIndicesUnsignedInt(i, rowDelta + (i + 1), rowDelta + i));
                    i += 1;
                }
                i += 1;
            }

            return(mesh);
        }
        public PolylineShapefile(
            Shapefile shapefile, 
            Context context, 
            Ellipsoid globeShape, 
            ShapefileAppearance appearance)
        {
            Verify.ThrowIfNull(shapefile);
            Verify.ThrowIfNull(context);
            Verify.ThrowIfNull(globeShape);
            Verify.ThrowIfNull(appearance);
            
            _polyline = new OutlinedPolylineTexture();

            int positionsCount = 0;
            int indicesCount = 0;
            PolylineCapacities(shapefile, out positionsCount, out indicesCount);

            VertexAttributeDoubleVector3 positionAttribute = new VertexAttributeDoubleVector3("position", positionsCount);
            VertexAttributeRGBA colorAttribute = new VertexAttributeRGBA("color", positionsCount);
            VertexAttributeRGBA outlineColorAttribute = new VertexAttributeRGBA("outlineColor", positionsCount);
            IndicesUnsignedInt indices = new IndicesUnsignedInt(indicesCount);

            foreach (Shape shape in shapefile)
            {
                if (shape.ShapeType != ShapeType.Polyline)
                {
                    throw new NotSupportedException("The type of an individual shape does not match the Shapefile type.");
                }

                PolylineShape polylineShape = (PolylineShape)shape;

                for (int j = 0; j < polylineShape.Count; ++j)
                {
                    ShapePart part = polylineShape[j];

                    for (int i = 0; i < part.Count; ++i)
                    {
                        Vector2D point = part[i];

                        positionAttribute.Values.Add(globeShape.ToVector3D(Trig.ToRadians(new Geodetic3D(point.X, point.Y))));
                        colorAttribute.AddColor(appearance.PolylineColor);
                        outlineColorAttribute.AddColor(appearance.PolylineOutlineColor);

                        if (i != 0)
                        {
                            indices.Values.Add((uint)positionAttribute.Values.Count - 2);
                            indices.Values.Add((uint)positionAttribute.Values.Count - 1);
                        }
                    }
                }
            }

            Mesh mesh = new Mesh();
            mesh.PrimitiveType = PrimitiveType.Lines;
            mesh.Attributes.Add(positionAttribute);
            mesh.Attributes.Add(colorAttribute);
            mesh.Attributes.Add(outlineColorAttribute);
            mesh.Indices = indices;
            _polyline.Set(context, mesh);
            _polyline.Width = appearance.PolylineWidth;
            _polyline.OutlineWidth = appearance.PolylineOutlineWidth;
        }