00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include "geometric_shapes/mesh_operations.h"
00038 #include "geometric_shapes/shape_operations.h"
00039
00040 #include <cstdio>
00041 #include <cmath>
00042 #include <algorithm>
00043 #include <set>
00044 #include <float.h>
00045
00046 #include <console_bridge/console.h>
00047 #include <resource_retriever/retriever.h>
00048
00049 #include <assimp/scene.h>
00050 #include <assimp/Importer.hpp>
00051 #include <assimp/postprocess.h>
00052
00053 #include <Eigen/Geometry>
00054
00055 #include <boost/math/constants/constants.hpp>
00056
00057 namespace shapes
00058 {
00059
00060 namespace detail
00061 {
00062
00063 namespace
00064 {
00065
00067 struct LocalVertexType
00068 {
00069 LocalVertexType() : x(0.0), y(0.0), z(0.0)
00070 {
00071 }
00072
00073 LocalVertexType(const Eigen::Vector3d &v) : x(v.x()), y(v.y()), z(v.z())
00074 {
00075 }
00076
00077 double x,y,z;
00078 unsigned int index;
00079 };
00080
00082 struct ltLocalVertexValue
00083 {
00084 bool operator()(const LocalVertexType &p1, const LocalVertexType &p2) const
00085 {
00086 if (p1.x < p2.x)
00087 return true;
00088 if (p1.x > p2.x)
00089 return false;
00090 if (p1.y < p2.y)
00091 return true;
00092 if (p1.y > p2.y)
00093 return false;
00094 if (p1.z < p2.z)
00095 return true;
00096 return false;
00097 }
00098 };
00099
00101 struct ltLocalVertexIndex
00102 {
00103 bool operator()(const LocalVertexType &p1, const LocalVertexType &p2) const
00104 {
00105 return p1.index < p2.index;
00106 }
00107 };
00108
00109 }
00110 }
00111
00112 Mesh* createMeshFromVertices(const EigenSTL::vector_Vector3d &vertices, const std::vector<unsigned int> &triangles)
00113 {
00114 unsigned int nt = triangles.size() / 3;
00115 Mesh *mesh = new Mesh(vertices.size(), nt);
00116 for (unsigned int i = 0 ; i < vertices.size() ; ++i)
00117 {
00118 mesh->vertices[3 * i ] = vertices[i].x();
00119 mesh->vertices[3 * i + 1] = vertices[i].y();
00120 mesh->vertices[3 * i + 2] = vertices[i].z();
00121 }
00122
00123 std::copy(triangles.begin(), triangles.end(), mesh->triangles);
00124 mesh->computeTriangleNormals();
00125 mesh->computeVertexNormals();
00126
00127 return mesh;
00128 }
00129
00130 Mesh* createMeshFromVertices(const EigenSTL::vector_Vector3d &source)
00131 {
00132 if (source.size() < 3)
00133 return NULL;
00134
00135 if (source.size() % 3 != 0)
00136 logError("The number of vertices to construct a mesh from is not divisible by 3. Probably constructed triangles will not make sense.");
00137
00138 std::set<detail::LocalVertexType, detail::ltLocalVertexValue> vertices;
00139 std::vector<unsigned int> triangles;
00140
00141 unsigned int n = source.size() / 3;
00142 for (unsigned int i = 0 ; i < n ; ++i)
00143 {
00144
00145 unsigned int i3 = i * 3;
00146 detail::LocalVertexType vt1(source[i3]);
00147 std::set<detail::LocalVertexType, detail::ltLocalVertexValue>::iterator p1 = vertices.find(vt1);
00148 if (p1 == vertices.end())
00149 {
00150 vt1.index = vertices.size();
00151 vertices.insert(vt1);
00152 }
00153 else
00154 vt1.index = p1->index;
00155 triangles.push_back(vt1.index);
00156
00157 detail::LocalVertexType vt2(source[++i3]);
00158 std::set<detail::LocalVertexType, detail::ltLocalVertexValue>::iterator p2 = vertices.find(vt2);
00159 if (p2 == vertices.end())
00160 {
00161 vt2.index = vertices.size();
00162 vertices.insert(vt2);
00163 }
00164 else
00165 vt2.index = p2->index;
00166 triangles.push_back(vt2.index);
00167
00168 detail::LocalVertexType vt3(source[++i3]);
00169 std::set<detail::LocalVertexType, detail::ltLocalVertexValue>::iterator p3 = vertices.find(vt3);
00170 if (p3 == vertices.end())
00171 {
00172 vt3.index = vertices.size();
00173 vertices.insert(vt3);
00174 }
00175 else
00176 vt3.index = p3->index;
00177
00178 triangles.push_back(vt3.index);
00179 }
00180
00181
00182 std::vector<detail::LocalVertexType> vt;
00183 vt.insert(vt.end(), vertices.begin(), vertices.end());
00184 std::sort(vt.begin(), vt.end(), detail::ltLocalVertexIndex());
00185
00186
00187 unsigned int nt = triangles.size() / 3;
00188
00189 Mesh *mesh = new Mesh(vt.size(), nt);
00190 for (unsigned int i = 0 ; i < vt.size() ; ++i)
00191 {
00192 unsigned int i3 = i * 3;
00193 mesh->vertices[i3 ] = vt[i].x;
00194 mesh->vertices[i3 + 1] = vt[i].y;
00195 mesh->vertices[i3 + 2] = vt[i].z;
00196 }
00197
00198 std::copy(triangles.begin(), triangles.end(), mesh->triangles);
00199 mesh->computeTriangleNormals();
00200 mesh->computeVertexNormals();
00201
00202 return mesh;
00203 }
00204
00205 Mesh* createMeshFromResource(const std::string& resource)
00206 {
00207 static const Eigen::Vector3d one(1.0, 1.0, 1.0);
00208 return createMeshFromResource(resource, one);
00209 }
00210
00211 Mesh* createMeshFromBinary(const char* buffer, std::size_t size,
00212 const std::string &assimp_hint)
00213 {
00214 static const Eigen::Vector3d one(1.0, 1.0, 1.0);
00215 return createMeshFromBinary(buffer, size, one, assimp_hint);
00216 }
00217
00218 Mesh* createMeshFromBinary(const char *buffer, std::size_t size, const Eigen::Vector3d &scale,
00219 const std::string &assimp_hint)
00220 {
00221 if (!buffer || size < 1)
00222 {
00223 logWarn("Cannot construct mesh from empty binary buffer");
00224 return NULL;
00225 }
00226
00227
00228 std::string hint;
00229 std::size_t pos = assimp_hint.find_last_of(".");
00230 if (pos != std::string::npos)
00231 {
00232 hint = assimp_hint.substr(pos + 1);
00233 std::transform(hint.begin(), hint.end(), hint.begin(), ::tolower);
00234 }
00235 if (hint.empty())
00236 hint = assimp_hint;
00237
00238
00239 Assimp::Importer importer;
00240
00241
00242
00243 importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS,
00244 aiComponent_NORMALS |
00245 aiComponent_TANGENTS_AND_BITANGENTS |
00246 aiComponent_COLORS |
00247 aiComponent_TEXCOORDS |
00248 aiComponent_BONEWEIGHTS |
00249 aiComponent_ANIMATIONS |
00250 aiComponent_TEXTURES |
00251 aiComponent_LIGHTS |
00252 aiComponent_CAMERAS |
00253 aiComponent_MATERIALS);
00254
00255
00256 const aiScene* scene = importer.ReadFileFromMemory(reinterpret_cast<const void*>(buffer), size,
00257 aiProcess_Triangulate |
00258 aiProcess_JoinIdenticalVertices |
00259 aiProcess_SortByPType |
00260 aiProcess_RemoveComponent, hint.c_str());
00261 if (!scene)
00262 return NULL;
00263
00264
00265
00266
00267
00268
00269 scene->mRootNode->mTransformation = aiMatrix4x4();
00270
00271
00272
00273 importer.ApplyPostProcessing(aiProcess_OptimizeMeshes | aiProcess_OptimizeGraph);
00274
00275 return createMeshFromAsset(scene, scale, hint);
00276 }
00277
00278 Mesh* createMeshFromResource(const std::string& resource, const Eigen::Vector3d &scale)
00279 {
00280 resource_retriever::Retriever retriever;
00281 resource_retriever::MemoryResource res;
00282 try
00283 {
00284 res = retriever.get(resource);
00285 }
00286 catch (resource_retriever::Exception& e)
00287 {
00288 logError("%s", e.what());
00289 return NULL;
00290 }
00291
00292 if (res.size == 0)
00293 {
00294 logWarn("Retrieved empty mesh for resource '%s'", resource.c_str());
00295 return NULL;
00296 }
00297
00298 Mesh *m = createMeshFromBinary(reinterpret_cast<const char*>(res.data.get()), res.size, scale, resource);
00299 if (!m)
00300 {
00301 logWarn("Assimp reports no scene in %s.", resource.c_str());
00302 logWarn("This could be because of a resource filename that is too long for the Assimp library, a known bug. As a workaround shorten the filename/path.");
00303 }
00304 return m;
00305 }
00306
00307 namespace
00308 {
00309 void extractMeshData(const aiScene *scene, const aiNode *node, const aiMatrix4x4 &parent_transform, const Eigen::Vector3d &scale,
00310 EigenSTL::vector_Vector3d &vertices, std::vector<unsigned int> &triangles)
00311 {
00312 aiMatrix4x4 transform = parent_transform;
00313 transform *= node->mTransformation;
00314 for (unsigned int j = 0 ; j < node->mNumMeshes; ++j)
00315 {
00316 const aiMesh* a = scene->mMeshes[node->mMeshes[j]];
00317 unsigned int offset = vertices.size();
00318 for (unsigned int i = 0 ; i < a->mNumVertices ; ++i)
00319 {
00320 aiVector3D v = transform * a->mVertices[i];
00321 vertices.push_back(Eigen::Vector3d(v.x * scale.x(), v.y * scale.y(), v.z * scale.z()));
00322 }
00323 for (unsigned int i = 0 ; i < a->mNumFaces ; ++i)
00324 if (a->mFaces[i].mNumIndices == 3)
00325 {
00326 triangles.push_back(offset + a->mFaces[i].mIndices[0]);
00327 triangles.push_back(offset + a->mFaces[i].mIndices[1]);
00328 triangles.push_back(offset + a->mFaces[i].mIndices[2]);
00329 }
00330 }
00331
00332 for (unsigned int n = 0; n < node->mNumChildren; ++n)
00333 extractMeshData(scene, node->mChildren[n], transform, scale, vertices, triangles);
00334 }
00335 }
00336
00337 Mesh* createMeshFromAsset(const aiScene* scene, const std::string &resource_name)
00338 {
00339 static const Eigen::Vector3d one(1.0, 1.0, 1.0);
00340 return createMeshFromAsset(scene, one, resource_name);
00341 }
00342
00343 Mesh* createMeshFromAsset(const aiScene* scene, const Eigen::Vector3d &scale, const std::string &resource_name)
00344 {
00345 if (!scene->HasMeshes())
00346 {
00347 logWarn("Assimp reports scene in %s has no meshes", resource_name.c_str());
00348 return NULL;
00349 }
00350 EigenSTL::vector_Vector3d vertices;
00351 std::vector<unsigned int> triangles;
00352 extractMeshData(scene, scene->mRootNode, aiMatrix4x4(), scale, vertices, triangles);
00353 if (vertices.empty())
00354 {
00355 logWarn("There are no vertices in the scene %s", resource_name.c_str());
00356 return NULL;
00357 }
00358 if (triangles.empty())
00359 {
00360 logWarn("There are no triangles in the scene %s", resource_name.c_str());
00361 return NULL;
00362 }
00363
00364 return createMeshFromVertices(vertices, triangles);
00365 }
00366
00367 Mesh* createMeshFromShape(const Shape *shape)
00368 {
00369 if (shape->type == shapes::SPHERE)
00370 return shapes::createMeshFromShape(static_cast<const shapes::Sphere&>(*shape));
00371 else
00372 if (shape->type == shapes::BOX)
00373 return shapes::createMeshFromShape(static_cast<const shapes::Box&>(*shape));
00374 else
00375 if (shape->type == shapes::CYLINDER)
00376 return shapes::createMeshFromShape(static_cast<const shapes::Cylinder&>(*shape));
00377 else
00378 if (shape->type == shapes::CONE)
00379 return shapes::createMeshFromShape(static_cast<const shapes::Cone&>(*shape));
00380 else
00381 logError("Conversion of shape of type '%s' to a mesh is not known", shapeStringName(shape).c_str());
00382 return NULL;
00383 }
00384
00385 Mesh* createMeshFromShape(const Box &box)
00386 {
00387 double x = box.size[0] / 2.0;
00388 double y = box.size[1] / 2.0;
00389 double z = box.size[2] / 2.0;
00390
00391
00392 Mesh *result = new Mesh(8, 12);
00393 result->vertices[0] = -x;
00394 result->vertices[1] = -y;
00395 result->vertices[2] = -z;
00396
00397 result->vertices[3] = x;
00398 result->vertices[4] = -y;
00399 result->vertices[5] = -z;
00400
00401 result->vertices[6] = x;
00402 result->vertices[7] = -y;
00403 result->vertices[8] = z;
00404
00405 result->vertices[9] = -x;
00406 result->vertices[10] = -y;
00407 result->vertices[11] = z;
00408
00409 result->vertices[12] = -x;
00410 result->vertices[13] = y;
00411 result->vertices[14] = z;
00412
00413 result->vertices[15] = -x;
00414 result->vertices[16] = y;
00415 result->vertices[17] = -z;
00416
00417 result->vertices[18] = x;
00418 result->vertices[19] = y;
00419 result->vertices[20] = z;
00420
00421 result->vertices[21] = x;
00422 result->vertices[22] = y;
00423 result->vertices[23] = -z;
00424
00425 static const unsigned int tri[] = {0, 1, 2,
00426 2, 3, 0,
00427 4, 3, 2,
00428 2, 6, 4,
00429 7, 6, 2,
00430 2, 1, 7,
00431 3, 4, 5,
00432 5, 0, 3,
00433 0, 5, 7,
00434 7, 1, 0,
00435 7, 5, 4,
00436 4, 6, 7};
00437 memcpy(result->triangles, tri, sizeof(unsigned int) * 36);
00438 result->computeTriangleNormals();
00439 result->computeVertexNormals();
00440 return result;
00441 }
00442
00443 Mesh* createMeshFromShape(const Sphere &sphere)
00444 {
00445
00446 EigenSTL::vector_Vector3d vertices;
00447 std::vector<unsigned int> triangles;
00448
00449 const double r = sphere.radius;
00450 const double pi = boost::math::constants::pi<double>();
00451 const unsigned int seg = std::max<unsigned int>(6, 0.5 + 2.0 * pi * r / 0.01);
00452 const unsigned int ring = std::max<unsigned int>(6, 2.0 * r / 0.01);
00453
00454 double phi, phid;
00455 phid = pi * 2.0 / seg;
00456 phi = 0.0;
00457
00458 double theta, thetad;
00459 thetad = pi / (ring + 1);
00460 theta = 0;
00461
00462 for (unsigned int i = 0; i < ring; ++i)
00463 {
00464 double theta_ = theta + thetad * (i + 1);
00465 for (unsigned int j = 0; j < seg; ++j)
00466 vertices.push_back(Eigen::Vector3d(r * sin(theta_) * cos(phi + j * phid),
00467 r * sin(theta_) * sin(phi + j * phid),
00468 r * cos(theta_)));
00469 }
00470 vertices.push_back(Eigen::Vector3d(0.0, 0.0, r));
00471 vertices.push_back(Eigen::Vector3d(0.0, 0.0, -r));
00472
00473 for (unsigned int i = 0 ; i < ring - 1; ++i)
00474 {
00475 for (unsigned int j = 0 ; j < seg ; ++j)
00476 {
00477 unsigned int a, b, c, d;
00478 a = i * seg + j;
00479 b = (j == seg - 1) ? (i * seg) : (i * seg + j + 1);
00480 c = (i + 1) * seg + j;
00481 d = (j == seg - 1) ? ((i + 1) * seg) : ((i + 1) * seg + j + 1);
00482 triangles.push_back(a);
00483 triangles.push_back(c);
00484 triangles.push_back(b);
00485 triangles.push_back(b);
00486 triangles.push_back(c);
00487 triangles.push_back(d);
00488 }
00489 }
00490
00491 for (unsigned int j = 0 ; j < seg ; ++j)
00492 {
00493 unsigned int a, b;
00494 a = j;
00495 b = (j == seg - 1) ? 0 : (j + 1);
00496 triangles.push_back(ring * seg);
00497 triangles.push_back(a);
00498 triangles.push_back(b);
00499
00500 a = (ring - 1) * seg + j;
00501 b = (j == seg - 1) ? (ring - 1) * seg : ((ring - 1) * seg + j + 1);
00502 triangles.push_back(a);
00503 triangles.push_back(ring * seg + 1);
00504 triangles.push_back(b);
00505 }
00506 return createMeshFromVertices(vertices, triangles);
00507 }
00508
00509 Mesh* createMeshFromShape(const Cylinder &cylinder)
00510 {
00511
00512 EigenSTL::vector_Vector3d vertices;
00513 std::vector<unsigned int> triangles;
00514
00515
00516 static unsigned int tot_for_unit_cylinder = 100;
00517
00518 double r = cylinder.radius;
00519 double h = cylinder.length;
00520
00521 const double pi = boost::math::constants::pi<double>();
00522 unsigned int tot = ceil(tot_for_unit_cylinder * r);
00523 double phid = pi * 2 / tot;
00524
00525 double circle_edge = phid * r;
00526 unsigned int h_num = ceil(h / circle_edge);
00527
00528 double phi = 0;
00529 double hd = h / h_num;
00530
00531 for (unsigned int i = 0 ; i < tot ; ++i)
00532 vertices.push_back(Eigen::Vector3d(r * cos(phi + phid * i), r * sin(phi + phid * i), h / 2));
00533
00534 for (unsigned int i = 0; i < h_num - 1 ; ++i)
00535 for(unsigned int j = 0; j < tot; ++j)
00536 vertices.push_back(Eigen::Vector3d(r * cos(phi + phid * j), r * sin(phi + phid * j), h / 2 - (i + 1) * hd));
00537
00538 for (unsigned int i = 0; i < tot; ++i)
00539 vertices.push_back(Eigen::Vector3d(r * cos(phi + phid * i), r * sin(phi + phid * i), - h / 2));
00540
00541 vertices.push_back(Eigen::Vector3d(0, 0, h / 2));
00542 vertices.push_back(Eigen::Vector3d(0, 0, -h / 2));
00543
00544 for (unsigned int i = 0; i < tot ; ++i)
00545 {
00546 triangles.push_back((h_num + 1) * tot);
00547 triangles.push_back(i);
00548 triangles.push_back((i == tot - 1) ? 0 : (i + 1));
00549 }
00550
00551 for (unsigned int i = 0; i < tot; ++i)
00552 {
00553 triangles.push_back((h_num + 1) * tot + 1);
00554 triangles.push_back(h_num * tot + ((i == tot - 1) ? 0 : (i + 1)));
00555 triangles.push_back(h_num * tot + i);
00556 }
00557
00558 for (unsigned int i = 0; i < h_num; ++i)
00559 {
00560 for (unsigned int j = 0; j < tot; ++j)
00561 {
00562 int a, b, c, d;
00563 a = j;
00564 b = (j == tot - 1) ? 0 : (j + 1);
00565 c = j + tot;
00566 d = (j == tot - 1) ? tot : (j + 1 + tot);
00567
00568 int start = i * tot;
00569 triangles.push_back(start + b);
00570 triangles.push_back(start + a);
00571 triangles.push_back(start + c);
00572 triangles.push_back(start + b);
00573 triangles.push_back(start + c);
00574 triangles.push_back(start + d);
00575 }
00576 }
00577 return createMeshFromVertices(vertices, triangles);
00578 }
00579
00580 Mesh* createMeshFromShape(const Cone &cone)
00581 {
00582
00583 EigenSTL::vector_Vector3d vertices;
00584 std::vector<unsigned int> triangles;
00585
00586
00587 static unsigned int tot_for_unit_cone = 100;
00588
00589 double r = cone.radius;
00590 double h = cone.length;
00591
00592 const double pi = boost::math::constants::pi<double>();
00593 unsigned int tot = tot_for_unit_cone * r;
00594 double phid = pi * 2 / tot;
00595
00596 double circle_edge = phid * r;
00597 unsigned int h_num = ceil(h / circle_edge);
00598
00599 double phi = 0;
00600 double hd = h / h_num;
00601
00602 for (unsigned int i = 0; i < h_num - 1; ++i)
00603 {
00604 double h_i = h / 2 - (i + 1) * hd;
00605 double rh = r * (0.5 - h_i / h);
00606 for(unsigned int j = 0; j < tot; ++j)
00607 vertices.push_back(Eigen::Vector3d(rh * cos(phi + phid * j), rh * sin(phi + phid * j), h_i));
00608 }
00609
00610 for (unsigned int i = 0; i < tot; ++i)
00611 vertices.push_back(Eigen::Vector3d(r * cos(phi + phid * i), r * sin(phi + phid * i), - h / 2));
00612
00613 vertices.push_back(Eigen::Vector3d(0, 0, h / 2));
00614 vertices.push_back(Eigen::Vector3d(0, 0, -h / 2));
00615
00616 for (unsigned int i = 0; i < tot; ++i)
00617 {
00618 triangles.push_back(h_num * tot);
00619 triangles.push_back(i);
00620 triangles.push_back((i == tot - 1) ? 0 : (i + 1));
00621 }
00622
00623 for (unsigned int i = 0; i < tot; ++i)
00624 {
00625 triangles.push_back(h_num * tot + 1);
00626 triangles.push_back((h_num - 1) * tot + ((i == tot - 1) ? 0 : (i + 1)));
00627 triangles.push_back((h_num - 1) * tot + i);
00628 }
00629
00630 for (unsigned int i = 0; i < h_num - 1; ++i)
00631 for (unsigned int j = 0; j < tot; ++j)
00632 {
00633 int a, b, c, d;
00634 a = j;
00635 b = (j == tot - 1) ? 0 : (j + 1);
00636 c = j + tot;
00637 d = (j == tot - 1) ? tot : (j + 1 + tot);
00638
00639 int start = i * tot;
00640 triangles.push_back(start + b);
00641 triangles.push_back(start + a);
00642 triangles.push_back(start + c);
00643 triangles.push_back(start + b);
00644 triangles.push_back(start + c);
00645 triangles.push_back(start + d);
00646 }
00647 return createMeshFromVertices(vertices, triangles);
00648 }
00649
00650 namespace
00651 {
00652 inline void writeFloatToSTL(char *&ptr , float data)
00653 {
00654 memcpy(ptr, &data, sizeof(float));
00655 ptr += sizeof(float);
00656 }
00657 inline void writeFloatToSTL(char *&ptr , double datad)
00658 {
00659 float data = datad;
00660 memcpy(ptr, &data, sizeof(float));
00661 ptr += sizeof(float);
00662 }
00663 }
00664
00665 void writeSTLBinary(const Mesh* mesh, std::vector<char> &buffer)
00666 {
00667 buffer.resize(84 + mesh->triangle_count * 50);
00668 memset(&buffer[0], 0, 80);
00669 char *ptr = &buffer[80];
00670 uint32_t nt = mesh->triangle_count;
00671 memcpy(ptr, &nt, sizeof(uint32_t));
00672 ptr += sizeof(uint32_t);
00673 for (unsigned int i = 0 ; i < mesh->triangle_count ; ++i)
00674 {
00675 unsigned int i3 = i * 3;
00676
00677 if (mesh->triangle_normals)
00678 {
00679 writeFloatToSTL(ptr, mesh->triangle_normals[i3]);
00680 writeFloatToSTL(ptr, mesh->triangle_normals[i3 + 1]);
00681 writeFloatToSTL(ptr, mesh->triangle_normals[i3 + 2]);
00682 }
00683 else
00684 {
00685 memset(ptr, 0, sizeof(float) * 3);
00686 ptr += sizeof(float) * 3;
00687 }
00688
00689 unsigned int index = mesh->triangles[i3] * 3;
00690 writeFloatToSTL(ptr, mesh->vertices[index]);
00691 writeFloatToSTL(ptr, mesh->vertices[index + 1]);
00692 writeFloatToSTL(ptr, mesh->vertices[index + 2]);
00693 index = mesh->triangles[i3 + 1] * 3;
00694 writeFloatToSTL(ptr, mesh->vertices[index]);
00695 writeFloatToSTL(ptr, mesh->vertices[index + 1]);
00696 writeFloatToSTL(ptr, mesh->vertices[index + 2]);
00697 index = mesh->triangles[i3 + 2] * 3;
00698 writeFloatToSTL(ptr, mesh->vertices[index]);
00699 writeFloatToSTL(ptr, mesh->vertices[index + 1]);
00700 writeFloatToSTL(ptr, mesh->vertices[index + 2]);
00701 memset(ptr, 0, 2);
00702 ptr += 2;
00703 }
00704 }
00705
00706 }