ply-parser 2.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,72 @@
1
+ Metadata-Version: 2.1
2
+ Name: ply_parser
3
+ Version: 2.0.0
4
+ Summary: A python module that parses ascii PLY (.ply) (Polygon File Format) files. It includes a class PLYObject for storing PLY file data and a function parse_ply_file() for reading PLY files and creating PLYObject instances and can easily be customized.
5
+ Home-page: https://github.com/Qrishna/ply_parser
6
+ Author: Krishna Bhattarai
7
+ Author-email: Krishna Bhattarai <krishna@kbhattarai.com>
8
+ Project-URL: Homepage, https://github.com/Qrishna/ply_parser
9
+ Project-URL: Bug Tracker, https://github.com/Qrishna/ply_parser/issues
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: OS Independent
13
+ Requires-Python: >=3.11.4
14
+ Description-Content-Type: text/markdown
15
+
16
+ ### PLY File Parser
17
+ This Python module provides a simple PLY (Polygon File Format) file parser. It includes a class PLYObject for storing PLY file data and a function parse_ply_file for reading PLY files and creating PLYObject instances.
18
+
19
+ ### Usage
20
+ ### PLYObject Class
21
+ The PLYObject class represents a PLY object with attributes:
22
+
23
+ `name`: Name of the PLY object.
24
+
25
+ `vertices`: List of vertex coordinates.
26
+
27
+ `faces`: List of face indices.
28
+
29
+ `colors`: List of RGB color values for vertices.
30
+
31
+
32
+ #### parse_ply_file Function
33
+ The parse_ply_file function takes a PLY file as input and returns a PLYObject instance. It reads the file, extracts vertex and face information, and handles color properties. If any inconsistencies or errors are detected in the PLY file, appropriate error messages are displayed.
34
+ ```
35
+ file = "data/cube_colors.ply"
36
+ parsed_object = parse_ply_file(file)
37
+ if parsed_object:
38
+ print("name:", parsed_object.name)
39
+ print("total_vertices:", len(parsed_object.vertices))
40
+ print("total_faces:", len(parsed_object.faces))
41
+ print("total_colors:", len(parsed_object.colors))
42
+ ```
43
+
44
+ ### Requirements
45
+ `Python 3.11.x`
46
+
47
+ ### PLY File Format Support
48
+ This parser currently supports PLY files with the following characteristics:
49
+
50
+ `ASCII format`
51
+
52
+ `Vertex coordinates (X, Y, Z)`
53
+
54
+ `Face indices (triangles and quads)`
55
+
56
+ `Vertex colors`
57
+
58
+ ### Testing
59
+ ```
60
+ python3 -m unittest tests/test_ply_parser.py -v
61
+ ```
62
+
63
+ ### Limitations
64
+ The parser assumes the input PLY file follows the standard specifications.
65
+ It may not handle non-standard or corrupted PLY files gracefully.
66
+
67
+
68
+ ### Contribution
69
+ Feel free to contribute by opening issues or submitting pull requests. Bug reports, suggestions, and improvements are welcome.
70
+
71
+ ### License
72
+ This PLY file parser is licensed under the MIT License. See the LICENSE file for details.
@@ -0,0 +1,57 @@
1
+ ### PLY File Parser
2
+ This Python module provides a simple PLY (Polygon File Format) file parser. It includes a class PLYObject for storing PLY file data and a function parse_ply_file for reading PLY files and creating PLYObject instances.
3
+
4
+ ### Usage
5
+ ### PLYObject Class
6
+ The PLYObject class represents a PLY object with attributes:
7
+
8
+ `name`: Name of the PLY object.
9
+
10
+ `vertices`: List of vertex coordinates.
11
+
12
+ `faces`: List of face indices.
13
+
14
+ `colors`: List of RGB color values for vertices.
15
+
16
+
17
+ #### parse_ply_file Function
18
+ The parse_ply_file function takes a PLY file as input and returns a PLYObject instance. It reads the file, extracts vertex and face information, and handles color properties. If any inconsistencies or errors are detected in the PLY file, appropriate error messages are displayed.
19
+ ```
20
+ file = "data/cube_colors.ply"
21
+ parsed_object = parse_ply_file(file)
22
+ if parsed_object:
23
+ print("name:", parsed_object.name)
24
+ print("total_vertices:", len(parsed_object.vertices))
25
+ print("total_faces:", len(parsed_object.faces))
26
+ print("total_colors:", len(parsed_object.colors))
27
+ ```
28
+
29
+ ### Requirements
30
+ `Python 3.11.x`
31
+
32
+ ### PLY File Format Support
33
+ This parser currently supports PLY files with the following characteristics:
34
+
35
+ `ASCII format`
36
+
37
+ `Vertex coordinates (X, Y, Z)`
38
+
39
+ `Face indices (triangles and quads)`
40
+
41
+ `Vertex colors`
42
+
43
+ ### Testing
44
+ ```
45
+ python3 -m unittest tests/test_ply_parser.py -v
46
+ ```
47
+
48
+ ### Limitations
49
+ The parser assumes the input PLY file follows the standard specifications.
50
+ It may not handle non-standard or corrupted PLY files gracefully.
51
+
52
+
53
+ ### Contribution
54
+ Feel free to contribute by opening issues or submitting pull requests. Bug reports, suggestions, and improvements are welcome.
55
+
56
+ ### License
57
+ This PLY file parser is licensed under the MIT License. See the LICENSE file for details.
@@ -0,0 +1,19 @@
1
+
2
+ [project]
3
+ name = "ply_parser"
4
+ version = "2.0.0"
5
+ authors = [
6
+ { name="Krishna Bhattarai", email="krishna@kbhattarai.com" },
7
+ ]
8
+ description = "A python module that parses ascii PLY (.ply) (Polygon File Format) files. It includes a class PLYObject for storing PLY file data and a function parse_ply_file() for reading PLY files and creating PLYObject instances and can easily be customized."
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ classifiers = [
12
+ "Programming Language :: Python :: 3",
13
+ "License :: OSI Approved :: MIT License",
14
+ "Operating System :: OS Independent",
15
+ ]
16
+
17
+ [project.urls]
18
+ "Homepage" = "https://github.com/Qrishna/ply_parser"
19
+ "Bug Tracker" = "https://github.com/Qrishna/ply_parser/issues"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,26 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ with open("README.md", "r", encoding="utf-8") as fh:
4
+ long_description = fh.read()
5
+
6
+ setup(
7
+ name='ply_parser',
8
+ version='2.0.0',
9
+ author='Krishna Bhattarai',
10
+ author_email='krishna@kbhattarai.com',
11
+ description='A python module that parses ascii PLY (.ply) (Polygon File Format) files. It includes a class PLYObject for storing PLY file data and a function parse_ply_file() for reading PLY files and creating PLYObject instances and can easily be customized. ',
12
+ long_description=long_description,
13
+ long_description_content_type="text/markdown",
14
+ url="https://github.com/Qrishna/ply_parser",
15
+ project_urls={
16
+ "Bug Tracker": "https://github.com/Qrishna/ply_parser/issues"
17
+ },
18
+ package_dir={'': "src"},
19
+ packages=find_packages("src"),
20
+ classifiers=[
21
+ 'Programming Language :: Python :: 3',
22
+ 'License :: OSI Approved :: MIT License',
23
+ 'Operating System :: OS Independent',
24
+ ],
25
+ python_requires='>=3.11.4',
26
+ )
@@ -0,0 +1 @@
1
+ from .ply_parser import *
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env python3
2
+ # Krishna Bhattarai
3
+ # Nov 23
4
+ import re
5
+
6
+
7
+ class PLYObject:
8
+ def __init__(self, vertices, faces, colors, name=None):
9
+ self.name = name
10
+ self.vertices = vertices
11
+ self.faces = faces
12
+ self.colors = colors
13
+
14
+
15
+ def get_file_data(file_name):
16
+ with open(file_name, 'r') as file:
17
+ data = file.readlines()
18
+ return data
19
+
20
+
21
+ def parse_ply_file_data(lines):
22
+ expected_faces = None
23
+ expected_vertices = None
24
+ vertices, faces, colors = [], [], []
25
+
26
+ vertex_count = 0
27
+ faces_count = 0
28
+
29
+ property_red = 0
30
+ property_blue = 0
31
+ property_green = 0
32
+
33
+ for x in range(0, len(lines)):
34
+ line = lines[x].strip()
35
+ if not line or line == '':
36
+ continue
37
+ if line.startswith("format"):
38
+ file_format = line.strip().split()[1]
39
+ if file_format.lower() != "ascii":
40
+ # print("File format is not ascii! It is: %s" % file_format)
41
+ raise ValueError("File format is not ascii! It is: %s" % file_format)
42
+
43
+ if line.startswith("comment"):
44
+ continue
45
+
46
+ if "element vertex" in line:
47
+ expected_vertices = int(re.match(r'^element\s+vertex\s+(\d+)', line).group(1))
48
+ continue
49
+
50
+ if "property uchar red" in line:
51
+ property_red += 1
52
+ continue
53
+
54
+ if "property uchar green" in line:
55
+ property_green += 1
56
+ continue
57
+
58
+ if "property uchar blue" in line:
59
+ property_blue += 1
60
+ continue
61
+
62
+ if re.match(r'^element\s+face\s+\d+', line):
63
+ expected_faces = int(re.match(r'^element\s+face\s+(\d+)', line).group(1))
64
+ continue
65
+
66
+ elif "end_header" in line:
67
+ continue
68
+
69
+ if re.match(r'^([-|\d]+(\.\d+)?)\s+([-|\d]+(\.\d+)?)\s+([-|\d]+(\.\d+)?)', line) and vertex_count != expected_vertices:
70
+ vertex_count += 1
71
+
72
+ if property_red and property_green and property_blue:
73
+ vertex = line.strip().split()[0:6]
74
+ vertices.append([float(vertex[0]), float(vertex[1]), float(vertex[2])])
75
+ colors.append([float(vertex[3]), float(vertex[4]), float(vertex[5])])
76
+ else:
77
+ vertex = line.strip().split()[0:3]
78
+ vertices.append([float(vertex[0]), float(vertex[1]), float(vertex[2])])
79
+
80
+ if re.match(r'^[34]\s+\d+\s+\d+\s\d+', line) and faces_count != expected_faces:
81
+ faces_count += 1
82
+ if line[0].startswith('3'):
83
+ face = line.strip().split()[1:4]
84
+ faces.append([int(face[0]), int(face[1]), int(face[2])])
85
+ elif line[0].startswith('4'):
86
+ face = line.strip().split()[1:5]
87
+ faces.append([int(face[0]), int(face[1]), int(face[2]), int(face[3])])
88
+
89
+ if len(vertices) != expected_vertices:
90
+ # print("Error: total vertices read: %s does not match expected vertices: %s" % (len(vertices), expected_vertices))
91
+ raise ValueError("Error: total vertices read: %s does not match expected vertices: %s" % (len(vertices), expected_vertices))
92
+
93
+ if len(faces) != expected_faces:
94
+ # print("Error: total faces read: %s does not match expected faces: %s" % (len(faces), expected_faces))
95
+ raise ValueError("Error: total faces read: %s does not match expected faces: %s" % (len(faces), expected_faces))
96
+
97
+ return [vertices, faces, colors]
98
+
99
+
100
+ def parse_ply_file(file_name):
101
+ file_data_lines = get_file_data(file_name)
102
+ parsed_data = parse_ply_file_data(file_data_lines)
103
+ if parsed_data:
104
+ v, f, c = parsed_data[0], parsed_data[1], parsed_data[2]
105
+ return PLYObject(v, f, c, file_name.strip())
@@ -0,0 +1,226 @@
1
+ import unittest
2
+ from ply_parser import *
3
+
4
+
5
+ class TestPLYParsing(unittest.TestCase):
6
+ def test_parse_ply_data_with_vertices_and_faces(self):
7
+ data = """ply
8
+ format ascii 1.0
9
+ comment Some comment
10
+ element vertex 3
11
+ property float x
12
+ property float y
13
+ property float z
14
+ element face 1
15
+ end_header
16
+ 1.0 2.0 3.0
17
+ 4.0 5.0 6.0
18
+ 7.0 8.0 9.0
19
+ 3 0 1 2"""
20
+
21
+ result = parse_ply_file_data(data.splitlines())
22
+ vertices, faces, colors = result[0], result[1], result[2]
23
+ self.assertEqual(len(vertices), 3)
24
+ self.assertEqual(len(faces), 1)
25
+ self.assertEqual(len(colors), 0)
26
+
27
+ def test_parse_ply_data_with_vertices_colors_and_faces(self):
28
+ data = """ply
29
+ format ascii 1.0
30
+ element vertex 3
31
+ property float x
32
+ property float y
33
+ property float z
34
+ property uchar red
35
+ property uchar green
36
+ property uchar blue
37
+ element face 1
38
+ property list uchar int vertex_indices
39
+ end_header
40
+ 1.0 2.0 3.0 255 0 0
41
+ 4.0 5.0 6.0 0 255 0
42
+ 7.0 8.0 9.0 0 0 255
43
+ 3 0 1 2"""
44
+
45
+ result = parse_ply_file_data(data.splitlines())
46
+ vertices, faces, colors = result[0], result[1], result[2]
47
+ self.assertEqual(len(vertices), 3)
48
+ self.assertEqual(len(faces), 1)
49
+ self.assertEqual(len(colors), 3)
50
+
51
+ def test_distinguish_and_count_lines_for_vertices_and_faces(self):
52
+ data = """ply
53
+ format ascii 1.0
54
+ element vertex 3
55
+ property float x
56
+ property float y
57
+ property float z
58
+ element face 3
59
+ property list uchar int vertex_indices
60
+ end_header
61
+ 1.0 2.0 3.0
62
+ 4.0 5.0 6.0
63
+ 7.0 8.0 9.0
64
+ 3 2 1 2
65
+ 3 2 2 3
66
+ 3 1 2 3"""
67
+
68
+ result = parse_ply_file_data(data.splitlines())
69
+ vertices, faces, colors = result[0], result[1], result[2]
70
+ self.assertEqual(len(vertices), 3)
71
+ self.assertEqual(vertices, [[1, 2, 3], [4, 5, 6], [7, 8, 9]])
72
+ self.assertEqual(len(faces), 3)
73
+ self.assertEqual(faces, [[2, 1, 2], [2, 2, 3], [1, 2, 3]])
74
+ self.assertEqual(len(colors), 0)
75
+
76
+ def test_handle_face_lines_starting_with_4(self):
77
+ data = """ply
78
+ format ascii 1.0
79
+ element vertex 3
80
+ property float x
81
+ property float y
82
+ property float z
83
+ element face 3
84
+ property list uchar int vertex_indices
85
+ end_header
86
+ 1.0 2.0 3.0
87
+ 4.0 5.0 6.0
88
+ 7.0 8.0 9.0
89
+ 4 2 1 2 2
90
+ 4 2 2 3 1
91
+ 4 1 2 3 2"""
92
+
93
+ result = parse_ply_file_data(data.splitlines())
94
+ vertices, faces, colors = result[0], result[1], result[2]
95
+ self.assertEqual(len(vertices), 3)
96
+ self.assertEqual(vertices, [[1, 2, 3], [4, 5, 6], [7, 8, 9]])
97
+ self.assertEqual(len(faces), 3)
98
+ self.assertEqual(faces, [[2, 1, 2, 2], [2, 2, 3, 1], [1, 2, 3, 2]])
99
+ self.assertEqual(len(colors), 0)
100
+
101
+ def test_parse_ply_data_with_no_vertices_or_faces(self):
102
+ data = """ply
103
+ format ascii 1.0
104
+ element vertex 0
105
+ element face 0
106
+ end_header"""
107
+
108
+ result = parse_ply_file_data(data.splitlines())
109
+ vertices, faces, colors = result[0], result[1], result[2]
110
+ self.assertEqual(len(vertices), 0)
111
+ self.assertEqual(len(faces), 0)
112
+ self.assertEqual(len(colors), 0)
113
+
114
+ def test_handle_invalid_ply_format(self):
115
+ invalid_format_data = """ply
116
+ format binary 1.0
117
+ element vertex 3
118
+ property float x
119
+ property float y
120
+ property float z
121
+ end_header
122
+ 1.0 2.0 3.0
123
+ 4.0 5.0 6.0
124
+ 7.0 8.0 9.0"""
125
+
126
+ with self.assertRaises(ValueError) as context:
127
+ parse_ply_file_data(invalid_format_data.splitlines())
128
+ self.assertEqual(str(context.exception), 'File format is not ascii! It is: binary')
129
+
130
+ def test_handle_incomplete_vertex_data(self):
131
+ incomplete_vertex_data = """ply
132
+ format ascii 1.0
133
+ element vertex 3
134
+ property float x
135
+ property float y
136
+ property float z
137
+ end_header
138
+ 1.0 2.0 3.0
139
+ 4.0 5.0 6.0"""
140
+
141
+ with self.assertRaises(ValueError) as context:
142
+ parse_ply_file_data(incomplete_vertex_data.splitlines())
143
+ self.assertEqual(str(context.exception), 'Error: total vertices read: 2 does not match expected vertices: 3')
144
+
145
+ def test_parse_ply_colors_data_if_described_in_header(self):
146
+ data = """ply
147
+ format ascii 1.0
148
+ element vertex 3
149
+ property float x
150
+ property float y
151
+ property float z
152
+ property uchar red
153
+ property uchar green
154
+ property uchar blue
155
+ element face 1
156
+ end_header
157
+ 1.0 2.0 3.0 255 0 0
158
+ 4.0 5.0 6.0 0 255 0
159
+ 7.0 8.0 9.0 0 0 255
160
+ 3 0 1 2"""
161
+
162
+ result = parse_ply_file_data(data.splitlines())
163
+ vertices, faces, colors = result[0], result[1], result[2]
164
+ self.assertEqual(len(vertices), 3)
165
+ self.assertEqual(len(faces), 1)
166
+ self.assertEqual(len(colors), 3)
167
+ self.assertEqual(colors, [[255, 0, 0], [0, 255, 0], [0, 0, 255]])
168
+
169
+ def test_not_parse_colors_if_color_property_not_described(self):
170
+ data = """ply
171
+ format ascii 1.0
172
+ element vertex 3
173
+ property float x
174
+ property float y
175
+ property float z
176
+ element face 1
177
+ end_header
178
+ 1.0 2.0 3.0 255 0 0
179
+ 4.0 5.0 6.0 0 255 0
180
+ 7.0 8.0 9.0 0 0 255
181
+ 3 0 1 2"""
182
+
183
+ result = parse_ply_file_data(data.splitlines())
184
+ vertices, faces, colors = result[0], result[1], result[2]
185
+ self.assertEqual(len(vertices), 3)
186
+ self.assertEqual(len(faces), 1)
187
+ self.assertEqual(len(colors), 0)
188
+
189
+ def test_parse_ply_data_with_negative_coordinates(self):
190
+ data = """ply
191
+ format ascii 1.0
192
+ element vertex 3
193
+ property float x
194
+ property float y
195
+ property float z
196
+ element face 1
197
+ end_header
198
+ -1.0 -2.0 -3.0
199
+ -4.0 -5.0 -6.0
200
+ -7.0 -8.0 -9.0
201
+ 3 0 1 2"""
202
+
203
+ result = parse_ply_file_data(data.splitlines())
204
+ vertices, faces, colors = result[0], result[1], result[2]
205
+ self.assertEqual(len(vertices), 3)
206
+ self.assertEqual(len(faces), 1)
207
+ self.assertEqual(len(colors), 0)
208
+
209
+ def test_handle_incomplete_face_data(self):
210
+ incomplete_face_data = """ply
211
+ format ascii 1.0
212
+ element vertex 3
213
+ element face 2
214
+ end_header
215
+ 1.0 2.0 3.0
216
+ 4.0 5.0 6.0
217
+ 7.0 8.0 9.0
218
+ 3 0 1 2"""
219
+
220
+ with self.assertRaises(ValueError) as context:
221
+ parse_ply_file_data(incomplete_face_data.splitlines())
222
+ self.assertEqual(str(context.exception), 'Error: total faces read: 1 does not match expected faces: 2')
223
+
224
+
225
+ if __name__ == '__main__':
226
+ unittest.main()
@@ -0,0 +1,72 @@
1
+ Metadata-Version: 2.1
2
+ Name: ply-parser
3
+ Version: 2.0.0
4
+ Summary: A python module that parses ascii PLY (.ply) (Polygon File Format) files. It includes a class PLYObject for storing PLY file data and a function parse_ply_file() for reading PLY files and creating PLYObject instances and can easily be customized.
5
+ Home-page: https://github.com/Qrishna/ply_parser
6
+ Author: Krishna Bhattarai
7
+ Author-email: Krishna Bhattarai <krishna@kbhattarai.com>
8
+ Project-URL: Homepage, https://github.com/Qrishna/ply_parser
9
+ Project-URL: Bug Tracker, https://github.com/Qrishna/ply_parser/issues
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: OS Independent
13
+ Requires-Python: >=3.11.4
14
+ Description-Content-Type: text/markdown
15
+
16
+ ### PLY File Parser
17
+ This Python module provides a simple PLY (Polygon File Format) file parser. It includes a class PLYObject for storing PLY file data and a function parse_ply_file for reading PLY files and creating PLYObject instances.
18
+
19
+ ### Usage
20
+ ### PLYObject Class
21
+ The PLYObject class represents a PLY object with attributes:
22
+
23
+ `name`: Name of the PLY object.
24
+
25
+ `vertices`: List of vertex coordinates.
26
+
27
+ `faces`: List of face indices.
28
+
29
+ `colors`: List of RGB color values for vertices.
30
+
31
+
32
+ #### parse_ply_file Function
33
+ The parse_ply_file function takes a PLY file as input and returns a PLYObject instance. It reads the file, extracts vertex and face information, and handles color properties. If any inconsistencies or errors are detected in the PLY file, appropriate error messages are displayed.
34
+ ```
35
+ file = "data/cube_colors.ply"
36
+ parsed_object = parse_ply_file(file)
37
+ if parsed_object:
38
+ print("name:", parsed_object.name)
39
+ print("total_vertices:", len(parsed_object.vertices))
40
+ print("total_faces:", len(parsed_object.faces))
41
+ print("total_colors:", len(parsed_object.colors))
42
+ ```
43
+
44
+ ### Requirements
45
+ `Python 3.11.x`
46
+
47
+ ### PLY File Format Support
48
+ This parser currently supports PLY files with the following characteristics:
49
+
50
+ `ASCII format`
51
+
52
+ `Vertex coordinates (X, Y, Z)`
53
+
54
+ `Face indices (triangles and quads)`
55
+
56
+ `Vertex colors`
57
+
58
+ ### Testing
59
+ ```
60
+ python3 -m unittest tests/test_ply_parser.py -v
61
+ ```
62
+
63
+ ### Limitations
64
+ The parser assumes the input PLY file follows the standard specifications.
65
+ It may not handle non-standard or corrupted PLY files gracefully.
66
+
67
+
68
+ ### Contribution
69
+ Feel free to contribute by opening issues or submitting pull requests. Bug reports, suggestions, and improvements are welcome.
70
+
71
+ ### License
72
+ This PLY file parser is licensed under the MIT License. See the LICENSE file for details.
@@ -0,0 +1,11 @@
1
+ README.md
2
+ pyproject.toml
3
+ setup.py
4
+ src/ply_parser/__init__.py
5
+ src/ply_parser/ply_parser.py
6
+ src/ply_parser/test_ply_parser.py
7
+ src/ply_parser.egg-info/PKG-INFO
8
+ src/ply_parser.egg-info/SOURCES.txt
9
+ src/ply_parser.egg-info/dependency_links.txt
10
+ src/ply_parser.egg-info/top_level.txt
11
+ tests/test_ply_parser.py
@@ -0,0 +1 @@
1
+ ply_parser
@@ -0,0 +1,226 @@
1
+ import unittest
2
+ from ply_parser import *
3
+
4
+
5
+ class TestPLYParsing(unittest.TestCase):
6
+ def test_parse_ply_data_with_vertices_and_faces(self):
7
+ data = """ply
8
+ format ascii 1.0
9
+ comment Some comment
10
+ element vertex 3
11
+ property float x
12
+ property float y
13
+ property float z
14
+ element face 1
15
+ end_header
16
+ 1.0 2.0 3.0
17
+ 4.0 5.0 6.0
18
+ 7.0 8.0 9.0
19
+ 3 0 1 2"""
20
+
21
+ result = parse_ply_file_data(data.splitlines())
22
+ vertices, faces, colors = result[0], result[1], result[2]
23
+ self.assertEqual(len(vertices), 3)
24
+ self.assertEqual(len(faces), 1)
25
+ self.assertEqual(len(colors), 0)
26
+
27
+ def test_parse_ply_data_with_vertices_colors_and_faces(self):
28
+ data = """ply
29
+ format ascii 1.0
30
+ element vertex 3
31
+ property float x
32
+ property float y
33
+ property float z
34
+ property uchar red
35
+ property uchar green
36
+ property uchar blue
37
+ element face 1
38
+ property list uchar int vertex_indices
39
+ end_header
40
+ 1.0 2.0 3.0 255 0 0
41
+ 4.0 5.0 6.0 0 255 0
42
+ 7.0 8.0 9.0 0 0 255
43
+ 3 0 1 2"""
44
+
45
+ result = parse_ply_file_data(data.splitlines())
46
+ vertices, faces, colors = result[0], result[1], result[2]
47
+ self.assertEqual(len(vertices), 3)
48
+ self.assertEqual(len(faces), 1)
49
+ self.assertEqual(len(colors), 3)
50
+
51
+ def test_distinguish_and_count_lines_for_vertices_and_faces(self):
52
+ data = """ply
53
+ format ascii 1.0
54
+ element vertex 3
55
+ property float x
56
+ property float y
57
+ property float z
58
+ element face 3
59
+ property list uchar int vertex_indices
60
+ end_header
61
+ 1.0 2.0 3.0
62
+ 4.0 5.0 6.0
63
+ 7.0 8.0 9.0
64
+ 3 2 1 2
65
+ 3 2 2 3
66
+ 3 1 2 3"""
67
+
68
+ result = parse_ply_file_data(data.splitlines())
69
+ vertices, faces, colors = result[0], result[1], result[2]
70
+ self.assertEqual(len(vertices), 3)
71
+ self.assertEqual(vertices, [[1, 2, 3], [4, 5, 6], [7, 8, 9]])
72
+ self.assertEqual(len(faces), 3)
73
+ self.assertEqual(faces, [[2, 1, 2], [2, 2, 3], [1, 2, 3]])
74
+ self.assertEqual(len(colors), 0)
75
+
76
+ def test_handle_face_lines_starting_with_4(self):
77
+ data = """ply
78
+ format ascii 1.0
79
+ element vertex 3
80
+ property float x
81
+ property float y
82
+ property float z
83
+ element face 3
84
+ property list uchar int vertex_indices
85
+ end_header
86
+ 1.0 2.0 3.0
87
+ 4.0 5.0 6.0
88
+ 7.0 8.0 9.0
89
+ 4 2 1 2 2
90
+ 4 2 2 3 1
91
+ 4 1 2 3 2"""
92
+
93
+ result = parse_ply_file_data(data.splitlines())
94
+ vertices, faces, colors = result[0], result[1], result[2]
95
+ self.assertEqual(len(vertices), 3)
96
+ self.assertEqual(vertices, [[1, 2, 3], [4, 5, 6], [7, 8, 9]])
97
+ self.assertEqual(len(faces), 3)
98
+ self.assertEqual(faces, [[2, 1, 2, 2], [2, 2, 3, 1], [1, 2, 3, 2]])
99
+ self.assertEqual(len(colors), 0)
100
+
101
+ def test_parse_ply_data_with_no_vertices_or_faces(self):
102
+ data = """ply
103
+ format ascii 1.0
104
+ element vertex 0
105
+ element face 0
106
+ end_header"""
107
+
108
+ result = parse_ply_file_data(data.splitlines())
109
+ vertices, faces, colors = result[0], result[1], result[2]
110
+ self.assertEqual(len(vertices), 0)
111
+ self.assertEqual(len(faces), 0)
112
+ self.assertEqual(len(colors), 0)
113
+
114
+ def test_handle_invalid_ply_format(self):
115
+ invalid_format_data = """ply
116
+ format binary 1.0
117
+ element vertex 3
118
+ property float x
119
+ property float y
120
+ property float z
121
+ end_header
122
+ 1.0 2.0 3.0
123
+ 4.0 5.0 6.0
124
+ 7.0 8.0 9.0"""
125
+
126
+ with self.assertRaises(ValueError) as context:
127
+ parse_ply_file_data(invalid_format_data.splitlines())
128
+ self.assertEqual(str(context.exception), 'File format is not ascii! It is: binary')
129
+
130
+ def test_handle_incomplete_vertex_data(self):
131
+ incomplete_vertex_data = """ply
132
+ format ascii 1.0
133
+ element vertex 3
134
+ property float x
135
+ property float y
136
+ property float z
137
+ end_header
138
+ 1.0 2.0 3.0
139
+ 4.0 5.0 6.0"""
140
+
141
+ with self.assertRaises(ValueError) as context:
142
+ parse_ply_file_data(incomplete_vertex_data.splitlines())
143
+ self.assertEqual(str(context.exception), 'Error: total vertices read: 2 does not match expected vertices: 3')
144
+
145
+ def test_parse_ply_colors_data_if_described_in_header(self):
146
+ data = """ply
147
+ format ascii 1.0
148
+ element vertex 3
149
+ property float x
150
+ property float y
151
+ property float z
152
+ property uchar red
153
+ property uchar green
154
+ property uchar blue
155
+ element face 1
156
+ end_header
157
+ 1.0 2.0 3.0 255 0 0
158
+ 4.0 5.0 6.0 0 255 0
159
+ 7.0 8.0 9.0 0 0 255
160
+ 3 0 1 2"""
161
+
162
+ result = parse_ply_file_data(data.splitlines())
163
+ vertices, faces, colors = result[0], result[1], result[2]
164
+ self.assertEqual(len(vertices), 3)
165
+ self.assertEqual(len(faces), 1)
166
+ self.assertEqual(len(colors), 3)
167
+ self.assertEqual(colors, [[255, 0, 0], [0, 255, 0], [0, 0, 255]])
168
+
169
+ def test_not_parse_colors_if_color_property_not_described(self):
170
+ data = """ply
171
+ format ascii 1.0
172
+ element vertex 3
173
+ property float x
174
+ property float y
175
+ property float z
176
+ element face 1
177
+ end_header
178
+ 1.0 2.0 3.0 255 0 0
179
+ 4.0 5.0 6.0 0 255 0
180
+ 7.0 8.0 9.0 0 0 255
181
+ 3 0 1 2"""
182
+
183
+ result = parse_ply_file_data(data.splitlines())
184
+ vertices, faces, colors = result[0], result[1], result[2]
185
+ self.assertEqual(len(vertices), 3)
186
+ self.assertEqual(len(faces), 1)
187
+ self.assertEqual(len(colors), 0)
188
+
189
+ def test_parse_ply_data_with_negative_coordinates(self):
190
+ data = """ply
191
+ format ascii 1.0
192
+ element vertex 3
193
+ property float x
194
+ property float y
195
+ property float z
196
+ element face 1
197
+ end_header
198
+ -1.0 -2.0 -3.0
199
+ -4.0 -5.0 -6.0
200
+ -7.0 -8.0 -9.0
201
+ 3 0 1 2"""
202
+
203
+ result = parse_ply_file_data(data.splitlines())
204
+ vertices, faces, colors = result[0], result[1], result[2]
205
+ self.assertEqual(len(vertices), 3)
206
+ self.assertEqual(len(faces), 1)
207
+ self.assertEqual(len(colors), 0)
208
+
209
+ def test_handle_incomplete_face_data(self):
210
+ incomplete_face_data = """ply
211
+ format ascii 1.0
212
+ element vertex 3
213
+ element face 2
214
+ end_header
215
+ 1.0 2.0 3.0
216
+ 4.0 5.0 6.0
217
+ 7.0 8.0 9.0
218
+ 3 0 1 2"""
219
+
220
+ with self.assertRaises(ValueError) as context:
221
+ parse_ply_file_data(incomplete_face_data.splitlines())
222
+ self.assertEqual(str(context.exception), 'Error: total faces read: 1 does not match expected faces: 2')
223
+
224
+
225
+ if __name__ == '__main__':
226
+ unittest.main()