Coverage Report

Created: 2025-11-11 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/assimp/code/AssetLib/X3D/X3DGeoHelper.cpp
Line
Count
Source
1
#include "X3DGeoHelper.h"
2
#include "X3DImporter.hpp"
3
4
#include <assimp/vector3.h>
5
#include <assimp/Exceptional.h>
6
#include <assimp/StringUtils.h>
7
8
#include <vector>
9
10
namespace Assimp {
11
12
0
aiVector3D X3DGeoHelper::make_point2D(float angle, float radius) {
13
0
    return aiVector3D(radius * std::cos(angle), radius * std::sin(angle), 0);
14
0
}
15
16
0
void X3DGeoHelper::make_arc2D(float pStartAngle, float pEndAngle, float pRadius, size_t numSegments, std::list<aiVector3D> &pVertices) {
17
    // check argument values ranges.
18
0
    if ((pStartAngle < -AI_MATH_TWO_PI_F) || (pStartAngle > AI_MATH_TWO_PI_F)) {
19
0
        throw DeadlyImportError("GeometryHelper_Make_Arc2D.pStartAngle");
20
0
    }
21
0
    if ((pEndAngle < -AI_MATH_TWO_PI_F) || (pEndAngle > AI_MATH_TWO_PI_F)) {
22
0
        throw DeadlyImportError("GeometryHelper_Make_Arc2D.pEndAngle");
23
0
    }
24
0
    if (pRadius <= 0) {
25
0
        throw DeadlyImportError("GeometryHelper_Make_Arc2D.pRadius");
26
0
    }
27
28
    // calculate arc angle and check type of arc
29
0
    float angle_full = std::fabs(pEndAngle - pStartAngle);
30
0
    if ((angle_full > AI_MATH_TWO_PI_F) || (angle_full == 0.0f)) {
31
0
        angle_full = AI_MATH_TWO_PI_F;
32
0
    }
33
34
    // calculate angle for one step - angle to next point of line.
35
0
    float angle_step = angle_full / (float)numSegments;
36
    // make points
37
0
    for (size_t pi = 0; pi <= numSegments; pi++) {
38
0
        float tangle = pStartAngle + pi * angle_step;
39
0
        pVertices.emplace_back(make_point2D(tangle, pRadius));
40
0
    } // for(size_t pi = 0; pi <= pNumSegments; pi++)
41
42
    // if we making full circle then add last vertex equal to first vertex
43
0
    if (angle_full == AI_MATH_TWO_PI_F) pVertices.push_back(*pVertices.begin());
44
0
}
45
46
0
void X3DGeoHelper::extend_point_to_line(const std::list<aiVector3D> &pPoint, std::list<aiVector3D> &pLine) {
47
0
    std::list<aiVector3D>::const_iterator pit = pPoint.begin();
48
0
    std::list<aiVector3D>::const_iterator pit_last = pPoint.end();
49
50
0
    --pit_last;
51
52
0
    if (pPoint.size() < 2) {
53
0
        throw DeadlyImportError("GeometryHelper_Extend_PointToLine.pPoint.size() can not be less than 2.");
54
0
    }
55
56
    // add first point of first line.
57
0
    pLine.push_back(*pit++);
58
    // add internal points
59
0
    while (pit != pit_last) {
60
0
        pLine.push_back(*pit); // second point of previous line
61
0
        pLine.push_back(*pit); // first point of next line
62
0
        ++pit;
63
0
    }
64
    // add last point of last line
65
0
    pLine.push_back(*pit);
66
0
}
67
68
0
void X3DGeoHelper::polylineIdx_to_lineIdx(const std::list<int32_t> &pPolylineCoordIdx, std::list<int32_t> &pLineCoordIdx) {
69
0
    std::list<int32_t>::const_iterator plit = pPolylineCoordIdx.begin();
70
71
0
    while (plit != pPolylineCoordIdx.end()) {
72
        // add first point of polyline
73
0
        pLineCoordIdx.push_back(*plit++);
74
0
        while ((*plit != (-1)) && (plit != pPolylineCoordIdx.end())) {
75
0
            std::list<int32_t>::const_iterator plit_next;
76
77
0
            plit_next = plit, ++plit_next;
78
0
            pLineCoordIdx.push_back(*plit); // second point of previous line.
79
0
            pLineCoordIdx.push_back(-1); // delimiter
80
0
            if ((*plit_next == (-1)) || (plit_next == pPolylineCoordIdx.end())) break; // current polyline is finished
81
82
0
            pLineCoordIdx.push_back(*plit); // first point of next line.
83
0
            plit = plit_next;
84
0
        } // while((*plit != (-1)) && (plit != pPolylineCoordIdx.end()))
85
0
    } // while(plit != pPolylineCoordIdx.end())
86
0
}
87
88
#define MACRO_FACE_ADD_QUAD_FA(pCCW, pOut, pIn, pP1, pP2, pP3, pP4) \
89
0
    do {                                                            \
90
0
        if (pCCW) {                                                 \
91
0
            pOut.push_back(pIn[pP1]);                               \
92
0
            pOut.push_back(pIn[pP2]);                               \
93
0
            pOut.push_back(pIn[pP3]);                               \
94
0
            pOut.push_back(pIn[pP4]);                               \
95
0
        } else {                                                    \
96
0
            pOut.push_back(pIn[pP4]);                               \
97
0
            pOut.push_back(pIn[pP3]);                               \
98
0
            pOut.push_back(pIn[pP2]);                               \
99
0
            pOut.push_back(pIn[pP1]);                               \
100
0
        }                                                           \
101
0
    } while (false)
102
103
#define MESH_RectParallelepiped_CREATE_VERT \
104
0
    aiVector3D vert_set[8];                 \
105
0
    float x1, x2, y1, y2, z1, z2, hs;       \
106
0
                                            \
107
0
    hs = pSize.x / 2, x1 = -hs, x2 = hs;    \
108
0
    hs = pSize.y / 2, y1 = -hs, y2 = hs;    \
109
0
    hs = pSize.z / 2, z1 = -hs, z2 = hs;    \
110
0
    vert_set[0].Set(x2, y1, z2);            \
111
0
    vert_set[1].Set(x2, y2, z2);            \
112
0
    vert_set[2].Set(x2, y2, z1);            \
113
0
    vert_set[3].Set(x2, y1, z1);            \
114
0
    vert_set[4].Set(x1, y1, z2);            \
115
0
    vert_set[5].Set(x1, y2, z2);            \
116
0
    vert_set[6].Set(x1, y2, z1);            \
117
0
    vert_set[7].Set(x1, y1, z1)
118
119
0
void X3DGeoHelper::rect_parallel_epiped(const aiVector3D &pSize, std::list<aiVector3D> &pVertices) {
120
0
    MESH_RectParallelepiped_CREATE_VERT;
121
0
    MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 3, 2, 1, 0); // front
122
0
    MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 6, 7, 4, 5); // back
