16.12.2021, 9:00 - 11:00: Due to updates GitLab may be unavailable for some minutes between 09:00 and 11:00.

geometrydatafactory.cpp 18.5 KB
Newer Older
1
2
3
4
// ================================================================================================
// 
// This file is part of the CAMPVis Software Framework.
// 
5
// If not explicitly stated otherwise: Copyright (C) 2012-2015, all rights reserved,
6
7
//      Christian Schulte zu Berge <christian.szb@in.tum.de>
//      Chair for Computer Aided Medical Procedures
8
9
//      Technische Universitaet Muenchen
//      Boltzmannstr. 3, 85748 Garching b. Muenchen, Germany
10
// 
11
12
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
// 
13
14
15
16
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 
// except in compliance with the License. You may obtain a copy of the License at
// 
// http://www.apache.org/licenses/LICENSE-2.0
17
// 
18
19
20
21
// Unless required by applicable law or agreed to in writing, software distributed under the 
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
// either express or implied. See the License for the specific language governing permissions 
// and limitations under the License.
22
23
24
25
26
// 
// ================================================================================================

#include "geometrydatafactory.h"

27
#include "cgt/assert.h"
28

29
30
#include "core/tools/teapot.h"

31
32
namespace campvis {

33
    std::unique_ptr<FaceGeometry> GeometryDataFactory::createQuad(const cgt::vec3& llf, const cgt::vec3& urb, const cgt::vec3& texLlf, const cgt::vec3& texUrb) {
34
        std::vector<cgt::vec3> vertices, texCorods;
35

36
37
38
39
        vertices.push_back(cgt::vec3(llf.x, llf.y, llf.z));
        vertices.push_back(cgt::vec3(urb.x, llf.y, llf.z));
        vertices.push_back(cgt::vec3(urb.x, urb.y, llf.z));
        vertices.push_back(cgt::vec3(llf.x, urb.y, llf.z));
40

41
42
43
44
        texCorods.push_back(cgt::vec3(texLlf.x, texLlf.y, texLlf.z));
        texCorods.push_back(cgt::vec3(texUrb.x, texLlf.y, texLlf.z));
        texCorods.push_back(cgt::vec3(texUrb.x, texUrb.y, texLlf.z));
        texCorods.push_back(cgt::vec3(texLlf.x, texUrb.y, texLlf.z));
45

46
        return std::unique_ptr<FaceGeometry>(new FaceGeometry(vertices, texCorods));
47
48
    }

49
    std::unique_ptr<MultiIndexedGeometry> GeometryDataFactory::createGrid(const cgt::vec3& llf, const cgt::vec3& urb, const cgt::vec3& texLlf, const cgt::vec3& texUrb, int xSegments, int ySegments) {
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
        cgtAssert(xSegments > 0 && ySegments > 1, "Grid must have at least one segment in each direction");

        int numVertices = (xSegments + 1) * (ySegments + 1);
        std::vector<cgt::vec3> vertices(numVertices);
        std::vector<cgt::vec3> textureCoordinates(numVertices);
        std::vector<cgt::vec3> normals(numVertices);

        // Compute vertices of the grid in x-major order
        for (int y = 0; y <= ySegments; ++y) {
            for (int x = 0; x <= xSegments; ++x) {
                int idx = y * (xSegments + 1) + x;

                float ux = x / static_cast<float>(xSegments);
                float uy = y / static_cast<float>(ySegments);

                vertices[idx] = cgt::vec3(llf.x * (1-ux) + urb.x * ux,
                                          llf.y * (1-uy) + urb.y * uy,
                                          llf.z);
                textureCoordinates[idx] = cgt::vec3(texLlf.x * (1-ux) + texUrb.x * ux,
                                                    texLlf.y * (1-uy) + texUrb.y * uy,
                                                    texLlf.z);
                normals[idx] = cgt::vec3(0, 0, 1);
            }
        }

75
        auto result = new MultiIndexedGeometry(vertices, textureCoordinates, std::vector<cgt::vec4>(), normals);
76

Jakob Weiss's avatar
Jakob Weiss committed
77
        // For each horizontal stripe, construct the indices for triangle strips
78
79
        int verticesPerStrip = (xSegments + 1) * 2;
        for (int y = 0; y < ySegments; ++y) {
Jakob Weiss's avatar
Jakob Weiss committed
80
81
            std::vector<MultiIndexedGeometry::index_t> indices(verticesPerStrip);
            for (MultiIndexedGeometry::index_t x = 0; x <= static_cast<MultiIndexedGeometry::index_t>(xSegments); ++x) {
82
83
84
85
86
87
88
                indices[x*2 + 0] = (y + 0) * (xSegments + 1) + x;
                indices[x*2 + 1] = (y + 1) * (xSegments + 1) + x;
            }

            result->addPrimitive(indices);
        }

89
        return std::unique_ptr<MultiIndexedGeometry>(result);
90
91
92
    }


93
    std::unique_ptr<MeshGeometry> GeometryDataFactory::createCube(const cgt::Bounds& bounds, const cgt::Bounds& texBounds, const cgt::mat4& trans/* = cgt::mat4::identit*/) {
94
95
96
97
        const cgt::vec3& llf = bounds.getLLF();
        const cgt::vec3& urb = bounds.getURB();
        const cgt::vec3& tLlf = texBounds.getLLF();
        const cgt::vec3& tUrb = texBounds.getURB();
98
99

        // not the most elegant method, but it works...
100
        std::vector<cgt::vec3> vertices, texCoords;
101
102
103
        std::vector<FaceGeometry> faces;

        // front
104
        texCoords.push_back(cgt::vec3(tLlf.x, tUrb.y, tLlf.z));
105
        vertices.push_back(trans*cgt::vec3(llf.x, urb.y, llf.z));
106
        texCoords.push_back(cgt::vec3(tUrb.x, tUrb.y, tLlf.z));
107
        vertices.push_back(trans*cgt::vec3(urb.x, urb.y, llf.z));
108
        texCoords.push_back(cgt::vec3(tUrb.x, tLlf.y, tLlf.z));
109
        vertices.push_back(trans*cgt::vec3(urb.x, llf.y, llf.z));
110
        texCoords.push_back(cgt::vec3(tLlf.x, tLlf.y, tLlf.z));
111
        vertices.push_back(trans*cgt::vec3(llf.x, llf.y, llf.z));
112
        faces.push_back(FaceGeometry(vertices, texCoords, std::vector<cgt::vec4>(), std::vector<cgt::vec3>(4, cgt::vec3(0.f, 0.f, -1.f))));
113
114
115
116
        vertices.clear();
        texCoords.clear();

        // right
117
        texCoords.push_back(cgt::vec3(tUrb.x, tUrb.y, tLlf.z));
118
        vertices.push_back(trans*cgt::vec3(urb.x, urb.y, llf.z));
119
        texCoords.push_back(cgt::vec3(tUrb.x, tUrb.y, tUrb.z));
120
        vertices.push_back(trans*cgt::vec3(urb.x, urb.y, urb.z));
121
        texCoords.push_back(cgt::vec3(tUrb.x, tLlf.y, tUrb.z));
122
        vertices.push_back(trans*cgt::vec3(urb.x, llf.y, urb.z));
123
        texCoords.push_back(cgt::vec3(tUrb.x, tLlf.y, tLlf.z));
124
        vertices.push_back(trans*cgt::vec3(urb.x, llf.y, llf.z));
125
        faces.push_back(FaceGeometry(vertices, texCoords, std::vector<cgt::vec4>(), std::vector<cgt::vec3>(4, cgt::vec3(1.f, 0.f, 0.f))));
126
127
128
129
        vertices.clear();
        texCoords.clear();

        // top
130
        texCoords.push_back(cgt::vec3(tLlf.x, tUrb.y, tUrb.z));
131
        vertices.push_back(trans*cgt::vec3(llf.x, urb.y, urb.z));
132
        texCoords.push_back(cgt::vec3(tUrb.x, tUrb.y, tUrb.z));
133
        vertices.push_back(trans*cgt::vec3(urb.x, urb.y, urb.z));
134
        texCoords.push_back(cgt::vec3(tUrb.x, tUrb.y, tLlf.z));
135
        vertices.push_back(trans*cgt::vec3(urb.x, urb.y, llf.z));
136
        texCoords.push_back(cgt::vec3(tLlf.x, tUrb.y, tLlf.z));
137
        vertices.push_back(trans*cgt::vec3(llf.x, urb.y, llf.z));
138
        faces.push_back(FaceGeometry(vertices, texCoords, std::vector<cgt::vec4>(), std::vector<cgt::vec3>(4, cgt::vec3(0.f, 1.f, 0.f))));
139
140
141
142
        vertices.clear();
        texCoords.clear();

        // left
143
        texCoords.push_back(cgt::vec3(tLlf.x, tUrb.y, tUrb.z));
144
        vertices.push_back(trans*cgt::vec3(llf.x, urb.y, urb.z));
145
        texCoords.push_back(cgt::vec3(tLlf.x, tUrb.y, tLlf.z));
146
        vertices.push_back(trans*cgt::vec3(llf.x, urb.y, llf.z));
147
        texCoords.push_back(cgt::vec3(tLlf.x, tLlf.y, tLlf.z));
148
        vertices.push_back(trans*cgt::vec3(llf.x, llf.y, llf.z));
149
        texCoords.push_back(cgt::vec3(tLlf.x, tLlf.y, tUrb.z));
150
        vertices.push_back(trans*cgt::vec3(llf.x, llf.y, urb.z));
151
        faces.push_back(FaceGeometry(vertices, texCoords, std::vector<cgt::vec4>(), std::vector<cgt::vec3>(4, cgt::vec3(-1.f, 0.f, 0.f))));
152
153
154
155
        vertices.clear();
        texCoords.clear();

        // bottom
156
        texCoords.push_back(cgt::vec3(tLlf.x, tLlf.y, tLlf.z));
157
        vertices.push_back(trans*cgt::vec3(llf.x, llf.y, llf.z));
158
        texCoords.push_back(cgt::vec3(tUrb.x, tLlf.y, tLlf.z));
159
        vertices.push_back(trans*cgt::vec3(urb.x, llf.y, llf.z));
160
        texCoords.push_back(cgt::vec3(tUrb.x, tLlf.y, tUrb.z));
161
        vertices.push_back(trans*cgt::vec3(urb.x, llf.y, urb.z));
162
        texCoords.push_back(cgt::vec3(tLlf.x, tLlf.y, tUrb.z));
163
        vertices.push_back(trans*cgt::vec3(llf.x, llf.y, urb.z));
164
        faces.push_back(FaceGeometry(vertices, texCoords, std::vector<cgt::vec4>(), std::vector<cgt::vec3>(4, cgt::vec3(0.f, -1.f, 0.f))));
165
166
167
168
        vertices.clear();
        texCoords.clear();

        // back
169
        texCoords.push_back(cgt::vec3(tUrb.x, tUrb.y, tUrb.z));
170
        vertices.push_back(trans*cgt::vec3(urb.x, urb.y, urb.z));
171
        texCoords.push_back(cgt::vec3(tLlf.x, tUrb.y, tUrb.z));
172
        vertices.push_back(trans*cgt::vec3(llf.x, urb.y, urb.z));
173
        texCoords.push_back(cgt::vec3(tLlf.x, tLlf.y, tUrb.z));
174
        vertices.push_back(trans*cgt::vec3(llf.x, llf.y, urb.z));
175
        texCoords.push_back(cgt::vec3(tUrb.x, tLlf.y, tUrb.z));
176
        vertices.push_back(trans*cgt::vec3(urb.x, llf.y, urb.z));
177
        faces.push_back(FaceGeometry(vertices, texCoords, std::vector<cgt::vec4>(), std::vector<cgt::vec3>(4, cgt::vec3(0.f, 0.f, 1.f))));
178
179
180
        vertices.clear();
        texCoords.clear();

181
        return std::unique_ptr<MeshGeometry>(new MeshGeometry(faces));
182
183
    }

184
    std::unique_ptr<MultiIndexedGeometry> GeometryDataFactory::createTeapot() {
185
        std::vector<cgt::vec3> vertices, normals;
186
187
        vertices.reserve(Teapot::num_teapot_vertices);
        normals.reserve(Teapot::num_teapot_vertices);
188

189
        for (size_t i = 0; i < Teapot::num_teapot_vertices; ++i) {
190
191
            vertices.push_back(cgt::vec3(Teapot::teapot_vertices + 3*i));
            normals.push_back(cgt::vec3(Teapot::teapot_normals + 3*i));
192
193
        }

194
        MultiIndexedGeometry* toReturn = new MultiIndexedGeometry(vertices, std::vector<cgt::vec3>(), std::vector<cgt::vec4>(), normals);
195
196
197

        // convert indices and add primitives 
        int currentOffset = 0;
198
        while (currentOffset < Teapot::num_teapot_indices) {
Jakob Weiss's avatar
Jakob Weiss committed
199
200
            MultiIndexedGeometry::index_t count = Teapot::new_teapot_indicies[currentOffset];
            toReturn->addPrimitive(std::vector<MultiIndexedGeometry::index_t>(Teapot::new_teapot_indicies + currentOffset + 1, Teapot::new_teapot_indicies + count + currentOffset + 1));
201
202
203
            currentOffset += count + 1;
        }

204
        return std::unique_ptr<MultiIndexedGeometry>(toReturn);
205
206
    }

207
    std::unique_ptr<MultiIndexedGeometry> GeometryDataFactory::createSphere(uint16_t numStacks /*= 6*/, uint16_t numSlices /*= 12*/, const cgt::vec3& exponents /*= cgt::vec3(1.f)*/) {
208
209
210
        cgtAssert(numStacks > 1 && numSlices > 2, "Sphere must have minimum 2 stacks and 3 slices!");
        std::vector<cgt::vec3> vertices;
        std::vector<cgt::vec3> textureCoordinates;
211
212

        // add top vertex
213
214
        vertices.push_back(cgt::vec3(0.f, 0.f, 1.f));
        textureCoordinates.push_back(cgt::vec3(0.f));
215
216
217

        // add middle vertices
        for (int i = 1; i < numStacks; ++i) {
218
            float phi = static_cast<float>(i) * cgt::PIf / static_cast<float>(numStacks);
219
220

            for (int j = 0; j < numSlices; ++j) {
221
                float theta = static_cast<float>(j) * 2.f*cgt::PIf / static_cast<float>(numSlices);
222
223
224
225
226
227
228
229
230
231
232

                // apply exponents for supersphere
                cgt::vec3 theVertex(cos(theta) * sin(phi), sin(theta) * sin(phi), cos(phi));
                for (size_t e = 0; e < 3; ++e) {
                    if (theVertex[e] < 0)
                        theVertex[e] = -pow(-theVertex[e], exponents[e]);
                    else
                        theVertex[e] = pow(theVertex[e], exponents[e]);
                }

                vertices.push_back(theVertex);
233
                textureCoordinates.push_back(cgt::vec3(theta / (2.f * cgt::PIf), phi / cgt::PIf, 0.f));
234
235
236
237
            }
        }

        // add bottom vertex
238
239
        vertices.push_back(cgt::vec3(0.f, 0.f, -1.f));
        textureCoordinates.push_back(cgt::vec3(1.f, 0.f, 0.f));
240
241

        // create geometry (in a unit sphere vertices = normals)
242
        MultiIndexedGeometry* toReturn = new MultiIndexedGeometry(vertices, textureCoordinates, std::vector<cgt::vec4>(), vertices);
243
244
245
246

        // add indices for primitives to geometry:
        {
            // top stack:
Jakob Weiss's avatar
Jakob Weiss committed
247
248
            std::vector<MultiIndexedGeometry::index_t> indices;
            for (MultiIndexedGeometry::index_t j = 0; j < numSlices; ++j) {
249
250
251
252
253
254
255
256
257
258
                indices.push_back(0);
                indices.push_back(j+1);
            }
            indices.push_back(0);
            indices.push_back(1);

            toReturn->addPrimitive(indices);
        }
        {
            // middle stacks:
Jakob Weiss's avatar
Jakob Weiss committed
259
260
261
            std::vector<MultiIndexedGeometry::index_t> indices;
            for (MultiIndexedGeometry::index_t i = 1; i < static_cast<MultiIndexedGeometry::index_t>(numStacks-1); ++i) {
                MultiIndexedGeometry::index_t startIndex = 1 + (i-1) * numSlices;
262

Jakob Weiss's avatar
Jakob Weiss committed
263
                for (MultiIndexedGeometry::index_t j = 0; j < numSlices; ++j) {
264
265
266
267
268
269
270
271
272
273
274
                    indices.push_back(startIndex + j);
                    indices.push_back(startIndex + numSlices + j);
                }
                indices.push_back(startIndex);
                indices.push_back(startIndex + numSlices);
            }

            toReturn->addPrimitive(indices);
        }
        {
            // bottom stack:
Jakob Weiss's avatar
Jakob Weiss committed
275
276
            std::vector<MultiIndexedGeometry::index_t> indices;
            MultiIndexedGeometry::index_t endIndex = static_cast<MultiIndexedGeometry::index_t>(vertices.size() - 1);
277

Jakob Weiss's avatar
Jakob Weiss committed
278
            for (MultiIndexedGeometry::index_t j = 0; j < numSlices; ++j) {
279
280
281
282
283
284
285
286
287
                indices.push_back(endIndex);
                indices.push_back(endIndex - (j+1));
            }
            indices.push_back(endIndex);
            indices.push_back(endIndex - 1);

            toReturn->addPrimitive(indices);
        }

288
        return std::unique_ptr<MultiIndexedGeometry>(toReturn);
289
290
    }

291
    std::unique_ptr<MultiIndexedGeometry> GeometryDataFactory::createArrow(uint16_t numSlices, float tipLen, float cylRadius, float tipRadius) {
292
293
294
295
296
297
        cgtAssert(numSlices > 2, "Arrow shaft must have minimum 3 slices!");
        cgtAssert(tipRadius > cylRadius, "Tip radius must exceed cyclinder radius (for correct normals)!");
        cgtAssert(tipLen > 0, "Tip length must be between 0 and 1!");
        cgtAssert(tipLen < 1, "Tip length must be between 0 and 1!");
        std::vector<cgt::vec3> vertices;
        std::vector<cgt::vec3> normals;
298

299
        // add bottom vertex
300
301
        vertices.push_back(cgt::vec3(0.f, 0.f, 0.f));
        normals.push_back(cgt::vec3(0.f, 0.f, -1.f));
302

303
304
        // add shaft floor vertices
        for (int i = 0; i < numSlices; ++i) {
305
306
307
            float theta = static_cast<float>(i) * 2.f*cgt::PIf / static_cast<float>(numSlices);
            vertices.push_back(cgt::vec3(cylRadius * cos(theta), cylRadius * sin(theta), 0.f));
            normals.push_back(cgt::vec3(0.f, 0.f, -1.f));
308
309
        }
        for (int i = 0; i < numSlices; ++i) {
310
311
312
            float theta = static_cast<float>(i) * 2.f*cgt::PIf / static_cast<float>(numSlices);
            vertices.push_back(cgt::vec3(cylRadius * cos(theta), cylRadius * sin(theta), 0.f));
            normals.push_back(cgt::vec3(cos(theta), sin(theta), 0.f));
313
        }
314

315
316
        // add shaft top vertices
        for (int i = 0; i < numSlices; ++i) {
317
318
319
            float theta = static_cast<float>(i) * 2.f*cgt::PIf / static_cast<float>(numSlices);
            vertices.push_back(cgt::vec3(cylRadius * cos(theta), cylRadius * sin(theta), 1.f - tipLen));
            normals.push_back(cgt::vec3(cos(theta), sin(theta), 0.f));
320
321
        }
        for (int i = 0; i < numSlices; ++i) {
322
323
324
            float theta = static_cast<float>(i) * 2.f*cgt::PIf / static_cast<float>(numSlices);
            vertices.push_back(cgt::vec3(cylRadius * cos(theta), cylRadius * sin(theta), 1.f - tipLen));
            normals.push_back(cgt::vec3(0.f, 0.f, -1.f));
325
        }
326

327
328
        // add arrow tip outer cone vertices
        for (int i = 0; i < numSlices; ++i) {
329
330
331
            float theta = static_cast<float>(i) * 2.f*cgt::PIf / static_cast<float>(numSlices);
            vertices.push_back(cgt::vec3(tipRadius * cos(theta), tipRadius * sin(theta), 1.f - tipLen));
            normals.push_back(cgt::vec3(0.f, 0.f, -1.f));
332
333
334
        }
        float phi = atan2f(tipRadius, tipLen);
        for (int i = 0; i < numSlices; ++i) {
335
336
337
            float theta = static_cast<float>(i) * 2.f*cgt::PIf / static_cast<float>(numSlices);
            vertices.push_back(cgt::vec3(tipRadius * cos(theta), tipRadius * sin(theta), 1.f - tipLen));
            normals.push_back(cgt::vec3(cos(theta) * cos(phi), sin(theta) * cos(phi), sin(phi)));
338
        }
339

340
        // add top vertex
341
342
        vertices.push_back(cgt::vec3(0.f, 0.f, 1.f));
        normals.push_back(cgt::vec3(0.f, 0.f, 1.f));
343
344

        // create geometry
345
        MultiIndexedGeometry* toReturn = new MultiIndexedGeometry(vertices, std::vector<cgt::vec3>(), std::vector<cgt::vec4>(), normals);
346
347
348
349

        // add indices for primitives to geometry:
        {
            // cylinder floor
Jakob Weiss's avatar
Jakob Weiss committed
350
351
            std::vector<MultiIndexedGeometry::index_t> indices;
            for (MultiIndexedGeometry::index_t j = 0; j < numSlices; ++j) {
352
353
354
355
356
357
358
359
                indices.push_back(0);
                indices.push_back(j+1);
            }
            indices.push_back(0);
            indices.push_back(1);

            toReturn->addPrimitive(indices);
        }
360
        {
361
            // cylinder shaft
Jakob Weiss's avatar
Jakob Weiss committed
362
363
            std::vector<MultiIndexedGeometry::index_t> indices;
            for (MultiIndexedGeometry::index_t j = 0; j < numSlices; ++j) {
364
365
366
367
368
369
370
371
                indices.push_back(j+1+numSlices);
                indices.push_back(j+1+numSlices*2);
            }
            indices.push_back(1+numSlices);
            indices.push_back(1+numSlices*2);

            toReturn->addPrimitive(indices);
        }
372
        {
373
            // arrow tip bottom area
Jakob Weiss's avatar
Jakob Weiss committed
374
375
            std::vector<MultiIndexedGeometry::index_t> indices;
            for (MultiIndexedGeometry::index_t j = 0; j < numSlices; ++j) {
376
377
378
379
380
381
382
383
                indices.push_back(j+1+numSlices*3);
                indices.push_back(j+1+numSlices*4);
            }
            indices.push_back(1+numSlices*3);
            indices.push_back(1+numSlices*4);

            toReturn->addPrimitive(indices);
        }
384
        {
385
            // arrow tip cone
386
            uint16_t m = static_cast<uint16_t>(vertices.size() - 1);
Jakob Weiss's avatar
Jakob Weiss committed
387
388
            std::vector<MultiIndexedGeometry::index_t> indices;
            for (MultiIndexedGeometry::index_t j = 0; j < numSlices; ++j) {
389
                indices.push_back(j+1+numSlices*5);
390
                indices.push_back(m);
391
392
393
394
395
396
397
            }
            indices.push_back(1+numSlices*5);
            indices.push_back(m);

            toReturn->addPrimitive(indices);
        }

398
        return std::unique_ptr<MultiIndexedGeometry>(toReturn);
399
    }
400

401
}