Skip to content

Commit

Permalink
X3D: Don't convert IndexedLineSet polylines with > 2 indices to trian…
Browse files Browse the repository at this point in the history
…gles/polygons

Currently, when the coordIndex attribute of an IndexedLineSet contains a
polyline with > 2 indices, X3DGeoHelper::coordIdx_str2faces_arr() will
incorrectly determine the primitive type to be aiPrimitiveType_TRIANGLE or
aiPrimitiveType_POLYGON instead of aiPrimitiveType_LINE.

To fix this, this commit adds functions to explicitly handle an IndexedLineSet.

Fixes assimp#3101
  • Loading branch information
andre-schulz authored and kimkulling committed Jan 9, 2024
1 parent c8ca1a4 commit 9d71a27
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 1 deletion.
81 changes: 81 additions & 0 deletions code/AssetLib/X3D/X3DGeoHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,51 @@ void X3DGeoHelper::coordIdx_str2faces_arr(const std::vector<int32_t> &pCoordIdx,
pFaces.clear();
}

void X3DGeoHelper::coordIdx_str2lines_arr(const std::vector<int32_t> &pCoordIdx, std::vector<aiFace> &pFaces) {
std::vector<int32_t> f_data(pCoordIdx);

if (f_data.back() != (-1)) {
f_data.push_back(-1);
}

// reserve average size.
pFaces.reserve(f_data.size() / 2);
for (std::vector<int32_t>::const_iterator startIt = f_data.cbegin(), endIt = f_data.cbegin(); endIt != f_data.cend(); ++endIt) {
// check for end of current polyline
if (*endIt != -1)
continue;

// found end of polyline, check if this is a valid polyline
std::size_t numIndices = std::distance(startIt, endIt);
if (numIndices <= 1)
goto mg_m_err;

// create line faces out of polyline indices
for (int32_t idx0 = *startIt++; startIt != endIt; ++startIt) {
int32_t idx1 = *startIt;

aiFace tface;
tface.mNumIndices = 2;
tface.mIndices = new unsigned int[2];
tface.mIndices[0] = idx0;
tface.mIndices[1] = idx1;
pFaces.push_back(tface);

idx0 = idx1;
}

++startIt;
}

return;

mg_m_err:
for (size_t i = 0, i_e = pFaces.size(); i < i_e; i++)
delete[] pFaces[i].mIndices;

pFaces.clear();
}

void X3DGeoHelper::add_color(aiMesh &pMesh, const std::list<aiColor3D> &pColors, const bool pColorPerVertex) {
std::list<aiColor4D> tcol;

Expand Down Expand Up @@ -528,4 +573,40 @@ aiMesh *X3DGeoHelper::make_mesh(const std::vector<int32_t> &pCoordIdx, const std
return tmesh;
}

aiMesh *X3DGeoHelper::make_line_mesh(const std::vector<int32_t> &pCoordIdx, const std::list<aiVector3D> &pVertices) {
std::vector<aiFace> faces;

// create faces array from input string with vertices indices.
X3DGeoHelper::coordIdx_str2lines_arr(pCoordIdx, faces);
if (!faces.size()) {
throw DeadlyImportError("Failed to create mesh, faces list is empty.");
}

//
// Create new mesh and copy geometry data.
//
aiMesh *tmesh = new aiMesh;
size_t ts = faces.size();
// faces
tmesh->mFaces = new aiFace[ts];
tmesh->mNumFaces = static_cast<unsigned int>(ts);
for (size_t i = 0; i < ts; i++)
tmesh->mFaces[i] = faces[i];

// vertices
std::list<aiVector3D>::const_iterator vit = pVertices.begin();

ts = pVertices.size();
tmesh->mVertices = new aiVector3D[ts];
tmesh->mNumVertices = static_cast<unsigned int>(ts);
for (size_t i = 0; i < ts; i++) {
tmesh->mVertices[i] = *vit++;
}

// set primitive type and return result.
tmesh->mPrimitiveTypes = aiPrimitiveType_LINE;

return tmesh;
}

} // namespace Assimp
2 changes: 2 additions & 0 deletions code/AssetLib/X3D/X3DGeoHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class X3DGeoHelper {
static void polylineIdx_to_lineIdx(const std::list<int32_t> &pPolylineCoordIdx, std::list<int32_t> &pLineCoordIdx);
static void rect_parallel_epiped(const aiVector3D &pSize, std::list<aiVector3D> &pVertices);
static void coordIdx_str2faces_arr(const std::vector<int32_t> &pCoordIdx, std::vector<aiFace> &pFaces, unsigned int &pPrimitiveTypes);
static void coordIdx_str2lines_arr(const std::vector<int32_t> &pCoordIdx, std::vector<aiFace> &pFaces);
static void add_color(aiMesh &pMesh, const std::list<aiColor3D> &pColors, const bool pColorPerVertex);
static void add_color(aiMesh &pMesh, const std::list<aiColor4D> &pColors, const bool pColorPerVertex);
static void add_color(aiMesh &pMesh, const std::vector<int32_t> &pCoordIdx, const std::vector<int32_t> &pColorIdx,
Expand All @@ -34,6 +35,7 @@ class X3DGeoHelper {
const std::list<aiVector2D> &pTexCoords);
static void add_tex_coord(aiMesh &pMesh, const std::list<aiVector2D> &pTexCoords);
static aiMesh *make_mesh(const std::vector<int32_t> &pCoordIdx, const std::list<aiVector3D> &pVertices);
static aiMesh *make_line_mesh(const std::vector<int32_t> &pCoordIdx, const std::list<aiVector3D> &pVertices);
};

} // namespace Assimp
2 changes: 1 addition & 1 deletion code/AssetLib/X3D/X3DImporter_Postprocess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ void X3DImporter::Postprocess_BuildMesh(const X3DNodeElementBase &pNodeElement,
// at first search for <Coordinate> node and create mesh.
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
*pMesh = X3DGeoHelper::make_mesh(tnemesh.CoordIndex, ((X3DNodeElementCoordinate *)*ch_it)->Value);
*pMesh = X3DGeoHelper::make_line_mesh(tnemesh.CoordIndex, ((X3DNodeElementCoordinate *)*ch_it)->Value);
}
}

Expand Down

0 comments on commit 9d71a27

Please sign in to comment.