Skip to content

Commit 5de70ce

Browse files
committed
Merged revision(s) 3059 from trunk:
Added some utilities to PolygonalMesh to generate brick- and cylinder-shaped meshes. These can be used for contact with the elastic foundation model.
1 parent dade779 commit 5de70ce

File tree

3 files changed

+429
-120
lines changed

3 files changed

+429
-120
lines changed

SimTKcommon/Geometry/include/SimTKcommon/internal/PolygonalMesh.h

Lines changed: 149 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* Biological Structures at Stanford, funded under the NIH Roadmap for *
1010
* Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody. *
1111
* *
12-
* Portions copyright (c) 2008-12 Stanford University and the Authors. *
12+
* Portions copyright (c) 2008-13 Stanford University and the Authors. *
1313
* Authors: Peter Eastman *
1414
* Contributors: Michael Sherman *
1515
* *
@@ -39,10 +39,11 @@ class PolygonalMeshImpl;
3939
extern template class PIMPLHandle<PolygonalMesh, PolygonalMeshImpl, true>;
4040
#endif
4141

42-
/** This class provides a description of a mesh made of polygonal faces. Its
43-
primary purpose is for loading geometry from files, which can then be used for
44-
visualization or collision detection. For example, the following lines load
45-
a mesh from a Wavefront OBJ file, then create a DecorativeMesh from it.
42+
/** This class provides a description of a mesh made of polygonal faces (not
43+
limited to triangles). Its primary purpose is for loading geometry from files,
44+
which can then be used for visualization or collision detection. For example,
45+
the following lines load a mesh from a Wavefront OBJ file, then create a
46+
DecorativeMesh from it.
4647
@code
4748
PolygonalMesh mesh;
4849
std::ifstream file;
@@ -53,84 +54,162 @@ a mesh from a Wavefront OBJ file, then create a DecorativeMesh from it.
5354
@endcode
5455
You can also read a polygon mesh from a VTK PolyData (.vtp) file.
5556
56-
We expect this to be a large object so give it shared (reference) semantics; that is,
57-
the copy constructor and copy assignment default to shallow copies (both handles
58-
will refer to the same data). If you want to make a deep (non-shared) copy of a
59-
PolygonalMesh, use the copyAssign() method provided by the PIMPLHandle base class.
60-
**/
57+
You can also build meshes programmatically, and some static methods are provided
58+
here for generating some common shapes.
59+
60+
The mesh has its own local frame and vertex locations are given in that
61+
frame. You can scale and transform the vertices relative to that frame
62+
(changing the values stored in the mesh) but more commonly the mesh will be
63+
placed on a body relative to that body's frame, meaning you can re-use the
64+
same mesh in various places.
65+
66+
We expect this to be a large object so give it shared (reference) semantics;
67+
that is, the copy constructor and copy assignment default to shallow copies
68+
(both handles will refer to the same data). If you want to make a deep
69+
(non-shared) copy of a PolygonalMesh, use the copyAssign() method provided by
70+
the PIMPLHandle base class. **/
6171
class SimTK_SimTKCOMMON_EXPORT PolygonalMesh
6272
: public PIMPLHandle<PolygonalMesh, PolygonalMeshImpl, true> {
6373
public:
64-
/**
65-
* Create a PolygonalMesh, which initially contains no vertices or faces.
66-
*/
74+
/** Create an empty %PolygonalMesh, with no vertices or faces. **/
6775
PolygonalMesh() {}
6876

69-
/**
70-
* Get the number of faces in the mesh.
71-
*/
77+
/** TODO: Create a sphere-shaped mesh. **/
78+
static PolygonalMesh createSphereMesh(Real radius, int resolution);
79+
80+
/** Create a brick-shaped mesh. A brick is a rectangular solid (a box)
81+
centered at and aligned with the mesh local frame. Note that its size is
82+
given with \e half dimensions. By default you will just get two mesh faces
83+
along the longest edge of the brick, with all other edges roughly the same
84+
size. You can control the mesh density with the \a resolution parameter.
85+
86+
@param halfDims
87+
The half-dimensions of the brick. The extreme vertices are at
88+
-halfDims and +halfDims, so the brick is centered around the mesh
89+
local frame.
90+
@param resolution
91+
Control for how dense a mesh to produce. For this shape, \a resolution
92+
is interpreted as the number of extra vertices to insert in the
93+
\e longest edge of the brick. Extra vertices are inserted into the
94+
shorter edges if needed to keep the edge lengths approximately
95+
uniform for every mesh face. \a resolution=0 gives only
96+
vertices at the corners; the default is 1 meaning that the longest
97+
edge is split once.
98+
@return A %PolygonalMesh representing a brick of the requested size.
99+
100+
<h3>Controlling the mesh density:</h3>
101+
If you want a brick mesh where all the edges in the mesh are roughly the
102+
same length, say \c wantEdgeLength, set \a resolution like this:
103+
@code
104+
Real wantEdgeLength = ...;
105+
Vec3 halfDims = ...;
106+
int resolution = (int)(max(halfDims)/wantEdgeLength + 0.5);
107+
@endcode
108+
109+
If you want a brick mesh where all the edges are roughly the same length
110+
as the shortest edge of the brick, just set
111+
<code>wantEdgeLength=min(halfDims)</code> in the above calculation. **/
112+
static PolygonalMesh createBrickMesh(const Vec3& halfDims,
113+
int resolution = 1);
114+
115+
/** Create a cylinder-shaped mesh, with the long axis in a given
116+
direction. By default you'll get a 12 sided polygon as the base and
117+
elements of roughly similar dimension along the edges. You can control the
118+
mesh density with the \a resolution parameter.
119+
120+
@param axis
121+
The central axis direction of the cylinder, in the mesh local frame.
122+
This can be provided using the constants XAxis, YAxis, or ZAxis, or
123+
you can provide a unit vector in any direction.
124+
@param radius
125+
The cylinder radius.
126+
@param halfLength
127+
Half the length of the cylinder along its axis. The bases are at
128+
-halfLength and +halfLength along the \a axis, so the cylinder is
129+
centered around the mesh local frame origin.
130+
@param resolution
131+
Control for how dense a mesh to produce (see below for details).
132+
@return A %PolygonalMesh representing a cylinder of the requested dimensions
133+
and orientation.
134+
135+
<h3>Controlling the mesh density:</h3>
136+
At resolution 0 the base is a hexagon with six triangular faces, and the
137+
tube is meshed with quad faces that are about as long
138+
as the diameter of the base. Resolution 1 (the default) makes the base
139+
a 12-sided polygon and introduces an intermediate 12-sided polygon of
140+
have the diameter. There will be triangles in the center still, but
141+
quad faces between the polygons. The length of the tube faces will be
142+
reduced to match. Higher resolutions refine the mesh similarly. **/
143+
static PolygonalMesh createCylinderMesh(const UnitVec3& axis,
144+
Real radius,
145+
Real halfLength,
146+
int resolution=1);
147+
148+
/** Restore this %PolygonalMesh to its default-constructed state, meaning
149+
that it will contain no vertices or faces after this call. **/
150+
void clear();
151+
152+
/** Get the number of faces in the mesh. **/
72153
int getNumFaces() const;
73-
/**
74-
* Get the number of vertices in the mesh.
75-
*/
154+
/** Get the number of vertices in the mesh. **/
76155
int getNumVertices() const;
77-
/**
78-
* Get the position of a vertex in the mesh.
79-
*
80-
* @param vertex the index of the vertex to get
81-
* @return the position of the specified vertex
82-
*/
156+
157+
/** Get the position of a vertex in the mesh.
158+
@param vertex The index of the vertex (as returned by addVertex()).
159+
@return The position of the specified vertex, measured and expressed in
160+
the mesh local frame. **/
83161
const Vec3& getVertexPosition(int vertex) const;
84-
/**
85-
* Get the number of vertices that make up a face.
86-
*
87-
* @param face the index of the face
88-
*/
162+
/** Get the number of vertices that make up a particular face.
163+
@param face The index of the face (as returned by addFace()). **/
89164
int getNumVerticesForFace(int face) const;
90-
/**
91-
* Get the index of one of the vertices of a face.
92-
*
93-
* @param face the index of the face
94-
* @param vertex the index of the vertex within the face
95-
* (from 0, 1, or 2 for a triangular face, etc.)
96-
* @return the index of the specified vertex
97-
*/
165+
/** Get the index of one of the vertices of a face.
166+
@param face The index of the face (as returned by addFace()).
167+
@param vertex The index of the vertex within the face (from 0, 1, or 2
168+
for a triangular face, etc.) These are ordered the same
169+
way as when the face was defined.
170+
@return The index of the specified vertex. **/
98171
int getFaceVertex(int face, int vertex) const;
99-
/**
100-
* Add a vertex to the mesh.
101-
*
102-
* @param position the position of the vertex to add
103-
* @return the index of the newly added vertex
104-
*/
172+
173+
/** Add a vertex to the mesh.
174+
@param position The position of the vertex to add, measured and
175+
expressed in the mesh local frame.
176+
@return The index of the newly added vertex. **/
105177
int addVertex(const Vec3& position);
106-
/**
107-
* Add a face to the mesh.
108-
*
109-
* @param vertices indices of the vertices which make up the new face
110-
* @return the index of the newly added face
111-
*/
178+
179+
/** Add a face to the mesh. Note that the ordering of the vertices defines
180+
the outward normal for the face; they must be counterclockwise around the
181+
desired normal.
182+
183+
@param vertices Indices of the vertices which make up the new face, in
184+
counterclockwise order with respect to the face normal.
185+
@return The index of the newly added face. **/
112186
int addFace(const Array_<int>& vertices);
113-
/**
114-
* Scale a mesh by multiplying every vertex by a fixed value.
115-
*/
116-
void scaleMesh(Real scale);
117-
/**
118-
* Transform a mesh by applying a Transform to every vertex.
119-
*/
120-
void transformMesh(const Transform& transform);
121-
/**
122-
* Load a Wavefront OBJ file, adding the vertices and faces it contains
123-
* to this mesh.
124-
*
125-
* @param file an input stream from which to load the file contents
126-
*/
187+
188+
/** Scale a mesh by multiplying every vertex by a fixed value. Note that
189+
this permanently modifies the vertex locations within the mesh. Since the
190+
vertices are measured in the mesh local frame, scaling will appear to
191+
occur around the mesh origin (that is, the origin will remain where it
192+
was while everything else changes.
193+
@param scale The scale factor. Can be any value except zero.
194+
@return A reference to this now-scaled mesh object. **/
195+
PolygonalMesh& scaleMesh(Real scale);
196+
197+
/** %Transform a mesh by applying the given Transform to every vertex,
198+
leaving the mesh permanently changed. This has the effect of replacing the
199+
mesh local frame M with a new frame A.
200+
@param X_AM The transform giving the pose of the mesh local frame in
201+
the new frame A. Every vertex v_M becomes v_A=X_AM*v_M.
202+
@return A reference to this now-transformed mesh object. **/
203+
PolygonalMesh& transformMesh(const Transform& X_AM);
204+
205+
/** Load a Wavefront OBJ file, adding the vertices and faces it contains
206+
to this mesh.
207+
@param file An input stream from which to load the file contents. **/
127208
void loadObjFile(std::istream& file);
128-
/**
129-
* Load a VTK PolyData (.vtp) file, adding the vertices and faces it
130-
* contains to this mesh.
131-
*
132-
* @param pathname the name of a .vtp file
133-
*/
209+
210+
/** Load a VTK PolyData (.vtp) file, adding the vertices and faces it
211+
contains to this mesh.
212+
@param pathname The name of a .vtp file. **/
134213
void loadVtpFile(const String& pathname);
135214

136215
private:

0 commit comments

Comments
 (0)