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); } }
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]); }
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)); }
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]); }
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); }
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]); }
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; }
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; }
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); }
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 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); }
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; }
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; }
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])); } } }
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; }
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; }
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; }