예제 #1
0
        public static PlyResult GetResult(byte[] content)
        {
            PlyResult plyResult    = null;
            var       header       = GetHeader(content);
            var       headerParsed = new PlyHeader(header);

            if (!headerParsed.VertexElement.IsValid ||
                (!headerParsed.FaceElement.IsValid && !headerParsed.LineElement.IsValid))
            {
                return(null);
            }

            if (headerParsed.Format == PlyFormat.Ascii)
            {
                plyResult = ParseAscii(GetLines(content), headerParsed);
            }
            else if (headerParsed.Format == PlyFormat.BinaryLittleEndian)
            {
                plyResult = ParseBinaryLittleEndian(content, headerParsed);
            }
            else // todo: support BinaryBigEndian
            {
                return(null);
            }

            return(plyResult); // new PlyResult(mesh, headerParsed.GloablMaterialElement.GetColor());
        }
예제 #2
0
        private static Color ParseColor(string[] xyzrgb, PlyHeader header)
        {
            int r = 255;
            int g = 255;
            int b = 255;
            int a = 255;

            if (header.RedIndex.HasValue)
            {
                int.TryParse(xyzrgb[header.RedIndex.Value], NumberStyles.Integer, CultureInfo.InvariantCulture, out r);
            }
            if (header.GreenIndex.HasValue)
            {
                int.TryParse(xyzrgb[header.GreenIndex.Value], NumberStyles.Integer, CultureInfo.InvariantCulture, out g);
            }
            if (header.BlueIndex.HasValue)
            {
                int.TryParse(xyzrgb[header.BlueIndex.Value], NumberStyles.Integer, CultureInfo.InvariantCulture, out b);
            }
            if (header.AlphaIndex.HasValue)
            {
                int.TryParse(xyzrgb[header.AlphaIndex.Value], NumberStyles.Integer, CultureInfo.InvariantCulture, out a);
            }
            return(new Color(r / 255f, g / 255f, b / 255f, a / 255f));
        }
예제 #3
0
        private static PlyResult ParseBinaryLittleEndian(byte[] content, PlyHeader header)
        {
            PlyResult plyResult = new PlyResult();

            plyResult.meshName  = header.GlobalMeshInfoElement.GetName();
            plyResult.meshColor = header.GloablMaterialElement.GetColor();

            var headerAsText  = header.RawHeader.Aggregate((a, b) => $"{a}\n{b}") + "\n";
            var headerAsBytes = Encoding.ASCII.GetBytes(headerAsText);
            var withoutHeader = content.Skip(headerAsBytes.Length).ToArray();

            int bytesUsed;

            header.VertexElement.ParseElementBinaryLittleEndian(withoutHeader, out bytesUsed, out plyResult.vertices, out plyResult.normals, out plyResult.colors);

            int bytesOffset = bytesUsed;

            header.FaceElement.ParseElementBinaryLittleEndian(withoutHeader, bytesOffset, out bytesUsed, out plyResult.triangles);

            bytesOffset = bytesOffset + bytesUsed;
            header.LineElement.ParseElementBinaryLittleEndian(withoutHeader, bytesOffset, out bytesUsed, out plyResult.lines);

            bytesOffset = bytesOffset + bytesUsed;
            header.LineColorElement.ParseElementBinaryLittleEndian(withoutHeader, bytesOffset, out bytesUsed, out plyResult.lineColors);

            return(plyResult);
        }
예제 #4
0
        private static List <int> GetTriangles(string faceVertexList, PlyHeader header)
        {
            switch (header.FaceParseMode)
            {
            case PlyFaceParseMode.VertexCountVertexIndex:
                var split = faceVertexList.Split(' ');
                var count = Convert.ToInt32(split.First());
                switch (count)
                {
                case 3:         // triangle
                    return(split.ToList().GetRange(1, 3).Select(x => Convert.ToInt32(x)).ToList());

                case 4:         // face
                    var triangles = new List <int>();
                    var indices   = split.ToList().GetRange(1, 4).Select(x => Convert.ToInt32(x)).ToList();
                    triangles.AddRange(QuadToTriangles(indices));
                    return(triangles);

                default:
                    Debug.LogWarning("Warning: Found a face with more than 4 vertices, skipping...");
                    return(new List <int>());
                }

            default:
                Debug.LogWarning("Ply GetTriangles: Unknown parse mode");
                return(new List <int>());
            }
        }
예제 #5
0
        private static Vector4b ParseColor(string[] xyzrgb, PlyHeader header)
        {
            byte r = 255;
            byte g = 255;
            byte b = 255;
            byte a = 255;

            if (header.RedIndex.HasValue)
            {
                byte.TryParse(xyzrgb[header.RedIndex.Value], NumberStyles.Integer, CultureInfo.InvariantCulture, out r);
            }
            if (header.GreenIndex.HasValue)
            {
                byte.TryParse(xyzrgb[header.GreenIndex.Value], NumberStyles.Integer, CultureInfo.InvariantCulture, out g);
            }
            if (header.BlueIndex.HasValue)
            {
                byte.TryParse(xyzrgb[header.BlueIndex.Value], NumberStyles.Integer, CultureInfo.InvariantCulture, out b);
            }
            if (header.AlphaIndex.HasValue)
            {
                byte.TryParse(xyzrgb[header.AlphaIndex.Value], NumberStyles.Integer, CultureInfo.InvariantCulture, out a);
            }
            return(new Vector4b(r, g, b, a));
        }