123
0
    MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 7, 3, 0, 4); // left
124
0
    MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 2, 6, 5, 1); // right
125
0
    MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 0, 1, 5, 4); // top
126
0
    MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 7, 6, 2, 3); // bottom
127
0
}
128
129
#undef MESH_RectParallelepiped_CREATE_VERT
130
131
static constexpr int InvalidIndex = -1;
132
133
0
void X3DGeoHelper::coordIdx_str2faces_arr(const std::vector<int32_t> &pCoordIdx, std::vector<aiFace> &pFaces, unsigned int &pPrimitiveTypes) {
134
0
    std::vector<int32_t> f_data(pCoordIdx);
135
0
    std::vector<unsigned int> inds;
136
0
    unsigned int prim_type = 0;
137
138
0
    if (!f_data.empty()) {
139
0
        if (f_data.back() != InvalidIndex) {
140
0
            f_data.push_back(InvalidIndex);
141
0
        }
142
0
    }
143
144
    // reserve average size.
145
0
    pFaces.reserve(f_data.size() / 3);
146
0
    inds.reserve(4);
147
    //PrintVectorSet("build. ci", pCoordIdx);
148
0
    for (std::vector<int32_t>::iterator it = f_data.begin(); it != f_data.end(); ++it) {
149
        // when face is got count how many indices in it.
150
0
        if (*it == (-1)) {
151
0
            aiFace tface;
152
0
            size_t ts;
153
154
0
            ts = inds.size();
155
0
            switch (ts) {
156
0
                case 0:
157
0
                    goto mg_m_err;
158
0
                case 1:
159
0
                    prim_type |= aiPrimitiveType_POINT;
160
0
                    break;
161
0
                case 2:
162
0
                    prim_type |= aiPrimitiveType_LINE;
163
0
                    break;
164
0
                case 3:
165
0
                    prim_type |= aiPrimitiveType_TRIANGLE;
166
0
                    break;
167
0
                default:
168
0
                    prim_type |= aiPrimitiveType_POLYGON;
169
0
                    break;
170
0
            }
171
172
0
            tface.mNumIndices = static_cast<unsigned int>(ts);
173
0
            tface.mIndices = new unsigned int[ts];
174
0
            memcpy(tface.mIndices, inds.data(), ts * sizeof(unsigned int));
175
0
            pFaces.push_back(tface);
176
0
            inds.clear();
177
0
        } // if(*it == (-1))
178
0
        else {
179
0
            inds.push_back(*it);
180
0
        } // if(*it == (-1)) else
181
0
    } // for(std::list<int32_t>::iterator it = f_data.begin(); it != f_data.end(); it++)
182
    //PrintVectorSet("build. faces", pCoordIdx);
183
184
0
    pPrimitiveTypes = prim_type;
185
186
0
    return;
187
188
0
mg_m_err:
189
0
    for (size_t i = 0, i_e = pFaces.size(); i < i_e; i++)
190
0
        delete[] pFaces.at(i).mIndices;
191
192
0
    pFaces.clear();
193
0
}
194
195
0
void X3DGeoHelper::coordIdx_str2lines_arr(const std::vector<int32_t> &pCoordIdx, std::vector<aiFace> &pFaces) {
196
0
    std::vector<int32_t> f_data(pCoordIdx);
197
198
0
    if (!f_data.empty()) {
199
0
        if (f_data.back() != InvalidIndex) {
200
0
            f_data.push_back(InvalidIndex);
201
0
        }
202
0
    }
203
204
    // reserve average size.
205
0
    pFaces.reserve(f_data.size() / 2);
206
0
    for (std::vector<int32_t>::const_iterator startIt = f_data.cbegin(), endIt = f_data.cbegin(); endIt != f_data.cend(); ++endIt) {
207
        // check for end of current polyline
208
0
        if (*endIt != -1)
209
0
            continue;
210
211
        // found end of polyline, check if this is a valid polyline
212
0
        std::size_t numIndices = std::distance(startIt, endIt);
213
0
        if (numIndices <= 1)
214
0
            goto mg_m_err;
215
216
        // create line faces out of polyline indices
217
0
        for (int32_t idx0 = *startIt++; startIt != endIt; ++startIt) {
218
0
            int32_t idx1 = *startIt;
219
220
0
            aiFace tface;
221
0
            tface.mNumIndices = 2;
222
0
            tface.mIndices = new unsigned int[2];
223
0
            tface.mIndices[0] = idx0;
224
0
            tface.mIndices[1] = idx1;
225
0
            pFaces.push_back(tface);
226
227
0
            idx0 = idx1;
228
0
        }
229
230
0
        ++startIt;
231
0
    }
232
233
0
    return;
234
235
0
mg_m_err:
236
0
    for (size_t i = 0, i_e = pFaces.size(); i < i_e; i++)
237
0
        delete[] pFaces[i].mIndices;
238
239
0
    pFaces.clear();
240
0
}
241
242
0
void X3DGeoHelper::add_color(aiMesh &pMesh, const std::list<aiColor3D> &pColors, const bool pColorPerVertex) {
243
0
    std::list<aiColor4D> tcol;
244
245
    // create RGBA array from RGB.
246
0
    for (std::list<aiColor3D>::const_iterator it = pColors.begin(); it != pColors.end(); ++it)
247
0
        tcol.emplace_back((*it).r, (*it).g, (*it).b, static_cast<ai_real>(1));
248
249
    // call existing function for adding RGBA colors
250
0
    add_color(pMesh, tcol, pColorPerVertex);
251
0
}
252
253
0
void X3DGeoHelper::add_color(aiMesh &pMesh, const std::list<aiColor4D> &pColors, const bool pColorPerVertex) {
254
0
    std::list<aiColor4D>::const_iterator col_it = pColors.begin();
255
256
0
    if (pColorPerVertex) {
257
0
        if (pColors.size() < pMesh.mNumVertices) {
258
0
            throw DeadlyImportError("MeshGeometry_AddColor1. Colors count(" + ai_to_string(pColors.size()) + ") can not be less than Vertices count(" +
259
0
                                    ai_to_string(pMesh.mNumVertices) + ").");
260
0
        }
261
262
        // copy colors to mesh
263
0
        pMesh.mColors[0] = new aiColor4D[pMesh.mNumVertices];
264
0
        for (size_t i = 0; i < pMesh.mNumVertices; i++)
265
0
            pMesh.mColors[0][i] = *col_it++;
266
0
    } // if(pColorPerVertex)
267
0
    else {
268
0
        if (pColors.size() < pMesh.mNumFaces) {
269
0
            throw DeadlyImportError("MeshGeometry_AddColor1. Colors count(" + ai_to_string(pColors.size()) + ") can not be less than Faces count(" +
270
0
                                    ai_to_string(pMesh.mNumFaces) + ").");
271
0
        }
272
273
        // copy colors to mesh
274
0
        pMesh.mColors[0] = new aiColor4D[pMesh.mNumVertices];
275
0
        for (size_t fi = 0; fi < pMesh.mNumFaces; fi++) {
276
            // apply color to all vertices of face
277
0
            for (size_t vi = 0, vi_e = pMesh.mFaces[fi].mNumIndices; vi < vi_e; vi++) {
278
0
                pMesh.mColors[0][pMesh.mFaces[fi].mIndices[vi]] = *col_it;
279
0
            }
280
281
0
            ++col_it;
282
0
        }
283
0
    } // if(pColorPerVertex) else
284
0
}
285
286
void X3DGeoHelper::add_color(aiMesh &pMesh, const std::vector<int32_t> &pCoordIdx, const std::vector<int32_t> &pColorIdx,
287
0
        const std::list<aiColor3D> &pColors, const bool pColorPerVertex) {
288
0
    std::list<aiColor4D> tcol;
289
290
    // create RGBA array from RGB.
291
0
    for (std::list<aiColor3D>::const_iterator it = pColors.begin(); it != pColors.end(); ++it) {
292
0
        tcol.emplace_back((*it).r, (*it).g, (*it).b, static_cast<ai_real>(1));
293
0
    }
294
295
    // call existing function for adding RGBA colors
296
0
    add_color(pMesh, pCoordIdx, pColorIdx, tcol, pColorPerVertex);
297
0
}
298
299
void X3DGeoHelper::add_color(aiMesh &pMesh, const std::vector<int32_t> &coordIdx, const std::vector<int32_t> &colorIdx,
300
0
        const std::list<aiColor4D> &colors, bool pColorPerVertex) {
301
0
    std::vector<aiColor4D> col_tgt_arr;
302
0
    std::list<aiColor4D> col_tgt_list;
303
0
    std::vector<aiColor4D> col_arr_copy;
304
305
0
    if (coordIdx.size() == 0) {
306
0
        throw DeadlyImportError("MeshGeometry_AddColor2. pCoordIdx can not be empty.");
307
0
    }
308
309
    // copy list to array because we are need indexed access to colors.
310
0
    col_arr_copy.reserve(colors.size());
311
0
    for (std::list<aiColor4D>::const_iterator it = colors.begin(); it != colors.end(); ++it) {
312
0
        col_arr_copy.push_back(*it);
313
0
    }
314
315
0
    if (pColorPerVertex) {
316
0
        if (colorIdx.size() > 0) {
317
            // check indices array count.
318
0
            if (colorIdx.size() < coordIdx.size()) {
319
0
                throw DeadlyImportError("MeshGeometry_AddColor2. Colors indices count(" + ai_to_string(colorIdx.size()) +
320
0
                                        ") can not be less than Coords indices count(" + ai_to_string(coordIdx.size()) + ").");
321
0
            }
322
            // create list with colors for every vertex.
323
0
            col_tgt_arr.resize(pMesh.mNumVertices);
324
0
            for (std::vector<int32_t>::const_iterator colidx_it = colorIdx.begin(), coordidx_it = coordIdx.begin(); colidx_it != colorIdx.end(); ++colidx_it, ++coordidx_it) {
325
0
                if (*colidx_it == (-1)) {
326
0
                    continue; // skip faces delimiter
327
0
                }
328
0
                if ((unsigned int)(*coordidx_it) > pMesh.mNumVertices) {
329
0
                    throw DeadlyImportError("MeshGeometry_AddColor2. Coordinate idx is out of range.");
330
0
                }
331
0
                if ((unsigned int)*colidx_it > pMesh.mNumVertices) {
332
0
                    throw DeadlyImportError("MeshGeometry_AddColor2. Color idx is out of range.");
333
0
                }
334
335
0
                col_tgt_arr[*coordidx_it] = col_arr_copy[*colidx_it];
336
0
            }
337
0
        } // if(pColorIdx.size() > 0)
338
0
        else {
339
            // when color indices list is absent use CoordIdx.
340
            // check indices array count.
341
0
            if (colors.size() < pMesh.mNumVertices) {
342
0
                throw DeadlyImportError("MeshGeometry_AddColor2. Colors count(" + ai_to_string(colors.size()) + ") can not be less than Vertices count(" +
343
0
                                        ai_to_string(pMesh.mNumVertices) + ").");
344
0
            }
345
            // create list with colors for every vertex.
346
0
            col_tgt_arr.resize(pMesh.mNumVertices);
347
0
            for (size_t i = 0; i < pMesh.mNumVertices; i++) {
348
0
                col_tgt_arr[i] = col_arr_copy[i];
349
0
            }
350
0
        } // if(pColorIdx.size() > 0) else
351
0
    } // if(pColorPerVertex)
352
0
    else {
353
0
        if (colorIdx.size() > 0) {
354
            // check indices array count.
355
0
            if (colorIdx.size() < pMesh.mNumFaces) {
356
0
                throw DeadlyImportError("MeshGeometry_AddColor2. Colors indices count(" + ai_to_string(colorIdx.size()) +
357
0
                                        ") can not be less than Faces count(" + ai_to_string(pMesh.mNumFaces) + ").");
358
0
            }
359
            // create list with colors for every vertex using faces indices.
360
0
            col_tgt_arr.resize(pMesh.mNumFaces);
361
362
0
            std::vector<int32_t>::const_iterator colidx_it = colorIdx.begin();
363
0
            for (size_t fi = 0; fi < pMesh.mNumFaces; fi++) {
364
0
                if ((unsigned int)*colidx_it > pMesh.mNumFaces) throw DeadlyImportError("MeshGeometry_AddColor2. Face idx is out of range.");
365
366
0
                col_tgt_arr[fi] = col_arr_copy[*colidx_it++];
367
0
            }
368
0
        } // if(pColorIdx.size() > 0)
369
0
        else {
370
            // when color indices list is absent use CoordIdx.
371
            // check indices array count.
372
0
            if (colors.size() < pMesh.mNumFaces) {
373
0
                throw DeadlyImportError("MeshGeometry_AddColor2. Colors count(" + ai_to_string(colors.size()) + ") can not be less than Faces count(" +
374
0
                                        ai_to_string(pMesh.mNumFaces) + ").");
375
0
            }
376
            // create list with colors for every vertex using faces indices.
377
0
            col_tgt_arr.resize(pMesh.mNumFaces);
378
0
            for (size_t fi = 0; fi < pMesh.mNumFaces; fi++)
379
0
                col_tgt_arr[fi] = col_arr_copy[fi];
380
381
0
        } // if(pColorIdx.size() > 0) else
382
0
    } // if(pColorPerVertex) else
383
384
    // copy array to list for calling function that add colors.
385
0
    for (std::vector<aiColor4D>::const_iterator it = col_tgt_arr.begin(); it != col_tgt_arr.end(); ++it)
386
0
        col_tgt_list.push_back(*it);
387
    // add prepared colors list to mesh.
388
0
    add_color(pMesh, col_tgt_list, pColorPerVertex);
389
0
}
390
391
void X3DGeoHelper::add_normal(aiMesh &pMesh, const std::vector<int32_t> &pCoordIdx, const std::vector<int32_t> &pNormalIdx,
392
0
        const std::list<aiVector3D> &pNormals, const bool pNormalPerVertex) {
393
0
    std::vector<size_t> tind;
394
0
    std::vector<aiVector3D> norm_arr_copy;
395
396
    // copy list to array because we are need indexed access to normals.
397
0
    norm_arr_copy.reserve(pNormals.size());
398
0
    for (std::list<aiVector3D>::const_iterator it = pNormals.begin(); it != pNormals.end(); ++it) {
399
0
        norm_arr_copy.push_back(*it);
400
0
    }
401
402
0
    if (pNormalPerVertex) {
403
0
        if (pNormalIdx.size() > 0) {
404
            // check indices array count.
405
0
            if (pNormalIdx.size() != pCoordIdx.size()) throw DeadlyImportError("Normals and Coords inidces count must be equal.");
406
407
0
            tind.reserve(pNormalIdx.size());
408
0
            for (std::vector<int32_t>::const_iterator it = pNormalIdx.begin(); it != pNormalIdx.end(); ++it) {
409
0
                if (*it != (-1)) tind.push_back(*it);
410
0
            }
411
412
            // copy normals to mesh
413
0
            pMesh.mNormals = new aiVector3D[pMesh.mNumVertices];
414
0
            for (size_t i = 0; (i < pMesh.mNumVertices) && (i < tind.size()); i++) {
415
0
                if (tind[i] >= norm_arr_copy.size())
416
0
                    throw DeadlyImportError("MeshGeometry_AddNormal. Normal index(" + ai_to_string(tind[i]) +
417
0
                                            ") is out of range. Normals count: " + ai_to_string(norm_arr_copy.size()) + ".");
418
419
0
                pMesh.mNormals[i] = norm_arr_copy[tind[i]];
420
0
            }
421
0
        } else {
422
0
            if (pNormals.size() != pMesh.mNumVertices) throw DeadlyImportError("MeshGeometry_AddNormal. Normals and vertices count must be equal.");
423
424
            // copy normals to mesh
425
0
            pMesh.mNormals = new aiVector3D[pMesh.mNumVertices];
426
0
            std::list<aiVector3D>::const_iterator norm_it = pNormals.begin();
427
0
            for (size_t i = 0; i < pMesh.mNumVertices; i++)
428
0
                pMesh.mNormals[i] = *norm_it++;
429
0
        }
430
0
    } // if(pNormalPerVertex)
431
0
    else {
432
0
        if (pNormalIdx.size() > 0) {
433
0
            if (pMesh.mNumFaces != pNormalIdx.size()) throw DeadlyImportError("Normals faces count must be equal to mesh faces count.");
434
435
0
            std::vector<int32_t>::const_iterator normidx_it = pNormalIdx.begin();
436
437
0
            tind.reserve(pNormalIdx.size());
438
0
            for (size_t i = 0, i_e = pNormalIdx.size(); i < i_e; i++)
439
0
                tind.push_back(*normidx_it++);
440
441
0
        } else {
442
0
            tind.reserve(pMesh.mNumFaces);
443
0
            for (size_t i = 0; i < pMesh.mNumFaces; i++)
444
0
                tind.push_back(i);
445
0
        }
446
447
        // copy normals to mesh
448
0
        pMesh.mNormals = new aiVector3D[pMesh.mNumVertices];
449
0
        for (size_t fi = 0; fi < pMesh.mNumFaces; fi++) {
450
0
            aiVector3D tnorm;
451
452
0
            tnorm = norm_arr_copy[tind[fi]];
453
0
            for (size_t vi = 0, vi_e = pMesh.mFaces[fi].mNumIndices; vi < vi_e; vi++)
454
0
                pMesh.mNormals[pMesh.mFaces[fi].mIndices[vi]] = tnorm;
455
0
        }
456
0
    } // if(pNormalPerVertex) else
457
0
}
458
459
0
void X3DGeoHelper::add_normal(aiMesh &pMesh, const std::list<aiVector3D> &pNormals, const bool pNormalPerVertex) {
460
0
    std::list<aiVector3D>::const_iterator norm_it = pNormals.begin();
461
462
0
    if (pNormalPerVertex) {
463
0
        if (pNormals.size() != pMesh.mNumVertices) throw DeadlyImportError("MeshGeometry_AddNormal. Normals and vertices count must be equal.");
464
465
        // copy normals to mesh
466
0
        pMesh.mNormals = new aiVector3D[pMesh.mNumVertices];
467
0
        for (size_t i = 0; i < pMesh.mNumVertices; i++)
468
0
            pMesh.mNormals[i] = *norm_it++;
469
0
    } // if(pNormalPerVertex)
470
0
    else {
471
0
        if (pNormals.size() != pMesh.mNumFaces) throw DeadlyImportError("MeshGeometry_AddNormal. Normals and faces count must be equal.");
472
473
        // copy normals to mesh
474
0
        pMesh.mNormals = new aiVector3D[pMesh.mNumVertices];
475
0
        for (size_t fi = 0; fi < pMesh.mNumFaces; fi++) {
476
            // apply color to all vertices of face
477
0
            for (size_t vi = 0, vi_e = pMesh.mFaces[fi].mNumIndices; vi < vi_e; vi++)
478
0
                pMesh.mNormals[pMesh.mFaces[fi].mIndices[vi]] = *norm_it;
479
480
0
            ++norm_it;
481
0
        }
482
0
    } // if(pNormalPerVertex) else
483
0
}
484
485
void X3DGeoHelper::add_tex_coord(aiMesh &pMesh, const std::vector<int32_t> &pCoordIdx, const std::vector<int32_t> &pTexCoordIdx,
486
0
        const std::list<aiVector2D> &pTexCoords) {
487
0
    std::vector<aiVector3D> texcoord_arr_copy;
488
0
    std::vector<aiFace> faces;
489
0
    unsigned int prim_type;
490
491
    // copy list to array because we are need indexed access to normals.
492
0
    texcoord_arr_copy.reserve(pTexCoords.size());
493
0
    for (std::list<aiVector2D>::const_iterator it = pTexCoords.begin(); it != pTexCoords.end(); ++it) {
494
0
        texcoord_arr_copy.emplace_back((*it).x, (*it).y, static_cast<ai_real>(0));
495
0
    }
496
497
0
    if (pTexCoordIdx.size() > 0) {
498
0
        coordIdx_str2faces_arr(pTexCoordIdx, faces, prim_type);
499
0
        if (faces.empty()) {
500
0
            throw DeadlyImportError("Failed to add texture coordinates to mesh, faces list is empty.");
501
0
        }
502
0
        if (faces.size() != pMesh.mNumFaces) {
503
0
            throw DeadlyImportError("Texture coordinates faces count must be equal to mesh faces count.");
504
0
        }
505
0
    } else {
506
0
        coordIdx_str2faces_arr(pCoordIdx, faces, prim_type);
507
0
    }
508
509
0
    pMesh.mTextureCoords[0] = new aiVector3D[pMesh.mNumVertices];
510
0
    pMesh.mNumUVComponents[0] = 2;
511
0
    for (size_t fi = 0, fi_e = faces.size(); fi < fi_e; fi++) {
512
0
        if (pMesh.mFaces[fi].mNumIndices != faces.at(fi).mNumIndices)
513
0
            throw DeadlyImportError("Number of indices in texture face and mesh face must be equal. Invalid face index: " + ai_to_string(fi) + ".");
514
515
0
        for (size_t ii = 0; ii < pMesh.mFaces[fi].mNumIndices; ii++) {
516
0
            size_t vert_idx = pMesh.mFaces[fi].mIndices[ii];
517
0
            size_t tc_idx = faces.at(fi).mIndices[ii];
518
519
0
            pMesh.mTextureCoords[0][vert_idx] = texcoord_arr_copy.at(tc_idx);
520
0
        }
521
0
    } // for(size_t fi = 0, fi_e = faces.size(); fi < fi_e; fi++)
522
0
}
523
524
0
void X3DGeoHelper::add_tex_coord(aiMesh &pMesh, const std::list<aiVector2D> &pTexCoords) {
525
0
    std::vector<aiVector3D> tc_arr_copy;
526
527
0
    if (pTexCoords.size() != pMesh.mNumVertices) {
528
0
        throw DeadlyImportError("MeshGeometry_AddTexCoord. Texture coordinates and vertices count must be equal.");
529
0
    }
530
531
    // copy list to array because we are need convert aiVector2D to aiVector3D and also get indexed access as a bonus.
532
0
    tc_arr_copy.reserve(pTexCoords.size());
533
0
    for (std::list<aiVector2D>::const_iterator it = pTexCoords.begin(); it != pTexCoords.end(); ++it) {
534
0
        tc_arr_copy.emplace_back((*it).x, (*it).y, static_cast<ai_real>(0));
535
0
    }
536
537
    // copy texture coordinates to mesh
538
0
    pMesh.mTextureCoords[0] = new aiVector3D[pMesh.mNumVertices];
539
0
    pMesh.mNumUVComponents[0] = 2;
540
0
    for (size_t i = 0; i < pMesh.mNumVertices; i++) {
541
0
        pMesh.mTextureCoords[0][i] = tc_arr_copy[i];
542
0
    }
543
0
}
544
545
0
aiMesh *X3DGeoHelper::make_mesh(const std::vector<int32_t> &pCoordIdx, const std::list<aiVector3D> &pVertices) {
546
0
    std::vector<aiFace> faces;
547
0
    unsigned int prim_type = 0;
548
549
    // create faces array from input string with vertices indices.
550
0
    X3DGeoHelper::coordIdx_str2faces_arr(pCoordIdx, faces, prim_type);
551
0
    if (!faces.size()) {
552
0
        throw DeadlyImportError("Failed to create mesh, faces list is empty.");
553
0
    }
554
555
    //
556
    // Create new mesh and copy geometry data.
557
    //
558
0
    aiMesh *tmesh = new aiMesh;
559
0
    size_t ts = faces.size();
560
    // faces
561
0
    tmesh->mFaces = new aiFace[ts];
562
0
    tmesh->mNumFaces = static_cast<unsigned int>(ts);
563
0
    for (size_t i = 0; i < ts; i++)
564
0
        tmesh->mFaces[i] = faces.at(i);
565
566
    // vertices
567
0
    std::list<aiVector3D>::const_iterator vit = pVertices.begin();
568
569
0
    ts = pVertices.size();
570
0
    tmesh->mVertices = new aiVector3D[ts];
571
0
    tmesh->mNumVertices = static_cast<unsigned int>(ts);
572
0
    for (size_t i = 0; i < ts; i++) {
573
0
        tmesh->mVertices[i] = *vit++;
574
0
    }
575
576
    // set primitives type and return result.
577
0
    tmesh->mPrimitiveTypes = prim_type;
578
579
0
    return tmesh;
580
0
}
581
582
0
aiMesh *X3DGeoHelper::make_line_mesh(const std::vector<int32_t> &pCoordIdx, const std::list<aiVector3D> &pVertices) {
583
0
    std::vector<aiFace> faces;
584
585
    // create faces array from input string with vertices indices.
586
0
    X3DGeoHelper::coordIdx_str2lines_arr(pCoordIdx, faces);
587
0
    if (!faces.size()) {
588
0
        throw DeadlyImportError("Failed to create mesh, faces list is empty.");
589
0
    }
590
591
    //
592
    // Create new mesh and copy geometry data.
593
    //
594
0
    aiMesh *tmesh = new aiMesh;
595
0
    size_t ts = faces.size();
596
    // faces
597
0
    tmesh->mFaces = new aiFace[ts];
598
0
    tmesh->mNumFaces = static_cast<unsigned int>(ts);
599
0
    for (size_t i = 0; i < ts; i++)
600
0
        tmesh->mFaces[i] = faces[i];
601
602
    // vertices
603
0
    std::list<aiVector3D>::const_iterator vit = pVertices.begin();
604
605
0
    ts = pVertices.size();
606
0
    tmesh->mVertices = new aiVector3D[ts];
607
0
    tmesh->mNumVertices = static_cast<unsigned int>(ts);
608
0
    for (size_t i = 0; i < ts; i++) {
609
0
        tmesh->mVertices[i] = *vit++;
610
0
    }
611
612
    // set primitive type and return result.
613
0
    tmesh->mPrimitiveTypes = aiPrimitiveType_LINE;
614
615
0
    return tmesh;
616
0
}
617
618
} // namespace Assimp