diff --git a/src/ifcgeom/mapping/IfcPolygonalFaceSet.cpp b/src/ifcgeom/mapping/IfcPolygonalFaceSet.cpp index c3f7ff7219..c965db542a 100644 --- a/src/ifcgeom/mapping/IfcPolygonalFaceSet.cpp +++ b/src/ifcgeom/mapping/IfcPolygonalFaceSet.cpp @@ -39,8 +39,25 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcPolygonalFaceSet* inst) { int max_index = (int)points.size(); + // When the optional PnIndex is present, CoordIndex values do not index into + // CoordList directly but into PnIndex, which in turn remaps to CoordList. + // Both index levels are 1-based per the IFC specification. + auto pn_index = inst->PnIndex(); + auto resolve = [&](int idx) -> const taxonomy::point3::ptr& { + if (pn_index) { + if (idx < 1 || idx > (int)pn_index->size()) { + throw IfcParse::IfcException("IfcPolygonalFaceSet PnIndex out of bounds for index " + boost::lexical_cast(idx)); + } + idx = (*pn_index)[idx - 1]; + } + if (idx < 1 || idx > max_index) { + throw IfcParse::IfcException("IfcPolygonalFaceSet index out of bounds for index " + boost::lexical_cast(idx)); + } + return points[idx - 1]; + }; + auto shell = taxonomy::make(); - + for (auto& f : *polygonal_faces) { auto fa = taxonomy::make(); shell->children.push_back(fa); @@ -52,17 +69,14 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcPolygonalFaceSet* inst) { auto indices = f->CoordIndex(); taxonomy::point3::ptr previous; for (std::vector::const_iterator jt = indices.begin(); jt != indices.end(); ++jt) { - if (*jt < 1 || *jt > max_index) { - throw IfcParse::IfcException("IfcPolygonalFaceSet index out of bounds for index " + boost::lexical_cast(*jt)); - } - auto current = points[(*jt) - 1]; + auto current = resolve(*jt); if (jt != indices.begin()) { loop->children.push_back(taxonomy::make(previous, current)); } previous = current; } if (!indices.empty()) { - auto current = points[indices.front() - 1]; + auto current = resolve(indices.front()); loop->children.push_back(taxonomy::make(previous, current)); } } @@ -77,17 +91,14 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcPolygonalFaceSet* inst) { loop->external = false; for (std::vector::const_iterator jt = li.begin(); jt != li.end(); ++jt) { - if (*jt < 1 || *jt > max_index) { - throw IfcParse::IfcException("IfcPolygonalFaceSet index out of bounds for index " + boost::lexical_cast(*jt)); - } - auto current = points[(*jt) - 1]; + auto current = resolve(*jt); if (jt != li.begin()) { loop->children.push_back(taxonomy::make(previous, current)); } previous = current; } if (!li.empty()) { - auto current = points[li.front() - 1]; + auto current = resolve(li.front()); loop->children.push_back(taxonomy::make(previous, current)); } } diff --git a/src/ifcgeom/mapping/IfcTriangulatedFaceSet.cpp b/src/ifcgeom/mapping/IfcTriangulatedFaceSet.cpp index 776ea59605..f234c3bd3f 100644 --- a/src/ifcgeom/mapping/IfcTriangulatedFaceSet.cpp +++ b/src/ifcgeom/mapping/IfcTriangulatedFaceSet.cpp @@ -39,6 +39,23 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcTriangulatedFaceSet* inst) { int max_index = (int)points.size(); + // When the optional PnIndex is present, CoordIndex values do not index into + // CoordList directly but into PnIndex, which in turn remaps to CoordList. + // Both index levels are 1-based per the IFC specification. + auto pn_index = inst->PnIndex(); + auto resolve = [&](int idx) -> const taxonomy::point3::ptr& { + if (pn_index) { + if (idx < 1 || idx > (int)pn_index->size()) { + throw IfcParse::IfcException("IfcTriangulatedFaceSet PnIndex out of bounds for index " + boost::lexical_cast(idx)); + } + idx = (*pn_index)[idx - 1]; + } + if (idx < 1 || idx > max_index) { + throw IfcParse::IfcException("IfcTriangulatedFaceSet index out of bounds for index " + boost::lexical_cast(idx)); + } + return points[idx - 1]; + }; + auto shell = taxonomy::make(); for (auto& indices : indices_list) { @@ -51,10 +68,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcTriangulatedFaceSet* inst) { loop->external = true; taxonomy::point3::ptr first, previous; for (std::vector::const_iterator jt = indices.begin(); jt != indices.end(); ++jt) { - if (*jt < 1 || *jt > max_index) { - throw IfcParse::IfcException("IfcTriangulatedFaceSet index out of bounds for index " + boost::lexical_cast(*jt)); - } - const taxonomy::point3::ptr& current = points[(*jt) - 1]; + const taxonomy::point3::ptr& current = resolve(*jt); if (jt == indices.begin()) { first = current; } else {