예제 #6
0
        private static List <Vector3> GetVertices(byte[] bytes, PlyHeader header, out List <Color> colors)
        {
            var vertices = new List <Vector3>();

            colors = new List <Color>();
            int  bpvc     = 4; // bytes per vertex component
            int  bpcc     = 1; // bytes per color component
            bool hasColor = header.RedIndex.HasValue && header.GreenIndex.HasValue && header.BlueIndex.HasValue;
            // todo: support other types than just float for vertex components and byte for color components
            int bytesPerVertex = GetByteCountPerVertex(header);

            for (int i = 0; i < header.VertexCount; i++)
            {
                int byteIndex = i * bytesPerVertex;
                var x         = System.BitConverter.ToSingle(bytes.SubArray(byteIndex + 0 * bpvc, bpvc), 0);
                var y         = System.BitConverter.ToSingle(bytes.SubArray(byteIndex + 1 * bpvc, bpvc), 0);
                var z         = System.BitConverter.ToSingle(bytes.SubArray(byteIndex + 2 * bpvc, bpvc), 0);
                if (hasColor)
                {
                    byte r, g, b, a = 255;
                    r = bytes[byteIndex + 3 * bpvc + 0 * bpcc];
                    g = bytes[byteIndex + 3 * bpvc + 1 * bpcc];
                    b = bytes[byteIndex + 3 * bpvc + 2 * bpcc];
                    if (header.AlphaIndex.HasValue)
                    {
                        a = bytes[byteIndex + 3 * bpvc + 3 * bpcc];
                    }
                    colors.Add(new Color(r / 255f, g / 255f, b / 255f, a / 255f));
                }


                vertices.Add(new Vector3(x, y, z));
            }
            return(vertices);
        }
예제 #7
0
        private static PlyResult ParseAscii(List <string> plyFile, PlyHeader header)
        {
            var vertices         = new List <Vector3f>();
            var triangles        = new List <int>();
            var colors           = new List <Vector4b>();
            var headerEndIndex   = plyFile.IndexOf("end_header");
            var vertexStartIndex = headerEndIndex + 1;
            var faceStartIndex   = vertexStartIndex + header.VertexCount + 1;

            plyFile.GetRange(vertexStartIndex, header.VertexCount).ForEach(vertex =>
            {
                var xyzrgb = vertex.Split(' ');
                vertices.Add(ParseVertex(xyzrgb, header));
                colors.Add(ParseColor(xyzrgb, header));
            });

            List <string> lines = plyFile.GetRange(faceStartIndex - 1, header.FaceCount); //???

            lines.ForEach(face =>
            {
                triangles.AddRange(GetTriangles(face, header));
            });

            return(new PlyResult(vertices, triangles, colors));
        }
예제 #8
0
        private static Vector3 ParseVertex(string[] xyzrgb, PlyHeader header)
        {
            decimal dx, dy, dz;

            decimal.TryParse(xyzrgb[header.XIndex], NumberStyles.Float, CultureInfo.InvariantCulture, out dx);
            decimal.TryParse(xyzrgb[header.YIndex], NumberStyles.Float, CultureInfo.InvariantCulture, out dy);
            decimal.TryParse(xyzrgb[header.ZIndex], NumberStyles.Float, CultureInfo.InvariantCulture, out dz);
            return(new Vector3((float)dx, (float)dy, (float)dz));
        }
예제 #9
0
        private static PlyResult ParseBinaryLittleEndian(string path, PlyHeader header)
        {
            var headerAsText  = header.RawHeader.Aggregate((a, b) => $"{a}\n{b}") + "\n";
            var headerAsBytes = Encoding.ASCII.GetBytes(headerAsText);
            var withoutHeader = File.ReadAllBytes(path).Skip(headerAsBytes.Length).ToArray();
            var colors        = new List <Color>();
            var vertices      = GetVertices(withoutHeader, header, out colors);
            var triangles     = GetTriangles(withoutHeader, header);

            return(new PlyResult(vertices, triangles, colors));
        }
예제 #10
0
        public PlyFaceElement(IList <string> headerUnparsed, PlyHeader header) : base("face")
        {
            _plyHeader = header;
            if (!ParseElementInfo(headerUnparsed))
            {
                IsValid = false;
                return;
            }

            IsValid = IsValid && IsElementValid();
        }
예제 #11
0
        private static int GetByteCountPerVertex(PlyHeader header)
        {
            int bpvc = 4; // bytes per vertex component
            int bpcc = 1; // bytes per color component
            // todo: support other types than just float for vertex components and byte for color components
            int r = header.RedIndex.HasValue ? bpcc : 0;
            int g = header.GreenIndex.HasValue ? bpcc : 0;
            int b = header.BlueIndex.HasValue ? bpcc : 0;
            int a = header.AlphaIndex.HasValue ? bpcc : 0;

            return(3 * bpvc + r + g + b + a);
        }
