1 #ifndef SimTK_SimTKCOMMON_POLYGONAL_MESH_H_ 2 #define SimTK_SimTKCOMMON_POLYGONAL_MESH_H_ 3 4 /* -------------------------------------------------------------------------- * 5 * Simbody(tm): SimTKcommon * 6 * -------------------------------------------------------------------------- * 7 * This is part of the SimTK biosimulation toolkit originating from * 8 * Simbios, the NIH National Center for Physics-Based Simulation of * 9 * Biological Structures at Stanford, funded under the NIH Roadmap for * 10 * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody. * 11 * * 12 * Portions Copyright (c) 2005-2017 Stanford University and the Authors. * 13 * Authors: Peter Eastman * 14 * Contributors: Michael Sherman * 15 * * 16 * Licensed under the Apache License, Version 2.0 (the "License"); you may * 17 * not use this file except in compliance with the License. You may obtain a * 18 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0. * 19 * * 20 * Unless required by applicable law or agreed to in writing, software * 21 * distributed under the License is distributed on an "AS IS" BASIS, * 22 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 23 * See the License for the specific language governing permissions and * 24 * limitations under the License. * 25 * -------------------------------------------------------------------------- */ 26 27 #include "SimTKcommon/Simmatrix.h" 28 #include "SimTKcommon/internal/PrivateImplementation.h" 29 30 namespace SimTK { 31 32 class PolygonalMesh; 33 class PolygonalMeshImpl; 34 35 // We only want the template instantiation to occur once. This symbol is defined 36 // in the SimTKcommon compilation unit that defines the PolygonalMesh class but 37 // should not be defined any other time. 38 #ifndef SWIG 39 #ifndef SimTK_SIMTKCOMMON_DEFINING_POLYGONALMESH 40 extern template class PIMPLHandle<PolygonalMesh, PolygonalMeshImpl, true>; 41 #endif 42 #endif 43 44 /** This class provides a description of a mesh made of polygonal faces (not 45 limited to triangles). Its primary purpose is for loading geometry from files, 46 which can then be used for visualization or collision detection. For example, 47 the following lines load a mesh from a Wavefront OBJ file, then create a 48 DecorativeMesh from it. 49 @code 50 PolygonalMesh mesh; 51 mesh.loadObjFile("teapot.obj"); 52 DecorativeMesh decoration(mesh); 53 @endcode 54 You can also read a polygon mesh from a VTK PolyData (.vtp) file, or an STL 55 file (.stl) that is in ascii or binary format. You can also build meshes 56 programmatically, and some static methods are provided here for generating some 57 common shapes. If you don't know what kind of file you have, you can attempt to 58 read it with the loadFile() method which will examine the file extension to 59 determine the expected format. 60 61 The mesh has its own local frame and vertex locations are given in that 62 frame. You can scale and transform the vertices relative to that frame 63 (changing the values stored in the mesh) but more commonly the mesh will be 64 placed on a body relative to that body's frame, meaning you can re-use the 65 same mesh in various places. 66 67 We expect this to be a large object so give it shared (reference) semantics; 68 that is, the copy constructor and copy assignment default to shallow copies 69 (both handles will refer to the same data). If you want to make a deep 70 (non-shared) copy of a PolygonalMesh, use the copyAssign() method provided by 71 the PIMPLHandle base class. **/ 72 class SimTK_SimTKCOMMON_EXPORT PolygonalMesh 73 : public PIMPLHandle<PolygonalMesh, PolygonalMeshImpl, true> { 74 public: 75 /** Create an empty %PolygonalMesh, with no vertices or faces. **/ PolygonalMesh()76 PolygonalMesh() {} 77 78 /** Create a sphere-shaped mesh, with roughly uniform mesh elements. 79 80 @param[in] radius 81 The radius of the underlying sphere. Vertices of the mesh will be on 82 the sphere, with mesh elements somewhat inside. 83 @param[in] resolution 84 Control for how dense a mesh to produce. Resolution 0 will produce an 85 octahedron (8 triangular faces). Resolution 1 (the default) gives 86 32 faces, resolution 2 gives 128. In general for resolution n there 87 will be 2*4^(n+1) faces. 88 @return A %PolygonalMesh representing a sphere of the specified radius. **/ 89 static PolygonalMesh createSphereMesh(Real radius, 90 int resolution = 1); 91 92 /** Create a brick-shaped mesh. A brick is a rectangular solid (a box) 93 centered at and aligned with the mesh local frame. Note that its size is 94 given with \e half dimensions. By default you will just get two mesh faces 95 along the longest edge of the brick, with all other edges roughly the same 96 size. You can control the mesh density with the \a resolution parameter. 97 98 @param[in] halfDims 99 The half-dimensions of the brick. The extreme vertices are at 100 -halfDims and +halfDims, so the brick is centered around the mesh 101 local frame. 102 @param[in] resolution 103 Control for how dense a mesh to produce. For this shape, \a resolution 104 is interpreted as the number of extra vertices to insert in the 105 \e longest edge of the brick. Extra vertices are inserted into the 106 shorter edges if needed to keep the edge lengths approximately 107 uniform for every mesh face. \a resolution=0 gives only 108 vertices at the corners; the default is 1 meaning that the longest 109 edge is split once. 110 @return A %PolygonalMesh representing a brick of the requested size. 111 112 <h3>Controlling the mesh density:</h3> 113 If you want a brick mesh where all the edges in the mesh are roughly the 114 same length, say \c wantEdgeLength, set \a resolution like this: 115 @code 116 Real wantEdgeLength = ...; 117 Vec3 halfDims = ...; 118 int resolution = (int)(max(halfDims)/wantEdgeLength + 0.5); 119 @endcode 120 121 If you want a brick mesh where all the edges are roughly the same length 122 as the shortest edge of the brick, just set 123 <code>wantEdgeLength=min(halfDims)</code> in the above calculation. **/ 124 static PolygonalMesh createBrickMesh(const Vec3& halfDims, 125 int resolution = 1); 126 127 /** Create a cylinder-shaped mesh, with the long axis in a given 128 direction. By default you'll get a 12 sided polygon as the base and 129 elements of roughly similar dimension along the edges. You can control the 130 mesh density with the \a resolution parameter. 131 132 @param[in] axis 133 The central axis direction of the cylinder, in the mesh local frame. 134 This can be provided using the constants XAxis, YAxis, or ZAxis, or 135 you can provide a unit vector in any direction. 136 @param[in] radius 137 The cylinder radius. 138 @param[in] halfLength 139 Half the length of the cylinder along its axis. The bases are at 140 -halfLength and +halfLength along the \a axis, so the cylinder is 141 centered around the mesh local frame origin. 142 @param[in] resolution 143 Control for how dense a mesh to produce (see below for details). 144 @return A %PolygonalMesh representing a cylinder of the requested dimensions 145 and orientation. 146 147 <h3>Controlling the mesh density:</h3> 148 At resolution 0 the base is a hexagon with six triangular faces, and the 149 tube is meshed with quad faces that are about as long 150 as the diameter of the base. Resolution 1 (the default) makes the base 151 a 12-sided polygon and introduces an intermediate 12-sided polygon of 152 have the diameter. There will be triangles in the center still, but 153 quad faces between the polygons. The length of the tube faces will be 154 reduced to match. Higher resolutions refine the mesh similarly. **/ 155 static PolygonalMesh createCylinderMesh(const UnitVec3& axis, 156 Real radius, 157 Real halfLength, 158 int resolution=1); 159 160 /** Restore this %PolygonalMesh to its default-constructed state, meaning 161 that it will contain no vertices or faces after this call. **/ 162 void clear(); 163 164 /** Get the number of faces in the mesh. **/ 165 int getNumFaces() const; 166 /** Get the number of vertices in the mesh. **/ 167 int getNumVertices() const; 168 169 /** Get the position of a vertex in the mesh. 170 @param[in] vertex The index of the vertex (as returned by addVertex()). 171 @return The position of the specified vertex, measured and expressed in 172 the mesh local frame. **/ 173 const Vec3& getVertexPosition(int vertex) const; 174 /** Get the number of vertices that make up a particular face. 175 @param[in] face The index of the face (as returned by addFace()). **/ 176 int getNumVerticesForFace(int face) const; 177 /** Get the index of one of the vertices of a face. 178 @param[in] face The index of the face (as returned by addFace()). 179 @param[in] vertex The index of the vertex within the face (from 0, 1, or 2 180 for a triangular face, etc.) These are ordered the same 181 way as when the face was defined. 182 @return The index of the specified vertex. **/ 183 int getFaceVertex(int face, int vertex) const; 184 185 /** Add a vertex to the mesh. 186 @param[in] position The position of the vertex to add, measured and 187 expressed in the mesh local frame. 188 @return The index of the newly added vertex. **/ 189 int addVertex(const Vec3& position); 190 191 /** Add a face to the mesh. Note that the ordering of the vertices defines 192 the outward normal for the face; they must be counterclockwise around the 193 desired normal. 194 195 @param[in] vertices Indices of the vertices which make up the new face, 196 in counterclockwise order with respect to the face 197 normal. 198 @return The index of the newly added face. **/ 199 int addFace(const Array_<int>& vertices); 200 201 /** Scale a mesh by multiplying every vertex by a fixed value. Note that 202 this permanently modifies the vertex locations within the mesh. Since the 203 vertices are measured in the mesh local frame, scaling will appear to 204 occur around the mesh origin (that is, the origin will remain where it 205 was while everything else changes. 206 @param[in] scale The scale factor. Can be any value except zero. 207 @return A reference to this now-scaled mesh object. **/ 208 PolygonalMesh& scaleMesh(Real scale); 209 210 /** %Transform a mesh by applying the given Transform to every vertex, 211 leaving the mesh permanently changed. This has the effect of replacing the 212 mesh local frame M with a new frame A. 213 @param[in] X_AM The transform giving the pose of the mesh local frame in 214 the new frame A. Every vertex v_M becomes v_A=X_AM*v_M. 215 @return A reference to this now-transformed mesh object. **/ 216 PolygonalMesh& transformMesh(const Transform& X_AM); 217 218 /** Attempt to interpret the given file as a mesh file, with the format 219 determined from the file name extension. If we recognize the extension 220 we'll call one of the specialized methods below; see the descriptions for 221 more information. Ignoring case, we recognize: 222 - <tt>.obj </tt>: Wavefront OBJ file 223 - <tt>.stl </tt>: 3D Systems Stereolithography file (ascii or binary) 224 - <tt>.stla</tt>: ascii-only stl extension 225 - <tt>.vtp </tt>: VTK PolyData file (we can only read the ascii version) 226 227 @param[in] pathname The name of a mesh file with a recognized extension. 228 **/ 229 void loadFile(const std::string& pathname); 230 #ifndef SWIG 231 /** Load a Wavefront OBJ (.obj) file, adding the vertices and faces it 232 contains to this mesh, and ignoring anything else in the file. The suffix 233 for these files is typically ".obj" but we don't check here. 234 @param[in] pathname The name of a .obj file. **/ 235 void loadObjFile(const String& pathname); 236 237 /** Alternate signature for Wavefront OBJ format that takes an already-open 238 istream rather than a pathname. This is useful for testing since it 239 can be supplied by a stringstream rather than a file. 240 @param[in,out] file An input stream from which to load the file 241 contents. **/ 242 void loadObjFile(std::istream& file); 243 244 /** Load a VTK PolyData (.vtp) file, adding the vertices and faces it 245 contains to this mesh and ignoring anything else in the file. The suffix 246 for these files is typically ".vtp" but we don't check here. 247 @param[in] pathname The name of a .vtp file. **/ 248 void loadVtpFile(const String& pathname); 249 250 /** Load an STL file, adding the vertices and faces it contains to this 251 mesh and ignoring anything else in the file. The file may be in ascii or 252 binary format. If the suffix is ".stla" then it can only be ascii. 253 Otherwise, including ".stl" or anything else, we'll examine the contents to 254 determine which format is used. STL files include many repeated vertices; 255 we will collapse any that coincide to within a small tolerance so that there 256 is some hope of getting a connected surface. 257 @param[in] pathname The name of a .stl or .stla file. **/ 258 void loadStlFile(const String& pathname); 259 #endif 260 private: PolygonalMesh(PolygonalMeshImpl * impl)261 explicit PolygonalMesh(PolygonalMeshImpl* impl) : HandleBase(impl) {} 262 void initializeHandleIfEmpty(); 263 }; 264 265 } // namespace SimTK 266 267 #endif // SimTK_SimTKCOMMON_POLYGONAL_MESH_H_ 268