protected virtual void BuildMesh(STLSolid solid, IMeshBuilder builder) { if (RebuildStrategy == Strategy.AutoBestResult) { DMesh3 result = BuildMesh_Auto(solid); builder.AppendNewMesh(result); } else if (RebuildStrategy == Strategy.IdenticalVertexWeld) { DMesh3 result = BuildMesh_IdenticalWeld(solid); builder.AppendNewMesh(result); } else if (RebuildStrategy == Strategy.TolerantVertexWeld) { DMesh3 result = BuildMesh_TolerantWeld(solid, WeldTolerance); builder.AppendNewMesh(result); } else { BuildMesh_NoMerge(solid, builder); } if (WantPerTriAttribs && solid.TriAttribs != null && builder.SupportsMetaData) { builder.AppendMetaData(PerTriAttribMetadataName, solid.TriAttribs); } }
public IOReadResult Read(TextReader reader, ReadOptions options, IMeshBuilder builder) { XmlSerializer serializer = new XmlSerializer(typeof(Model)); Model model; try { model = (Model)serializer.Deserialize(reader); } catch (Exception e) { return(new IOReadResult(IOCode.FileParsingError, $"XML parsing error: {e}")); } foreach (var @object in model.resources.objects) { var mesh = @object.mesh; int meshId = builder.AppendNewMesh(false, false, false, true); var mapV = new int[mesh.vertices.vertices.Length]; for (int k = 0; k < mesh.vertices.vertices.Length; ++k) { var vertex = mesh.vertices.vertices[k]; mapV[k] = builder.AppendVertex(vertex.x, vertex.y, vertex.z); } for (int j = 0; j < mesh.triangles.triangles.Length; ++j) { var triangle = mesh.triangles.triangles[j]; builder.AppendTriangle(mapV[triangle.v1], mapV[triangle.v2], mapV[triangle.v3]); } } return(IOReadResult.Ok); }
public IOReadResult Read(TextReader reader, ReadOptions options, IMeshBuilder builder) { XmlSerializer serializer = new XmlSerializer(typeof(AMF)); AMF amf; try { amf = (AMF)serializer.Deserialize(reader); } catch (Exception e) { return(new IOReadResult(IOCode.FileParsingError, $"XML parsing error: {e}")); } foreach (var @object in amf.objects) { foreach (var mesh in @object.meshes) { int meshId = builder.AppendNewMesh(false, false, false, true); var mapV = new int[mesh.vertices.vertices.Length]; for (int k = 0; k < mesh.vertices.vertices.Length; ++k) { var coordinates = mesh.vertices.vertices[k].coordinates; mapV[k] = builder.AppendVertex(coordinates.x, coordinates.y, coordinates.z); } for (int i = 0; i < mesh.volumes.Length; ++i) { for (int j = 0; j < mesh.volumes[i].triangles.Length; ++j) { var triangle = mesh.volumes[i].triangles[j]; builder.AppendTriangle(mapV[triangle.v1], mapV[triangle.v2], mapV[triangle.v3], i); } } } } return(IOReadResult.Ok); }
public IOReadResult Read(BinaryReader reader, ReadOptions options, IMeshBuilder builder) { int nMeshes = reader.ReadInt32(); for (int k = 0; k < nMeshes; ++k) { var m = new DMesh3(); gSerialization.Restore(m, reader); builder.AppendNewMesh(m); } return(new IOReadResult(IOCode.Ok, "")); }
protected virtual void BuildMesh(STLSolid solid, IMeshBuilder builder) { if (RebuildStrategy == Strategy.AutoBestResult) { DMesh3 result = BuildMesh_Auto(solid); builder.AppendNewMesh(result); } else if (RebuildStrategy == Strategy.IdenticalVertexWeld) { DMesh3 result = BuildMesh_IdenticalWeld(solid); builder.AppendNewMesh(result); } else if (RebuildStrategy == Strategy.TolerantVertexWeld) { DMesh3 result = BuildMesh_TolerantWeld(solid, WeldTolerance); builder.AppendNewMesh(result); } else { BuildMesh_NoMerge(solid, builder); } }
unsafe IOReadResult BuildMeshes_Simple(ReadOptions options, IMeshBuilder builder) { if (vPositions.Length == 0) { return(new IOReadResult(IOCode.GarbageDataError, "No vertices in file")); } if (vTriangles.Length == 0) { return(new IOReadResult(IOCode.GarbageDataError, "No triangles in file")); } // [TODO] support non-per-vertex normals/colors bool bHaveNormals = (vNormals.Length == vPositions.Length); bool bHaveColors = (vColors.Length == vPositions.Length); bool bHaveUVs = (vUVs.Length / 2 == vPositions.Length / 3); int nVertices = vPositions.Length / 3; int[] mapV = new int[nVertices]; int meshID = builder.AppendNewMesh(bHaveNormals, bHaveColors, bHaveUVs, false); for (int k = 0; k < nVertices; ++k) { vtx_key vk = new vtx_key() { vi = k, ci = k, ni = k, ui = k }; mapV[k] = append_vertex(builder, vk, bHaveNormals, bHaveColors, bHaveUVs); } // [TODO] this doesn't handle missing vertices... for (int k = 0; k < vTriangles.Length; ++k) { append_triangle(builder, k, mapV); } if (UsedMaterials.Count == 1) // [RMS] should not be in here otherwise { int material_id = UsedMaterials.Keys.First(); string sMatName = UsedMaterials[material_id]; OBJMaterial useMat = Materials[sMatName]; int matID = builder.BuildMaterial(useMat); builder.AssignMaterial(matID, meshID); } return(new IOReadResult(IOCode.Ok, "")); }
protected virtual void BuildMesh_NoMerge(STLSolid solid, IMeshBuilder builder) { /*int meshID = */ builder.AppendNewMesh(false, false, false, false); DVectorArray3f vertices = solid.Vertices; int nTris = vertices.Count / 3; for (int ti = 0; ti < nTris; ++ti) { Vector3f va = vertices[3 * ti]; int a = builder.AppendVertex(va.x, va.y, va.z); Vector3f vb = vertices[3 * ti + 1]; int b = builder.AppendVertex(vb.x, vb.y, vb.z); Vector3f vc = vertices[3 * ti + 2]; int c = builder.AppendVertex(vc.x, vc.y, vc.z); builder.AppendTriangle(a, b, c); } }
protected virtual void BuildMesh_IdenticalWeld(STLSolid solid, IMeshBuilder builder) { /*int meshID = */ builder.AppendNewMesh(false, false, false, false); DVectorArray3f vertices = solid.Vertices; int N = vertices.Count; int[] mapV = new int[N]; Dictionary <Vector3f, int> uniqueV = new Dictionary <Vector3f, int>(); for (int vi = 0; vi < N; ++vi) { Vector3f v = vertices[vi]; int existing_idx; if (uniqueV.TryGetValue(v, out existing_idx)) { mapV[vi] = existing_idx; } else { int vid = builder.AppendVertex(v.x, v.y, v.z); uniqueV[v] = vid; mapV[vi] = vid; } } int nTris = N / 3; for (int ti = 0; ti < nTris; ++ti) { int a = mapV[3 * ti]; int b = mapV[3 * ti + 1]; int c = mapV[3 * ti + 2]; if (a == b || a == c || b == c) // don't try to add degenerate triangles { continue; } builder.AppendTriangle(a, b, c); } }
public IOReadResult Read(TextReader reader, ReadOptions options, IMeshBuilder builder) { // format is: // // OFF // VCOUNT TCOUNT (2 ints) // x y z // ... // 3 va vb vc // ... // string first_line = reader.ReadLine(); if (first_line.StartsWith("OFF") == false) { return(new IOReadResult(IOCode.FileParsingError, "ascii OFF file must start with OFF header")); } int nVertexCount = 0; int nTriangleCount = 0; int nLines = 0; while (reader.Peek() >= 0) { string line = reader.ReadLine(); nLines++; string[] tokens = line.Split((char[])null, StringSplitOptions.RemoveEmptyEntries); if (tokens.Length == 0) { continue; } if (tokens[0].StartsWith("#")) { continue; } if (tokens.Length != 3) { return(new IOReadResult(IOCode.FileParsingError, "first non-comment line of OFF must be vertex/tri/edge counts, found: " + line)); } nVertexCount = int.Parse(tokens[0]); nTriangleCount = int.Parse(tokens[1]); //int nEdgeCount = int.Parse(tokens[2]); break; } builder.AppendNewMesh(false, false, false, false); int vi = 0; while (vi < nVertexCount && reader.Peek() > 0) { string line = reader.ReadLine(); nLines++; string[] tokens = line.Split((char[])null, StringSplitOptions.RemoveEmptyEntries); if (tokens.Length == 0) { continue; } if (tokens[0].StartsWith("#")) { continue; } if (tokens.Length != 3) { emit_warning("found invalid OFF vertex line: " + line); } double x = Double.Parse(tokens[0]); double y = Double.Parse(tokens[1]); double z = Double.Parse(tokens[2]); builder.AppendVertex(x, y, z); vi++; } if (vi < nVertexCount) { return(new IOReadResult(IOCode.FileParsingError, string.Format("File specified {0} vertices but only found {1}", nVertexCount, vi))); } int ti = 0; while (ti < nTriangleCount && reader.Peek() > 0) { string line = reader.ReadLine(); nLines++; string[] tokens = line.Split((char[])null, StringSplitOptions.RemoveEmptyEntries); if (tokens.Length == 0) { continue; } if (tokens[0].StartsWith("#")) { continue; } if (tokens.Length < 4) { emit_warning("found invalid OFF triangle line: " + line); } int nV = int.Parse(tokens[0]); if (nV != 3) { emit_warning("found non-triangle polygon in OFF, currently unsupported: " + line); } int a = int.Parse(tokens[1]); int b = int.Parse(tokens[2]); int c = int.Parse(tokens[3]); builder.AppendTriangle(a, b, c); ti++; } if (ti < nTriangleCount) { emit_warning(string.Format("File specified {0} triangles but only found {1}", nTriangleCount, ti)); } return(new IOReadResult(IOCode.Ok, "")); }
IOReadResult BuildMeshes_ByMaterial(ReadOptions options, IMeshBuilder builder) { if (vPositions.Length == 0) { return(new IOReadResult(IOCode.GarbageDataError, "No vertices in file")); } if (vTriangles.Length == 0) { return(new IOReadResult(IOCode.GarbageDataError, "No triangles in file")); } bool bHaveNormals = (vNormals.Length > 0); bool bHaveColors = (vColors.Length > 0); bool bHaveUVs = (vUVs.Length > 0); var usedMaterialIDs = new List <int>(UsedMaterials.Keys); usedMaterialIDs.Add(Triangle.InvalidMaterialID); foreach (int material_id in usedMaterialIDs) { int matID = Triangle.InvalidMaterialID; if (material_id != Triangle.InvalidMaterialID) { string sMatName = UsedMaterials[material_id]; OBJMaterial useMat = Materials[sMatName]; matID = builder.BuildMaterial(useMat); } bool bMatHaveUVs = (material_id == Triangle.InvalidMaterialID) ? false : bHaveUVs; // don't append mesh until we actually see triangles int meshID = -1; var mapV = new Dictionary <Index3i, int>(); for (int k = 0; k < vTriangles.Length; ++k) { Triangle t = vTriangles[k]; if (t.nMaterialID == material_id) { if (meshID == -1) { meshID = builder.AppendNewMesh(bHaveNormals, bHaveColors, bMatHaveUVs, false); } var t2 = new Triangle(); for (int j = 0; j < 3; ++j) { var vk = new Index3i( t.vIndices[j] - 1, t.vNormals[j] - 1, t.vUVs[j] - 1); int use_vtx = -1; if (mapV.ContainsKey(vk) == false) { use_vtx = append_vertex(builder, vk, bHaveNormals, bHaveColors, bMatHaveUVs); mapV[vk] = use_vtx; } else { use_vtx = mapV[vk]; } t2.vIndices[j] = use_vtx; } append_triangle(builder, t2); } } if (matID != Triangle.InvalidMaterialID) { builder.AssignMaterial(matID, meshID); } } return(new IOReadResult(IOCode.Ok, "")); }
private bool hasMesh; // used to show that at least one mesh has been found public IOReadResult Read(TextReader reader, ReadOptions options, IMeshBuilder builder) { string[] chunks; List <element> elements = new List <element>(); // we will decant the element specifications into here string proj = ""; string line; bool binary = false; // check for the magic number which in a PLY file is "ply" if (!reader.ReadLine().Contains("ply")) { return(new IOReadResult(IOCode.GarbageDataError, "Not a valid PLY file - Magic number failure")); } // Read header line = reader.ReadLine(); if (line == null) { return(new IOReadResult(IOCode.GarbageDataError, "Not a valid PLY file - header is corrupt")); } /* * The header is a format defintion and a series of element definitions and/or comment lines * cycle through these until end-header */ do { /* * iterate through all of the element blocks in the header and enumerate the number of members and the properties */ if (line.StartsWith("element")) { chunks = line.Split(' '); if ((chunks.Length != 3)) { return(new IOReadResult(IOCode.GarbageDataError, "Not a valid PLY file - header is corrupt")); } element element = new element(); element.properties = new List <string>(); element.types = new List <string>(); element.list = new List <bool>(); element.name = chunks[1]; element.size = ParseInt(chunks[2]); do { line = reader.ReadLine(); if (line == null) { return(new IOReadResult(IOCode.GarbageDataError, "Not a valid PLY file - header is corrupt")); } if (line.StartsWith("property")) { chunks = line.Split(' '); switch (chunks.Length) { case 3: element.properties.Add(chunks[2].ToLower()); element.types.Add(chunks[1].ToLower()); element.list.Add(false); break; case 5: element.properties.Add(chunks[4].ToLower()); element.types.Add(chunks[3].ToLower()); element.list.Add(true); break; default: return(new IOReadResult(IOCode.GarbageDataError, "Not a valid PLY file - invalid element line" + line)); } } else { break; } }while (true); elements.Add(element); } // if end - stop looping else if (line.StartsWith("end_header")) { break; } //if binary - give up else if (line.StartsWith("binary")) { binary = true; } // if "comment crs" assume that the rest is the crs data else if (line.StartsWith("comment crs ")) { line.Remove(12); proj = line; line = reader.ReadLine(); if (line == null) { return(new IOReadResult(IOCode.GarbageDataError, "Not a valid PLY file - header is corrupt")); } } // probably a comment line else { line = reader.ReadLine(); if (line == null) { return(new IOReadResult(IOCode.GarbageDataError, "Not a valid PLY file - header is corrupt")); } } }while (true); // // create new DMesh // bool bHasColors = false; bool bHasNormals = false; bool bHasUVs = false; for (int elid = 0; elid < elements.Count; ++elid) { element el = elements[elid]; if (el.name == "vertex") { if ( (!el.properties.Contains("x")) || (!el.properties.Contains("y")) || (!el.properties.Contains("z")) ) { return(new IOReadResult(IOCode.GarbageDataError, "Verteces do not have XYZ")); } if ( el.properties.Contains("red") && el.properties.Contains("blue") && el.properties.Contains("green") ) { bHasColors = true; } if ( el.properties.Contains("nx") && el.properties.Contains("ny") && el.properties.Contains("nz") ) { bHasNormals = true; } if ( el.properties.Contains("u") && el.properties.Contains("v") ) { bHasUVs = true; } } if (el.name == "faces") { if (!el.properties.Contains("vertex_indices")) { return(new IOReadResult(IOCode.GarbageDataError, "Faces do not have vertex indices")); } } if (el.name == "edges") { if ( (!el.properties.Contains("vertex1")) || (!el.properties.Contains("vertex2")) ) { return(new IOReadResult(IOCode.GarbageDataError, "Edges do not have vertex indices")); } } } int mesh_idx = builder.AppendNewMesh(bHasNormals, bHasColors, bHasUVs, false); /* * load the elements in order */ line = reader.ReadLine(); if (line == null) { return(new IOReadResult(IOCode.GarbageDataError, "Not a valid PLY file - header is corrupt")); } chunks = line.Split(' '); for (int elid = 0; elid < elements.Count; ++elid) { element el = elements[elid]; // load the data for (int i = 0; i < el.size; ++i) { /* * set the line size - we will only deal with one list at the begining of the line */ int nChunks = el.properties.Count; if (el.list[0]) { nChunks += ParseInt(chunks[0]); } if (chunks.Length != nChunks) { return(new IOReadResult(IOCode.GarbageDataError, "Not a valid PLY file - contains invalid line : " + line)); } /* * Load the vertexes */ if (el.name == "vertex") { Vector3d vertex = new Vector3d(); Vector3f normal = new Vector3f(); Vector3f color = new Vector3f(); Vector2f uvs = new Vector2f(); vertex.x = ParseValue(chunks[el.properties.FindIndex(item => item == "x")]); vertex.y = ParseValue(chunks[el.properties.FindIndex(item => item == "y")]); vertex.z = ParseValue(chunks[el.properties.FindIndex(item => item == "z")]); if (bHasNormals) { normal.x = (float)ParseValue(chunks[el.properties.FindIndex(item => item == "nx")]); normal.y = (float)ParseValue(chunks[el.properties.FindIndex(item => item == "ny")]); normal.z = (float)ParseValue(chunks[el.properties.FindIndex(item => item == "nz")]); } if (bHasColors) { color.x = (float)ParseValue(chunks[el.properties.FindIndex(item => item == "red")]); color.y = (float)ParseValue(chunks[el.properties.FindIndex(item => item == "blue")]); color.z = (float)ParseValue(chunks[el.properties.FindIndex(item => item == "green")]); } if (bHasUVs) { uvs.x = (float)ParseValue(chunks[el.properties.FindIndex(item => item == "u")]); uvs.y = (float)ParseValue(chunks[el.properties.FindIndex(item => item == "v")]); } append_vertex(builder, vertex, normal, color, uvs, bHasNormals, bHasColors, bHasUVs); } /* * load the faces */ else if (el.name == "face") { int faceSize = ParseInt(chunks[0]); if (faceSize != 3) { emit_warning("[PLYReader] cann only read triangles"); return(new IOReadResult(IOCode.FormatNotSupportedError, "Can only read tri faces")); } Index3i tri = new Index3i(); tri.a = ParseInt(chunks[1]); tri.b = ParseInt(chunks[2]); tri.c = ParseInt(chunks[3]); append_triangle(builder, tri); } // any other element ignore and move to the next line line = reader.ReadLine(); if (line == null) { // if it is supposed to be the last line - don't look further if (elid != (elements.Count - 1) && i != (el.size - 1)) { return(new IOReadResult(IOCode.GarbageDataError, " does not contain enough definitions of type " + el.name)); } } chunks = line?.Split(' '); } } return(new IOReadResult(IOCode.Ok, "")); }
private bool is3ds; // usd to shwo that the 4D4D magic number has been found public IOReadResult Read(BinaryReader reader, ReadOptions options, IMeshBuilder builder) { ushort ChunkID; String ChnkID = ""; UInt32 Clength; MeshName = ""; hasMesh = false; is3ds = false; // Process the file - fails very politely when there is no more data while (true) { //Get the Id of the next Chunk try { ChunkID = reader.ReadUInt16(); } catch { break; } ChnkID = ChunkID.ToString("X"); //Get the size of the next chunk in chars Clength = reader.ReadUInt32(); //Process based on Chunk ID switch (ChnkID) { case "4D4D": //This is a new file header is3ds = true; reader.ReadChars(10); break; case "3D3D": //This is a new Object Header reader.ReadChars(10); break; case "4000": //This is an object Block. Store the name temporarily in case it is a mesh List <char> name = new List <char>(); while (true) { char next = reader.ReadChar(); if (next == 0) { break; } name.Add(next); } MeshName = new String(name.ToArray <char>()); break; case "4100": // This is a new Mesh. Retrieve the name and add if the builder supports Metadata builder.AppendNewMesh(false, false, false, false); if (builder.SupportsMetaData) { builder.AppendMetaData("name", MeshName); } break; case "4110": // List of Vertexes ushort VertexCount = reader.ReadUInt16(); for (int x = 0; x < VertexCount; x++) { double X = reader.ReadSingle(); double Y = reader.ReadSingle(); double Z = reader.ReadSingle(); builder.AppendVertex(X, Y, Z); } break; case "4120": // List of Triangles ushort PolygonCount = reader.ReadUInt16(); for (int j = 0; j < PolygonCount; j++) { int a = reader.ReadInt16(); int b = reader.ReadInt16(); int c = reader.ReadInt16(); int flags = reader.ReadUInt16(); builder.AppendTriangle(a, b, c); } break; case "4130": // Mapping from Vertex to Material - retrieved but not currently used List <char> mname = new List <char>(); while (true) { char next = reader.ReadChar(); if (next == 0) { break; } mname.Add(next); } string MatName = new String(mname.ToArray <char>()); ushort entries = reader.ReadUInt16(); for (int i = 0; i < entries; i++) { ushort face = reader.ReadUInt16(); } break; case "4140": // List of UVs per vertex ushort uvCount = reader.ReadUInt16(); for (ushort y = 0; y < uvCount; y++) { Vector2f UV = new Vector2f(reader.ReadSingle(), reader.ReadSingle()); builder.SetVertexUV(y, UV); } break; default: // Any other chunk - retrieved and not used - held in dump temporarily for debug char[] dump = reader.ReadChars((int)Clength - 6); break; } } if (!is3ds) { return(new IOReadResult(IOCode.FileAccessError, "File is not in .3DS format")); } else if (!hasMesh) { return(new IOReadResult(IOCode.FileParsingError, "no mesh found in file")); } else { return(new IOReadResult(IOCode.Ok, "")); } }