예제 #12
0
        public PlyVertexElement(IList <string> headerUnparsed, PlyHeader header) : base("vertex")
        {
            _header = header;
            if (!ParseElementInfo(headerUnparsed))
            {
                IsValid = false;
                return;
            }

            HasPosition = DictProperties.ContainsKey("x") && DictProperties.ContainsKey("y") && DictProperties.ContainsKey("z");
            HasNormal   = DictProperties.ContainsKey("nx") && DictProperties.ContainsKey("ny") && DictProperties.ContainsKey("nz");
            HasColor    = DictProperties.ContainsKey("red") && DictProperties.ContainsKey("green") &&
                          DictProperties.ContainsKey("blue") && DictProperties.ContainsKey("alpha");


            IsValid = IsValid && IsElementValid();
        }
예제 #13
0
        public static PlyResult GetVerticesAndTriangles(string path)
        {
            List <string> header       = File.ReadLines(path).TakeUntilIncluding(x => x == "end_header").ToList();
            var           headerParsed = new PlyHeader(header);

            if (headerParsed.Format == PlyFormat.Ascii)
            {
                return(ParseAscii(File.ReadAllLines(path).ToList(), headerParsed));
            }
            else if (headerParsed.Format == PlyFormat.BinaryLittleEndian)
            {
                return(ParseBinaryLittleEndian(path, headerParsed));
            }
            else // todo: support BinaryBigEndian
            {
                return(null);
            }
        }
예제 #14
0
        public static PlyResult FromFile(string path)
        {
            List <string> header       = File.ReadLines(path).TakeUntilIncluding(x => x == "end_header").ToList();
            var           headerParsed = new PlyHeader(header);

            switch (headerParsed.Format)
            {
            case PlyFormat.Ascii:
                return(ParseAscii(File.ReadAllLines(path).ToList(), headerParsed));

            case PlyFormat.BinaryLittleEndian:
                return(ParseBinaryLittleEndian(path, headerParsed));

            case PlyFormat.BinaryBigEndian:
            // todo: support BinaryBigEndian
            default:
                return(null);
            }
        }
예제 #15
0
        private static PlyResult ParseAscii(List <string> plyFile, PlyHeader header)
        {
            PlyResult plyResult = new PlyResult();

            plyResult.meshName  = header.GlobalMeshInfoElement.GetName();
            plyResult.meshColor = header.GloablMaterialElement.GetColor();

            // TODO: order independent
            var headerEndIndex      = plyFile.IndexOf("end_header");
            var vertexStartIndex    = headerEndIndex + 1;
            var faceStartIndex      = vertexStartIndex + header.VertexElement.NElement;
            var lineStartIndex      = faceStartIndex + header.FaceElement.NElement;
            var lineColorStartIndex = lineStartIndex + header.LineElement.NElement;

            header.VertexElement.ParseElement(plyFile.GetRange(vertexStartIndex, header.VertexElement.NElement),
                                              out plyResult.vertices, out plyResult.normals, out plyResult.colors);
            header.FaceElement.ParseElement(plyFile.GetRange(faceStartIndex, header.FaceElement.NElement), out plyResult.triangles);
            header.LineElement.ParseElement(plyFile.GetRange(lineStartIndex, header.LineElement.NElement), out plyResult.lines);
            header.LineColorElement.ParseElement(plyFile.GetRange(lineColorStartIndex, header.LineColorElement.NElement), out plyResult.lineColors);

            return(plyResult);
        }
예제 #16
0
        private static List <int> GetTriangles(byte[] bytes, PlyHeader header)
        {
            var toSkip                = header.VertexCount * GetByteCountPerVertex(header);
            var triangles             = new List <int>();
            int facesRead             = 0;
            int bytesRead             = 0;
            int bytesPerTriangleIndex = 4;

            while (facesRead < header.FaceCount)
            {
                var faceIndex  = toSkip + bytesRead;
                var indexCount = bytes[faceIndex];
                if (indexCount == 3)
                {
                    for (int i = 0; i < indexCount; i++)
                    {
                        triangles.Add(System.BitConverter.ToInt32(bytes.SubArray(faceIndex + 1 + i * bytesPerTriangleIndex, bytesPerTriangleIndex), 0));
                    }
                    bytesRead += 1 + indexCount * bytesPerTriangleIndex;
                }
                else if (indexCount == 4)
                {
                    var tmp = new List <int>();
                    for (int i = 0; i < indexCount; i++)
                    {
                        tmp.Add(System.BitConverter.ToInt32(bytes.SubArray(faceIndex + 1 + i * bytesPerTriangleIndex, bytesPerTriangleIndex), 0));
                    }
                    triangles.AddRange(QuadToTriangles(tmp));
                    bytesRead += 1 + indexCount * bytesPerTriangleIndex;
                }
                else
                {
                    Debug.LogWarning("Warning: Found a face with more than 4 vertices, skipping...");
                }

                facesRead++;
            }
            return(triangles);
        }