forked from libigl/libigl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstyle-guidelines.html
394 lines (303 loc) · 15.8 KB
/
style-guidelines.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>libigl</title>
<meta name="author" content="Alec Jacobson and Daniele Panozzo and others"/>
<link type="text/css" rel="stylesheet" href="tutorial/style.css"/>
<script type='text/javascript' src='http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML'></script>
<link rel='stylesheet' href='http://yandex.st/highlightjs/7.3/styles/default.min.css'>
<script src='http://yandex.st/highlightjs/7.3/highlight.min.js'></script>
<script>hljs.initHighlightingOnLoad();</script>
</head>
<body>
<h1 id="libiglstyleguidelines">Libigl Style Guidelines</h1>
<p>Libigl is used and developed by many people. This document highlights some
style guidelines for <em>developers</em> of the library, but also acts as
best-practices for users.</p>
<h2 id="filefunction">One function, one .h/.cpp pair</h2>
<p>The structure of libigl is very flat and function-based. For every
function/sub-routine, create a single .h and .cpp file. For example, if you have
a function that determines connected components from a face list <code>F</code> you would
create the header <code>connected_components.h</code> and <code>connected_components.cpp</code> and the only
function defined should be <code>void connected_components(const ... F, ... C)</code>. If the
implementation of <code>connected_components</code> requires a subroutine to compute an
adjacency matrix then <em>create another pair</em> <code>adjacency_matrix.h</code> and
<code>adjacency_matrix.cpp</code> with a single function <code>void adjacency_matrix(const ... F, ... A)</code>.</p>
<h3 id="example">Example</h3>
<p>Here is an example function that would be defined in
<code>include/igl/example_fun.h</code> and implemented in <code>include/igl/example_fun.cpp</code>.</p>
<h4 id="example_fun.h"><code>example_fun.h</code></h4>
<pre><code class="cpp">// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2015 [Your Name] [your email address]
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/
#ifndef IGL_EXAMPLE_FUN_H
#define IGL_EXAMPLE_FUN_H
#include "igl_inline.h"
namespace igl
{
// This is an example of a function, it takes a templated parameter and
// shovels it into cout
//
// Input:
// input some input of a Printable type
// Returns true for the sake of returning something
template <typename Printable>
IGL_INLINE bool example_fun(const Printable & input);
}
#ifndef IGL_STATIC_LIBRARY
# include "example_fun.cpp"
#endif
#endif
</code></pre>
<h4 id="example_fun.cpp"><code>example_fun.cpp</code></h4>
<pre><code>// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2015 [Your Name] [your email address]
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/
#include "igl/example_fun.h"
#include <iostream>
template <typename Printable>
IGL_INLINE bool igl::example_fun(const Printable & input)
{
using namespace std;
cout<<"example_fun: "<<input<<endl;
return true;
}
#ifdef IGL_STATIC_LIBRARY
template bool igl::example_fun<double>(const double& input);
template bool igl::example_fun<int>(const int& input);
#endif
</code></pre>
<h3 id="avoidstatichelperfunctions">Avoid static “helper” functions</h3>
<p>Strive to encapsulate sub-functions that could possibly be useful outside of
the implementation of your current function. This might mean abstracting the
interface a bit. If it doesn’t dramatically effect performance then create a
new pair of .h/.cpp files with this sub-function.</p>
<h4 id="lambdafunctions">Lambda functions</h4>
<p>If encapsulation in a separate file is not possible or does not make sense,
then avoid crowding the namespace by creating lambda functions within the
function implementation.</p>
<p>These lambda functions must still be documented with clear <a href="#headerdocumentation">input and output
arguments</a>. Avoid using full capturing of all automatic
variables: do not use <code>[&]</code> or <code>[=]</code>. Rather specify each captured variable
individually.</p>
<h3 id="avoidhelperclasses">Avoid “helper” classes</h3>
<p>Libigl is built around the high-performance paradigm of “struct of arrays”
rather than “array of structs”. The way we achieve this is to avoid classes and
pass “basic types” directly. The price we pay is long function interfaces, but
this increases code reuse dramatically. A “basic type” in our context is a
Eigen type, stl type, or basic C type.</p>
<h2 id="headerdocumentation">Header Documentation</h2>
<p>Each function prototype should be well documented in its corresponding .h
header file. A typical documentation consists of four parts:</p>
<pre><code class="cpp">// [A human readable description of what the function does.]
//
// Inputs:
// [variable name of first (const) input] [dimensions and description of
// this input variable]
// [variable name of second (const) input] [dimensions and description of
// this input variable]
// ...
// Outputs:
// [variable name of first output ] [dimensions and description of this
// output variable]
// [variable name of second output ] [dimensions and description of this
// output variable]
// ...
// Returns [description of return value]
</code></pre>
<h3 id="example">Example</h3>
<p>For example the header <code>barycenter.h</code></p>
<pre><code>// Computes the barycenter of every simplex
//
// Inputs:
// V #V by dim matrix of vertex coordinates
// F #F by simplex_size matrix of indices of simplex corners into V
// Output:
// BC #F by dim matrix of 3d vertices
//
</code></pre>
<h2 id="constinputs">Const inputs</h2>
<p>All input parameters should be demarcated <code>const</code>. If an input is also an
output than consider exposing two parameters (one <code>const</code>) or be sure to list
the variable under both <code>// Inputs:</code> and <code>// Outputs:</code> in the header comments.</p>
<h2 id="referenceparameters">Reference parameters</h2>
<p>All but simple types should be passed by reference (e.g. <code>Matrix & mat</code>) rather
than pointers (e.g. <code>Matrix * mat</code>) or value (e.g. <code>Matrix mat</code>).</p>
<h2 id="returnsvsoutputparameters">Returns vs output parameters</h2>
<p>All functions should be implemented with at least one overload that has a
<code>void</code> or simple return type (e.g. <code>bool</code> on success/failure). With this
implementation its then possible to write an overload that returns a single
output. Please see <a href="#templatingwitheigen">Templating with Eigen</a>.</p>
<p>For example:</p>
<pre><code class="cpp">template <typename Atype>
void adjacency_matrix(const ... & F, Eigen::SparseMatrix<AType> & A);
template <typename Atype>
Eigen::SparseMatrix<Atype> adjacency_matrix(const ... & F);
</code></pre>
<h2 id="templatingwitheigen">Templating with Eigen</h2>
<p>Functions taking Eigen dense matrices/arrays as inputs and outputs (but <strong>not</strong>
return arguments), should template on top of <code>Eigen::PlainObjectBase</code>. <strong>Each
parameter</strong> should be derived using its own template.</p>
<p>For example,</p>
<pre><code class="cpp">template <typename DerivedV, typename DerivedF, typename DerivedBC>
void barycenter(
const Eigen::PlainObjectBase<DerivedV> & V,
const Eigen::PlainObjectBase<DerivedF> & F,
const Eigen::PlainObjectBase<DerivedBC> & BC);
</code></pre>
<p>The <code>Derived*</code> template encodes the scalar type (e.g. <code>double</code>, <code>int</code>), the
number of rows and cols at compile time, and the data storage (Row-major vs.
column-major). </p>
<p>Returning Eigen types is discouraged. In cases where the size and scalar type
are a fixed <strong>and matching</strong> function of an input <code>Derived*</code> template, then
return that <code>Derived*</code> type. <strong>Do not</strong> return
<code>Eigen::PlainObjectBase<...></code> types. For example, this function scales fits a
given set of points to the unit cube. The return is a new set of vertex
positions so its type should <em>match</em> that of the input points:</p>
<pre><code class="cpp">template <typename DerivedV>
void DerivedV fit_to_unit_cube(const Eigen::PlainObjectBase<DerivedV> & V);
</code></pre>
<p>To implement this function, it is <strong>required</strong> to implement a more generic
output-argument version and call that. So a full implementation looks like:</p>
<p>In <code>igl/fit_in_unit_cube.h</code>:</p>
<pre><code class="cpp">template <typename DerivedV, typename DerivedW>
void fit_to_unit_cube(
const Eigen::PlainObjectBase<DerivedV> & V,
Eigen::PlainObjectBase<DerivedW> & W);
template <typename DerivedV>
void DerivedV fit_to_unit_cube(const Eigen::PlainObjectBase<DerivedV> & V);
</code></pre>
<p>In <code>igl/fit_in_unit_cube.cpp</code>:</p>
<pre><code>template <typename DerivedV, typename DerivedW>
void fit_to_unit_cube(
const Eigen::PlainObjectBase<DerivedV> & V,
Eigen::PlainObjectBase<DerivedW> & W)
{
W = (V.rowwise()-V.colwise().minCoeff()).array() /
(V.maxCoeff()-V.minCoeff());
}
template <typename DerivedV>
void DerivedV fit_to_unit_cube(const Eigen::PlainObjectBase<DerivedV> & V)
{
DerivedV W;
fit_to_unit_cube(V,W);
return W;
}
</code></pre>
<p>Notice that <code>W</code> is declared as a <code>DerivedV</code> type and <strong>not</strong>
<code>Eigen::PlainObjectBase<DerivedV></code> type.</p>
<p><strong>Note:</strong> Not all functions are suitable for returning Eigen types. For example
<code>igl::barycenter</code> above outputs a #F by dim list of barycenters. Returning a
<code>DerivedV</code> type would be inappropriate since the number of rows in <code>DerivedV</code>
will be #V and may not match the number of rows in <code>DerivedF</code> (#F).</p>
<h2 id="functionnamingconventions">Function naming conventions</h2>
<p>Functions (and <a href="#filefunction">thus also files</a>) should have simple,
descriptive names using lowercase letters and underscores between words. Avoid
unnecessary prefaces. For example, instead of <code>compute_adjacency_matrix</code>,
<code>construct_adjacency_matrix</code>, <code>extract_adjacency_matrix</code>,
<code>get_adjacency_matrix</code>, or <code>set_adjacency_matrix</code> just call the function
<code>adjacency_matrix</code>.</p>
<h2 id="variablenamingconventions">Variable naming conventions</h2>
<p>Libigl prefers short (even single character) variable names <em>with heavy
documentation</em> in the comments in the header file or above the declaration of
the function. When possible use <code>V</code> to mean a list of vertex positions and <code>F</code>
to mean a list of faces/triangles.</p>
<h2 id="classnamingconventions">Class naming conventions</h2>
<p>Classes should be avoided. When naming a class use CamelCase (e.g.
SortableRow.h).</p>
<h2 id="enumnamingconvertion">Enum naming convertion</h2>
<p>Enums types should be placed in the appropriate <code>igl::</code> namespace and should be
named in CamelCase (e.g. <code>igl::SolverStatus</code>) and instances should be named in
ALL_CAPS with underscores between words and prefaced with the name of the enum.
For example:</p>
<pre><code class="cpp">namespace igl
{
enum SolverStatus
{
// Good
SOLVER_STATUS_CONVERGED = 0,
// OK
SOLVER_STATUS_MAX_ITER = 1,
// Bad
SOLVER_STATUS_ERROR = 2,
NUM_SOLVER_STATUSES = 3,
};
};
</code></pre>
<h3 id="exceptionforfileio">Exception for file IO</h3>
<p>For legacy reasons, file reading and writing functions use a different naming
convention. A functions reading a <code>.xyz</code> file should be named <code>readXYZ</code> and a
function writing <code>.xyz</code> files should be names <code>writeXYZ</code>.</p>
<h2 id="usingnamespace...inglobalscope"><code>using namespace ...</code> in global scope</h2>
<p>Writing <code>using namespace std;</code>, <code>using namespace Eigen;</code> etc. outside of a
global scope is strictly forbidden. Place these lines at the top of each
function instead.</p>
<h2 id="namespacesandexternaldependencies">Namespaces and external dependencies</h2>
<p>Functions in the main library (directly in <code>include/igl</code>) should only depend on
Eigen and stl. These functions should have the <code>igl::</code> namespace.</p>
<p>Functions with other dependencies should be placed into
appropriate sub-directories (e.g. if <code>myfunction</code> depends on tetgen then create
<code>igl/copyleft/tetgen/myfunction.h</code> and <code>igl/copyleft/tetgen/myfunction.cpp</code> and give the function
the namespace <code>igl::copyleft::tetgen::myfunction</code>.</p>
<h3 id="copyleftsubdirectorynamespace">copyleft subdirectory/namespace</h3>
<p>Dependencies that require users of libigl to release their projects open source
(e.g. GPL) are considered aggressively “copyleft” and should be placed in the
<code>include/igl/copyleft/</code> sub-directory and <code>igl::copyleft::</code> namespace.</p>
<h2 id="assertions">Assertions</h2>
<p>Be generous with assertions and always identify the assertion with strings:</p>
<pre><code class="cpp">assert(m < n && "m must be less than n");
</code></pre>
<h2 id="ifndefincludeguard">ifndef include guard</h2>
<p>Every header file should be wrapped in an <code>#ifndef</code> compiler directive. The
name of the guard should be in direct correspondence with the path of the .h
file. For example, <code>include/igl/copyleft/tetgen/tetrahedralize.h</code> should be</p>
<pre><code class="cpp">#ifndef IGL_COPYLEFT_TETGEN_TETRAHEDRALIZE_H
#define IGL_COPYLEFT_TETGEN_TETRAHEDRALIZE_H
...
#endif
</code></pre>
<h2 id="spacesvs.tabsindentation">Spaces vs. tabs indentation</h2>
<p>Do not use tabs. Use 2 spaces for each indentation level.</p>
<h2 id="maxlinelength">Max line length</h2>
<p>Limit lines to 80 characters. Break up long lines into many operations (this
also helps performance).</p>
<h2 id="includeorder">Include order</h2>
<p><code>#include</code> directives at the top of a .h or .cpp file should be sorted
according to a simple principle: place headers of files most likely to be
edited by you first. This means for
<code>include/igl/copyleft/tetgen/tetrahedralize.cpp</code> you might see</p>
<pre><code class="cpp">// [Includes of headers in this directory]
#include "tetrahedralize.h"
#include "mesh_to_tetgenio.h"
#include "tetgenio_to_tetmesh.h"
// [Includes of headers in this project]
#include "../../matrix_to_list.h"
#include "../../list_to_matrix.h"
#include "../../boundary_facets.h"
// [Includes of headers of related projects]
#include <Eigen/Core>
// [Includes of headers of standard libraries]
#include <cassert>
#include <iostream>
</code></pre>
<h2 id="placementofincludes">Placement of includes</h2>
<p>Whenever possible <code>#include</code> directives should be placed in the <code>.cpp</code>
implementation file rather than the <code>.h</code> header file.</p>
<h2 id="warnings">Warnings</h2>
<p>Code should compile without firing any warnings.</p>
<h3 id="anexception">An Exception</h3>
<p>The only exception is for the use of the deprecated
<code>Eigen::DynamicSparseMatrix</code> in core sub-routines (e.g. <code>igl::cat</code>). This class
is still supported and faster than the standard, non-deprecated Eigen
implementation so we’re keeping it as long as possible and profitable.</p>
</body>
</html>