Panda3D
 All Classes Functions Variables Enumerations
ptsToBam.cxx
1 // Filename: ptsToBam.cxx
2 // Created by: drose (28Jun00)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "ptsToBam.h"
16 
17 #include "config_util.h"
18 #include "geomPoints.h"
19 #include "bamFile.h"
20 #include "pandaNode.h"
21 #include "geomNode.h"
22 #include "dcast.h"
23 #include "pystub.h"
24 #include "string_utils.h"
25 #include "config_egg2pg.h"
26 
27 ////////////////////////////////////////////////////////////////////
28 // Function: PtsToBam::Constructor
29 // Access: Public
30 // Description:
31 ////////////////////////////////////////////////////////////////////
32 PtsToBam::
33 PtsToBam() : WithOutputFile(true, false, true)
34 {
35  set_program_brief("convert point cloud data into a .bam file");
36  set_program_description
37  ("This program reads a point clound in a pts file and outputs a bam files, "
38  "suitable for viewing in Panda.");
39 
40  clear_runlines();
41  add_runline("[opts] input.pts output.bam");
42  add_runline("[opts] -o output.bam input.pts");
43 
44  add_option
45  ("o", "filename", 0,
46  "Specify the filename to which the resulting .bam file will be written. "
47  "If this option is omitted, the last parameter name is taken to be the "
48  "name of the output file.",
49  &PtsToBam::dispatch_filename, &_got_output_filename, &_output_filename);
50 
51  add_option
52  ("d", "divisor", 0,
53  "Decimates the point cloud by the indicated divisor. The number of points\n"
54  "added is 1/divisor; numbers larger than 1.0 mean correspondingly fewer\n"
55  "points.",
56  &PtsToBam::dispatch_double, NULL, &_decimate_divisor);
57 
58  _decimate_divisor = 1.0;
59 }
60 
61 ////////////////////////////////////////////////////////////////////
62 // Function: PtsToBam::run
63 // Access: Public
64 // Description:
65 ////////////////////////////////////////////////////////////////////
66 void PtsToBam::
67 run() {
68  pifstream pts;
69  _pts_filename.set_text();
70  if (!_pts_filename.open_read(pts)) {
71  nout << "Cannot open " << _pts_filename << "\n";
72  exit(1);
73  }
74 
75  _gnode = new GeomNode(_pts_filename.get_basename());
76 
77  _num_points_expected = 0;
78  _num_points_found = 0;
79  _num_points_added = 0;
80  _decimate_factor = 1.0 / max(1.0, _decimate_divisor);
81  _line_number = 0;
82  _point_number = 0;
83  _decimated_point_number = 0.0;
84  _num_vdatas = 0;
85  string line;
86  while (getline(pts, line)) {
87  process_line(line);
88  }
89  close_vertex_data();
90 
91  nout << "\nFound " << _num_points_found << " points of " << _num_points_expected << " expected.\n";
92  nout << "Generated " << _num_points_added << " points to bam file.\n";
93 
94  // This should be guaranteed because we pass false to the
95  // constructor, above.
96  nassertv(has_output_filename());
97 
98  Filename filename = get_output_filename();
99  filename.make_dir();
100  nout << "Writing " << filename << "\n";
101  BamFile bam_file;
102  if (!bam_file.open_write(filename)) {
103  nout << "Error in writing.\n";
104  exit(1);
105  }
106 
107  if (!bam_file.write_object(_gnode.p())) {
108  nout << "Error in writing.\n";
109  exit(1);
110  }
111 }
112 
113 ////////////////////////////////////////////////////////////////////
114 // Function: PtsToBam::handle_args
115 // Access: Protected, Virtual
116 // Description:
117 ////////////////////////////////////////////////////////////////////
118 bool PtsToBam::
119 handle_args(ProgramBase::Args &args) {
120  if (args.empty()) {
121  nout << "You must specify the pts file to read on the command line.\n";
122  return false;
123  }
124 
125  if (args.size() > 1) {
126  nout << "Specify only one pts on the command line.\n";
127  return false;
128  }
129 
130  _pts_filename = Filename::from_os_specific(args[0]);
131 
132  return true;
133 }
134 
135 ////////////////////////////////////////////////////////////////////
136 // Function: PtsToBam::process_line
137 // Access: Private
138 // Description: Reads a single line from the pts file.
139 ////////////////////////////////////////////////////////////////////
140 void PtsToBam::
141 process_line(const string &line) {
142  _line_number++;
143 
144  if (_line_number % 1000000 == 0) {
145  cerr << "." << flush;
146  }
147 
148  if (line.empty() || !isdigit(line[0])) {
149  return;
150  }
151 
152  if (_line_number == 1) {
153  // The first line might be just the number of points.
154  vector_string words;
155  tokenize(trim(line), words, " \t", true);
156  if (words.size() == 1) {
157  string tail;
158  _num_points_expected = string_to_int(words[0], tail);
159  nout << "Expecting " << _num_points_expected << " points, will generate "
160  << (int)(_num_points_expected * _decimate_factor) << "\n";
161  return;
162  }
163  }
164 
165  // Here we might have a point.
166  _num_points_found++;
167  _decimated_point_number += _decimate_factor;
168  int point_number = int(_decimated_point_number);
169  if (point_number > _point_number) {
170  _point_number = point_number;
171 
172  vector_string words;
173  tokenize(trim(line), words, " \t", true);
174  if (words.size() >= 3) {
175  add_point(words);
176  }
177  }
178 }
179 
180 ////////////////////////////////////////////////////////////////////
181 // Function: PtsToBam::add_point
182 // Access: Private
183 // Description: Adds a point from the pts file.
184 ////////////////////////////////////////////////////////////////////
185 void PtsToBam::
186 add_point(const vector_string &words) {
187  if (_data == NULL || _data->get_num_rows() >= egg_max_vertices) {
188  open_vertex_data();
189  }
190 
191  string tail;
192  double x, y, z;
193  x = string_to_double(words[0], tail);
194  y = string_to_double(words[1], tail);
195  z = string_to_double(words[2], tail);
196  _vertex.add_data3d(x, y, z);
197  _num_points_added++;
198 }
199 
200 ////////////////////////////////////////////////////////////////////
201 // Function: PtsToBam::open_vertex_data
202 // Access: Private
203 // Description: Creates a new GeomVertexData.
204 ////////////////////////////////////////////////////////////////////
205 void PtsToBam::
206 open_vertex_data() {
207  if (_data != (GeomVertexData *)NULL) {
208  close_vertex_data();
209  }
210  CPT(GeomVertexFormat) format = GeomVertexFormat::get_v3();
211  _data = new GeomVertexData("pts", format, GeomEnums::UH_static);
212  _vertex = GeomVertexWriter(_data, "vertex");
213 }
214 
215 ////////////////////////////////////////////////////////////////////
216 // Function: PtsToBam::close_vertex_data
217 // Access: Private
218 // Description: Closes a previous GeomVertexData and adds it to the
219 // scene graph.
220 ////////////////////////////////////////////////////////////////////
221 void PtsToBam::
222 close_vertex_data() {
223  if (_data == NULL) {
224  return;
225  }
226 
227  _num_vdatas++;
228  nout << "\nGenerating " << _num_points_added << " points in " << _num_vdatas << " GeomVertexDatas\n";
229 
230  PT(Geom) geom = new Geom(_data);
231 
232  int num_vertices = _data->get_num_rows();
233  int vertices_so_far = 0;
234  while (num_vertices > 0) {
235  int this_num_vertices = min(num_vertices, (int)egg_max_indices);
236  PT(GeomPrimitive) points = new GeomPoints(GeomEnums::UH_static);
237  points->add_consecutive_vertices(vertices_so_far, this_num_vertices);
238  geom->add_primitive(points);
239  vertices_so_far += this_num_vertices;
240  num_vertices -= this_num_vertices;
241  }
242 
243  _gnode->add_geom(geom);
244 
245  _data = NULL;
246 }
247 
248 int main(int argc, char *argv[]) {
249  // A call to pystub() to force libpystub.so to be linked in.
250  pystub();
251 
252  PtsToBam prog;
253  prog.parse_command_line(argc, argv);
254  prog.run();
255  return 0;
256 }
The principle public interface to reading and writing Bam disk files.
Definition: bamFile.h:45
bool write_object(const TypedWritable *object)
Writes the indicated object to the Bam file.
Definition: bamFile.cxx:258
bool make_dir() const
Creates all the directories in the path to the file specified in the filename, except for the basenam...
Definition: filename.cxx:2730
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
Defines a series of disconnected points.
Definition: geomPoints.h:25
virtual void parse_command_line(int argc, char **argv)
Dispatches on each of the options on the command line, and passes the remaining parameters to handle_...
This class exists just to provide scoping for the various enumerated types used by Geom...
Definition: geomEnums.h:27
void set_text()
Indicates that the filename represents a text file.
Definition: filename.I:507
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
Definition: geomPrimitive.h:63
bool open_read(ifstream &stream) const
Opens the indicated ifstream for reading the file, if possible.
Definition: filename.cxx:2003
Filename get_output_filename() const
If has_output_filename() returns true, this is the filename that the user specified.
bool has_output_filename() const
Returns true if the user specified an output filename, false otherwise (e.g.
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
A container for geometry primitives.
Definition: geom.h:58
void add_data3d(double x, double y, double z)
Sets the write row to a particular 3-component value, and advances the write row. ...
This is the bare functionality (intended to be inherited from along with ProgramBase or some derivati...
string get_basename() const
Returns the basename part of the filename.
Definition: filename.I:436
bool open_write(const Filename &bam_filename, bool report_errors=true)
Attempts to open the indicated file for writing.
Definition: bamFile.cxx:217
A node that holds Geom objects, renderable pieces of geometry.
Definition: geomNode.h:37
static Filename from_os_specific(const string &os_specific, Type type=T_general)
This named constructor returns a Panda-style filename (that is, using forward slashes, and no drive letter) based on the supplied filename string that describes a filename in the local system conventions (for instance, on Windows, it may use backslashes or begin with a drive letter and a colon).
Definition: filename.cxx:332