stl_loader.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008, Willow Garage, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Willow Garage, Inc. nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include "stl_loader.h"
31 #include <ros/console.h>
32 
33 #include <OgreManualObject.h>
34 
35 namespace ogre_tools
36 {
38 {
39 }
40 
42 {
43 }
44 
45 bool STLLoader::load(const std::string& path)
46 {
47  FILE* input = fopen(path.c_str(), "r");
48  if (!input)
49  {
50  ROS_ERROR("Could not open '%s' for read", path.c_str());
51  return false;
52  }
53 
54  /* from wikipedia:
55  * Because ASCII STL files can become very large, a binary version of STL exists. A binary STL file has
56  * an 80 character header
57  * (which is generally ignored - but which should never begin with 'solid' because that will lead most
58  * software to assume that
59  * this is an ASCII STL file). Following the header is a 4 byte unsigned integer indicating the number
60  * of triangular facets in
61  * the file. Following that is data describing each triangle in turn. The file simply ends after the
62  * last triangle.
63  *
64  * Each triangle is described by twelve 32-bit-floating point numbers: three for the normal and then
65  * three for the X/Y/Z coordinate
66  * of each vertex - just as with the ASCII version of STL. After the twelve floats there is a two byte
67  * unsigned 'short' integer that
68  * is the 'attribute byte count' - in the standard format, this should be zero because most software
69  * does not understand anything else.
70  *
71  * Floating point numbers are represented as IEEE floating point numbers and the endianness is assumed
72  * to be little endian although this
73  * is not stated in documentation.
74  */
75 
76  // find the file size
77  fseek(input, 0, SEEK_END);
78  long fileSize = ftell(input);
79  rewind(input);
80 
81  std::vector<uint8_t> buffer_vec(fileSize);
82  uint8_t* buffer = &buffer_vec[0];
83 
84  long num_bytes_read = fread(buffer, 1, fileSize, input);
85  if (num_bytes_read != fileSize)
86  {
87  ROS_ERROR("STLLoader::load( \"%s\" ) only read %ld bytes out of total %ld.", path.c_str(),
88  num_bytes_read, fileSize);
89  fclose(input);
90  return false;
91  }
92  fclose(input);
93 
94  return this->load(buffer, num_bytes_read, path);
95 }
96 
97 bool STLLoader::load(uint8_t* buffer, const size_t num_bytes, const std::string& origin)
98 {
99  // check for ascii since we can only load binary types with this class
100  std::string buffer_str = std::string(reinterpret_cast<char*>(buffer), num_bytes);
101 
102  if (buffer_str.substr(0, 5) == std::string("solid"))
103  {
104  // file says that it is ascii, but why should we trust it?
105 
106  // check for "endsolid" as well
107  if (buffer_str.find("endsolid", 5) != std::string::npos)
108  {
109  ROS_ERROR_STREAM("The STL file '" << origin
110  << "' is malformed. It "
111  "starts with the word 'solid' and also contains the "
112  "word 'endsolid', indicating that it's an ASCII STL "
113  "file, but rviz can only load binary STL files so it "
114  "will not be loaded. Please convert it to a "
115  "binary STL file.");
116  return false;
117  }
118 
119  // chastise the user for malformed files
120  ROS_WARN_STREAM("The STL file '" << origin
121  << "' is malformed. It starts "
122  "with the word 'solid', indicating that it's an ASCII "
123  "STL file, but it does not contain the word 'endsolid' so "
124  "it is either a malformed ASCII STL file or it is actually "
125  "a binary STL file. Trying to interpret it as a binary "
126  "STL file instead.");
127  }
128 
129  // make sure there's enough data for a binary STL header and triangle count
130  static const size_t binary_stl_header_len = 84;
131  if (num_bytes <= binary_stl_header_len)
132  {
133  ROS_ERROR_STREAM("The STL file '" << origin
134  << "' is malformed. It "
135  "appears to be a binary STL file but does not contain "
136  "enough data for the 80 byte header and 32-bit integer "
137  "triangle count.");
138  return false;
139  }
140 
141  // one last check to make sure that the size matches the number of triangles
142  unsigned int num_triangles = *(reinterpret_cast<uint32_t*>(buffer + 80));
143  static const size_t number_of_bytes_per_triangle = 50;
144  size_t expected_size = binary_stl_header_len + num_triangles * number_of_bytes_per_triangle;
145  if (num_bytes < expected_size)
146  {
147  ROS_ERROR_STREAM("The STL file '"
148  << origin << "' is malformed. According to the binary STL header it should have '"
149  << num_triangles
150  << "' triangles, but it has too little data for that to be the case.");
151  return false;
152  }
153  else if (num_bytes > expected_size)
154  {
155  ROS_WARN_STREAM("The STL file '"
156  << origin << "' is malformed. According to the binary STL header it should have '"
157  << num_triangles
158  << "' triangles, but it has too much data for that to be the case. "
159  "The extra data will be ignored.");
160  }
161 
162  // load the binary STL data
163  return this->load_binary(buffer);
164 }
165 
166 bool STLLoader::load_binary(uint8_t* buffer)
167 {
168  uint8_t* pos = buffer;
169 
170  pos += 80; // skip the 80 byte header
171 
172  unsigned int numTriangles = *(unsigned int*)pos;
173  pos += 4;
174 
175  for (unsigned int currentTriangle = 0; currentTriangle < numTriangles; ++currentTriangle)
176  {
177  Triangle tri;
178 
179  tri.normal_.x = *(float*)pos;
180  pos += 4;
181  tri.normal_.y = *(float*)pos;
182  pos += 4;
183  tri.normal_.z = *(float*)pos;
184  pos += 4;
185 
186  tri.vertices_[0].x = *(float*)pos;
187  pos += 4;
188  tri.vertices_[0].y = *(float*)pos;
189  pos += 4;
190  tri.vertices_[0].z = *(float*)pos;
191  pos += 4;
192 
193  tri.vertices_[1].x = *(float*)pos;
194  pos += 4;
195  tri.vertices_[1].y = *(float*)pos;
196  pos += 4;
197  tri.vertices_[1].z = *(float*)pos;
198  pos += 4;
199 
200  tri.vertices_[2].x = *(float*)pos;
201  pos += 4;
202  tri.vertices_[2].y = *(float*)pos;
203  pos += 4;
204  tri.vertices_[2].z = *(float*)pos;
205  pos += 4;
206 
207  // Blender was writing a large number into this short... am I misinterpreting what the attribute byte
208  // count is supposed to do?
209  // unsigned short attributeByteCount = *(unsigned short*)pos;
210  pos += 2;
211 
212  // pos += attributeByteCount;
213 
214  if (tri.normal_.squaredLength() < 0.001)
215  {
216  Ogre::Vector3 side1 = tri.vertices_[0] - tri.vertices_[1];
217  Ogre::Vector3 side2 = tri.vertices_[1] - tri.vertices_[2];
218  tri.normal_ = side1.crossProduct(side2);
219  }
220  tri.normal_.normalise();
221 
222  triangles_.push_back(tri);
223  }
224 
225  return true;
226 }
227 
228 void calculateUV(const Ogre::Vector3& vec, float& u, float& v)
229 {
230  Ogre::Vector3 pos(vec);
231  pos.normalise();
232  u = acos(pos.y / pos.length());
233 
234  float val = pos.x / (sin(u));
235  v = acos(val);
236 
237  u /= Ogre::Math::PI;
238  v /= Ogre::Math::PI;
239 }
240 
241 
242 Ogre::MeshPtr STLLoader::toMesh(const std::string& name)
243 {
244  Ogre::ManualObject* object = new Ogre::ManualObject("the one and only");
245  object->begin("BaseWhiteNoLighting", Ogre::RenderOperation::OT_TRIANGLE_LIST);
246 
247  unsigned int vertexCount = 0;
248  V_Triangle::const_iterator it = triangles_.begin();
249  V_Triangle::const_iterator end = triangles_.end();
250  for (; it != end; ++it)
251  {
252  if (vertexCount >= 2004)
253  {
254  // Subdivide large meshes into submeshes with at most 2004
255  // vertices to prevent problems on some graphics cards.
256  object->end();
257  object->begin("BaseWhiteNoLighting", Ogre::RenderOperation::OT_TRIANGLE_LIST);
258  vertexCount = 0;
259  }
260 
261  const STLLoader::Triangle& tri = *it;
262 
263  float u, v;
264  u = v = 0.0f;
265  object->position(tri.vertices_[0]);
266  object->normal(tri.normal_);
267  calculateUV(tri.vertices_[0], u, v);
268  object->textureCoord(u, v);
269 
270  object->position(tri.vertices_[1]);
271  object->normal(tri.normal_);
272  calculateUV(tri.vertices_[1], u, v);
273  object->textureCoord(u, v);
274 
275  object->position(tri.vertices_[2]);
276  object->normal(tri.normal_);
277  calculateUV(tri.vertices_[2], u, v);
278  object->textureCoord(u, v);
279 
280  object->triangle(vertexCount + 0, vertexCount + 1, vertexCount + 2);
281 
282  vertexCount += 3;
283  }
284 
285  object->end();
286 
287  Ogre::MeshPtr mesh =
288  object->convertToMesh(name, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
289  mesh->buildEdgeList();
290 
291  delete object;
292 
293  return mesh;
294 }
295 
296 } // namespace ogre_tools
V_Triangle triangles_
Definition: stl_loader.h:61
bool load_binary(uint8_t *buffer)
Load a binary STL file.
Definition: stl_loader.cpp:166
void calculateUV(const Ogre::Vector3 &vec, float &u, float &v)
Definition: stl_loader.cpp:228
bool load(const std::string &path)
Definition: stl_loader.cpp:45
Ogre::Vector3 vertices_[3]
Definition: stl_loader.h:56
#define ROS_WARN_STREAM(args)
INLINE Rall1d< T, V, S > acos(const Rall1d< T, V, S > &x)
Ogre::MeshPtr toMesh(const std::string &name)
Definition: stl_loader.cpp:242
#define ROS_ERROR_STREAM(args)
#define ROS_ERROR(...)
INLINE Rall1d< T, V, S > sin(const Rall1d< T, V, S > &arg)


rviz
Author(s): Dave Hershberger, David Gossow, Josh Faust
autogenerated on Sat May 27 2023 02:06:25