ply 0.9
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.
- data/.autotest +23 -0
- data/.gemtest +0 -0
- data/History.txt +3 -0
- data/LICENSE.txt +28 -0
- data/Manifest.txt +15 -0
- data/README.rdoc +227 -0
- data/README.txt +227 -0
- data/Rakefile +8 -0
- data/bin/ply2ascii +49 -0
- data/examples/cube_ascii.ply +30 -0
- data/examples/cube_binary_big_endian.ply +0 -0
- data/examples/cube_binary_little_endian.ply +0 -0
- data/examples/examples.rb +100 -0
- data/lib/ply.rb +188 -0
- data/test/test_ply.rb +56 -0
- data/test/test_ply2ascii.rb +23 -0
- metadata +113 -0
data/.autotest
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'autotest/restart'
|
4
|
+
|
5
|
+
# Autotest.add_hook :initialize do |at|
|
6
|
+
# at.extra_files << "../some/external/dependency.rb"
|
7
|
+
#
|
8
|
+
# at.libs << ":../some/external"
|
9
|
+
#
|
10
|
+
# at.add_exception 'vendor'
|
11
|
+
#
|
12
|
+
# at.add_mapping(/dependency.rb/) do |f, _|
|
13
|
+
# at.files_matching(/test_.*rb$/)
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# %w(TestA TestB).each do |klass|
|
17
|
+
# at.extra_class_map[klass] = "test/test_misc.rb"
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
|
21
|
+
# Autotest.add_hook :run_command do |at|
|
22
|
+
# system "rake build"
|
23
|
+
# end
|
data/.gemtest
ADDED
File without changes
|
data/History.txt
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
== LICENSE:
|
2
|
+
|
3
|
+
(The BSD 2-clause License)
|
4
|
+
|
5
|
+
Copyright (c) 2013 Jim Wise
|
6
|
+
All rights reserved.
|
7
|
+
|
8
|
+
Redistribution and use in source and binary forms, with or without
|
9
|
+
modification, are permitted provided that the following conditions
|
10
|
+
are met:
|
11
|
+
|
12
|
+
1. Redistributions of source code must retain the above copyright
|
13
|
+
notice, this list of conditions and the following disclaimer.
|
14
|
+
2. Redistributions in binary form must reproduce the above copyright
|
15
|
+
notice, this list of conditions and the following disclaimer in the
|
16
|
+
documentation and/or other materials provided with the distribution.
|
17
|
+
|
18
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
19
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
20
|
+
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
21
|
+
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
|
22
|
+
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
23
|
+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
24
|
+
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
25
|
+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
26
|
+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
27
|
+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
28
|
+
POSSIBILITY OF SUCH DAMAGE.
|
data/Manifest.txt
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
.autotest
|
2
|
+
History.txt
|
3
|
+
LICENSE.txt
|
4
|
+
Manifest.txt
|
5
|
+
README.txt
|
6
|
+
README.rdoc
|
7
|
+
Rakefile
|
8
|
+
bin/ply2ascii
|
9
|
+
examples/cube_ascii.ply
|
10
|
+
examples/cube_binary_big_endian.ply
|
11
|
+
examples/cube_binary_little_endian.ply
|
12
|
+
examples/examples.rb
|
13
|
+
lib/ply.rb
|
14
|
+
test/test_ply.rb
|
15
|
+
test/test_ply2ascii.rb
|
data/README.rdoc
ADDED
@@ -0,0 +1,227 @@
|
|
1
|
+
= ply
|
2
|
+
|
3
|
+
https://github.com/jimwise/ply
|
4
|
+
|
5
|
+
Author:: Jim Wise (mailto:jwise@draga.com)
|
6
|
+
Copyright:: Copyright (c) 2013 Jim Wise
|
7
|
+
License:: 2-clause BSD-Style (see LICENSE.txt)
|
8
|
+
|
9
|
+
== DESCRIPTION:
|
10
|
+
|
11
|
+
Ply is a ruby gem for reading Stanford PLY-format 3D model files.
|
12
|
+
|
13
|
+
The PLY file format is a flexible format for storing semi-structured binary data,
|
14
|
+
and is often used to stored polygonalized 3D models generated with range
|
15
|
+
scanning hardware. You can find some examples of the format at the the
|
16
|
+
{Stanford 3D Scanning Repository}[http://graphics.stanford.edu/data/3Dscanrep/].
|
17
|
+
|
18
|
+
Ply provides a simple API for quick access to the data in a PLY file
|
19
|
+
(including examining the structure of a particular file's content), and
|
20
|
+
an almost-as-simple event-driven API which can be used to process extremely
|
21
|
+
large ply files in a streaming fashion, without needing to keep the full
|
22
|
+
dataset represented in the file in memory. Ply handles all three types of
|
23
|
+
PLY files (ascii, binary-big-endian and binary-little-endian).
|
24
|
+
|
25
|
+
If you don't have any Stanford PLY files on hand, you probably don't need
|
26
|
+
this gem, but if you're curious, the PLY file format, described at
|
27
|
+
Wikipedia[http://en.wikipedia.org/wiki/PLY_(file_format)]
|
28
|
+
|
29
|
+
|
30
|
+
== REQUIREMENTS:
|
31
|
+
|
32
|
+
Ply currently requires Ruby 1.9.3 -- if you have a need to run Ply with Ruby
|
33
|
+
1.8.7, drop me an email[mailto:jwise@draga.com], and I'll look into
|
34
|
+
backporting it. Ply has no other dependencies.
|
35
|
+
|
36
|
+
== INSTALL:
|
37
|
+
|
38
|
+
$ gem install ply
|
39
|
+
|
40
|
+
== SYNOPSIS:
|
41
|
+
|
42
|
+
=== How to Use This Gem
|
43
|
+
|
44
|
+
To get started, include this gem using
|
45
|
+
|
46
|
+
require 'ply'
|
47
|
+
|
48
|
+
This gem provides the Ply module. This module provides a single class,
|
49
|
+
Ply::PlyFile, which can be used directly to parse a PLY file into memory, or
|
50
|
+
subclassed to take advantage of Ply's event-driven API for handling large
|
51
|
+
PLY files.
|
52
|
+
|
53
|
+
=== The Simple API
|
54
|
+
|
55
|
+
To parse a PLY file into memory, simply instantiate the Ply::PlyFile class,
|
56
|
+
passing either the name of the PLY file or an IO object open on a PLY file
|
57
|
+
to Ply::PlyFile.new. Thus this:
|
58
|
+
|
59
|
+
pf = Ply::PlyFile.new "horse.ply"
|
60
|
+
|
61
|
+
and this:
|
62
|
+
|
63
|
+
pf = Ply::PlyFile.new File.new("horse.ply")
|
64
|
+
|
65
|
+
do the same thing.
|
66
|
+
|
67
|
+
The PLY file is parsed at construction time, and provides the following
|
68
|
+
read-only accessors:
|
69
|
+
|
70
|
+
Ply::PlyFile#version::
|
71
|
+
The version of the PLY format used in this file, as a String -- at this
|
72
|
+
time the only defined PLY version is 1.0.
|
73
|
+
|
74
|
+
Ply::PlyFile#format::
|
75
|
+
The format of this PLY file as a String-- one of +ascii+,
|
76
|
+
+binary_big_endian+, or +binary_little_endian+.
|
77
|
+
|
78
|
+
Ply::PlyFile#elements::
|
79
|
+
The structure of the data in this PLY file, as an array of Hashes, in the
|
80
|
+
order the elements will appear in the file. Each Hash contains the
|
81
|
+
following keys:
|
82
|
+
|
83
|
+
:name:: the name of this element type
|
84
|
+
|
85
|
+
:count:: the number of elements of this type in this PLY file
|
86
|
+
|
87
|
+
:properties::
|
88
|
+
an array of Hashes describing the properties of this element
|
89
|
+
type. Each Hash in the +:properties+ array contains the following keys:
|
90
|
+
|
91
|
+
:name:: the name of this property of the current element
|
92
|
+
|
93
|
+
:type::
|
94
|
+
the type of this property (an integral or floating point type, as
|
95
|
+
defined in the PLY file format, or +list+. If the current property is
|
96
|
+
of type +list+ (a PLY array type), its property Hash also contains the
|
97
|
+
following keys:
|
98
|
+
|
99
|
+
:index_type::
|
100
|
+
the type of the index of this list
|
101
|
+
|
102
|
+
:element_type::
|
103
|
+
the type of the elements in this list
|
104
|
+
|
105
|
+
If you are using the Ply::PlyFile class directly (as opposed to subclassing
|
106
|
+
it in order to use Ply's event-driven API for handling large PLY files), an
|
107
|
+
additional read-only accessor is available
|
108
|
+
|
109
|
+
Ply::PlyFile#data::
|
110
|
+
|
111
|
+
The actual data in this file, in the structure defined by the return value
|
112
|
+
of Ply::PlyFile#elements, as a Hash of Arrays of Hashes. This data is returned
|
113
|
+
as a Hash keyed by the name of each element type in the file (as a
|
114
|
+
String), and containing an array of Hashes for each element type in the
|
115
|
+
file, keyed by the property names of that element, as Strings.
|
116
|
+
|
117
|
+
That's not as complicated as it sounds! If the file +horse.ply+ defines a
|
118
|
+
+vertex+ element, with properties +x+, +y+, and +z+, then
|
119
|
+
|
120
|
+
pf = Ply::PlyFile.new "horse.ply"
|
121
|
+
verts = pf.data["vertex"]
|
122
|
+
|
123
|
+
will return an array of all vertices in the file, and
|
124
|
+
|
125
|
+
verts[0]["x"]
|
126
|
+
|
127
|
+
will give you the value of the +x+ property of the first +vertex+ element
|
128
|
+
in the file, as an Integer, Float, or Array, depending on the declared
|
129
|
+
type of that property in the PLY file.
|
130
|
+
|
131
|
+
=== The Event-Driven API
|
132
|
+
|
133
|
+
The above API is easy to use, but has the disadvantage that the entire data
|
134
|
+
stored in the PLY file must be able to fit in memory, in order to be
|
135
|
+
returned by Ply::PlyFile::data. For this reason, a simple event-driven API
|
136
|
+
for handling PLY data is also provided. To make use of this, simply
|
137
|
+
subclass the class Ply::PlyFile, and provide your own version of the method
|
138
|
+
Ply::PlyFile#element_callback. When a new object of your subclass is
|
139
|
+
constructed from a PLY file, your implementation of this method will be
|
140
|
+
called once for each element in the file, and passed two arguments:
|
141
|
+
|
142
|
+
* The type of the current element, in the same format as a member of the
|
143
|
+
array returned by Ply::PlyFile::elements
|
144
|
+
|
145
|
+
* The current element, in the same format as the members of the arrays
|
146
|
+
returned by Ply::PlyFile::data
|
147
|
+
|
148
|
+
Note that if your subclass provides a #initialize method, it is your
|
149
|
+
responsibility to ensure that PlyFile
|
150
|
+
|
151
|
+
As an example, the following code defines a subclass of PlyFile which merely
|
152
|
+
*counts* the elements of each type present in PLY file, without reading them
|
153
|
+
all into memory at the same time:
|
154
|
+
|
155
|
+
class PlyFileCounter < Ply::PlyFile
|
156
|
+
attr_reader :counts
|
157
|
+
|
158
|
+
def initialize f
|
159
|
+
@counts = {}
|
160
|
+
super f
|
161
|
+
end
|
162
|
+
|
163
|
+
def element_callback e, v
|
164
|
+
@counts[e[:name]] ||= 0
|
165
|
+
@counts[e[:name]] = @counts[e[:name]] + 1
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
p = PlyFileCounter.new "horse.ply"
|
170
|
+
puts "There are #{p.counts["vertex"]} vertices in the file."
|
171
|
+
|
172
|
+
=== Example Files
|
173
|
+
|
174
|
+
In addition to the large models in the {Stanford 3D Scanning
|
175
|
+
Repository}[http://graphics.stanford.edu/data/3Dscanrep/], the +examples/+
|
176
|
+
subdirectory of this gem includes a simple triangulated cube model in all
|
177
|
+
three PLY file formats, as well as a script to generate these three files
|
178
|
+
which you may modify for your own purposes.
|
179
|
+
|
180
|
+
=== ply2ascii
|
181
|
+
|
182
|
+
Finally, this gem includes a simple script, +ply2ascii+, which can be used
|
183
|
+
to parse any of the three PLY file formats containing a triangulated scene
|
184
|
+
with vertices in an element named +vertex+ with (at least) scalar properties
|
185
|
+
+x+, +y+, and +z+, and faces in an elemnt named +face+ containing a list
|
186
|
+
property +vertex_indices+, and produce a simple ASCII dump of the described
|
187
|
+
scene in two files.
|
188
|
+
|
189
|
+
Run +ply2ascii+ with no arguments for (a little) more information.
|
190
|
+
|
191
|
+
== DEVELOPERS:
|
192
|
+
|
193
|
+
After checking out the source, run:
|
194
|
+
|
195
|
+
$ rake newb
|
196
|
+
|
197
|
+
This task will install any missing dependencies, run the tests/specs,
|
198
|
+
and generate the RDoc.
|
199
|
+
|
200
|
+
== LICENSE:
|
201
|
+
|
202
|
+
(The BSD 2-clause License)
|
203
|
+
|
204
|
+
Copyright (c) 2013 Jim Wise
|
205
|
+
All rights reserved.
|
206
|
+
|
207
|
+
Redistribution and use in source and binary forms, with or without
|
208
|
+
modification, are permitted provided that the following conditions
|
209
|
+
are met:
|
210
|
+
|
211
|
+
1. Redistributions of source code must retain the above copyright
|
212
|
+
notice, this list of conditions and the following disclaimer.
|
213
|
+
2. Redistributions in binary form must reproduce the above copyright
|
214
|
+
notice, this list of conditions and the following disclaimer in the
|
215
|
+
documentation and/or other materials provided with the distribution.
|
216
|
+
|
217
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
218
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
219
|
+
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
220
|
+
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
|
221
|
+
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
222
|
+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
223
|
+
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
224
|
+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
225
|
+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
226
|
+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
227
|
+
POSSIBILITY OF SUCH DAMAGE.
|
data/README.txt
ADDED
@@ -0,0 +1,227 @@
|
|
1
|
+
= ply
|
2
|
+
|
3
|
+
https://github.com/jimwise/ply
|
4
|
+
|
5
|
+
Author:: Jim Wise (mailto:jwise@draga.com)
|
6
|
+
Copyright:: Copyright (c) 2013 Jim Wise
|
7
|
+
License:: 2-clause BSD-Style (see LICENSE.txt)
|
8
|
+
|
9
|
+
== DESCRIPTION:
|
10
|
+
|
11
|
+
Ply is a ruby gem for reading Stanford PLY-format 3D model files.
|
12
|
+
|
13
|
+
The PLY file format is a flexible format for storing semi-structured binary data,
|
14
|
+
and is often used to stored polygonalized 3D models generated with range
|
15
|
+
scanning hardware. You can find some examples of the format at the the
|
16
|
+
{Stanford 3D Scanning Repository}[http://graphics.stanford.edu/data/3Dscanrep/].
|
17
|
+
|
18
|
+
Ply provides a simple API for quick access to the data in a PLY file
|
19
|
+
(including examining the structure of a particular file's content), and
|
20
|
+
an almost-as-simple event-driven API which can be used to process extremely
|
21
|
+
large ply files in a streaming fashion, without needing to keep the full
|
22
|
+
dataset represented in the file in memory. Ply handles all three types of
|
23
|
+
PLY files (ascii, binary-big-endian and binary-little-endian).
|
24
|
+
|
25
|
+
If you don't have any Stanford PLY files on hand, you probably don't need
|
26
|
+
this gem, but if you're curious, the PLY file format, described at
|
27
|
+
Wikipedia[http://en.wikipedia.org/wiki/PLY_(file_format)]
|
28
|
+
|
29
|
+
|
30
|
+
== REQUIREMENTS:
|
31
|
+
|
32
|
+
Ply currently requires Ruby 1.9.3 -- if you have a need to run Ply with Ruby
|
33
|
+
1.8.7, drop me an email[mailto:jwise@draga.com], and I'll look into
|
34
|
+
backporting it. Ply has no other dependencies.
|
35
|
+
|
36
|
+
== INSTALL:
|
37
|
+
|
38
|
+
$ gem install ply
|
39
|
+
|
40
|
+
== SYNOPSIS:
|
41
|
+
|
42
|
+
=== How to Use This Gem
|
43
|
+
|
44
|
+
To get started, include this gem using
|
45
|
+
|
46
|
+
require 'ply'
|
47
|
+
|
48
|
+
This gem provides the Ply module. This module provides a single class,
|
49
|
+
Ply::PlyFile, which can be used directly to parse a PLY file into memory, or
|
50
|
+
subclassed to take advantage of Ply's event-driven API for handling large
|
51
|
+
PLY files.
|
52
|
+
|
53
|
+
=== The Simple API
|
54
|
+
|
55
|
+
To parse a PLY file into memory, simply instantiate the Ply::PlyFile class,
|
56
|
+
passing either the name of the PLY file or an IO object open on a PLY file
|
57
|
+
to Ply::PlyFile.new. Thus this:
|
58
|
+
|
59
|
+
pf = Ply::PlyFile.new "horse.ply"
|
60
|
+
|
61
|
+
and this:
|
62
|
+
|
63
|
+
pf = Ply::PlyFile.new File.new("horse.ply")
|
64
|
+
|
65
|
+
do the same thing.
|
66
|
+
|
67
|
+
The PLY file is parsed at construction time, and provides the following
|
68
|
+
read-only accessors:
|
69
|
+
|
70
|
+
Ply::PlyFile#version::
|
71
|
+
The version of the PLY format used in this file, as a String -- at this
|
72
|
+
time the only defined PLY version is 1.0.
|
73
|
+
|
74
|
+
Ply::PlyFile#format::
|
75
|
+
The format of this PLY file as a String-- one of +ascii+,
|
76
|
+
+binary_big_endian+, or +binary_little_endian+.
|
77
|
+
|
78
|
+
Ply::PlyFile#elements::
|
79
|
+
The structure of the data in this PLY file, as an array of Hashes, in the
|
80
|
+
order the elements will appear in the file. Each Hash contains the
|
81
|
+
following keys:
|
82
|
+
|
83
|
+
:name:: the name of this element type
|
84
|
+
|
85
|
+
:count:: the number of elements of this type in this PLY file
|
86
|
+
|
87
|
+
:properties::
|
88
|
+
an array of Hashes describing the properties of this element
|
89
|
+
type. Each Hash in the +:properties+ array contains the following keys:
|
90
|
+
|
91
|
+
:name:: the name of this property of the current element
|
92
|
+
|
93
|
+
:type::
|
94
|
+
the type of this property (an integral or floating point type, as
|
95
|
+
defined in the PLY file format, or +list+. If the current property is
|
96
|
+
of type +list+ (a PLY array type), its property Hash also contains the
|
97
|
+
following keys:
|
98
|
+
|
99
|
+
:index_type::
|
100
|
+
the type of the index of this list
|
101
|
+
|
102
|
+
:element_type::
|
103
|
+
the type of the elements in this list
|
104
|
+
|
105
|
+
If you are using the Ply::PlyFile class directly (as opposed to subclassing
|
106
|
+
it in order to use Ply's event-driven API for handling large PLY files), an
|
107
|
+
additional read-only accessor is available
|
108
|
+
|
109
|
+
Ply::PlyFile#data::
|
110
|
+
|
111
|
+
The actual data in this file, in the structure defined by the return value
|
112
|
+
of Ply::PlyFile#elements, as a Hash of Arrays of Hashes. This data is returned
|
113
|
+
as a Hash keyed by the name of each element type in the file (as a
|
114
|
+
String), and containing an array of Hashes for each element type in the
|
115
|
+
file, keyed by the property names of that element, as Strings.
|
116
|
+
|
117
|
+
That's not as complicated as it sounds! If the file +horse.ply+ defines a
|
118
|
+
+vertex+ element, with properties +x+, +y+, and +z+, then
|
119
|
+
|
120
|
+
pf = Ply::PlyFile.new "horse.ply"
|
121
|
+
verts = pf.data["vertex"]
|
122
|
+
|
123
|
+
will return an array of all vertices in the file, and
|
124
|
+
|
125
|
+
verts[0]["x"]
|
126
|
+
|
127
|
+
will give you the value of the +x+ property of the first +vertex+ element
|
128
|
+
in the file, as an Integer, Float, or Array, depending on the declared
|
129
|
+
type of that property in the PLY file.
|
130
|
+
|
131
|
+
=== The Event-Driven API
|
132
|
+
|
133
|
+
The above API is easy to use, but has the disadvantage that the entire data
|
134
|
+
stored in the PLY file must be able to fit in memory, in order to be
|
135
|
+
returned by Ply::PlyFile::data. For this reason, a simple event-driven API
|
136
|
+
for handling PLY data is also provided. To make use of this, simply
|
137
|
+
subclass the class Ply::PlyFile, and provide your own version of the method
|
138
|
+
Ply::PlyFile#element_callback. When a new object of your subclass is
|
139
|
+
constructed from a PLY file, your implementation of this method will be
|
140
|
+
called once for each element in the file, and passed two arguments:
|
141
|
+
|
142
|
+
* The type of the current element, in the same format as a member of the
|
143
|
+
array returned by Ply::PlyFile::elements
|
144
|
+
|
145
|
+
* The current element, in the same format as the members of the arrays
|
146
|
+
returned by Ply::PlyFile::data
|
147
|
+
|
148
|
+
Note that if your subclass provides a #initialize method, it is your
|
149
|
+
responsibility to ensure that PlyFile
|
150
|
+
|
151
|
+
As an example, the following code defines a subclass of PlyFile which merely
|
152
|
+
*counts* the elements of each type present in PLY file, without reading them
|
153
|
+
all into memory at the same time:
|
154
|
+
|
155
|
+
class PlyFileCounter < Ply::PlyFile
|
156
|
+
attr_reader :counts
|
157
|
+
|
158
|
+
def initialize f
|
159
|
+
@counts = {}
|
160
|
+
super f
|
161
|
+
end
|
162
|
+
|
163
|
+
def element_callback e, v
|
164
|
+
@counts[e[:name]] ||= 0
|
165
|
+
@counts[e[:name]] = @counts[e[:name]] + 1
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
p = PlyFileCounter.new "horse.ply"
|
170
|
+
puts "There are #{p.counts["vertex"]} vertices in the file."
|
171
|
+
|
172
|
+
=== Example Files
|
173
|
+
|
174
|
+
In addition to the large models in the {Stanford 3D Scanning
|
175
|
+
Repository}[http://graphics.stanford.edu/data/3Dscanrep/], the +examples/+
|
176
|
+
subdirectory of this gem includes a simple triangulated cube model in all
|
177
|
+
three PLY file formats, as well as a script to generate these three files
|
178
|
+
which you may modify for your own purposes.
|
179
|
+
|
180
|
+
=== ply2ascii
|
181
|
+
|
182
|
+
Finally, this gem includes a simple script, +ply2ascii+, which can be used
|
183
|
+
to parse any of the three PLY file formats containing a triangulated scene
|
184
|
+
with vertices in an element named +vertex+ with (at least) scalar properties
|
185
|
+
+x+, +y+, and +z+, and faces in an elemnt named +face+ containing a list
|
186
|
+
property +vertex_indices+, and produce a simple ASCII dump of the described
|
187
|
+
scene in two files.
|
188
|
+
|
189
|
+
Run +ply2ascii+ with no arguments for (a little) more information.
|
190
|
+
|
191
|
+
== DEVELOPERS:
|
192
|
+
|
193
|
+
After checking out the source, run:
|
194
|
+
|
195
|
+
$ rake newb
|
196
|
+
|
197
|
+
This task will install any missing dependencies, run the tests/specs,
|
198
|
+
and generate the RDoc.
|
199
|
+
|
200
|
+
== LICENSE:
|
201
|
+
|
202
|
+
(The BSD 2-clause License)
|
203
|
+
|
204
|
+
Copyright (c) 2013 Jim Wise
|
205
|
+
All rights reserved.
|
206
|
+
|
207
|
+
Redistribution and use in source and binary forms, with or without
|
208
|
+
modification, are permitted provided that the following conditions
|
209
|
+
are met:
|
210
|
+
|
211
|
+
1. Redistributions of source code must retain the above copyright
|
212
|
+
notice, this list of conditions and the following disclaimer.
|
213
|
+
2. Redistributions in binary form must reproduce the above copyright
|
214
|
+
notice, this list of conditions and the following disclaimer in the
|
215
|
+
documentation and/or other materials provided with the distribution.
|
216
|
+
|
217
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
218
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
219
|
+
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
220
|
+
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
|
221
|
+
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
222
|
+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
223
|
+
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
224
|
+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
225
|
+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
226
|
+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
227
|
+
POSSIBILITY OF SUCH DAMAGE.
|
data/Rakefile
ADDED
data/bin/ply2ascii
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'ply'
|
4
|
+
|
5
|
+
USAGE = "usage: #{$0} <ply file> ..."
|
6
|
+
HELP = <<EOL
|
7
|
+
This utility translates ply files with vertex and triangle information
|
8
|
+
into simple ASCII files.
|
9
|
+
|
10
|
+
Each plyfile specified on the command line is read, and corresponding
|
11
|
+
triangle and vertex files are created in the current directory.
|
12
|
+
EOL
|
13
|
+
|
14
|
+
class Ply2Ascii < Ply::PlyFile
|
15
|
+
def initialize infile, outname
|
16
|
+
@verts = File.new("vertices_#{outname}.ascii", "w")
|
17
|
+
@verts.puts("# written by ply.rb")
|
18
|
+
@tris = File.new("triangles_#{outname}.ascii", "w")
|
19
|
+
@tris.puts("# written by ply.rb")
|
20
|
+
super infile
|
21
|
+
end
|
22
|
+
|
23
|
+
def element_callback elt, val
|
24
|
+
case elt[:name]
|
25
|
+
when "vertex"
|
26
|
+
@verts.puts "#{val["x"]} #{val["y"]} #{val["z"]}"
|
27
|
+
when "face"
|
28
|
+
@tris.puts val["vertex_indices"].join " "
|
29
|
+
else
|
30
|
+
puts "skipping unknown element type #{elt[:name]}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
if ARGV.size == 0
|
36
|
+
puts USAGE
|
37
|
+
puts HELP
|
38
|
+
end
|
39
|
+
|
40
|
+
ARGV.each do |fname|
|
41
|
+
begin
|
42
|
+
outname = File.basename(fname, ".ply")
|
43
|
+
Ply2Ascii.new(fname, outname)
|
44
|
+
rescue Ply::BadFile => bf
|
45
|
+
puts "#{fname}: #{bf}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# -*- ruby -*-
|
@@ -0,0 +1,30 @@
|
|
1
|
+
ply
|
2
|
+
format ascii 1.0
|
3
|
+
comment simple triangulated cube example
|
4
|
+
element vertex 8
|
5
|
+
property float32 x
|
6
|
+
property float32 y
|
7
|
+
property float32 z
|
8
|
+
element face 12
|
9
|
+
property list uint8 uint32 vertex_indices
|
10
|
+
end_header
|
11
|
+
0.0 0.0 0.0
|
12
|
+
0.0 1.0 0.0
|
13
|
+
1.0 0.0 0.0
|
14
|
+
1.0 1.0 0.0
|
15
|
+
0.0 0.0 1.0
|
16
|
+
0.0 1.0 1.0
|
17
|
+
1.0 0.0 1.0
|
18
|
+
1.0 1.0 1.0
|
19
|
+
3 0 1 3
|
20
|
+
3 1 3 2
|
21
|
+
3 0 1 5
|
22
|
+
3 0 5 4
|
23
|
+
3 4 0 2
|
24
|
+
3 4 2 6
|
25
|
+
3 2 3 7
|
26
|
+
3 2 7 6
|
27
|
+
3 4 5 7
|
28
|
+
3 4 7 6
|
29
|
+
3 1 5 7
|
30
|
+
3 1 7 3
|
Binary file
|
Binary file
|
@@ -0,0 +1,100 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
|
3
|
+
# 6---------7
|
4
|
+
# /: /|
|
5
|
+
# / : / |
|
6
|
+
# / : / |
|
7
|
+
# 2---------3 |
|
8
|
+
# | 4.....|...5
|
9
|
+
# | ' | /
|
10
|
+
# | ' | /
|
11
|
+
# |' |/
|
12
|
+
# 0---------1
|
13
|
+
#
|
14
|
+
# Y Z
|
15
|
+
# |/
|
16
|
+
# *-X
|
17
|
+
|
18
|
+
Cube_vertices = [
|
19
|
+
[0.0, 0.0, 0.0],
|
20
|
+
[0.0, 1.0, 0.0],
|
21
|
+
[1.0, 0.0, 0.0],
|
22
|
+
[1.0, 1.0, 0.0],
|
23
|
+
[0.0, 0.0, 1.0],
|
24
|
+
[0.0, 1.0, 1.0],
|
25
|
+
[1.0, 0.0, 1.0],
|
26
|
+
[1.0, 1.0, 1.0]
|
27
|
+
]
|
28
|
+
|
29
|
+
Cube_faces = [
|
30
|
+
[0, 1, 3],
|
31
|
+
[1, 3, 2],
|
32
|
+
|
33
|
+
[0, 1, 5],
|
34
|
+
[0, 5, 4],
|
35
|
+
|
36
|
+
[4, 0, 2],
|
37
|
+
[4, 2, 6],
|
38
|
+
|
39
|
+
[2, 3, 7],
|
40
|
+
[2, 7, 6],
|
41
|
+
|
42
|
+
[4, 5, 7],
|
43
|
+
[4, 7, 6],
|
44
|
+
|
45
|
+
[1, 5, 7],
|
46
|
+
[1, 7, 3]
|
47
|
+
]
|
48
|
+
|
49
|
+
def header f, format
|
50
|
+
f.puts "ply"
|
51
|
+
f.puts "format #{format} 1.0"
|
52
|
+
f.puts "comment simple triangulated cube example"
|
53
|
+
f.puts "element vertex 8"
|
54
|
+
f.puts "property float32 x"
|
55
|
+
f.puts "property float32 y"
|
56
|
+
f.puts "property float32 z"
|
57
|
+
f.puts "element face 12"
|
58
|
+
f.puts "property list uint8 uint32 vertex_indices"
|
59
|
+
f.puts "end_header"
|
60
|
+
end
|
61
|
+
|
62
|
+
def ascii_cube fname
|
63
|
+
f = File.new(fname, "w")
|
64
|
+
header f, "ascii"
|
65
|
+
Cube_vertices.each do |vert|
|
66
|
+
f.puts vert.map{|p| p.to_s}.join(" ")
|
67
|
+
end
|
68
|
+
Cube_faces.each do |face|
|
69
|
+
f.print "#{face.size} "
|
70
|
+
f.puts face.map{|p| p.to_s}.join(" ")
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def bin_be_cube fname
|
75
|
+
f = File.new(fname, "w")
|
76
|
+
header f, "binary_big_endian"
|
77
|
+
Cube_vertices.each do |vert|
|
78
|
+
f.write vert.pack("g*")
|
79
|
+
end
|
80
|
+
Cube_faces.each do |face|
|
81
|
+
f.write [ face.size ].pack("C")
|
82
|
+
f.write face.pack("L>*")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def bin_le_cube fname
|
87
|
+
f = File.new(fname, "w")
|
88
|
+
header f, "binary_little_endian"
|
89
|
+
Cube_vertices.each do |vert|
|
90
|
+
f.write vert.pack("e*")
|
91
|
+
end
|
92
|
+
Cube_faces.each do |face|
|
93
|
+
f.write [ face.size ].pack("C")
|
94
|
+
f.write face.pack("L<*")
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
ascii_cube "cube_ascii.ply"
|
99
|
+
bin_be_cube "cube_binary_big_endian.ply"
|
100
|
+
bin_le_cube "cube_binary_little_endian.ply"
|
data/lib/ply.rb
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
# ply.rb
|
2
|
+
|
3
|
+
# Copyright (c) 2013 Jim Wise
|
4
|
+
# All rights reserved.
|
5
|
+
#
|
6
|
+
# Redistribution and use in source and binary forms, with or without
|
7
|
+
# modification, are permitted provided that the following conditions
|
8
|
+
# are met:
|
9
|
+
#
|
10
|
+
# 1. Redistributions of source code must retain the above copyright
|
11
|
+
# notice, this list of conditions and the following disclaimer.
|
12
|
+
# 2. Redistributions in binary form must reproduce the above copyright
|
13
|
+
# notice, this list of conditions and the following disclaimer in the
|
14
|
+
# documentation and/or other materials provided with the distribution.
|
15
|
+
#
|
16
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
17
|
+
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
18
|
+
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
19
|
+
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
|
20
|
+
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
21
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
22
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
23
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
24
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
25
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
26
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
|
28
|
+
module Ply
|
29
|
+
VERSION = '0.9'
|
30
|
+
|
31
|
+
# module for working with ply file format -- see
|
32
|
+
# http://en.wikipedia.org/wiki/PLY_(file_format)
|
33
|
+
# right now, this supports reading, but not writing ply files
|
34
|
+
|
35
|
+
class PlyFile
|
36
|
+
attr_reader :format, :version, :elements, :data
|
37
|
+
|
38
|
+
# versions of the ply file format we know how to parse (this is the only defined version as of the time of writing)
|
39
|
+
Versions = %w{1.0}
|
40
|
+
# formats of the ply file format we know about (we don't yet implement ascii)
|
41
|
+
Formats = %w{binary_big_endian binary_little_endian ascii}
|
42
|
+
# property types defined by the ply format; we assume ILP32 meaning of types without explicit widths
|
43
|
+
Types = %w{char uchar short ushort int uint float double int8 uint8 int16 uint16 int32 uint32 float32 float64 list}
|
44
|
+
|
45
|
+
# parse a ply file takes a file name or an IO stream as argument
|
46
|
+
def initialize f
|
47
|
+
unless f.instance_of? IO
|
48
|
+
f = File.new(f)
|
49
|
+
end
|
50
|
+
@source = f
|
51
|
+
@elements = []
|
52
|
+
parse_header f
|
53
|
+
parse_body f
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def parse_header f
|
59
|
+
raise BadFile.new("missing magic") unless f.gets.chomp == "ply"
|
60
|
+
|
61
|
+
raise BadFile.new("malformed format line") unless md =
|
62
|
+
f.gets.chomp.match(/^format\s+(?<format>[^\s]+)\s+(?<version>[\d.]+)$/)
|
63
|
+
@format = md[:format]
|
64
|
+
@version = md[:version]
|
65
|
+
|
66
|
+
raise BadFile.new("unknown version: #{version}") unless Versions.find(version)
|
67
|
+
raise BadFile.new("unknown format: #{format}") unless Formats.find(version)
|
68
|
+
|
69
|
+
current_element = false
|
70
|
+
f.each do |s|
|
71
|
+
cmd = s.chomp.split
|
72
|
+
case cmd[0]
|
73
|
+
when "comment"
|
74
|
+
when "obj_info"
|
75
|
+
when "end_header"
|
76
|
+
# stash last element
|
77
|
+
@elements << current_element if current_element
|
78
|
+
break
|
79
|
+
when "element"
|
80
|
+
# stash previous element
|
81
|
+
@elements << current_element if current_element
|
82
|
+
# puts "new element #{cmd[1]}"
|
83
|
+
current_element = { name: cmd[1], count: cmd[2].to_i, properties: [] }
|
84
|
+
when "property"
|
85
|
+
type = cmd[1]
|
86
|
+
raise BadFile.new("unknown element type: #{type}") unless Types.find(type)
|
87
|
+
|
88
|
+
current_element[:properties] << if type == "list"
|
89
|
+
# puts "new property #{cmd[4]} of element #{current_element[:name]} has type list indexed by #{cmd[2]} of #{cmd[3]}"
|
90
|
+
{ name: cmd[4], type: "list", index_type: cmd[2], element_type: cmd[3]}
|
91
|
+
else
|
92
|
+
# puts "new property #{cmd[2]} of element #{current_element[:name]} has type #{type}"
|
93
|
+
{ name: cmd[2], type: type}
|
94
|
+
end
|
95
|
+
else
|
96
|
+
raise BadFile.new("unknown ply command #{cmd[0]}")
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# parse the body of a ply file, using the structures already parsed out of the header
|
102
|
+
# for each element type foo defined in the header, fills in @data[foo] with an array of hashes keyed on the property names
|
103
|
+
def parse_body f
|
104
|
+
@elements.each do |elt|
|
105
|
+
elt[:count].times do
|
106
|
+
element_callback elt, read_element(f, elt)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# by default, we accumulate all elements of a given type e, in-memory, into an array @data[e]
|
112
|
+
# this is non-ideal for big files, of course -- to change this behavior, subclass PlyFile, and provide your own
|
113
|
+
# element callback -- it will be called once for each read element, and passed the element definition (in elt), and
|
114
|
+
# the actual values just read (in val)
|
115
|
+
def element_callback elt, val
|
116
|
+
@data ||= {}
|
117
|
+
@data[elt[:name]] ||= []
|
118
|
+
@data[elt[:name]] << val
|
119
|
+
end
|
120
|
+
|
121
|
+
def read_element f, elt
|
122
|
+
current_element = {}
|
123
|
+
if @format == "ascii"
|
124
|
+
fields = f.gets.chomp.split
|
125
|
+
elt[:properties].each do |prop|
|
126
|
+
current_element[prop[:name]] = read_property_ascii(fields, prop[:type], prop[:index_type], prop[:element_type])
|
127
|
+
end
|
128
|
+
else
|
129
|
+
elt[:properties].each do |prop|
|
130
|
+
# last two will be nil for non-list
|
131
|
+
current_element[prop[:name]] = read_property_binary(f, prop[:type], prop[:index_type], prop[:element_type])
|
132
|
+
end
|
133
|
+
end
|
134
|
+
current_element
|
135
|
+
end
|
136
|
+
|
137
|
+
def read_property_ascii fields, type, index_type=false, element_type=false
|
138
|
+
#print "reading one #{type}: "
|
139
|
+
case type
|
140
|
+
when "char", "int8", "uchar", "uint8", "short", "int16", "ushort", "uint16", "int", "int32", "uint", "uint32"
|
141
|
+
# integer types
|
142
|
+
fields.shift.to_i
|
143
|
+
when "float", "float32", "double", "float64"
|
144
|
+
# floating point types
|
145
|
+
fields.shift.to_f
|
146
|
+
when "list"
|
147
|
+
count = read_property_ascii(fields, index_type)
|
148
|
+
count.times.collect { read_property_ascii(fields, element_type) }
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# read one property from an IO stream in ply binary format, assuming ILP32 widths for generic types
|
153
|
+
def read_property_binary f, type, index_type=false, element_type=false
|
154
|
+
# print "reading one #{type}: "
|
155
|
+
# pick String#unpack specifiers based on our endian-ness
|
156
|
+
case @format
|
157
|
+
when "binary_big_endian"
|
158
|
+
e, f32, f64 = ">", "g", "G"
|
159
|
+
when "binary_little_endian"
|
160
|
+
e, f32, f64 = "<", "e", "E"
|
161
|
+
end
|
162
|
+
case type
|
163
|
+
when "char", "int8"
|
164
|
+
f.read(1).unpack("c").first
|
165
|
+
when "uchar", "uint8"
|
166
|
+
f.read(1).unpack("C").first
|
167
|
+
when "short", "int16"
|
168
|
+
f.read(2).unpack("s#{e}").first
|
169
|
+
when "ushort", "uint16"
|
170
|
+
f.read(2).unpack("S#{e}").first
|
171
|
+
when "int", "int32"
|
172
|
+
f.read(4).unpack("l#{e}").first
|
173
|
+
when "uint", "uint32"
|
174
|
+
f.read(4).unpack("L#{e}").first
|
175
|
+
when "float", "float32"
|
176
|
+
f.read(4).unpack(f32).first
|
177
|
+
when "double", "float64"
|
178
|
+
f.read(8).unpack(f64).first
|
179
|
+
when "list"
|
180
|
+
count = read_property_binary(f, index_type)
|
181
|
+
count.times.collect { read_property_binary(f, element_type) }
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
class BadFile < Exception
|
187
|
+
end
|
188
|
+
end
|
data/test/test_ply.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require "ply"
|
3
|
+
|
4
|
+
class TestPly < Test::Unit::TestCase
|
5
|
+
def test_ascii
|
6
|
+
verify_cube_file "examples/cube_ascii.ply"
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_binary_big_endian
|
10
|
+
verify_cube_file "examples/cube_binary_big_endian.ply"
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_binary_little_endian
|
14
|
+
verify_cube_file "examples/cube_binary_little_endian.ply"
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_ascii_callback
|
18
|
+
verify_cube_callback "examples/cube_ascii.ply"
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_binary_big_endian_callback
|
22
|
+
verify_cube_callback "examples/cube_binary_big_endian.ply"
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_binary_little_endian_callback
|
26
|
+
verify_cube_callback "examples/cube_binary_little_endian.ply"
|
27
|
+
end
|
28
|
+
|
29
|
+
def verify_cube_file c
|
30
|
+
p = Ply::PlyFile.new c
|
31
|
+
assert p.data["vertex"].size == 8
|
32
|
+
assert p.data["face"].size == 12
|
33
|
+
assert p.data["vertex"][7]["x"] == 1.0
|
34
|
+
assert p.data["face"][11]["vertex_indices"][2] == 3
|
35
|
+
end
|
36
|
+
|
37
|
+
class PlyFileCounter < Ply::PlyFile
|
38
|
+
attr_reader :counts
|
39
|
+
|
40
|
+
def initialize f
|
41
|
+
@counts = {}
|
42
|
+
super f
|
43
|
+
end
|
44
|
+
|
45
|
+
def element_callback e, v
|
46
|
+
@counts[e[:name]] ||= 0
|
47
|
+
@counts[e[:name]] = @counts[e[:name]] + 1
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def verify_cube_callback c
|
52
|
+
p = PlyFileCounter.new c
|
53
|
+
assert p.counts["vertex"] == 8
|
54
|
+
assert p.counts["face"] == 12
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require "ply"
|
3
|
+
|
4
|
+
class TestPly2Ascii < Test::Unit::TestCase
|
5
|
+
def test_ply2ascii
|
6
|
+
assert system("env RUBYOPT=-I./lib bin/ply2ascii examples/cube_binary_big_endian.ply")
|
7
|
+
verts = File.new "vertices_cube_binary_big_endian.ascii"
|
8
|
+
tris = File.new "triangles_cube_binary_big_endian.ascii"
|
9
|
+
nv, nt = 0, 0
|
10
|
+
verts.lines {|l| nv = nv + 1}
|
11
|
+
tris.lines {|l| nt = nt + 1}
|
12
|
+
assert nv == 9
|
13
|
+
assert nt == 13
|
14
|
+
ensure
|
15
|
+
File.unlink "vertices_cube_binary_big_endian.ascii"
|
16
|
+
File.unlink "triangles_cube_binary_big_endian.ascii"
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_help
|
20
|
+
out = `env RUBYOPT=-I./lib bin/ply2ascii`
|
21
|
+
assert out.match(/^This utility/)
|
22
|
+
end
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ply
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.9'
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jim Wise
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-05 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rdoc
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '3.10'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3.10'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: hoe
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '3.5'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '3.5'
|
46
|
+
description: ! "Ply is a ruby gem for reading Stanford PLY-format 3D model files.\n\nThe
|
47
|
+
PLY file format is a flexible format for storing semi-structured binary data,\nand
|
48
|
+
is often used to stored polygonalized 3D models generated with range\nscanning hardware.
|
49
|
+
\ You can find some examples of the format at the the\n{Stanford 3D Scanning Repository}[http://graphics.stanford.edu/data/3Dscanrep/].\n
|
50
|
+
\nPly provides a simple API for quick access to the data in a PLY file\n(including
|
51
|
+
examining the structure of a particular file's content), and\nan almost-as-simple
|
52
|
+
event-driven API which can be used to process extremely\nlarge ply files in a streaming
|
53
|
+
fashion, without needing to keep the full\ndataset represented in the file in memory.
|
54
|
+
\ Ply handles all three types of\nPLY files (ascii, binary-big-endian and binary-little-endian).\n\nIf
|
55
|
+
you don't have any Stanford PLY files on hand, you probably don't need\nthis gem,
|
56
|
+
but if you're curious, the PLY file format, described at\nWikipedia[http://en.wikipedia.org/wiki/PLY_(file_format)]"
|
57
|
+
email:
|
58
|
+
- jwise@draga.com
|
59
|
+
executables:
|
60
|
+
- ply2ascii
|
61
|
+
extensions: []
|
62
|
+
extra_rdoc_files:
|
63
|
+
- History.txt
|
64
|
+
- LICENSE.txt
|
65
|
+
- Manifest.txt
|
66
|
+
- README.txt
|
67
|
+
- README.rdoc
|
68
|
+
files:
|
69
|
+
- .autotest
|
70
|
+
- History.txt
|
71
|
+
- LICENSE.txt
|
72
|
+
- Manifest.txt
|
73
|
+
- README.txt
|
74
|
+
- README.rdoc
|
75
|
+
- Rakefile
|
76
|
+
- bin/ply2ascii
|
77
|
+
- examples/cube_ascii.ply
|
78
|
+
- examples/cube_binary_big_endian.ply
|
79
|
+
- examples/cube_binary_little_endian.ply
|
80
|
+
- examples/examples.rb
|
81
|
+
- lib/ply.rb
|
82
|
+
- test/test_ply.rb
|
83
|
+
- test/test_ply2ascii.rb
|
84
|
+
- .gemtest
|
85
|
+
homepage: https://github.com/jimwise/ply
|
86
|
+
licenses: []
|
87
|
+
post_install_message:
|
88
|
+
rdoc_options:
|
89
|
+
- --main
|
90
|
+
- README.txt
|
91
|
+
require_paths:
|
92
|
+
- lib
|
93
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ! '>='
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
requirements: []
|
106
|
+
rubyforge_project: ply
|
107
|
+
rubygems_version: 1.8.24
|
108
|
+
signing_key:
|
109
|
+
specification_version: 3
|
110
|
+
summary: Ply is a ruby gem for reading Stanford PLY-format 3D model files
|
111
|
+
test_files:
|
112
|
+
- test/test_ply.rb
|
113
|
+
- test/test_ply2ascii.rb
|