/src/assimp/code/Common/StandardShapes.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | Open Asset Import Library (assimp) |
3 | | ---------------------------------------------------------------------- |
4 | | |
5 | | Copyright (c) 2006-2025, assimp team |
6 | | |
7 | | All rights reserved. |
8 | | |
9 | | Redistribution and use of this software in source and binary forms, |
10 | | with or without modification, are permitted provided that the |
11 | | following conditions are met: |
12 | | |
13 | | * Redistributions of source code must retain the above |
14 | | copyright notice, this list of conditions and the |
15 | | following disclaimer. |
16 | | |
17 | | * Redistributions in binary form must reproduce the above |
18 | | copyright notice, this list of conditions and the |
19 | | following disclaimer in the documentation and/or other |
20 | | materials provided with the distribution. |
21 | | |
22 | | * Neither the name of the assimp team, nor the names of its |
23 | | contributors may be used to endorse or promote products |
24 | | derived from this software without specific prior |
25 | | written permission of the assimp team. |
26 | | |
27 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
28 | | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
29 | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
30 | | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
31 | | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
32 | | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
33 | | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
34 | | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
35 | | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
36 | | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
37 | | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
38 | | |
39 | | ---------------------------------------------------------------------- |
40 | | */ |
41 | | |
42 | | /** @file StandardShapes.cpp |
43 | | * @brief Implementation of the StandardShapes class |
44 | | * |
45 | | * The primitive geometry data comes from |
46 | | * http://geometrictools.com/Documentation/PlatonicSolids.pdf. |
47 | | */ |
48 | | |
49 | | #include <assimp/StandardShapes.h> |
50 | | #include <assimp/StringComparison.h> |
51 | | #include <assimp/mesh.h> |
52 | | |
53 | | namespace Assimp { |
54 | | |
55 | | #define ADD_TRIANGLE(n0, n1, n2) \ |
56 | 15.9k | positions.push_back(n0); \ |
57 | 15.9k | positions.push_back(n1); \ |
58 | 15.9k | positions.push_back(n2); |
59 | | |
60 | | #define ADD_PENTAGON(n0, n1, n2, n3, n4) \ |
61 | 192 | if (polygons) { \ |
62 | 0 | positions.push_back(n0); \ |
63 | 0 | positions.push_back(n1); \ |
64 | 0 | positions.push_back(n2); \ |
65 | 0 | positions.push_back(n3); \ |
66 | 0 | positions.push_back(n4); \ |
67 | 192 | } else { \ |
68 | 192 | ADD_TRIANGLE(n0, n1, n2) \ |
69 | 192 | ADD_TRIANGLE(n0, n2, n3) \ |
70 | 192 | ADD_TRIANGLE(n0, n3, n4) \ |
71 | 192 | } |
72 | | |
73 | | #define ADD_QUAD(n0, n1, n2, n3) \ |
74 | 0 | if (polygons) { \ |
75 | 0 | positions.push_back(n0); \ |
76 | 0 | positions.push_back(n1); \ |
77 | 0 | positions.push_back(n2); \ |
78 | 0 | positions.push_back(n3); \ |
79 | 0 | } else { \ |
80 | 0 | ADD_TRIANGLE(n0, n1, n2) \ |
81 | 0 | ADD_TRIANGLE(n0, n2, n3) \ |
82 | 0 | } |
83 | | |
84 | | // ------------------------------------------------------------------------------------------------ |
85 | | // Fast subdivision for a mesh whose verts have a magnitude of 1 |
86 | 12 | void Subdivide(std::vector<aiVector3D> &positions) { |
87 | | // assume this to be constant - (fixme: must be 1.0? I think so) |
88 | 12 | const ai_real fl1 = positions[0].Length(); |
89 | | |
90 | 12 | unsigned int origSize = (unsigned int)positions.size(); |
91 | 5.11k | for (unsigned int i = 0; i < origSize; i += 3) { |
92 | 5.10k | aiVector3D &tv0 = positions[i]; |
93 | 5.10k | aiVector3D &tv1 = positions[i + 1]; |
94 | 5.10k | aiVector3D &tv2 = positions[i + 2]; |
95 | | |
96 | 5.10k | aiVector3D a = tv0, b = tv1, c = tv2; |
97 | 5.10k | aiVector3D v1 = aiVector3D(a.x + b.x, a.y + b.y, a.z + b.z).Normalize() * fl1; |
98 | 5.10k | aiVector3D v2 = aiVector3D(a.x + c.x, a.y + c.y, a.z + c.z).Normalize() * fl1; |
99 | 5.10k | aiVector3D v3 = aiVector3D(b.x + c.x, b.y + c.y, b.z + c.z).Normalize() * fl1; |
100 | | |
101 | 5.10k | tv0 = v1; |
102 | 5.10k | tv1 = v3; |
103 | 5.10k | tv2 = v2; // overwrite the original |
104 | 5.10k | ADD_TRIANGLE(v1, v2, a); |
105 | 5.10k | ADD_TRIANGLE(v2, v3, c); |
106 | 5.10k | ADD_TRIANGLE(v3, v1, b); |
107 | 5.10k | } |
108 | 12 | } |
109 | | |
110 | | // ------------------------------------------------------------------------------------------------ |
111 | | // Construct a mesh from given vertex positions |
112 | | aiMesh *StandardShapes::MakeMesh(const std::vector<aiVector3D> &positions, |
113 | 0 | unsigned int numIndices) { |
114 | 0 | if (positions.empty() || !numIndices) { |
115 | 0 | return nullptr; |
116 | 0 | } |
117 | | |
118 | | // Determine which kinds of primitives the mesh consists of |
119 | 0 | aiMesh *out = new aiMesh(); |
120 | 0 | switch (numIndices) { |
121 | 0 | case 1: |
122 | 0 | out->mPrimitiveTypes = aiPrimitiveType_POINT; |
123 | 0 | break; |
124 | 0 | case 2: |
125 | 0 | out->mPrimitiveTypes = aiPrimitiveType_LINE; |
126 | 0 | break; |
127 | 0 | case 3: |
128 | 0 | out->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; |
129 | 0 | break; |
130 | 0 | default: |
131 | 0 | out->mPrimitiveTypes = aiPrimitiveType_POLYGON; |
132 | 0 | break; |
133 | 0 | }; |
134 | |
|
135 | 0 | out->mNumFaces = (unsigned int)positions.size() / numIndices; |
136 | 0 | out->mFaces = new aiFace[out->mNumFaces]; |
137 | 0 | for (unsigned int i = 0, a = 0; i < out->mNumFaces; ++i) { |
138 | 0 | aiFace &f = out->mFaces[i]; |
139 | 0 | f.mNumIndices = numIndices; |
140 | 0 | f.mIndices = new unsigned int[numIndices]; |
141 | 0 | for (unsigned int j = 0; j < numIndices; ++j, ++a) { |
142 | 0 | f.mIndices[j] = a; |
143 | 0 | } |
144 | 0 | } |
145 | 0 | out->mNumVertices = (unsigned int)positions.size(); |
146 | 0 | out->mVertices = new aiVector3D[out->mNumVertices]; |
147 | 0 | ::memcpy(out->mVertices, &positions[0], out->mNumVertices * sizeof(aiVector3D)); |
148 | |
|
149 | 0 | return out; |
150 | 0 | } |
151 | | |
152 | | // ------------------------------------------------------------------------------------------------ |
153 | | // Construct a mesh with a specific shape (callback) |
154 | | aiMesh *StandardShapes::MakeMesh(unsigned int (*GenerateFunc)( |
155 | 0 | std::vector<aiVector3D> &)) { |
156 | 0 | std::vector<aiVector3D> temp; |
157 | 0 | unsigned num = (*GenerateFunc)(temp); |
158 | 0 | return MakeMesh(temp, num); |
159 | 0 | } |
160 | | |
161 | | // ------------------------------------------------------------------------------------------------ |
162 | | // Construct a mesh with a specific shape (callback) |
163 | | aiMesh *StandardShapes::MakeMesh(unsigned int (*GenerateFunc)( |
164 | 0 | std::vector<aiVector3D> &, bool)) { |
165 | 0 | std::vector<aiVector3D> temp; |
166 | 0 | unsigned num = (*GenerateFunc)(temp, true); |
167 | 0 | return MakeMesh(temp, num); |
168 | 0 | } |
169 | | |
170 | | // ------------------------------------------------------------------------------------------------ |
171 | | // Construct a mesh with a specific shape (callback) |
172 | | aiMesh *StandardShapes::MakeMesh(unsigned int num, void (*GenerateFunc)( |
173 | 0 | unsigned int, std::vector<aiVector3D> &)) { |
174 | 0 | std::vector<aiVector3D> temp; |
175 | 0 | (*GenerateFunc)(num, temp); |
176 | 0 | return MakeMesh(temp, 3); |
177 | 0 | } |
178 | | |
179 | | // ------------------------------------------------------------------------------------------------ |
180 | | // Build an incosahedron with points.magnitude == 1 |
181 | 3 | unsigned int StandardShapes::MakeIcosahedron(std::vector<aiVector3D> &positions) { |
182 | 3 | positions.reserve(positions.size() + 60); |
183 | | |
184 | 3 | const ai_real t = (ai_real(1.0) + ai_real(2.236067977)) / ai_real(2.0); |
185 | 3 | const ai_real s = std::sqrt(ai_real(1.0) + t * t); |
186 | | |
187 | 3 | const aiVector3D v0 = aiVector3D(t, 1.0, 0.0) / s; |
188 | 3 | const aiVector3D v1 = aiVector3D(-t, 1.0, 0.0) / s; |
189 | 3 | const aiVector3D v2 = aiVector3D(t, -1.0, 0.0) / s; |
190 | 3 | const aiVector3D v3 = aiVector3D(-t, -1.0, 0.0) / s; |
191 | 3 | const aiVector3D v4 = aiVector3D(1.0, 0.0, t) / s; |
192 | 3 | const aiVector3D v5 = aiVector3D(1.0, 0.0, -t) / s; |
193 | 3 | const aiVector3D v6 = aiVector3D(-1.0, 0.0, t) / s; |
194 | 3 | const aiVector3D v7 = aiVector3D(-1.0, 0.0, -t) / s; |
195 | 3 | const aiVector3D v8 = aiVector3D(0.0, t, 1.0) / s; |
196 | 3 | const aiVector3D v9 = aiVector3D(0.0, -t, 1.0) / s; |
197 | 3 | const aiVector3D v10 = aiVector3D(0.0, t, -1.0) / s; |
198 | 3 | const aiVector3D v11 = aiVector3D(0.0, -t, -1.0) / s; |
199 | | |
200 | 3 | ADD_TRIANGLE(v0, v8, v4); |
201 | 3 | ADD_TRIANGLE(v0, v5, v10); |
202 | 3 | ADD_TRIANGLE(v2, v4, v9); |
203 | 3 | ADD_TRIANGLE(v2, v11, v5); |
204 | | |
205 | 3 | ADD_TRIANGLE(v1, v6, v8); |
206 | 3 | ADD_TRIANGLE(v1, v10, v7); |
207 | 3 | ADD_TRIANGLE(v3, v9, v6); |
208 | 3 | ADD_TRIANGLE(v3, v7, v11); |
209 | | |
210 | 3 | ADD_TRIANGLE(v0, v10, v8); |
211 | 3 | ADD_TRIANGLE(v1, v8, v10); |
212 | 3 | ADD_TRIANGLE(v2, v9, v11); |
213 | 3 | ADD_TRIANGLE(v3, v11, v9); |
214 | | |
215 | 3 | ADD_TRIANGLE(v4, v2, v0); |
216 | 3 | ADD_TRIANGLE(v5, v0, v2); |
217 | 3 | ADD_TRIANGLE(v6, v1, v3); |
218 | 3 | ADD_TRIANGLE(v7, v3, v1); |
219 | | |
220 | 3 | ADD_TRIANGLE(v8, v6, v4); |
221 | 3 | ADD_TRIANGLE(v9, v4, v6); |
222 | 3 | ADD_TRIANGLE(v10, v5, v7); |
223 | 3 | ADD_TRIANGLE(v11, v7, v5); |
224 | 3 | return 3; |
225 | 3 | } |
226 | | |
227 | | // ------------------------------------------------------------------------------------------------ |
228 | | // Build a dodecahedron with points.magnitude == 1 |
229 | | unsigned int StandardShapes::MakeDodecahedron(std::vector<aiVector3D> &positions, |
230 | 16 | bool polygons /*= false*/) { |
231 | 16 | positions.reserve(positions.size() + 108); |
232 | | |
233 | 16 | const ai_real a = ai_real(1.0) / ai_real(1.7320508); |
234 | 16 | const ai_real b = std::sqrt((ai_real(3.0) - ai_real(2.23606797)) / ai_real(6.0)); |
235 | 16 | const ai_real c = std::sqrt((ai_real(3.0) + ai_real(2.23606797f)) / ai_real(6.0)); |
236 | | |
237 | 16 | const aiVector3D v0 = aiVector3D(a, a, a); |
238 | 16 | const aiVector3D v1 = aiVector3D(a, a, -a); |
239 | 16 | const aiVector3D v2 = aiVector3D(a, -a, a); |
240 | 16 | const aiVector3D v3 = aiVector3D(a, -a, -a); |
241 | 16 | const aiVector3D v4 = aiVector3D(-a, a, a); |
242 | 16 | const aiVector3D v5 = aiVector3D(-a, a, -a); |
243 | 16 | const aiVector3D v6 = aiVector3D(-a, -a, a); |
244 | 16 | const aiVector3D v7 = aiVector3D(-a, -a, -a); |
245 | 16 | const aiVector3D v8 = aiVector3D(b, c, 0.0); |
246 | 16 | const aiVector3D v9 = aiVector3D(-b, c, 0.0); |
247 | 16 | const aiVector3D v10 = aiVector3D(b, -c, 0.0); |
248 | 16 | const aiVector3D v11 = aiVector3D(-b, -c, 0.0); |
249 | 16 | const aiVector3D v12 = aiVector3D(c, 0.0, b); |
250 | 16 | const aiVector3D v13 = aiVector3D(c, 0.0, -b); |
251 | 16 | const aiVector3D v14 = aiVector3D(-c, 0.0, b); |
252 | 16 | const aiVector3D v15 = aiVector3D(-c, 0.0, -b); |
253 | 16 | const aiVector3D v16 = aiVector3D(0.0, b, c); |
254 | 16 | const aiVector3D v17 = aiVector3D(0.0, -b, c); |
255 | 16 | const aiVector3D v18 = aiVector3D(0.0, b, -c); |
256 | 16 | const aiVector3D v19 = aiVector3D(0.0, -b, -c); |
257 | | |
258 | 16 | ADD_PENTAGON(v0, v8, v9, v4, v16); |
259 | 16 | ADD_PENTAGON(v0, v12, v13, v1, v8); |
260 | 16 | ADD_PENTAGON(v0, v16, v17, v2, v12); |
261 | 16 | ADD_PENTAGON(v8, v1, v18, v5, v9); |
262 | 16 | ADD_PENTAGON(v12, v2, v10, v3, v13); |
263 | 16 | ADD_PENTAGON(v16, v4, v14, v6, v17); |
264 | 16 | ADD_PENTAGON(v9, v5, v15, v14, v4); |
265 | | |
266 | 16 | ADD_PENTAGON(v6, v11, v10, v2, v17); |
267 | 16 | ADD_PENTAGON(v3, v19, v18, v1, v13); |
268 | 16 | ADD_PENTAGON(v7, v15, v5, v18, v19); |
269 | 16 | ADD_PENTAGON(v7, v11, v6, v14, v15); |
270 | 16 | ADD_PENTAGON(v7, v19, v3, v10, v11); |
271 | 16 | return (polygons ? 5 : 3); |
272 | 16 | } |
273 | | |
274 | | // ------------------------------------------------------------------------------------------------ |
275 | | // Build an octahedron with points.magnitude == 1 |
276 | 0 | unsigned int StandardShapes::MakeOctahedron(std::vector<aiVector3D> &positions) { |
277 | 0 | positions.reserve(positions.size() + 24); |
278 | |
|
279 | 0 | const aiVector3D v0 = aiVector3D(1.0, 0.0, 0.0); |
280 | 0 | const aiVector3D v1 = aiVector3D(-1.0, 0.0, 0.0); |
281 | 0 | const aiVector3D v2 = aiVector3D(0.0, 1.0, 0.0); |
282 | 0 | const aiVector3D v3 = aiVector3D(0.0, -1.0, 0.0); |
283 | 0 | const aiVector3D v4 = aiVector3D(0.0, 0.0, 1.0); |
284 | 0 | const aiVector3D v5 = aiVector3D(0.0, 0.0, -1.0); |
285 | |
|
286 | 0 | ADD_TRIANGLE(v4, v0, v2); |
287 | 0 | ADD_TRIANGLE(v4, v2, v1); |
288 | 0 | ADD_TRIANGLE(v4, v1, v3); |
289 | 0 | ADD_TRIANGLE(v4, v3, v0); |
290 | |
|
291 | 0 | ADD_TRIANGLE(v5, v2, v0); |
292 | 0 | ADD_TRIANGLE(v5, v1, v2); |
293 | 0 | ADD_TRIANGLE(v5, v3, v1); |
294 | 0 | ADD_TRIANGLE(v5, v0, v3); |
295 | 0 | return 3; |
296 | 0 | } |
297 | | |
298 | | // ------------------------------------------------------------------------------------------------ |
299 | | // Build a tetrahedron with points.magnitude == 1 |
300 | 0 | unsigned int StandardShapes::MakeTetrahedron(std::vector<aiVector3D> &positions) { |
301 | 0 | positions.reserve(positions.size() + 9); |
302 | |
|
303 | 0 | const ai_real invThree = ai_real(1.0) / ai_real(3.0); |
304 | 0 | const ai_real a = ai_real(1.41421) * invThree; |
305 | 0 | const ai_real b = ai_real(2.4494) * invThree; |
306 | |
|
307 | 0 | const aiVector3D v0 = aiVector3D(0.0, 0.0, 1.0); |
308 | 0 | const aiVector3D v1 = aiVector3D(2 * a, 0, -invThree); |
309 | 0 | const aiVector3D v2 = aiVector3D(-a, b, -invThree); |
310 | 0 | const aiVector3D v3 = aiVector3D(-a, -b, -invThree); |
311 | |
|
312 | 0 | ADD_TRIANGLE(v0, v1, v2); |
313 | 0 | ADD_TRIANGLE(v0, v2, v3); |
314 | 0 | ADD_TRIANGLE(v0, v3, v1); |
315 | 0 | ADD_TRIANGLE(v1, v3, v2); |
316 | 0 | return 3; |
317 | 0 | } |
318 | | |
319 | | // ------------------------------------------------------------------------------------------------ |
320 | | // Build a hexahedron with points.magnitude == 1 |
321 | | unsigned int StandardShapes::MakeHexahedron(std::vector<aiVector3D> &positions, |
322 | 0 | bool polygons /*= false*/) { |
323 | 0 | positions.reserve(positions.size() + 36); |
324 | 0 | const ai_real length = ai_real(1.0) / ai_real(1.73205080); |
325 | |
|
326 | 0 | const aiVector3D v0 = aiVector3D(-1.0, -1.0, -1.0) * length; |
327 | 0 | const aiVector3D v1 = aiVector3D(1.0, -1.0, -1.0) * length; |
328 | 0 | const aiVector3D v2 = aiVector3D(1.0, 1.0, -1.0) * length; |
329 | 0 | const aiVector3D v3 = aiVector3D(-1.0, 1.0, -1.0) * length; |
330 | 0 | const aiVector3D v4 = aiVector3D(-1.0, -1.0, 1.0) * length; |
331 | 0 | const aiVector3D v5 = aiVector3D(1.0, -1.0, 1.0) * length; |
332 | 0 | const aiVector3D v6 = aiVector3D(1.0, 1.0, 1.0) * length; |
333 | 0 | const aiVector3D v7 = aiVector3D(-1.0, 1.0, 1.0) * length; |
334 | |
|
335 | 0 | ADD_QUAD(v0, v3, v2, v1); |
336 | 0 | ADD_QUAD(v0, v1, v5, v4); |
337 | 0 | ADD_QUAD(v0, v4, v7, v3); |
338 | 0 | ADD_QUAD(v6, v5, v1, v2); |
339 | 0 | ADD_QUAD(v6, v2, v3, v7); |
340 | 0 | ADD_QUAD(v6, v7, v4, v5); |
341 | 0 | return (polygons ? 4 : 3); |
342 | 0 | } |
343 | | |
344 | | // Cleanup ... |
345 | | #undef ADD_TRIANGLE |
346 | | #undef ADD_QUAD |
347 | | #undef ADD_PENTAGON |
348 | | |
349 | | // ------------------------------------------------------------------------------------------------ |
350 | | // Create a subdivision sphere |
351 | | void StandardShapes::MakeSphere(unsigned int tess, |
352 | 3 | std::vector<aiVector3D> &positions) { |
353 | | // Reserve enough storage. Every subdivision |
354 | | // splits each triangle in 4, the icosahedron consists of 60 verts |
355 | 3 | positions.reserve(positions.size() + 60 * integer_pow(4, tess)); |
356 | | |
357 | | // Construct an icosahedron to start with |
358 | 3 | MakeIcosahedron(positions); |
359 | | |
360 | | // ... and subdivide it until the requested output |
361 | | // tessellation is reached |
362 | 15 | for (unsigned int i = 0; i < tess; ++i) |
363 | 12 | Subdivide(positions); |
364 | 3 | } |
365 | | |
366 | | // ------------------------------------------------------------------------------------------------ |
367 | | // Build a cone |
368 | | void StandardShapes::MakeCone(ai_real height, ai_real radius1, |
369 | | ai_real radius2, unsigned int tess, |
370 | 0 | std::vector<aiVector3D> &positions, bool bOpen /*= false */) { |
371 | | // Sorry, a cone with less than 3 segments makes ABSOLUTELY NO SENSE |
372 | 0 | if (tess < 3 || !height) |
373 | 0 | return; |
374 | | |
375 | 0 | size_t old = positions.size(); |
376 | | |
377 | | // No negative radii |
378 | 0 | radius1 = std::fabs(radius1); |
379 | 0 | radius2 = std::fabs(radius2); |
380 | |
|
381 | 0 | ai_real halfHeight = height / ai_real(2.0); |
382 | | |
383 | | // radius1 is always the smaller one |
384 | 0 | if (radius2 > radius1) { |
385 | 0 | std::swap(radius2, radius1); |
386 | 0 | halfHeight = -halfHeight; |
387 | 0 | } else |
388 | 0 | old = SIZE_MAX; |
389 | | |
390 | | // Use a large epsilon to check whether the cone is pointy |
391 | 0 | if (radius1 < (radius2 - radius1) * 10e-3) radius1 = 0.0; |
392 | | |
393 | | // We will need 3*2 verts per segment + 3*2 verts per segment |
394 | | // if the cone is closed |
395 | 0 | const unsigned int mem = tess * 6 + (!bOpen ? tess * 3 * (radius1 ? 2 : 1) : 0); |
396 | 0 | positions.reserve(positions.size() + mem); |
397 | | |
398 | | // Now construct all segments |
399 | 0 | const ai_real angle_delta = (ai_real)AI_MATH_TWO_PI / tess; |
400 | 0 | const ai_real angle_max = (ai_real)AI_MATH_TWO_PI; |
401 | |
|
402 | 0 | ai_real s = 1.0; // std::cos(angle == 0); |
403 | 0 | ai_real t = 0.0; // std::sin(angle == 0); |
404 | |
|
405 | 0 | for (ai_real angle = 0.0; angle < angle_max;) { |
406 | 0 | const aiVector3D v1 = aiVector3D(s * radius1, -halfHeight, t * radius1); |
407 | 0 | const aiVector3D v2 = aiVector3D(s * radius2, halfHeight, t * radius2); |
408 | |
|
409 | 0 | const ai_real next = angle + angle_delta; |
410 | 0 | ai_real s2 = std::cos(next); |
411 | 0 | ai_real t2 = std::sin(next); |
412 | |
|
413 | 0 | const aiVector3D v3 = aiVector3D(s2 * radius2, halfHeight, t2 * radius2); |
414 | 0 | const aiVector3D v4 = aiVector3D(s2 * radius1, -halfHeight, t2 * radius1); |
415 | |
|
416 | 0 | positions.push_back(v1); |
417 | 0 | positions.push_back(v2); |
418 | 0 | positions.push_back(v3); |
419 | 0 | positions.push_back(v4); |
420 | 0 | positions.push_back(v1); |
421 | 0 | positions.push_back(v3); |
422 | |
|
423 | 0 | if (!bOpen) { |
424 | 0 | const ai_real zero(0.0); |
425 | | |
426 | | // generate the end 'cap' |
427 | 0 | positions.emplace_back(s * radius2, halfHeight, t * radius2); |
428 | 0 | positions.emplace_back(s2 * radius2, halfHeight, t2 * radius2); |
429 | 0 | positions.emplace_back(zero, halfHeight, zero); |
430 | |
|
431 | 0 | if (radius1) { |
432 | | // generate the other end 'cap' |
433 | 0 | positions.emplace_back(s * radius1, -halfHeight, t * radius1); |
434 | 0 | positions.emplace_back(s2 * radius1, -halfHeight, t2 * radius1); |
435 | 0 | positions.emplace_back(zero, -halfHeight, zero); |
436 | 0 | } |
437 | 0 | } |
438 | 0 | s = s2; |
439 | 0 | t = t2; |
440 | 0 | angle = next; |
441 | 0 | } |
442 | | |
443 | | // Need to flip face order? |
444 | 0 | if (SIZE_MAX != old) { |
445 | 0 | for (size_t p = old; p < positions.size(); p += 3) { |
446 | 0 | std::swap(positions[p], positions[p + 1]); |
447 | 0 | } |
448 | 0 | } |
449 | 0 | } |
450 | | |
451 | | // ------------------------------------------------------------------------------------------------ |
452 | | // Build a circle |
453 | | void StandardShapes::MakeCircle(ai_real radius, unsigned int tess, |
454 | 0 | std::vector<aiVector3D> &positions) { |
455 | | // Sorry, a circle with less than 3 segments makes ABSOLUTELY NO SENSE |
456 | 0 | if (tess < 3 || !radius) |
457 | 0 | return; |
458 | | |
459 | 0 | radius = std::fabs(radius); |
460 | | |
461 | | // We will need 3 vertices per segment |
462 | 0 | positions.reserve(positions.size() + tess * 3); |
463 | |
|
464 | 0 | const ai_real angle_delta = (ai_real)AI_MATH_TWO_PI / tess; |
465 | 0 | const ai_real angle_max = (ai_real)AI_MATH_TWO_PI; |
466 | |
|
467 | 0 | ai_real s = 1.0; // std::cos(angle == 0); |
468 | 0 | ai_real t = 0.0; // std::sin(angle == 0); |
469 | |
|
470 | 0 | for (ai_real angle = 0.0; angle < angle_max;) { |
471 | 0 | const ai_real zero(0.0); |
472 | 0 | positions.emplace_back(s * radius, zero, t * radius); |
473 | 0 | angle += angle_delta; |
474 | 0 | s = std::cos(angle); |
475 | 0 | t = std::sin(angle); |
476 | 0 | positions.emplace_back(s * radius, zero, t * radius); |
477 | |
|
478 | 0 | positions.emplace_back(zero, zero, zero); |
479 | 0 | } |
480 | 0 | } |
481 | | |
482 | | } // namespace Assimp |