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