closes https://github.com/assimp/assimp/issues/1044: set default value in case of light intensity envelopes-

pull/3495/head
Kim Kulling 2020-11-11 19:38:42 +01:00
parent de610b8ce9
commit 456b54988a
14 changed files with 2039 additions and 2374 deletions

View File

@ -123,20 +123,20 @@ const aiImporterDesc *FBXImporter::GetInfo() const {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Setup configuration properties for the loader // Setup configuration properties for the loader
void FBXImporter::SetupProperties(const Importer *pImp) { void FBXImporter::SetupProperties(const Importer *pImp) {
settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true); mSettings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false); mSettings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true); mSettings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
settings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true); mSettings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true); mSettings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true); mSettings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true); mSettings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
settings.readWeights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_WEIGHTS, true); mSettings.readWeights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_WEIGHTS, true);
settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false); mSettings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true); mSettings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
settings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true); mSettings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
settings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false); mSettings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
settings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true); mSettings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
settings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false); mSettings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -181,10 +181,10 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
Parser parser(tokens, is_binary); Parser parser(tokens, is_binary);
// take the raw parse-tree and convert it to a FBX DOM // take the raw parse-tree and convert it to a FBX DOM
Document doc(parser, settings); Document doc(parser, mSettings);
// convert the FBX DOM to aiScene // convert the FBX DOM to aiScene
ConvertToAssimpScene(pScene, doc, settings.removeEmptyBones); ConvertToAssimpScene(pScene, doc, mSettings.removeEmptyBones);
// size relative to cm // size relative to cm
float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor(); float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor();

View File

@ -70,27 +70,16 @@ typedef class basic_formatter<char, std::char_traits<char>, std::allocator<char>
class FBXImporter : public BaseImporter, public LogFunctions<FBXImporter> { class FBXImporter : public BaseImporter, public LogFunctions<FBXImporter> {
public: public:
FBXImporter(); FBXImporter();
virtual ~FBXImporter(); ~FBXImporter() override;
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const;
// --------------------
bool CanRead(const std::string &pFile,
IOSystem *pIOHandler,
bool checkSig) const;
protected: protected:
// --------------------
const aiImporterDesc *GetInfo() const; const aiImporterDesc *GetInfo() const;
// --------------------
void SetupProperties(const Importer *pImp); void SetupProperties(const Importer *pImp);
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler);
// --------------------
void InternReadFile(const std::string &pFile,
aiScene *pScene,
IOSystem *pIOHandler);
private: private:
FBX::ImportSettings settings; FBX::ImportSettings mSettings;
}; // !class FBXImporter }; // !class FBXImporter
} // end of namespace Assimp } // end of namespace Assimp

View File

@ -48,12 +48,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <functional> #include <functional>
#include "FBXMeshGeometry.h"
#include "FBXDocument.h" #include "FBXDocument.h"
#include "FBXImporter.h"
#include "FBXImportSettings.h"
#include "FBXDocumentUtil.h" #include "FBXDocumentUtil.h"
#include "FBXImportSettings.h"
#include "FBXImporter.h"
#include "FBXMeshGeometry.h"
namespace Assimp { namespace Assimp {
namespace FBX { namespace FBX {
@ -61,17 +60,15 @@ namespace FBX {
using namespace Util; using namespace Util;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Geometry::Geometry(uint64_t id, const Element& element, const std::string& name, const Document& doc) Geometry::Geometry(uint64_t id, const Element &element, const std::string &name, const Document &doc) :
: Object(id, element, name) Object(id, element, name), skin() {
, skin() const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer");
{ for (const Connection *con : conns) {
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer"); const Skin *const sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
for(const Connection* con : conns) { if (sk) {
const Skin* const sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
if(sk) {
skin = sk; skin = sk;
} }
const BlendShape* const bsp = ProcessSimpleConnection<BlendShape>(*con, false, "BlendShape -> Geometry", element); const BlendShape *const bsp = ProcessSimpleConnection<BlendShape>(*con, false, "BlendShape -> Geometry", element);
if (bsp) { if (bsp) {
blendShapes.push_back(bsp); blendShapes.push_back(bsp);
} }
@ -79,48 +76,46 @@ Geometry::Geometry(uint64_t id, const Element& element, const std::string& name,
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Geometry::~Geometry() Geometry::~Geometry() {
{
// empty // empty
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const std::vector<const BlendShape*>& Geometry::GetBlendShapes() const { const std::vector<const BlendShape *> &Geometry::GetBlendShapes() const {
return blendShapes; return blendShapes;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const Skin* Geometry::DeformerSkin() const { const Skin *Geometry::DeformerSkin() const {
return skin; return skin;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc) MeshGeometry::MeshGeometry(uint64_t id, const Element &element, const std::string &name, const Document &doc) :
: Geometry(id, element,name, doc) Geometry(id, element, name, doc) {
{ const Scope *sc = element.Compound();
const Scope* sc = element.Compound();
if (!sc) { if (!sc) {
DOMError("failed to read Geometry object (class: Mesh), no data scope found"); DOMError("failed to read Geometry object (class: Mesh), no data scope found");
} }
// must have Mesh elements: // must have Mesh elements:
const Element& Vertices = GetRequiredElement(*sc,"Vertices",&element); const Element &Vertices = GetRequiredElement(*sc, "Vertices", &element);
const Element& PolygonVertexIndex = GetRequiredElement(*sc,"PolygonVertexIndex",&element); const Element &PolygonVertexIndex = GetRequiredElement(*sc, "PolygonVertexIndex", &element);
// optional Mesh elements: // optional Mesh elements:
const ElementCollection& Layer = sc->GetCollection("Layer"); const ElementCollection &Layer = sc->GetCollection("Layer");
std::vector<aiVector3D> tempVerts; std::vector<aiVector3D> tempVerts;
ParseVectorDataArray(tempVerts,Vertices); ParseVectorDataArray(tempVerts, Vertices);
if(tempVerts.empty()) { if (tempVerts.empty()) {
FBXImporter::LogWarn("encountered mesh with no vertices"); FBXImporter::LogWarn("encountered mesh with no vertices");
} }
std::vector<int> tempFaces; std::vector<int> tempFaces;
ParseVectorDataArray(tempFaces,PolygonVertexIndex); ParseVectorDataArray(tempFaces, PolygonVertexIndex);
if(tempFaces.empty()) { if (tempFaces.empty()) {
FBXImporter::LogWarn("encountered mesh with no faces"); FBXImporter::LogWarn("encountered mesh with no faces");
} }
@ -128,7 +123,7 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
m_faces.reserve(tempFaces.size() / 3); m_faces.reserve(tempFaces.size() / 3);
m_mapping_offsets.resize(tempVerts.size()); m_mapping_offsets.resize(tempVerts.size());
m_mapping_counts.resize(tempVerts.size(),0); m_mapping_counts.resize(tempVerts.size(), 0);
m_mappings.resize(tempFaces.size()); m_mappings.resize(tempFaces.size());
const size_t vertex_count = tempVerts.size(); const size_t vertex_count = tempVerts.size();
@ -136,10 +131,10 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
// generate output vertices, computing an adjacency table to // generate output vertices, computing an adjacency table to
// preserve the mapping from fbx indices to *this* indexing. // preserve the mapping from fbx indices to *this* indexing.
unsigned int count = 0; unsigned int count = 0;
for(int index : tempFaces) { for (int index : tempFaces) {
const int absi = index < 0 ? (-index - 1) : index; const int absi = index < 0 ? (-index - 1) : index;
if(static_cast<size_t>(absi) >= vertex_count) { if (static_cast<size_t>(absi) >= vertex_count) {
DOMError("polygon vertex index out of range",&PolygonVertexIndex); DOMError("polygon vertex index out of range", &PolygonVertexIndex);
} }
m_vertices.push_back(tempVerts[absi]); m_vertices.push_back(tempVerts[absi]);
@ -162,7 +157,7 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
} }
cursor = 0; cursor = 0;
for(int index : tempFaces) { for (int index : tempFaces) {
const int absi = index < 0 ? (-index - 1) : index; const int absi = index < 0 ? (-index - 1) : index;
m_mappings[m_mapping_offsets[absi] + m_mapping_counts[absi]++] = cursor++; m_mappings[m_mapping_offsets[absi] + m_mapping_counts[absi]++] = cursor++;
} }
@ -172,19 +167,18 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
// if settings.readAllLayers is false: // if settings.readAllLayers is false:
// * read only the layer with index 0, but warn about any further layers // * read only the layer with index 0, but warn about any further layers
for (ElementMap::const_iterator it = Layer.first; it != Layer.second; ++it) { for (ElementMap::const_iterator it = Layer.first; it != Layer.second; ++it) {
const TokenList& tokens = (*it).second->Tokens(); const TokenList &tokens = (*it).second->Tokens();
const char* err; const char *err;
const int index = ParseTokenAsInt(*tokens[0], err); const int index = ParseTokenAsInt(*tokens[0], err);
if(err) { if (err) {
DOMError(err,&element); DOMError(err, &element);
} }
if(doc.Settings().readAllLayers || index == 0) { if (doc.Settings().readAllLayers || index == 0) {
const Scope& layer = GetRequiredScope(*(*it).second); const Scope &layer = GetRequiredScope(*(*it).second);
ReadLayer(layer); ReadLayer(layer);
} } else {
else {
FBXImporter::LogWarn("ignoring additional geometry layers"); FBXImporter::LogWarn("ignoring additional geometry layers");
} }
} }
@ -196,151 +190,142 @@ MeshGeometry::~MeshGeometry() {
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const std::vector<aiVector3D>& MeshGeometry::GetVertices() const { const std::vector<aiVector3D> &MeshGeometry::GetVertices() const {
return m_vertices; return m_vertices;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const std::vector<aiVector3D>& MeshGeometry::GetNormals() const { const std::vector<aiVector3D> &MeshGeometry::GetNormals() const {
return m_normals; return m_normals;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const std::vector<aiVector3D>& MeshGeometry::GetTangents() const { const std::vector<aiVector3D> &MeshGeometry::GetTangents() const {
return m_tangents; return m_tangents;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const std::vector<aiVector3D>& MeshGeometry::GetBinormals() const { const std::vector<aiVector3D> &MeshGeometry::GetBinormals() const {
return m_binormals; return m_binormals;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const std::vector<unsigned int>& MeshGeometry::GetFaceIndexCounts() const { const std::vector<unsigned int> &MeshGeometry::GetFaceIndexCounts() const {
return m_faces; return m_faces;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const std::vector<aiVector2D>& MeshGeometry::GetTextureCoords( unsigned int index ) const { const std::vector<aiVector2D> &MeshGeometry::GetTextureCoords(unsigned int index) const {
static const std::vector<aiVector2D> empty; static const std::vector<aiVector2D> empty;
return index >= AI_MAX_NUMBER_OF_TEXTURECOORDS ? empty : m_uvs[ index ]; return index >= AI_MAX_NUMBER_OF_TEXTURECOORDS ? empty : m_uvs[index];
} }
std::string MeshGeometry::GetTextureCoordChannelName( unsigned int index ) const { std::string MeshGeometry::GetTextureCoordChannelName(unsigned int index) const {
return index >= AI_MAX_NUMBER_OF_TEXTURECOORDS ? "" : m_uvNames[ index ]; return index >= AI_MAX_NUMBER_OF_TEXTURECOORDS ? "" : m_uvNames[index];
} }
const std::vector<aiColor4D>& MeshGeometry::GetVertexColors( unsigned int index ) const { const std::vector<aiColor4D> &MeshGeometry::GetVertexColors(unsigned int index) const {
static const std::vector<aiColor4D> empty; static const std::vector<aiColor4D> empty;
return index >= AI_MAX_NUMBER_OF_COLOR_SETS ? empty : m_colors[ index ]; return index >= AI_MAX_NUMBER_OF_COLOR_SETS ? empty : m_colors[index];
} }
const MatIndexArray& MeshGeometry::GetMaterialIndices() const { const MatIndexArray &MeshGeometry::GetMaterialIndices() const {
return m_materials; return m_materials;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const unsigned int* MeshGeometry::ToOutputVertexIndex( unsigned int in_index, unsigned int& count ) const { const unsigned int *MeshGeometry::ToOutputVertexIndex(unsigned int in_index, unsigned int &count) const {
if ( in_index >= m_mapping_counts.size() ) { if (in_index >= m_mapping_counts.size()) {
return nullptr; return nullptr;
} }
ai_assert( m_mapping_counts.size() == m_mapping_offsets.size() ); ai_assert(m_mapping_counts.size() == m_mapping_offsets.size());
count = m_mapping_counts[ in_index ]; count = m_mapping_counts[in_index];
ai_assert( m_mapping_offsets[ in_index ] + count <= m_mappings.size() ); ai_assert(m_mapping_offsets[in_index] + count <= m_mappings.size());
return &m_mappings[ m_mapping_offsets[ in_index ] ]; return &m_mappings[m_mapping_offsets[in_index]];
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
unsigned int MeshGeometry::FaceForVertexIndex( unsigned int in_index ) const { unsigned int MeshGeometry::FaceForVertexIndex(unsigned int in_index) const {
ai_assert( in_index < m_vertices.size() ); ai_assert(in_index < m_vertices.size());
// in the current conversion pattern this will only be needed if // in the current conversion pattern this will only be needed if
// weights are present, so no need to always pre-compute this table // weights are present, so no need to always pre-compute this table
if ( m_facesVertexStartIndices.empty() ) { if (m_facesVertexStartIndices.empty()) {
m_facesVertexStartIndices.resize( m_faces.size() + 1, 0 ); m_facesVertexStartIndices.resize(m_faces.size() + 1, 0);
std::partial_sum( m_faces.begin(), m_faces.end(), m_facesVertexStartIndices.begin() + 1 ); std::partial_sum(m_faces.begin(), m_faces.end(), m_facesVertexStartIndices.begin() + 1);
m_facesVertexStartIndices.pop_back(); m_facesVertexStartIndices.pop_back();
} }
ai_assert( m_facesVertexStartIndices.size() == m_faces.size() ); ai_assert(m_facesVertexStartIndices.size() == m_faces.size());
const std::vector<unsigned int>::iterator it = std::upper_bound( const std::vector<unsigned int>::iterator it = std::upper_bound(
m_facesVertexStartIndices.begin(), m_facesVertexStartIndices.begin(),
m_facesVertexStartIndices.end(), m_facesVertexStartIndices.end(),
in_index in_index);
);
return static_cast< unsigned int >( std::distance( m_facesVertexStartIndices.begin(), it - 1 ) ); return static_cast<unsigned int>(std::distance(m_facesVertexStartIndices.begin(), it - 1));
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void MeshGeometry::ReadLayer(const Scope& layer) void MeshGeometry::ReadLayer(const Scope &layer) {
{ const ElementCollection &LayerElement = layer.GetCollection("LayerElement");
const ElementCollection& LayerElement = layer.GetCollection("LayerElement");
for (ElementMap::const_iterator eit = LayerElement.first; eit != LayerElement.second; ++eit) { for (ElementMap::const_iterator eit = LayerElement.first; eit != LayerElement.second; ++eit) {
const Scope& elayer = GetRequiredScope(*(*eit).second); const Scope &elayer = GetRequiredScope(*(*eit).second);
ReadLayerElement(elayer); ReadLayerElement(elayer);
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void MeshGeometry::ReadLayerElement(const Scope& layerElement) void MeshGeometry::ReadLayerElement(const Scope &layerElement) {
{ const Element &Type = GetRequiredElement(layerElement, "Type");
const Element& Type = GetRequiredElement(layerElement,"Type"); const Element &TypedIndex = GetRequiredElement(layerElement, "TypedIndex");
const Element& TypedIndex = GetRequiredElement(layerElement,"TypedIndex");
const std::string& type = ParseTokenAsString(GetRequiredToken(Type,0)); const std::string &type = ParseTokenAsString(GetRequiredToken(Type, 0));
const int typedIndex = ParseTokenAsInt(GetRequiredToken(TypedIndex,0)); const int typedIndex = ParseTokenAsInt(GetRequiredToken(TypedIndex, 0));
const Scope& top = GetRequiredScope(element); const Scope &top = GetRequiredScope(element);
const ElementCollection candidates = top.GetCollection(type); const ElementCollection candidates = top.GetCollection(type);
for (ElementMap::const_iterator it = candidates.first; it != candidates.second; ++it) { for (ElementMap::const_iterator it = candidates.first; it != candidates.second; ++it) {
const int index = ParseTokenAsInt(GetRequiredToken(*(*it).second,0)); const int index = ParseTokenAsInt(GetRequiredToken(*(*it).second, 0));
if(index == typedIndex) { if (index == typedIndex) {
ReadVertexData(type,typedIndex,GetRequiredScope(*(*it).second)); ReadVertexData(type, typedIndex, GetRequiredScope(*(*it).second));
return; return;
} }
} }
FBXImporter::LogError(Formatter::format("failed to resolve vertex layer element: ") FBXImporter::LogError(Formatter::format("failed to resolve vertex layer element: ")
<< type << ", index: " << typedIndex); << type << ", index: " << typedIndex);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scope& source) void MeshGeometry::ReadVertexData(const std::string &type, int index, const Scope &source) {
{ const std::string &MappingInformationType = ParseTokenAsString(GetRequiredToken(
const std::string& MappingInformationType = ParseTokenAsString(GetRequiredToken( GetRequiredElement(source, "MappingInformationType"), 0));
GetRequiredElement(source,"MappingInformationType"),0)
);
const std::string& ReferenceInformationType = ParseTokenAsString(GetRequiredToken( const std::string &ReferenceInformationType = ParseTokenAsString(GetRequiredToken(
GetRequiredElement(source,"ReferenceInformationType"),0) GetRequiredElement(source, "ReferenceInformationType"), 0));
);
if (type == "LayerElementUV") { if (type == "LayerElementUV") {
if(index >= AI_MAX_NUMBER_OF_TEXTURECOORDS) { if (index >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
FBXImporter::LogError(Formatter::format("ignoring UV layer, maximum number of UV channels exceeded: ") FBXImporter::LogError(Formatter::format("ignoring UV layer, maximum number of UV channels exceeded: ")
<< index << " (limit is " << AI_MAX_NUMBER_OF_TEXTURECOORDS << ")" ); << index << " (limit is " << AI_MAX_NUMBER_OF_TEXTURECOORDS << ")");
return; return;
} }
const Element* Name = source["Name"]; const Element *Name = source["Name"];
m_uvNames[index] = ""; m_uvNames[index] = "";
if(Name) { if (Name) {
m_uvNames[index] = ParseTokenAsString(GetRequiredToken(*Name,0)); m_uvNames[index] = ParseTokenAsString(GetRequiredToken(*Name, 0));
} }
ReadVertexDataUV(m_uvs[index],source, ReadVertexDataUV(m_uvs[index], source,
MappingInformationType, MappingInformationType,
ReferenceInformationType ReferenceInformationType);
); } else if (type == "LayerElementMaterial") {
}
else if (type == "LayerElementMaterial") {
if (m_materials.size() > 0) { if (m_materials.size() > 0) {
FBXImporter::LogError("ignoring additional material layer"); FBXImporter::LogError("ignoring additional material layer");
return; return;
@ -348,10 +333,9 @@ void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scop
std::vector<int> temp_materials; std::vector<int> temp_materials;
ReadVertexDataMaterials(temp_materials,source, ReadVertexDataMaterials(temp_materials, source,
MappingInformationType, MappingInformationType,
ReferenceInformationType ReferenceInformationType);
);
// sometimes, there will be only negative entries. Drop the material // sometimes, there will be only negative entries. Drop the material
// layer in such a case (I guess it means a default material should // layer in such a case (I guess it means a default material should
@ -359,58 +343,50 @@ void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scop
// avoids losing the material if there are more material layers // avoids losing the material if there are more material layers
// coming of which at least one contains actual data (did observe // coming of which at least one contains actual data (did observe
// that with one test file). // that with one test file).
const size_t count_neg = std::count_if(temp_materials.begin(),temp_materials.end(),[](int n) { return n < 0; }); const size_t count_neg = std::count_if(temp_materials.begin(), temp_materials.end(), [](int n) { return n < 0; });
if(count_neg == temp_materials.size()) { if (count_neg == temp_materials.size()) {
FBXImporter::LogWarn("ignoring dummy material layer (all entries -1)"); FBXImporter::LogWarn("ignoring dummy material layer (all entries -1)");
return; return;
} }
std::swap(temp_materials, m_materials); std::swap(temp_materials, m_materials);
} } else if (type == "LayerElementNormal") {
else if (type == "LayerElementNormal") {
if (m_normals.size() > 0) { if (m_normals.size() > 0) {
FBXImporter::LogError("ignoring additional normal layer"); FBXImporter::LogError("ignoring additional normal layer");
return; return;
} }
ReadVertexDataNormals(m_normals,source, ReadVertexDataNormals(m_normals, source,
MappingInformationType, MappingInformationType,
ReferenceInformationType ReferenceInformationType);
); } else if (type == "LayerElementTangent") {
}
else if (type == "LayerElementTangent") {
if (m_tangents.size() > 0) { if (m_tangents.size() > 0) {
FBXImporter::LogError("ignoring additional tangent layer"); FBXImporter::LogError("ignoring additional tangent layer");
return; return;
} }
ReadVertexDataTangents(m_tangents,source, ReadVertexDataTangents(m_tangents, source,
MappingInformationType, MappingInformationType,
ReferenceInformationType ReferenceInformationType);
); } else if (type == "LayerElementBinormal") {
}
else if (type == "LayerElementBinormal") {
if (m_binormals.size() > 0) { if (m_binormals.size() > 0) {
FBXImporter::LogError("ignoring additional binormal layer"); FBXImporter::LogError("ignoring additional binormal layer");
return; return;
} }
ReadVertexDataBinormals(m_binormals,source, ReadVertexDataBinormals(m_binormals, source,
MappingInformationType, MappingInformationType,
ReferenceInformationType ReferenceInformationType);
); } else if (type == "LayerElementColor") {
} if (index >= AI_MAX_NUMBER_OF_COLOR_SETS) {
else if (type == "LayerElementColor") {
if(index >= AI_MAX_NUMBER_OF_COLOR_SETS) {
FBXImporter::LogError(Formatter::format("ignoring vertex color layer, maximum number of color sets exceeded: ") FBXImporter::LogError(Formatter::format("ignoring vertex color layer, maximum number of color sets exceeded: ")
<< index << " (limit is " << AI_MAX_NUMBER_OF_COLOR_SETS << ")" ); << index << " (limit is " << AI_MAX_NUMBER_OF_COLOR_SETS << ")");
return; return;
} }
ReadVertexDataColors(m_colors[index],source, ReadVertexDataColors(m_colors[index], source,
MappingInformationType, MappingInformationType,
ReferenceInformationType ReferenceInformationType);
);
} }
} }
@ -419,21 +395,20 @@ void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scop
// output is in polygon vertex order. This logic is used for reading normals, UVs, colors, // output is in polygon vertex order. This logic is used for reading normals, UVs, colors,
// tangents .. // tangents ..
template <typename T> template <typename T>
void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source, void ResolveVertexDataArray(std::vector<T> &data_out, const Scope &source,
const std::string& MappingInformationType, const std::string &MappingInformationType,
const std::string& ReferenceInformationType, const std::string &ReferenceInformationType,
const char* dataElementName, const char *dataElementName,
const char* indexDataElementName, const char *indexDataElementName,
size_t vertex_count, size_t vertex_count,
const std::vector<unsigned int>& mapping_counts, const std::vector<unsigned int> &mapping_counts,
const std::vector<unsigned int>& mapping_offsets, const std::vector<unsigned int> &mapping_offsets,
const std::vector<unsigned int>& mappings) const std::vector<unsigned int> &mappings) {
{
bool isDirect = ReferenceInformationType == "Direct"; bool isDirect = ReferenceInformationType == "Direct";
bool isIndexToDirect = ReferenceInformationType == "IndexToDirect"; bool isIndexToDirect = ReferenceInformationType == "IndexToDirect";
// fall-back to direct data if there is no index data element // fall-back to direct data if there is no index data element
if ( isIndexToDirect && !HasElement( source, indexDataElementName ) ) { if (isIndexToDirect && !HasElement(source, indexDataElementName)) {
isDirect = true; isDirect = true;
isIndexToDirect = false; isIndexToDirect = false;
} }
@ -461,13 +436,12 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
data_out[mappings[j]] = tempData[i]; data_out[mappings[j]] = tempData[i];
} }
} }
} } else if (MappingInformationType == "ByVertice" && isIndexToDirect) {
else if (MappingInformationType == "ByVertice" && isIndexToDirect) { std::vector<T> tempData;
std::vector<T> tempData; ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
std::vector<int> uvIndices; std::vector<int> uvIndices;
ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName)); ParseVectorDataArray(uvIndices, GetRequiredElement(source, indexDataElementName));
if (uvIndices.size() != vertex_count) { if (uvIndices.size() != vertex_count) {
FBXImporter::LogError(Formatter::format("length of input data unexpected for ByVertice mapping: ") FBXImporter::LogError(Formatter::format("length of input data unexpected for ByVertice mapping: ")
@ -481,32 +455,29 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i]; const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];
for (unsigned int j = istart; j < iend; ++j) { for (unsigned int j = istart; j < iend; ++j) {
if (static_cast<size_t>(uvIndices[i]) >= tempData.size()) { if (static_cast<size_t>(uvIndices[i]) >= tempData.size()) {
DOMError("index out of range",&GetRequiredElement(source,indexDataElementName)); DOMError("index out of range", &GetRequiredElement(source, indexDataElementName));
} }
data_out[mappings[j]] = tempData[uvIndices[i]]; data_out[mappings[j]] = tempData[uvIndices[i]];
} }
} }
} } else if (MappingInformationType == "ByPolygonVertex" && isDirect) {
else if (MappingInformationType == "ByPolygonVertex" && isDirect) { std::vector<T> tempData;
std::vector<T> tempData; ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
if (tempData.size() != vertex_count) { if (tempData.size() != vertex_count) {
FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ") FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ")
<< tempData.size() << ", expected " << vertex_count << tempData.size() << ", expected " << vertex_count);
);
return; return;
} }
data_out.swap(tempData); data_out.swap(tempData);
} } else if (MappingInformationType == "ByPolygonVertex" && isIndexToDirect) {
else if (MappingInformationType == "ByPolygonVertex" && isIndexToDirect) { std::vector<T> tempData;
std::vector<T> tempData; ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
std::vector<int> uvIndices; std::vector<int> uvIndices;
ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName)); ParseVectorDataArray(uvIndices, GetRequiredElement(source, indexDataElementName));
if (uvIndices.size() != vertex_count) { if (uvIndices.size() != vertex_count) {
FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygonVertex mapping: ") FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygonVertex mapping: ")
@ -518,120 +489,111 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
const T empty; const T empty;
unsigned int next = 0; unsigned int next = 0;
for(int i : uvIndices) { for (int i : uvIndices) {
if ( -1 == i ) { if (-1 == i) {
data_out[ next++ ] = empty; data_out[next++] = empty;
continue; continue;
} }
if (static_cast<size_t>(i) >= tempData.size()) { if (static_cast<size_t>(i) >= tempData.size()) {
DOMError("index out of range",&GetRequiredElement(source,indexDataElementName)); DOMError("index out of range", &GetRequiredElement(source, indexDataElementName));
} }
data_out[next++] = tempData[i]; data_out[next++] = tempData[i];
} }
} } else {
else {
FBXImporter::LogError(Formatter::format("ignoring vertex data channel, access type not implemented: ") FBXImporter::LogError(Formatter::format("ignoring vertex data channel, access type not implemented: ")
<< MappingInformationType << "," << ReferenceInformationType); << MappingInformationType << "," << ReferenceInformationType);
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void MeshGeometry::ReadVertexDataNormals(std::vector<aiVector3D>& normals_out, const Scope& source, void MeshGeometry::ReadVertexDataNormals(std::vector<aiVector3D> &normals_out, const Scope &source,
const std::string& MappingInformationType, const std::string &MappingInformationType,
const std::string& ReferenceInformationType) const std::string &ReferenceInformationType) {
{ ResolveVertexDataArray(normals_out, source, MappingInformationType, ReferenceInformationType,
ResolveVertexDataArray(normals_out,source,MappingInformationType,ReferenceInformationType, "Normals",
"Normals", "NormalsIndex",
"NormalsIndex", m_vertices.size(),
m_vertices.size(), m_mapping_counts,
m_mapping_counts, m_mapping_offsets,
m_mapping_offsets, m_mappings);
m_mappings);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void MeshGeometry::ReadVertexDataUV(std::vector<aiVector2D>& uv_out, const Scope& source, void MeshGeometry::ReadVertexDataUV(std::vector<aiVector2D> &uv_out, const Scope &source,
const std::string& MappingInformationType, const std::string &MappingInformationType,
const std::string& ReferenceInformationType) const std::string &ReferenceInformationType) {
{ ResolveVertexDataArray(uv_out, source, MappingInformationType, ReferenceInformationType,
ResolveVertexDataArray(uv_out,source,MappingInformationType,ReferenceInformationType, "UV",
"UV", "UVIndex",
"UVIndex", m_vertices.size(),
m_vertices.size(), m_mapping_counts,
m_mapping_counts, m_mapping_offsets,
m_mapping_offsets, m_mappings);
m_mappings);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void MeshGeometry::ReadVertexDataColors(std::vector<aiColor4D>& colors_out, const Scope& source, void MeshGeometry::ReadVertexDataColors(std::vector<aiColor4D> &colors_out, const Scope &source,
const std::string& MappingInformationType, const std::string &MappingInformationType,
const std::string& ReferenceInformationType) const std::string &ReferenceInformationType) {
{ ResolveVertexDataArray(colors_out, source, MappingInformationType, ReferenceInformationType,
ResolveVertexDataArray(colors_out,source,MappingInformationType,ReferenceInformationType, "Colors",
"Colors", "ColorIndex",
"ColorIndex", m_vertices.size(),
m_vertices.size(), m_mapping_counts,
m_mapping_counts, m_mapping_offsets,
m_mapping_offsets, m_mappings);
m_mappings);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
static const char *TangentIndexToken = "TangentIndex"; static const char *TangentIndexToken = "TangentIndex";
static const char *TangentsIndexToken = "TangentsIndex"; static const char *TangentsIndexToken = "TangentsIndex";
void MeshGeometry::ReadVertexDataTangents(std::vector<aiVector3D>& tangents_out, const Scope& source, void MeshGeometry::ReadVertexDataTangents(std::vector<aiVector3D> &tangents_out, const Scope &source,
const std::string& MappingInformationType, const std::string &MappingInformationType,
const std::string& ReferenceInformationType) const std::string &ReferenceInformationType) {
{ const char *str = source.Elements().count("Tangents") > 0 ? "Tangents" : "Tangent";
const char * str = source.Elements().count( "Tangents" ) > 0 ? "Tangents" : "Tangent"; const char *strIdx = source.Elements().count("Tangents") > 0 ? TangentsIndexToken : TangentIndexToken;
const char * strIdx = source.Elements().count( "Tangents" ) > 0 ? TangentsIndexToken : TangentIndexToken; ResolveVertexDataArray(tangents_out, source, MappingInformationType, ReferenceInformationType,
ResolveVertexDataArray(tangents_out,source,MappingInformationType,ReferenceInformationType, str,
str, strIdx,
strIdx, m_vertices.size(),
m_vertices.size(), m_mapping_counts,
m_mapping_counts, m_mapping_offsets,
m_mapping_offsets, m_mappings);
m_mappings);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
static const std::string BinormalIndexToken = "BinormalIndex"; static const std::string BinormalIndexToken = "BinormalIndex";
static const std::string BinormalsIndexToken = "BinormalsIndex"; static const std::string BinormalsIndexToken = "BinormalsIndex";
void MeshGeometry::ReadVertexDataBinormals(std::vector<aiVector3D>& binormals_out, const Scope& source, void MeshGeometry::ReadVertexDataBinormals(std::vector<aiVector3D> &binormals_out, const Scope &source,
const std::string& MappingInformationType, const std::string &MappingInformationType,
const std::string& ReferenceInformationType) const std::string &ReferenceInformationType) {
{ const char *str = source.Elements().count("Binormals") > 0 ? "Binormals" : "Binormal";
const char * str = source.Elements().count( "Binormals" ) > 0 ? "Binormals" : "Binormal"; const char *strIdx = source.Elements().count("Binormals") > 0 ? BinormalsIndexToken.c_str() : BinormalIndexToken.c_str();
const char * strIdx = source.Elements().count( "Binormals" ) > 0 ? BinormalsIndexToken.c_str() : BinormalIndexToken.c_str(); ResolveVertexDataArray(binormals_out, source, MappingInformationType, ReferenceInformationType,
ResolveVertexDataArray(binormals_out,source,MappingInformationType,ReferenceInformationType, str,
str, strIdx,
strIdx, m_vertices.size(),
m_vertices.size(), m_mapping_counts,
m_mapping_counts, m_mapping_offsets,
m_mapping_offsets, m_mappings);
m_mappings);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void MeshGeometry::ReadVertexDataMaterials(std::vector<int>& materials_out, const Scope& source, void MeshGeometry::ReadVertexDataMaterials(std::vector<int> &materials_out, const Scope &source,
const std::string& MappingInformationType, const std::string &MappingInformationType,
const std::string& ReferenceInformationType) const std::string &ReferenceInformationType) {
{
const size_t face_count = m_faces.size(); const size_t face_count = m_faces.size();
if( 0 == face_count ) if (0 == face_count) {
{
return; return;
} }
// materials are handled separately. First of all, they are assigned per-face // materials are handled separately. First of all, they are assigned per-face
// and not per polyvert. Secondly, ReferenceInformationType=IndexToDirect // and not per polyvert. Secondly, ReferenceInformationType=IndexToDirect
// has a slightly different meaning for materials. // has a slightly different meaning for materials.
ParseVectorDataArray(materials_out,GetRequiredElement(source,"Materials")); ParseVectorDataArray(materials_out, GetRequiredElement(source, "Materials"));
if (MappingInformationType == "AllSame") { if (MappingInformationType == "AllSame") {
// easy - same material for all faces // easy - same material for all faces
@ -648,27 +610,26 @@ void MeshGeometry::ReadVertexDataMaterials(std::vector<int>& materials_out, cons
} else if (MappingInformationType == "ByPolygon" && ReferenceInformationType == "IndexToDirect") { } else if (MappingInformationType == "ByPolygon" && ReferenceInformationType == "IndexToDirect") {
materials_out.resize(face_count); materials_out.resize(face_count);
if(materials_out.size() != face_count) { if (materials_out.size() != face_count) {
FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ") FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ")
<< materials_out.size() << ", expected " << face_count << materials_out.size() << ", expected " << face_count);
);
return; return;
} }
} else { } else {
FBXImporter::LogError(Formatter::format("ignoring material assignments, access type not implemented: ") FBXImporter::LogError(Formatter::format("ignoring material assignments, access type not implemented: ")
<< MappingInformationType << "," << ReferenceInformationType); << MappingInformationType << "," << ReferenceInformationType);
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
ShapeGeometry::ShapeGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc) ShapeGeometry::ShapeGeometry(uint64_t id, const Element &element, const std::string &name, const Document &doc) :
: Geometry(id, element, name, doc) { Geometry(id, element, name, doc) {
const Scope *sc = element.Compound(); const Scope *sc = element.Compound();
if (nullptr == sc) { if (nullptr == sc) {
DOMError("failed to read Geometry object (class: Shape), no data scope found"); DOMError("failed to read Geometry object (class: Shape), no data scope found");
} }
const Element& Indexes = GetRequiredElement(*sc, "Indexes", &element); const Element &Indexes = GetRequiredElement(*sc, "Indexes", &element);
const Element& Normals = GetRequiredElement(*sc, "Normals", &element); const Element &Normals = GetRequiredElement(*sc, "Normals", &element);
const Element& Vertices = GetRequiredElement(*sc, "Vertices", &element); const Element &Vertices = GetRequiredElement(*sc, "Vertices", &element);
ParseVectorDataArray(m_indices, Indexes); ParseVectorDataArray(m_indices, Indexes);
ParseVectorDataArray(m_vertices, Vertices); ParseVectorDataArray(m_vertices, Vertices);
ParseVectorDataArray(m_normals, Normals); ParseVectorDataArray(m_normals, Normals);
@ -679,27 +640,26 @@ ShapeGeometry::~ShapeGeometry() {
// empty // empty
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const std::vector<aiVector3D>& ShapeGeometry::GetVertices() const { const std::vector<aiVector3D> &ShapeGeometry::GetVertices() const {
return m_vertices; return m_vertices;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const std::vector<aiVector3D>& ShapeGeometry::GetNormals() const { const std::vector<aiVector3D> &ShapeGeometry::GetNormals() const {
return m_normals; return m_normals;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const std::vector<unsigned int>& ShapeGeometry::GetIndices() const { const std::vector<unsigned int> &ShapeGeometry::GetIndices() const {
return m_indices; return m_indices;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
LineGeometry::LineGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc) LineGeometry::LineGeometry(uint64_t id, const Element &element, const std::string &name, const Document &doc) :
: Geometry(id, element, name, doc) Geometry(id, element, name, doc) {
{ const Scope *sc = element.Compound();
const Scope* sc = element.Compound();
if (!sc) { if (!sc) {
DOMError("failed to read Geometry object (class: Line), no data scope found"); DOMError("failed to read Geometry object (class: Line), no data scope found");
} }
const Element& Points = GetRequiredElement(*sc, "Points", &element); const Element &Points = GetRequiredElement(*sc, "Points", &element);
const Element& PointsIndex = GetRequiredElement(*sc, "PointsIndex", &element); const Element &PointsIndex = GetRequiredElement(*sc, "PointsIndex", &element);
ParseVectorDataArray(m_vertices, Points); ParseVectorDataArray(m_vertices, Points);
ParseVectorDataArray(m_indices, PointsIndex); ParseVectorDataArray(m_indices, PointsIndex);
} }
@ -709,14 +669,13 @@ LineGeometry::~LineGeometry() {
// empty // empty
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const std::vector<aiVector3D>& LineGeometry::GetVertices() const { const std::vector<aiVector3D> &LineGeometry::GetVertices() const {
return m_vertices; return m_vertices;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const std::vector<int>& LineGeometry::GetIndices() const { const std::vector<int> &LineGeometry::GetIndices() const {
return m_indices; return m_indices;
} }
} // !FBX } // namespace FBX
} // !Assimp } // namespace Assimp
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -55,20 +55,19 @@ namespace Assimp {
namespace IFC { namespace IFC {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void TempOpening::Transform(const IfcMatrix4& mat) { void TempOpening::Transform(const IfcMatrix4 &mat) {
if(profileMesh) { if (profileMesh) {
profileMesh->Transform(mat); profileMesh->Transform(mat);
} }
if(profileMesh2D) { if (profileMesh2D) {
profileMesh2D->Transform(mat); profileMesh2D->Transform(mat);
} }
extrusionDir *= IfcMatrix3(mat); extrusionDir *= IfcMatrix3(mat);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
aiMesh* TempMesh::ToMesh() aiMesh *TempMesh::ToMesh() {
{ ai_assert(mVerts.size() == std::accumulate(mVertcnt.begin(), mVertcnt.end(), size_t(0)));
ai_assert(mVerts.size() == std::accumulate(mVertcnt.begin(),mVertcnt.end(),size_t(0)));
if (mVerts.empty()) { if (mVerts.empty()) {
return nullptr; return nullptr;
@ -79,14 +78,14 @@ aiMesh* TempMesh::ToMesh()
// copy vertices // copy vertices
mesh->mNumVertices = static_cast<unsigned int>(mVerts.size()); mesh->mNumVertices = static_cast<unsigned int>(mVerts.size());
mesh->mVertices = new aiVector3D[mesh->mNumVertices]; mesh->mVertices = new aiVector3D[mesh->mNumVertices];
std::copy(mVerts.begin(),mVerts.end(),mesh->mVertices); std::copy(mVerts.begin(), mVerts.end(), mesh->mVertices);
// and build up faces // and build up faces
mesh->mNumFaces = static_cast<unsigned int>(mVertcnt.size()); mesh->mNumFaces = static_cast<unsigned int>(mVertcnt.size());
mesh->mFaces = new aiFace[mesh->mNumFaces]; mesh->mFaces = new aiFace[mesh->mNumFaces];
for(unsigned int i = 0,n=0, acc = 0; i < mesh->mNumFaces; ++n) { for (unsigned int i = 0, n = 0, acc = 0; i < mesh->mNumFaces; ++n) {
aiFace& f = mesh->mFaces[i]; aiFace &f = mesh->mFaces[i];
if (!mVertcnt[n]) { if (!mVertcnt[n]) {
--mesh->mNumFaces; --mesh->mNumFaces;
continue; continue;
@ -94,7 +93,7 @@ aiMesh* TempMesh::ToMesh()
f.mNumIndices = mVertcnt[n]; f.mNumIndices = mVertcnt[n];
f.mIndices = new unsigned int[f.mNumIndices]; f.mIndices = new unsigned int[f.mNumIndices];
for(unsigned int a = 0; a < f.mNumIndices; ++a) { for (unsigned int a = 0; a < f.mNumIndices; ++a) {
f.mIndices[a] = acc++; f.mIndices[a] = acc++;
} }
@ -105,36 +104,31 @@ aiMesh* TempMesh::ToMesh()
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void TempMesh::Clear() void TempMesh::Clear() {
{
mVerts.clear(); mVerts.clear();
mVertcnt.clear(); mVertcnt.clear();
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void TempMesh::Transform(const IfcMatrix4& mat) void TempMesh::Transform(const IfcMatrix4 &mat) {
{ for (IfcVector3 &v : mVerts) {
for(IfcVector3& v : mVerts) {
v *= mat; v *= mat;
} }
} }
// ------------------------------------------------------------------------------ // ------------------------------------------------------------------------------
IfcVector3 TempMesh::Center() const IfcVector3 TempMesh::Center() const {
{ return (mVerts.size() == 0) ? IfcVector3(0.0f, 0.0f, 0.0f) : (std::accumulate(mVerts.begin(), mVerts.end(), IfcVector3()) / static_cast<IfcFloat>(mVerts.size()));
return (mVerts.size() == 0) ? IfcVector3(0.0f, 0.0f, 0.0f) : (std::accumulate(mVerts.begin(),mVerts.end(),IfcVector3()) / static_cast<IfcFloat>(mVerts.size()));
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void TempMesh::Append(const TempMesh& other) void TempMesh::Append(const TempMesh &other) {
{ mVerts.insert(mVerts.end(), other.mVerts.begin(), other.mVerts.end());
mVerts.insert(mVerts.end(),other.mVerts.begin(),other.mVerts.end()); mVertcnt.insert(mVertcnt.end(), other.mVertcnt.begin(), other.mVertcnt.end());
mVertcnt.insert(mVertcnt.end(),other.mVertcnt.begin(),other.mVertcnt.end());
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void TempMesh::RemoveDegenerates() void TempMesh::RemoveDegenerates() {
{
// The strategy is simple: walk the mesh and compute normals using // The strategy is simple: walk the mesh and compute normals using
// Newell's algorithm. The length of the normals gives the area // Newell's algorithm. The length of the normals gives the area
// of the polygons, which is close to zero for lines. // of the polygons, which is close to zero for lines.
@ -161,52 +155,48 @@ void TempMesh::RemoveDegenerates()
++it; ++it;
} }
if(drop) { if (drop) {
IFCImporter::LogVerboseDebug("removing degenerate faces"); IFCImporter::LogVerboseDebug("removing degenerate faces");
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
IfcVector3 TempMesh::ComputePolygonNormal(const IfcVector3* vtcs, size_t cnt, bool normalize) IfcVector3 TempMesh::ComputePolygonNormal(const IfcVector3 *vtcs, size_t cnt, bool normalize) {
{ const size_t Capa = cnt + 2;
std::vector<IfcFloat> temp((cnt+2)*3); std::vector<IfcFloat> temp((Capa)*3);
for( size_t vofs = 0, i = 0; vofs < cnt; ++vofs ) for (size_t vofs = 0, i = 0; vofs < cnt; ++vofs) {
{ const IfcVector3 &v = vtcs[vofs];
const IfcVector3& v = vtcs[vofs];
temp[i++] = v.x; temp[i++] = v.x;
temp[i++] = v.y; temp[i++] = v.y;
temp[i++] = v.z; temp[i++] = v.z;
} }
IfcVector3 nor; IfcVector3 nor;
NewellNormal<3, 3, 3>(nor, static_cast<int>(cnt), &temp[0], &temp[1], &temp[2]); NewellNormal<3, 3, 3>(nor, static_cast<int>(cnt), &temp[0], &temp[1], &temp[2], Capa);
return normalize ? nor.Normalize() : nor; return normalize ? nor.Normalize() : nor;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void TempMesh::ComputePolygonNormals(std::vector<IfcVector3>& normals, void TempMesh::ComputePolygonNormals(std::vector<IfcVector3> &normals, bool normalize, size_t ofs) const {
bool normalize,
size_t ofs) const
{
size_t max_vcount = 0; size_t max_vcount = 0;
std::vector<unsigned int>::const_iterator begin = mVertcnt.begin()+ofs, end = mVertcnt.end(), iit; std::vector<unsigned int>::const_iterator begin = mVertcnt.begin() + ofs, end = mVertcnt.end(), iit;
for(iit = begin; iit != end; ++iit) { for (iit = begin; iit != end; ++iit) {
max_vcount = std::max(max_vcount,static_cast<size_t>(*iit)); max_vcount = std::max(max_vcount, static_cast<size_t>(*iit));
} }
const size_t Capa = max_vcount + 2;
std::vector<IfcFloat> temp((max_vcount+2)*4); std::vector<IfcFloat> temp(Capa * 4);
normals.reserve( normals.size() + mVertcnt.size()-ofs ); normals.reserve(normals.size() + mVertcnt.size() - ofs);
// `NewellNormal()` currently has a relatively strange interface and need to // `NewellNormal()` currently has a relatively strange interface and need to
// re-structure things a bit to meet them. // re-structure things a bit to meet them.
size_t vidx = std::accumulate(mVertcnt.begin(),begin,0); size_t vidx = std::accumulate(mVertcnt.begin(), begin, 0);
for(iit = begin; iit != end; vidx += *iit++) { for (iit = begin; iit != end; vidx += *iit++) {
if (!*iit) { if (!*iit) {
normals.push_back(IfcVector3()); normals.push_back(IfcVector3());
continue; continue;
} }
for(size_t vofs = 0, cnt = 0; vofs < *iit; ++vofs) { for (size_t vofs = 0, cnt = 0; vofs < *iit; ++vofs) {
const IfcVector3& v = mVerts[vidx+vofs]; const IfcVector3 &v = mVerts[vidx + vofs];
temp[cnt++] = v.x; temp[cnt++] = v.x;
temp[cnt++] = v.y; temp[cnt++] = v.y;
temp[cnt++] = v.z; temp[cnt++] = v.z;
@ -217,11 +207,11 @@ void TempMesh::ComputePolygonNormals(std::vector<IfcVector3>& normals,
} }
normals.push_back(IfcVector3()); normals.push_back(IfcVector3());
NewellNormal<4,4,4>(normals.back(),*iit,&temp[0],&temp[1],&temp[2]); NewellNormal<4, 4, 4>(normals.back(), *iit, &temp[0], &temp[1], &temp[2], Capa);
} }
if(normalize) { if (normalize) {
for(IfcVector3& n : normals) { for (IfcVector3 &n : normals) {
n.Normalize(); n.Normalize();
} }
} }
@ -229,62 +219,55 @@ void TempMesh::ComputePolygonNormals(std::vector<IfcVector3>& normals,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Compute the normal of the last polygon in the given mesh // Compute the normal of the last polygon in the given mesh
IfcVector3 TempMesh::ComputeLastPolygonNormal(bool normalize) const IfcVector3 TempMesh::ComputeLastPolygonNormal(bool normalize) const {
{
return ComputePolygonNormal(&mVerts[mVerts.size() - mVertcnt.back()], mVertcnt.back(), normalize); return ComputePolygonNormal(&mVerts[mVerts.size() - mVertcnt.back()], mVertcnt.back(), normalize);
} }
struct CompareVector struct CompareVector {
{ bool operator()(const IfcVector3 &a, const IfcVector3 &b) const {
bool operator () (const IfcVector3& a, const IfcVector3& b) const
{
IfcVector3 d = a - b; IfcVector3 d = a - b;
IfcFloat eps = 1e-6; IfcFloat eps = 1e-6;
return d.x < -eps || (std::abs(d.x) < eps && d.y < -eps) || (std::abs(d.x) < eps && std::abs(d.y) < eps && d.z < -eps); return d.x < -eps || (std::abs(d.x) < eps && d.y < -eps) || (std::abs(d.x) < eps && std::abs(d.y) < eps && d.z < -eps);
} }
}; };
struct FindVector struct FindVector {
{
IfcVector3 v; IfcVector3 v;
FindVector(const IfcVector3& p) : v(p) { } FindVector(const IfcVector3 &p) :
bool operator () (const IfcVector3& p) { return FuzzyVectorCompare(1e-6)(p, v); } v(p) {}
bool operator()(const IfcVector3 &p) { return FuzzyVectorCompare(1e-6)(p, v); }
}; };
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void TempMesh::FixupFaceOrientation() void TempMesh::FixupFaceOrientation() {
{
const IfcVector3 vavg = Center(); const IfcVector3 vavg = Center();
// create a list of start indices for all faces to allow random access to faces // create a list of start indices for all faces to allow random access to faces
std::vector<size_t> faceStartIndices(mVertcnt.size()); std::vector<size_t> faceStartIndices(mVertcnt.size());
for( size_t i = 0, a = 0; a < mVertcnt.size(); i += mVertcnt[a], ++a ) for (size_t i = 0, a = 0; a < mVertcnt.size(); i += mVertcnt[a], ++a)
faceStartIndices[a] = i; faceStartIndices[a] = i;
// list all faces on a vertex // list all faces on a vertex
std::map<IfcVector3, std::vector<size_t>, CompareVector> facesByVertex; std::map<IfcVector3, std::vector<size_t>, CompareVector> facesByVertex;
for( size_t a = 0; a < mVertcnt.size(); ++a ) for (size_t a = 0; a < mVertcnt.size(); ++a) {
{ for (size_t b = 0; b < mVertcnt[a]; ++b)
for( size_t b = 0; b < mVertcnt[a]; ++b )
facesByVertex[mVerts[faceStartIndices[a] + b]].push_back(a); facesByVertex[mVerts[faceStartIndices[a] + b]].push_back(a);
} }
// determine neighbourhood for all polys // determine neighbourhood for all polys
std::vector<size_t> neighbour(mVerts.size(), SIZE_MAX); std::vector<size_t> neighbour(mVerts.size(), SIZE_MAX);
std::vector<size_t> tempIntersect(10); std::vector<size_t> tempIntersect(10);
for( size_t a = 0; a < mVertcnt.size(); ++a ) for (size_t a = 0; a < mVertcnt.size(); ++a) {
{ for (size_t b = 0; b < mVertcnt[a]; ++b) {
for( size_t b = 0; b < mVertcnt[a]; ++b )
{
size_t ib = faceStartIndices[a] + b, nib = faceStartIndices[a] + (b + 1) % mVertcnt[a]; size_t ib = faceStartIndices[a] + b, nib = faceStartIndices[a] + (b + 1) % mVertcnt[a];
const std::vector<size_t>& facesOnB = facesByVertex[mVerts[ib]]; const std::vector<size_t> &facesOnB = facesByVertex[mVerts[ib]];
const std::vector<size_t>& facesOnNB = facesByVertex[mVerts[nib]]; const std::vector<size_t> &facesOnNB = facesByVertex[mVerts[nib]];
// there should be exactly one or two faces which appear in both lists. Our face and the other side // there should be exactly one or two faces which appear in both lists. Our face and the other side
std::vector<size_t>::iterator sectstart = tempIntersect.begin(); std::vector<size_t>::iterator sectstart = tempIntersect.begin();
std::vector<size_t>::iterator sectend = std::set_intersection( std::vector<size_t>::iterator sectend = std::set_intersection(
facesOnB.begin(), facesOnB.end(), facesOnNB.begin(), facesOnNB.end(), sectstart); facesOnB.begin(), facesOnB.end(), facesOnNB.begin(), facesOnNB.end(), sectstart);
if( std::distance(sectstart, sectend) != 2 ) if (std::distance(sectstart, sectend) != 2)
continue; continue;
if( *sectstart == a ) if (*sectstart == a)
++sectstart; ++sectstart;
neighbour[ib] = *sectstart; neighbour[ib] = *sectstart;
} }
@ -294,30 +277,31 @@ void TempMesh::FixupFaceOrientation()
// facing outwards. So we reverse this face to point outwards in relation to the center. Then we adapt neighbouring // facing outwards. So we reverse this face to point outwards in relation to the center. Then we adapt neighbouring
// faces to have the same winding until all faces have been tested. // faces to have the same winding until all faces have been tested.
std::vector<bool> faceDone(mVertcnt.size(), false); std::vector<bool> faceDone(mVertcnt.size(), false);
while( std::count(faceDone.begin(), faceDone.end(), false) != 0 ) while (std::count(faceDone.begin(), faceDone.end(), false) != 0) {
{
// find the farthest of the remaining faces // find the farthest of the remaining faces
size_t farthestIndex = SIZE_MAX; size_t farthestIndex = SIZE_MAX;
IfcFloat farthestDistance = -1.0; IfcFloat farthestDistance = -1.0;
for( size_t a = 0; a < mVertcnt.size(); ++a ) for (size_t a = 0; a < mVertcnt.size(); ++a) {
{ if (faceDone[a])
if( faceDone[a] )
continue; continue;
IfcVector3 faceCenter = std::accumulate(mVerts.begin() + faceStartIndices[a], IfcVector3 faceCenter = std::accumulate(mVerts.begin() + faceStartIndices[a],
mVerts.begin() + faceStartIndices[a] + mVertcnt[a], IfcVector3(0.0)) / IfcFloat(mVertcnt[a]); mVerts.begin() + faceStartIndices[a] + mVertcnt[a], IfcVector3(0.0)) /
IfcFloat(mVertcnt[a]);
IfcFloat dst = (faceCenter - vavg).SquareLength(); IfcFloat dst = (faceCenter - vavg).SquareLength();
if( dst > farthestDistance ) { farthestDistance = dst; farthestIndex = a; } if (dst > farthestDistance) {
farthestDistance = dst;
farthestIndex = a;
}
} }
// calculate its normal and reverse the poly if its facing towards the mesh center // calculate its normal and reverse the poly if its facing towards the mesh center
IfcVector3 farthestNormal = ComputePolygonNormal(mVerts.data() + faceStartIndices[farthestIndex], mVertcnt[farthestIndex]); IfcVector3 farthestNormal = ComputePolygonNormal(mVerts.data() + faceStartIndices[farthestIndex], mVertcnt[farthestIndex]);
IfcVector3 farthestCenter = std::accumulate(mVerts.begin() + faceStartIndices[farthestIndex], IfcVector3 farthestCenter = std::accumulate(mVerts.begin() + faceStartIndices[farthestIndex],
mVerts.begin() + faceStartIndices[farthestIndex] + mVertcnt[farthestIndex], IfcVector3(0.0)) mVerts.begin() + faceStartIndices[farthestIndex] + mVertcnt[farthestIndex], IfcVector3(0.0)) /
/ IfcFloat(mVertcnt[farthestIndex]); IfcFloat(mVertcnt[farthestIndex]);
// We accept a bit of negative orientation without reversing. In case of doubt, prefer the orientation given in // We accept a bit of negative orientation without reversing. In case of doubt, prefer the orientation given in
// the file. // the file.
if( (farthestNormal * (farthestCenter - vavg).Normalize()) < -0.4 ) if ((farthestNormal * (farthestCenter - vavg).Normalize()) < -0.4) {
{
size_t fsi = faceStartIndices[farthestIndex], fvc = mVertcnt[farthestIndex]; size_t fsi = faceStartIndices[farthestIndex], fvc = mVertcnt[farthestIndex];
std::reverse(mVerts.begin() + fsi, mVerts.begin() + fsi + fvc); std::reverse(mVerts.begin() + fsi, mVerts.begin() + fsi + fvc);
std::reverse(neighbour.begin() + fsi, neighbour.begin() + fsi + fvc); std::reverse(neighbour.begin() + fsi, neighbour.begin() + fsi + fvc);
@ -326,7 +310,7 @@ void TempMesh::FixupFaceOrientation()
// Before: points A - B - C - D with edge neighbour p - q - r - s // Before: points A - B - C - D with edge neighbour p - q - r - s
// After: points D - C - B - A, reversed neighbours are s - r - q - p, but the should be // After: points D - C - B - A, reversed neighbours are s - r - q - p, but the should be
// r q p s // r q p s
for( size_t a = 0; a < fvc - 1; ++a ) for (size_t a = 0; a < fvc - 1; ++a)
std::swap(neighbour[fsi + a], neighbour[fsi + a + 1]); std::swap(neighbour[fsi + a], neighbour[fsi + a + 1]);
} }
faceDone[farthestIndex] = true; faceDone[farthestIndex] = true;
@ -334,21 +318,19 @@ void TempMesh::FixupFaceOrientation()
todo.push_back(farthestIndex); todo.push_back(farthestIndex);
// go over its neighbour faces recursively and adapt their winding order to match the farthest face // go over its neighbour faces recursively and adapt their winding order to match the farthest face
while( !todo.empty() ) while (!todo.empty()) {
{
size_t tdf = todo.back(); size_t tdf = todo.back();
size_t vsi = faceStartIndices[tdf], vc = mVertcnt[tdf]; size_t vsi = faceStartIndices[tdf], vc = mVertcnt[tdf];
todo.pop_back(); todo.pop_back();
// check its neighbours // check its neighbours
for( size_t a = 0; a < vc; ++a ) for (size_t a = 0; a < vc; ++a) {
{
// ignore neighbours if we already checked them // ignore neighbours if we already checked them
size_t nbi = neighbour[vsi + a]; size_t nbi = neighbour[vsi + a];
if( nbi == SIZE_MAX || faceDone[nbi] ) if (nbi == SIZE_MAX || faceDone[nbi])
continue; continue;
const IfcVector3& vp = mVerts[vsi + a]; const IfcVector3 &vp = mVerts[vsi + a];
size_t nbvsi = faceStartIndices[nbi], nbvc = mVertcnt[nbi]; size_t nbvsi = faceStartIndices[nbi], nbvc = mVertcnt[nbi];
std::vector<IfcVector3>::iterator it = std::find_if(mVerts.begin() + nbvsi, mVerts.begin() + nbvsi + nbvc, FindVector(vp)); std::vector<IfcVector3>::iterator it = std::find_if(mVerts.begin() + nbvsi, mVerts.begin() + nbvsi + nbvc, FindVector(vp));
ai_assert(it != mVerts.begin() + nbvsi + nbvc); ai_assert(it != mVerts.begin() + nbvsi + nbvc);
@ -358,8 +340,7 @@ void TempMesh::FixupFaceOrientation()
// to reverse the neighbour // to reverse the neighbour
nb_vidx = (nb_vidx + 1) % nbvc; nb_vidx = (nb_vidx + 1) % nbvc;
size_t oursideidx = (a + 1) % vc; size_t oursideidx = (a + 1) % vc;
if( FuzzyVectorCompare(1e-6)(mVerts[vsi + oursideidx], mVerts[nbvsi + nb_vidx]) ) if (FuzzyVectorCompare(1e-6)(mVerts[vsi + oursideidx], mVerts[nbvsi + nb_vidx])) {
{
std::reverse(mVerts.begin() + nbvsi, mVerts.begin() + nbvsi + nbvc); std::reverse(mVerts.begin() + nbvsi, mVerts.begin() + nbvsi + nbvc);
std::reverse(neighbour.begin() + nbvsi, neighbour.begin() + nbvsi + nbvc); std::reverse(neighbour.begin() + nbvsi, neighbour.begin() + nbvsi + nbvc);
for (size_t aa = 0; aa < nbvc - 1; ++aa) { for (size_t aa = 0; aa < nbvc - 1; ++aa) {
@ -381,17 +362,16 @@ void TempMesh::FixupFaceOrientation()
void TempMesh::RemoveAdjacentDuplicates() { void TempMesh::RemoveAdjacentDuplicates() {
bool drop = false; bool drop = false;
std::vector<IfcVector3>::iterator base = mVerts.begin(); std::vector<IfcVector3>::iterator base = mVerts.begin();
for(unsigned int& cnt : mVertcnt) { for (unsigned int &cnt : mVertcnt) {
if (cnt < 2){ if (cnt < 2) {
base += cnt; base += cnt;
continue; continue;
} }
IfcVector3 vmin,vmax; IfcVector3 vmin, vmax;
ArrayBounds(&*base, cnt ,vmin,vmax); ArrayBounds(&*base, cnt, vmin, vmax);
const IfcFloat epsilon = (vmax - vmin).SquareLength() / static_cast<IfcFloat>(1e9);
const IfcFloat epsilon = (vmax-vmin).SquareLength() / static_cast<IfcFloat>(1e9);
//const IfcFloat dotepsilon = 1e-9; //const IfcFloat dotepsilon = 1e-9;
//// look for vertices that lie directly on the line between their predecessor and their //// look for vertices that lie directly on the line between their predecessor and their
@ -419,153 +399,127 @@ void TempMesh::RemoveAdjacentDuplicates() {
// drop any identical, adjacent vertices. this pass will collect the dropouts // drop any identical, adjacent vertices. this pass will collect the dropouts
// of the previous pass as a side-effect. // of the previous pass as a side-effect.
FuzzyVectorCompare fz(epsilon); FuzzyVectorCompare fz(epsilon);
std::vector<IfcVector3>::iterator end = base+cnt, e = std::unique( base, end, fz ); std::vector<IfcVector3>::iterator end = base + cnt, e = std::unique(base, end, fz);
if (e != end) { if (e != end) {
cnt -= static_cast<unsigned int>(std::distance(e, end)); cnt -= static_cast<unsigned int>(std::distance(e, end));
mVerts.erase(e,end); mVerts.erase(e, end);
drop = true; drop = true;
} }
// check front and back vertices for this polygon // check front and back vertices for this polygon
if (cnt > 1 && fz(*base,*(base+cnt-1))) { if (cnt > 1 && fz(*base, *(base + cnt - 1))) {
mVerts.erase(base+ --cnt); mVerts.erase(base + --cnt);
drop = true; drop = true;
} }
// removing adjacent duplicates shouldn't erase everything :-) // removing adjacent duplicates shouldn't erase everything :-)
ai_assert(cnt>0); ai_assert(cnt > 0);
base += cnt; base += cnt;
} }
if(drop) { if (drop) {
IFCImporter::LogVerboseDebug("removing duplicate vertices"); IFCImporter::LogVerboseDebug("removing duplicate vertices");
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void TempMesh::Swap(TempMesh& other) void TempMesh::Swap(TempMesh &other) {
{
mVertcnt.swap(other.mVertcnt); mVertcnt.swap(other.mVertcnt);
mVerts.swap(other.mVerts); mVerts.swap(other.mVerts);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool IsTrue(const ::Assimp::STEP::EXPRESS::BOOLEAN& in) bool IsTrue(const ::Assimp::STEP::EXPRESS::BOOLEAN &in) {
{
return (std::string)in == "TRUE" || (std::string)in == "T"; return (std::string)in == "TRUE" || (std::string)in == "T";
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
IfcFloat ConvertSIPrefix(const std::string& prefix) IfcFloat ConvertSIPrefix(const std::string &prefix) {
{
if (prefix == "EXA") { if (prefix == "EXA") {
return 1e18f; return 1e18f;
} } else if (prefix == "PETA") {
else if (prefix == "PETA") {
return 1e15f; return 1e15f;
} } else if (prefix == "TERA") {
else if (prefix == "TERA") {
return 1e12f; return 1e12f;
} } else if (prefix == "GIGA") {
else if (prefix == "GIGA") {
return 1e9f; return 1e9f;
} } else if (prefix == "MEGA") {
else if (prefix == "MEGA") {
return 1e6f; return 1e6f;
} } else if (prefix == "KILO") {
else if (prefix == "KILO") {
return 1e3f; return 1e3f;
} } else if (prefix == "HECTO") {
else if (prefix == "HECTO") {
return 1e2f; return 1e2f;
} } else if (prefix == "DECA") {
else if (prefix == "DECA") {
return 1e-0f; return 1e-0f;
} } else if (prefix == "DECI") {
else if (prefix == "DECI") {
return 1e-1f; return 1e-1f;
} } else if (prefix == "CENTI") {
else if (prefix == "CENTI") {
return 1e-2f; return 1e-2f;
} } else if (prefix == "MILLI") {
else if (prefix == "MILLI") {
return 1e-3f; return 1e-3f;
} } else if (prefix == "MICRO") {
else if (prefix == "MICRO") {
return 1e-6f; return 1e-6f;
} } else if (prefix == "NANO") {
else if (prefix == "NANO") {
return 1e-9f; return 1e-9f;
} } else if (prefix == "PICO") {
else if (prefix == "PICO") {
return 1e-12f; return 1e-12f;
} } else if (prefix == "FEMTO") {
else if (prefix == "FEMTO") {
return 1e-15f; return 1e-15f;
} } else if (prefix == "ATTO") {
else if (prefix == "ATTO") {
return 1e-18f; return 1e-18f;
} } else {
else {
IFCImporter::LogError("Unrecognized SI prefix: " + prefix); IFCImporter::LogError("Unrecognized SI prefix: " + prefix);
return 1; return 1;
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertColor(aiColor4D& out, const Schema_2x3::IfcColourRgb& in) void ConvertColor(aiColor4D &out, const Schema_2x3::IfcColourRgb &in) {
{ out.r = static_cast<float>(in.Red);
out.r = static_cast<float>( in.Red ); out.g = static_cast<float>(in.Green);
out.g = static_cast<float>( in.Green ); out.b = static_cast<float>(in.Blue);
out.b = static_cast<float>( in.Blue ); out.a = static_cast<float>(1.f);
out.a = static_cast<float>( 1.f );
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertColor(aiColor4D& out, const Schema_2x3::IfcColourOrFactor& in,ConversionData& conv,const aiColor4D* base) void ConvertColor(aiColor4D &out, const Schema_2x3::IfcColourOrFactor &in, ConversionData &conv, const aiColor4D *base) {
{ if (const ::Assimp::STEP::EXPRESS::REAL *const r = in.ToPtr<::Assimp::STEP::EXPRESS::REAL>()) {
if (const ::Assimp::STEP::EXPRESS::REAL* const r = in.ToPtr<::Assimp::STEP::EXPRESS::REAL>()) {
out.r = out.g = out.b = static_cast<float>(*r); out.r = out.g = out.b = static_cast<float>(*r);
if(base) { if (base) {
out.r *= static_cast<float>( base->r ); out.r *= static_cast<float>(base->r);
out.g *= static_cast<float>( base->g ); out.g *= static_cast<float>(base->g);
out.b *= static_cast<float>( base->b ); out.b *= static_cast<float>(base->b);
out.a = static_cast<float>( base->a ); out.a = static_cast<float>(base->a);
} } else
else out.a = 1.0; out.a = 1.0;
} } else if (const Schema_2x3::IfcColourRgb *const rgb = in.ResolveSelectPtr<Schema_2x3::IfcColourRgb>(conv.db)) {
else if (const Schema_2x3::IfcColourRgb* const rgb = in.ResolveSelectPtr<Schema_2x3::IfcColourRgb>(conv.db)) { ConvertColor(out, *rgb);
ConvertColor(out,*rgb); } else {
}
else {
IFCImporter::LogWarn("skipping unknown IfcColourOrFactor entity"); IFCImporter::LogWarn("skipping unknown IfcColourOrFactor entity");
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertCartesianPoint(IfcVector3& out, const Schema_2x3::IfcCartesianPoint& in) void ConvertCartesianPoint(IfcVector3 &out, const Schema_2x3::IfcCartesianPoint &in) {
{
out = IfcVector3(); out = IfcVector3();
for(size_t i = 0; i < in.Coordinates.size(); ++i) { for (size_t i = 0; i < in.Coordinates.size(); ++i) {
out[static_cast<unsigned int>(i)] = in.Coordinates[i]; out[static_cast<unsigned int>(i)] = in.Coordinates[i];
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertVector(IfcVector3& out, const Schema_2x3::IfcVector& in) void ConvertVector(IfcVector3 &out, const Schema_2x3::IfcVector &in) {
{ ConvertDirection(out, in.Orientation);
ConvertDirection(out,in.Orientation);
out *= in.Magnitude; out *= in.Magnitude;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertDirection(IfcVector3& out, const Schema_2x3::IfcDirection& in) void ConvertDirection(IfcVector3 &out, const Schema_2x3::IfcDirection &in) {
{
out = IfcVector3(); out = IfcVector3();
for(size_t i = 0; i < in.DirectionRatios.size(); ++i) { for (size_t i = 0; i < in.DirectionRatios.size(); ++i) {
out[static_cast<unsigned int>(i)] = in.DirectionRatios[i]; out[static_cast<unsigned int>(i)] = in.DirectionRatios[i];
} }
const IfcFloat len = out.Length(); const IfcFloat len = out.Length();
if (len<1e-6) { if (len < 1e-6) {
IFCImporter::LogWarn("direction vector magnitude too small, normalization would result in a division by zero"); IFCImporter::LogWarn("direction vector magnitude too small, normalization would result in a division by zero");
return; return;
} }
@ -573,8 +527,7 @@ void ConvertDirection(IfcVector3& out, const Schema_2x3::IfcDirection& in)
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void AssignMatrixAxes(IfcMatrix4& out, const IfcVector3& x, const IfcVector3& y, const IfcVector3& z) void AssignMatrixAxes(IfcMatrix4 &out, const IfcVector3 &x, const IfcVector3 &y, const IfcVector3 &z) {
{
out.a1 = x.x; out.a1 = x.x;
out.b1 = x.y; out.b1 = x.y;
out.c1 = x.z; out.c1 = x.z;
@ -589,116 +542,105 @@ void AssignMatrixAxes(IfcMatrix4& out, const IfcVector3& x, const IfcVector3& y,
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement3D& in) void ConvertAxisPlacement(IfcMatrix4 &out, const Schema_2x3::IfcAxis2Placement3D &in) {
{
IfcVector3 loc; IfcVector3 loc;
ConvertCartesianPoint(loc,in.Location); ConvertCartesianPoint(loc, in.Location);
IfcVector3 z(0.f,0.f,1.f),r(1.f,0.f,0.f),x; IfcVector3 z(0.f, 0.f, 1.f), r(1.f, 0.f, 0.f), x;
if (in.Axis) { if (in.Axis) {
ConvertDirection(z,*in.Axis.Get()); ConvertDirection(z, *in.Axis.Get());
} }
if (in.RefDirection) { if (in.RefDirection) {
ConvertDirection(r,*in.RefDirection.Get()); ConvertDirection(r, *in.RefDirection.Get());
} }
IfcVector3 v = r.Normalize(); IfcVector3 v = r.Normalize();
IfcVector3 tmpx = z * (v*z); IfcVector3 tmpx = z * (v * z);
x = (v-tmpx).Normalize(); x = (v - tmpx).Normalize();
IfcVector3 y = (z^x); IfcVector3 y = (z ^ x);
IfcMatrix4::Translation(loc,out); IfcMatrix4::Translation(loc, out);
AssignMatrixAxes(out,x,y,z); AssignMatrixAxes(out, x, y, z);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement2D& in) void ConvertAxisPlacement(IfcMatrix4 &out, const Schema_2x3::IfcAxis2Placement2D &in) {
{
IfcVector3 loc; IfcVector3 loc;
ConvertCartesianPoint(loc,in.Location); ConvertCartesianPoint(loc, in.Location);
IfcVector3 x(1.f,0.f,0.f); IfcVector3 x(1.f, 0.f, 0.f);
if (in.RefDirection) { if (in.RefDirection) {
ConvertDirection(x,*in.RefDirection.Get()); ConvertDirection(x, *in.RefDirection.Get());
} }
const IfcVector3 y = IfcVector3(x.y,-x.x,0.f); const IfcVector3 y = IfcVector3(x.y, -x.x, 0.f);
IfcMatrix4::Translation(loc,out); IfcMatrix4::Translation(loc, out);
AssignMatrixAxes(out,x,y,IfcVector3(0.f,0.f,1.f)); AssignMatrixAxes(out, x, y, IfcVector3(0.f, 0.f, 1.f));
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertAxisPlacement(IfcVector3& axis, IfcVector3& pos, const Schema_2x3::IfcAxis1Placement& in) void ConvertAxisPlacement(IfcVector3 &axis, IfcVector3 &pos, const Schema_2x3::IfcAxis1Placement &in) {
{ ConvertCartesianPoint(pos, in.Location);
ConvertCartesianPoint(pos,in.Location);
if (in.Axis) { if (in.Axis) {
ConvertDirection(axis,in.Axis.Get()); ConvertDirection(axis, in.Axis.Get());
} } else {
else { axis = IfcVector3(0.f, 0.f, 1.f);
axis = IfcVector3(0.f,0.f,1.f);
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement& in, ConversionData& conv) void ConvertAxisPlacement(IfcMatrix4 &out, const Schema_2x3::IfcAxis2Placement &in, ConversionData &conv) {
{ if (const Schema_2x3::IfcAxis2Placement3D *pl3 = in.ResolveSelectPtr<Schema_2x3::IfcAxis2Placement3D>(conv.db)) {
if(const Schema_2x3::IfcAxis2Placement3D* pl3 = in.ResolveSelectPtr<Schema_2x3::IfcAxis2Placement3D>(conv.db)) { ConvertAxisPlacement(out, *pl3);
ConvertAxisPlacement(out,*pl3); } else if (const Schema_2x3::IfcAxis2Placement2D *pl2 = in.ResolveSelectPtr<Schema_2x3::IfcAxis2Placement2D>(conv.db)) {
} ConvertAxisPlacement(out, *pl2);
else if(const Schema_2x3::IfcAxis2Placement2D* pl2 = in.ResolveSelectPtr<Schema_2x3::IfcAxis2Placement2D>(conv.db)) { } else {
ConvertAxisPlacement(out,*pl2);
}
else {
IFCImporter::LogWarn("skipping unknown IfcAxis2Placement entity"); IFCImporter::LogWarn("skipping unknown IfcAxis2Placement entity");
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertTransformOperator(IfcMatrix4& out, const Schema_2x3::IfcCartesianTransformationOperator& op) void ConvertTransformOperator(IfcMatrix4 &out, const Schema_2x3::IfcCartesianTransformationOperator &op) {
{
IfcVector3 loc; IfcVector3 loc;
ConvertCartesianPoint(loc,op.LocalOrigin); ConvertCartesianPoint(loc, op.LocalOrigin);
IfcVector3 x(1.f,0.f,0.f),y(0.f,1.f,0.f),z(0.f,0.f,1.f); IfcVector3 x(1.f, 0.f, 0.f), y(0.f, 1.f, 0.f), z(0.f, 0.f, 1.f);
if (op.Axis1) { if (op.Axis1) {
ConvertDirection(x,*op.Axis1.Get()); ConvertDirection(x, *op.Axis1.Get());
} }
if (op.Axis2) { if (op.Axis2) {
ConvertDirection(y,*op.Axis2.Get()); ConvertDirection(y, *op.Axis2.Get());
} }
if (const Schema_2x3::IfcCartesianTransformationOperator3D* op2 = op.ToPtr<Schema_2x3::IfcCartesianTransformationOperator3D>()) { if (const Schema_2x3::IfcCartesianTransformationOperator3D *op2 = op.ToPtr<Schema_2x3::IfcCartesianTransformationOperator3D>()) {
if(op2->Axis3) { if (op2->Axis3) {
ConvertDirection(z,*op2->Axis3.Get()); ConvertDirection(z, *op2->Axis3.Get());
} }
} }
IfcMatrix4 locm; IfcMatrix4 locm;
IfcMatrix4::Translation(loc,locm); IfcMatrix4::Translation(loc, locm);
AssignMatrixAxes(out,x,y,z); AssignMatrixAxes(out, x, y, z);
IfcVector3 vscale; IfcVector3 vscale;
if (const Schema_2x3::IfcCartesianTransformationOperator3DnonUniform* nuni = op.ToPtr<Schema_2x3::IfcCartesianTransformationOperator3DnonUniform>()) { if (const Schema_2x3::IfcCartesianTransformationOperator3DnonUniform *nuni = op.ToPtr<Schema_2x3::IfcCartesianTransformationOperator3DnonUniform>()) {
vscale.x = nuni->Scale?op.Scale.Get():1.f; vscale.x = nuni->Scale ? op.Scale.Get() : 1.f;
vscale.y = nuni->Scale2?nuni->Scale2.Get():1.f; vscale.y = nuni->Scale2 ? nuni->Scale2.Get() : 1.f;
vscale.z = nuni->Scale3?nuni->Scale3.Get():1.f; vscale.z = nuni->Scale3 ? nuni->Scale3.Get() : 1.f;
} } else {
else { const IfcFloat sc = op.Scale ? op.Scale.Get() : 1.f;
const IfcFloat sc = op.Scale?op.Scale.Get():1.f; vscale = IfcVector3(sc, sc, sc);
vscale = IfcVector3(sc,sc,sc);
} }
IfcMatrix4 s; IfcMatrix4 s;
IfcMatrix4::Scaling(vscale,s); IfcMatrix4::Scaling(vscale, s);
out = locm * out * s; out = locm * out * s;
} }
} // namespace IFC
} // ! IFC } // namespace Assimp
} // ! Assimp
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -44,20 +44,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef INCLUDED_AI_IMPORTER_H #ifndef INCLUDED_AI_IMPORTER_H
#define INCLUDED_AI_IMPORTER_H #define INCLUDED_AI_IMPORTER_H
#include <map>
#include <vector>
#include <string>
#include <assimp/matrix4x4.h> #include <assimp/matrix4x4.h>
#include <map>
#include <string>
#include <vector>
struct aiScene; struct aiScene;
namespace Assimp { namespace Assimp {
class ProgressHandler; class ProgressHandler;
class IOSystem; class IOSystem;
class BaseImporter; class BaseImporter;
class BaseProcess; class BaseProcess;
class SharedPostProcessInfo; class SharedPostProcessInfo;
//! @cond never //! @cond never
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -70,7 +69,7 @@ namespace Assimp {
class ImporterPimpl { class ImporterPimpl {
public: public:
// Data type to store the key hash // Data type to store the key hash
typedef unsigned int KeyType; using KeyType = unsigned int;
// typedefs for our four configuration maps. // typedefs for our four configuration maps.
// We don't need more, so there is no need for a generic solution // We don't need more, so there is no need for a generic solution
@ -80,21 +79,21 @@ public:
typedef std::map<KeyType, aiMatrix4x4> MatrixPropertyMap; typedef std::map<KeyType, aiMatrix4x4> MatrixPropertyMap;
/** IO handler to use for all file accesses. */ /** IO handler to use for all file accesses. */
IOSystem* mIOHandler; IOSystem *mIOHandler;
bool mIsDefaultHandler; bool mIsDefaultHandler;
/** Progress handler for feedback. */ /** Progress handler for feedback. */
ProgressHandler* mProgressHandler; ProgressHandler *mProgressHandler;
bool mIsDefaultProgressHandler; bool mIsDefaultProgressHandler;
/** Format-specific importer worker objects - one for each format we can read.*/ /** Format-specific importer worker objects - one for each format we can read.*/
std::vector< BaseImporter* > mImporter; std::vector<BaseImporter *> mImporter;
/** Post processing steps we can apply at the imported data. */ /** Post processing steps we can apply at the imported data. */
std::vector< BaseProcess* > mPostProcessingSteps; std::vector<BaseProcess *> mPostProcessingSteps;
/** The imported data, if ReadFile() was successful, nullptr otherwise. */ /** The imported data, if ReadFile() was successful, nullptr otherwise. */
aiScene* mScene; aiScene *mScene;
/** The error description, if there was one. In the case of an exception, /** The error description, if there was one. In the case of an exception,
* mException will carry the full details. */ * mException will carry the full details. */
@ -120,29 +119,27 @@ public:
bool bExtraVerbose; bool bExtraVerbose;
/** Used by post-process steps to share data */ /** Used by post-process steps to share data */
SharedPostProcessInfo* mPPShared; SharedPostProcessInfo *mPPShared;
/// The default class constructor. /// The default class constructor.
ImporterPimpl() AI_NO_EXCEPT; ImporterPimpl() AI_NO_EXCEPT;
}; };
inline inline ImporterPimpl::ImporterPimpl() AI_NO_EXCEPT : mIOHandler(nullptr),
ImporterPimpl::ImporterPimpl() AI_NO_EXCEPT : mIsDefaultHandler(false),
mIOHandler( nullptr ), mProgressHandler(nullptr),
mIsDefaultHandler( false ), mIsDefaultProgressHandler(false),
mProgressHandler( nullptr ), mImporter(),
mIsDefaultProgressHandler( false ), mPostProcessingSteps(),
mImporter(), mScene(nullptr),
mPostProcessingSteps(), mErrorString(),
mScene( nullptr ), mException(),
mErrorString(), mIntProperties(),
mException(), mFloatProperties(),
mIntProperties(), mStringProperties(),
mFloatProperties(), mMatrixProperties(),
mStringProperties(), bExtraVerbose(false),
mMatrixProperties(), mPPShared(nullptr) {
bExtraVerbose( false ),
mPPShared( nullptr ) {
// empty // empty
} }
//! @endcond //! @endcond
@ -164,17 +161,17 @@ public:
/** Wraps a full list of configuration properties for an importer. /** Wraps a full list of configuration properties for an importer.
* Properties can be set using SetGenericProperty */ * Properties can be set using SetGenericProperty */
struct PropertyMap { struct PropertyMap {
ImporterPimpl::IntPropertyMap ints; ImporterPimpl::IntPropertyMap ints;
ImporterPimpl::FloatPropertyMap floats; ImporterPimpl::FloatPropertyMap floats;
ImporterPimpl::StringPropertyMap strings; ImporterPimpl::StringPropertyMap strings;
ImporterPimpl::MatrixPropertyMap matrices; ImporterPimpl::MatrixPropertyMap matrices;
bool operator == (const PropertyMap& prop) const { bool operator==(const PropertyMap &prop) const {
// fixme: really isocpp? gcc complains // fixme: really isocpp? gcc complains
return ints == prop.ints && floats == prop.floats && strings == prop.strings && matrices == prop.matrices; return ints == prop.ints && floats == prop.floats && strings == prop.strings && matrices == prop.matrices;
} }
bool empty () const { bool empty() const {
return ints.empty() && floats.empty() && strings.empty() && matrices.empty(); return ints.empty() && floats.empty() && strings.empty() && matrices.empty();
} }
}; };
@ -184,7 +181,7 @@ public:
/** Construct a batch loader from a given IO system to be used /** Construct a batch loader from a given IO system to be used
* to access external files * to access external files
*/ */
explicit BatchLoader(IOSystem* pIO, bool validate = false ); explicit BatchLoader(IOSystem *pIO, bool validate = false);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** The class destructor. /** The class destructor.
@ -195,14 +192,14 @@ public:
/** Sets the validation step. True for enable validation during postprocess. /** Sets the validation step. True for enable validation during postprocess.
* @param enable True for validation. * @param enable True for validation.
*/ */
void setValidation( bool enabled ); void setValidation(bool enabled);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns the current validation step. /** Returns the current validation step.
* @return The current validation step. * @return The current validation step.
*/ */
bool getValidation() const; bool getValidation() const;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Add a new file to the list of files to be loaded. /** Add a new file to the list of files to be loaded.
* @param file File to be loaded * @param file File to be loaded
@ -211,11 +208,10 @@ public:
* @return 'Load request channel' - an unique ID that can later * @return 'Load request channel' - an unique ID that can later
* be used to access the imported file data. * be used to access the imported file data.
* @see GetImport */ * @see GetImport */
unsigned int AddLoadRequest ( unsigned int AddLoadRequest(
const std::string& file, const std::string &file,
unsigned int steps = 0, unsigned int steps = 0,
const PropertyMap *map = nullptr const PropertyMap *map = nullptr);
);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Get an imported scene. /** Get an imported scene.
@ -226,9 +222,8 @@ public:
* @param which LRWC returned by AddLoadRequest(). * @param which LRWC returned by AddLoadRequest().
* @return nullptr if there is no scene with this file name * @return nullptr if there is no scene with this file name
* in the queue of the scene hasn't been loaded yet. */ * in the queue of the scene hasn't been loaded yet. */
aiScene* GetImport( aiScene *GetImport(
unsigned int which unsigned int which);
);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Waits until all scenes have been loaded. This returns /** Waits until all scenes have been loaded. This returns

View File

@ -45,8 +45,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef AI_POLYTOOLS_H_INCLUDED #ifndef AI_POLYTOOLS_H_INCLUDED
#define AI_POLYTOOLS_H_INCLUDED #define AI_POLYTOOLS_H_INCLUDED
#include <assimp/material.h>
#include <assimp/ai_assert.h> #include <assimp/ai_assert.h>
#include <assimp/material.h>
#include <assimp/vector3.h>
namespace Assimp { namespace Assimp {
@ -55,8 +56,7 @@ namespace Assimp {
* The function accepts an unconstrained template parameter for use with * The function accepts an unconstrained template parameter for use with
* both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/ * both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/
template <typename T> template <typename T>
inline double GetArea2D(const T& v1, const T& v2, const T& v3) inline double GetArea2D(const T &v1, const T &v2, const T &v3) {
{
return 0.5 * (v1.x * ((double)v3.y - v2.y) + v2.x * ((double)v1.y - v3.y) + v3.x * ((double)v2.y - v1.y)); return 0.5 * (v1.x * ((double)v3.y - v2.y) + v2.x * ((double)v1.y - v3.y) + v3.x * ((double)v2.y - v1.y));
} }
@ -65,9 +65,8 @@ inline double GetArea2D(const T& v1, const T& v2, const T& v3)
* The function accepts an unconstrained template parameter for use with * The function accepts an unconstrained template parameter for use with
* both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/ * both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/
template <typename T> template <typename T>
inline bool OnLeftSideOfLine2D(const T& p0, const T& p1,const T& p2) inline bool OnLeftSideOfLine2D(const T &p0, const T &p1, const T &p2) {
{ return GetArea2D(p0, p2, p1) > 0;
return GetArea2D(p0,p2,p1) > 0;
} }
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
@ -75,8 +74,7 @@ inline bool OnLeftSideOfLine2D(const T& p0, const T& p1,const T& p2)
* The function accepts an unconstrained template parameter for use with * The function accepts an unconstrained template parameter for use with
* both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/ * both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/
template <typename T> template <typename T>
inline bool PointInTriangle2D(const T& p0, const T& p1,const T& p2, const T& pp) inline bool PointInTriangle2D(const T &p0, const T &p1, const T &p2, const T &pp) {
{
// Point in triangle test using baryzentric coordinates // Point in triangle test using baryzentric coordinates
const aiVector2D v0 = p1 - p0; const aiVector2D v0 = p1 - p0;
const aiVector2D v1 = p2 - p0; const aiVector2D v1 = p2 - p0;
@ -95,7 +93,6 @@ inline bool PointInTriangle2D(const T& p0, const T& p1,const T& p2, const T& pp)
return (dot11 > 0) && (dot00 > 0) && (dot11 + dot00 < 1); return (dot11 > 0) && (dot00 > 0) && (dot11 + dot00 < 1);
} }
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
/** Check whether the winding order of a given polygon is counter-clockwise. /** Check whether the winding order of a given polygon is counter-clockwise.
* The function accepts an unconstrained template parameter, but is intended * The function accepts an unconstrained template parameter, but is intended
@ -104,7 +101,7 @@ inline bool PointInTriangle2D(const T& p0, const T& p1,const T& p2, const T& pp)
* @note Code taken from http://cgm.cs.mcgill.ca/~godfried/teaching/cg-projects/97/Ian/applet1.html and translated to C++ * @note Code taken from http://cgm.cs.mcgill.ca/~godfried/teaching/cg-projects/97/Ian/applet1.html and translated to C++
*/ */
template <typename T> template <typename T>
inline bool IsCCW(T* in, size_t npoints) { inline bool IsCCW(T *in, size_t npoints) {
double aa, bb, cc, b, c, theta; double aa, bb, cc, b, c, theta;
double convex_turn; double convex_turn;
double convex_sum = 0; double convex_sum = 0;
@ -112,44 +109,43 @@ inline bool IsCCW(T* in, size_t npoints) {
ai_assert(npoints >= 3); ai_assert(npoints >= 3);
for (size_t i = 0; i < npoints - 2; i++) { for (size_t i = 0; i < npoints - 2; i++) {
aa = ((in[i+2].x - in[i].x) * (in[i+2].x - in[i].x)) + aa = ((in[i + 2].x - in[i].x) * (in[i + 2].x - in[i].x)) +
((-in[i+2].y + in[i].y) * (-in[i+2].y + in[i].y)); ((-in[i + 2].y + in[i].y) * (-in[i + 2].y + in[i].y));
bb = ((in[i+1].x - in[i].x) * (in[i+1].x - in[i].x)) + bb = ((in[i + 1].x - in[i].x) * (in[i + 1].x - in[i].x)) +
((-in[i+1].y + in[i].y) * (-in[i+1].y + in[i].y)); ((-in[i + 1].y + in[i].y) * (-in[i + 1].y + in[i].y));
cc = ((in[i+2].x - in[i+1].x) * cc = ((in[i + 2].x - in[i + 1].x) *
(in[i+2].x - in[i+1].x)) + (in[i + 2].x - in[i + 1].x)) +
((-in[i+2].y + in[i+1].y) * ((-in[i + 2].y + in[i + 1].y) *
(-in[i+2].y + in[i+1].y)); (-in[i + 2].y + in[i + 1].y));
b = std::sqrt(bb); b = std::sqrt(bb);
c = std::sqrt(cc); c = std::sqrt(cc);
theta = std::acos((bb + cc - aa) / (2 * b * c)); theta = std::acos((bb + cc - aa) / (2 * b * c));
if (OnLeftSideOfLine2D(in[i],in[i+2],in[i+1])) { if (OnLeftSideOfLine2D(in[i], in[i + 2], in[i + 1])) {
// if (convex(in[i].x, in[i].y, // if (convex(in[i].x, in[i].y,
// in[i+1].x, in[i+1].y, // in[i+1].x, in[i+1].y,
// in[i+2].x, in[i+2].y)) { // in[i+2].x, in[i+2].y)) {
convex_turn = AI_MATH_PI_F - theta; convex_turn = AI_MATH_PI_F - theta;
convex_sum += convex_turn; convex_sum += convex_turn;
} } else {
else {
convex_sum -= AI_MATH_PI_F - theta; convex_sum -= AI_MATH_PI_F - theta;
} }
} }
aa = ((in[1].x - in[npoints-2].x) * aa = ((in[1].x - in[npoints - 2].x) *
(in[1].x - in[npoints-2].x)) + (in[1].x - in[npoints - 2].x)) +
((-in[1].y + in[npoints-2].y) * ((-in[1].y + in[npoints - 2].y) *
(-in[1].y + in[npoints-2].y)); (-in[1].y + in[npoints - 2].y));
bb = ((in[0].x - in[npoints-2].x) * bb = ((in[0].x - in[npoints - 2].x) *
(in[0].x - in[npoints-2].x)) + (in[0].x - in[npoints - 2].x)) +
((-in[0].y + in[npoints-2].y) * ((-in[0].y + in[npoints - 2].y) *
(-in[0].y + in[npoints-2].y)); (-in[0].y + in[npoints - 2].y));
cc = ((in[1].x - in[0].x) * (in[1].x - in[0].x)) + cc = ((in[1].x - in[0].x) * (in[1].x - in[0].x)) +
((-in[1].y + in[0].y) * (-in[1].y + in[0].y)); ((-in[1].y + in[0].y) * (-in[1].y + in[0].y));
b = std::sqrt(bb); b = std::sqrt(bb);
c = std::sqrt(cc); c = std::sqrt(cc);
@ -158,18 +154,16 @@ inline bool IsCCW(T* in, size_t npoints) {
//if (convex(in[npoints-2].x, in[npoints-2].y, //if (convex(in[npoints-2].x, in[npoints-2].y,
// in[0].x, in[0].y, // in[0].x, in[0].y,
// in[1].x, in[1].y)) { // in[1].x, in[1].y)) {
if (OnLeftSideOfLine2D(in[npoints-2],in[1],in[0])) { if (OnLeftSideOfLine2D(in[npoints - 2], in[1], in[0])) {
convex_turn = AI_MATH_PI_F - theta; convex_turn = AI_MATH_PI_F - theta;
convex_sum += convex_turn; convex_sum += convex_turn;
} } else {
else {
convex_sum -= AI_MATH_PI_F - theta; convex_sum -= AI_MATH_PI_F - theta;
} }
return convex_sum >= (2 * AI_MATH_PI_F); return convex_sum >= (2 * AI_MATH_PI_F);
} }
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
/** Compute the normal of an arbitrary polygon in R3. /** Compute the normal of an arbitrary polygon in R3.
* *
@ -185,45 +179,50 @@ inline bool IsCCW(T* in, size_t npoints) {
* @note The data arrays must have storage for at least num+2 elements. Using * @note The data arrays must have storage for at least num+2 elements. Using
* this method is much faster than the 'other' NewellNormal() * this method is much faster than the 'other' NewellNormal()
*/ */
template <int ofs_x, int ofs_y, int ofs_z, typename TReal> template <size_t ofs_x, size_t ofs_y, size_t ofs_z, typename TReal>
inline void NewellNormal (aiVector3t<TReal>& out, int num, TReal* x, TReal* y, TReal* z) inline void NewellNormal(aiVector3t<TReal> &out, size_t num, TReal *x, TReal *y, TReal *z, size_t bufferSize) {
{ ai_assert(bufferSize > num);
if (nullptr == x || nullptr == y || nullptr == z || 0 == bufferSize || 0 == num) {
return;
}
// Duplicate the first two vertices at the end // Duplicate the first two vertices at the end
x[(num+0)*ofs_x] = x[0]; x[(num + 0) * ofs_x] = x[0];
x[(num+1)*ofs_x] = x[ofs_x]; x[(num + 1) * ofs_x] = x[ofs_x];
y[(num+0)*ofs_y] = y[0]; y[(num + 0) * ofs_y] = y[0];
y[(num+1)*ofs_y] = y[ofs_y]; y[(num + 1) * ofs_y] = y[ofs_y];
z[(num+0)*ofs_z] = z[0]; z[(num + 0) * ofs_z] = z[0];
z[(num+1)*ofs_z] = z[ofs_z]; z[(num + 1) * ofs_z] = z[ofs_z];
TReal sum_xy = 0.0, sum_yz = 0.0, sum_zx = 0.0; TReal sum_xy = 0.0, sum_yz = 0.0, sum_zx = 0.0;
TReal *xptr = x +ofs_x, *xlow = x, *xhigh = x + ofs_x*2; TReal *xptr = x + ofs_x, *xlow = x, *xhigh = x + ofs_x * 2;
TReal *yptr = y +ofs_y, *ylow = y, *yhigh = y + ofs_y*2; TReal *yptr = y + ofs_y, *ylow = y, *yhigh = y + ofs_y * 2;
TReal *zptr = z +ofs_z, *zlow = z, *zhigh = z + ofs_z*2; TReal *zptr = z + ofs_z, *zlow = z, *zhigh = z + ofs_z * 2;
for (int tmp=0; tmp < num; tmp++) { for (size_t tmp = 0; tmp < num; ++tmp ) {
sum_xy += (*xptr) * ( (*yhigh) - (*ylow) ); sum_xy += (*xptr) * ((*yhigh) - (*ylow));
sum_yz += (*yptr) * ( (*zhigh) - (*zlow) ); sum_yz += (*yptr) * ((*zhigh) - (*zlow));
sum_zx += (*zptr) * ( (*xhigh) - (*xlow) ); sum_zx += (*zptr) * ((*xhigh) - (*xlow));
xptr += ofs_x; xptr += ofs_x;
xlow += ofs_x; xlow += ofs_x;
xhigh += ofs_x; xhigh += ofs_x;
yptr += ofs_y; yptr += ofs_y;
ylow += ofs_y; ylow += ofs_y;
yhigh += ofs_y; yhigh += ofs_y;
zptr += ofs_z; zptr += ofs_z;
zlow += ofs_z; zlow += ofs_z;
zhigh += ofs_z; zhigh += ofs_z;
} }
out = aiVector3t<TReal>(sum_yz,sum_zx,sum_xy); out = aiVector3t<TReal>(sum_yz, sum_zx, sum_xy);
} }
} // ! Assimp } // namespace Assimp
#endif #endif

View File

@ -60,14 +60,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_TRIANGULATE_PROCESS #ifndef ASSIMP_BUILD_NO_TRIANGULATE_PROCESS
#include "PostProcessing/TriangulateProcess.h" #include "PostProcessing/TriangulateProcess.h"
#include "PostProcessing/ProcessHelper.h"
#include "Common/PolyTools.h" #include "Common/PolyTools.h"
#include "PostProcessing/ProcessHelper.h"
#include <memory>
#include <cstdint> #include <cstdint>
#include <memory>
//#define AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING //#define AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING
//#define AI_BUILD_TRIANGULATE_DEBUG_POLYS #define AI_BUILD_TRIANGULATE_DEBUG_POLYS
#define POLY_GRID_Y 40 #define POLY_GRID_Y 40
#define POLY_GRID_X 70 #define POLY_GRID_X 70
@ -78,86 +78,91 @@ using namespace Assimp;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
TriangulateProcess::TriangulateProcess() TriangulateProcess::TriangulateProcess() {
{
// nothing to do here // nothing to do here
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Destructor, private as well // Destructor, private as well
TriangulateProcess::~TriangulateProcess() TriangulateProcess::~TriangulateProcess() {
{
// nothing to do here // nothing to do here
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
bool TriangulateProcess::IsActive( unsigned int pFlags) const bool TriangulateProcess::IsActive(unsigned int pFlags) const {
{
return (pFlags & aiProcess_Triangulate) != 0; return (pFlags & aiProcess_Triangulate) != 0;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void TriangulateProcess::Execute( aiScene* pScene) void TriangulateProcess::Execute(aiScene *pScene) {
{
ASSIMP_LOG_DEBUG("TriangulateProcess begin"); ASSIMP_LOG_DEBUG("TriangulateProcess begin");
bool bHas = false; bool bHas = false;
for( unsigned int a = 0; a < pScene->mNumMeshes; a++) for (unsigned int a = 0; a < pScene->mNumMeshes; a++) {
{ if (pScene->mMeshes[a]) {
if (pScene->mMeshes[ a ]) { if (TriangulateMesh(pScene->mMeshes[a])) {
if ( TriangulateMesh( pScene->mMeshes[ a ] ) ) {
bHas = true; bHas = true;
} }
} }
} }
if ( bHas ) { if (bHas) {
ASSIMP_LOG_INFO( "TriangulateProcess finished. All polygons have been triangulated." ); ASSIMP_LOG_INFO("TriangulateProcess finished. All polygons have been triangulated.");
} else { } else {
ASSIMP_LOG_DEBUG( "TriangulateProcess finished. There was nothing to be done." ); ASSIMP_LOG_DEBUG("TriangulateProcess finished. There was nothing to be done.");
}
}
// ------------------------------------------------------------------------------------------------
static bool validateNumIndices(aiMesh *mesh) {
bool bNeed = false;
for (unsigned int a = 0; a < mesh->mNumFaces; a++) {
const aiFace &face = mesh->mFaces[a];
if (face.mNumIndices != 3) {
bNeed = true;
break;
}
}
return bNeed;
}
static void calulateNumOutputFaces(aiMesh *mesh, size_t &numOut, size_t &maxOut, bool &getNormals) {
numOut = maxOut = 0;
getNormals = true;
for (unsigned int a = 0; a < mesh->mNumFaces; a++) {
aiFace &face = mesh->mFaces[a];
if (face.mNumIndices <= 4) {
getNormals = false;
}
if (face.mNumIndices <= 3) {
numOut++;
} else {
numOut += face.mNumIndices - 2;
maxOut = std::max(maxOut, static_cast<size_t>(face.mNumIndices));
}
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Triangulates the given mesh. // Triangulates the given mesh.
bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh) bool TriangulateProcess::TriangulateMesh(aiMesh *pMesh) {
{
// Now we have aiMesh::mPrimitiveTypes, so this is only here for test cases // Now we have aiMesh::mPrimitiveTypes, so this is only here for test cases
if (!pMesh->mPrimitiveTypes) {
bool bNeed = false;
for( unsigned int a = 0; a < pMesh->mNumFaces; a++) { if (!pMesh->mPrimitiveTypes) {
const aiFace& face = pMesh->mFaces[a]; if (!validateNumIndices(pMesh)) {
if( face.mNumIndices != 3) {
bNeed = true;
}
}
if (!bNeed)
return false; return false;
} }
else if (!(pMesh->mPrimitiveTypes & aiPrimitiveType_POLYGON)) { } else if (!(pMesh->mPrimitiveTypes & aiPrimitiveType_POLYGON)) {
return false; return false;
} }
// Find out how many output faces we'll get // Find out how many output faces we'll get
uint32_t numOut = 0, max_out = 0; size_t numOut = 0, max_out = 0;
bool get_normals = true; bool getNormals = true;
for( unsigned int a = 0; a < pMesh->mNumFaces; a++) { calulateNumOutputFaces(pMesh, numOut, max_out, getNormals);
aiFace& face = pMesh->mFaces[a];
if (face.mNumIndices <= 4) {
get_normals = false;
}
if( face.mNumIndices <= 3) {
numOut++;
}
else {
numOut += face.mNumIndices-2;
max_out = std::max(max_out,face.mNumIndices);
}
}
// Just another check whether aiMesh::mPrimitiveTypes is correct // Just another check whether aiMesh::mPrimitiveTypes is correct
ai_assert(numOut != pMesh->mNumFaces); ai_assert(numOut != pMesh->mNumFaces);
@ -166,87 +171,87 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
// if we don't have normals yet, but expect them to be a cheap side // if we don't have normals yet, but expect them to be a cheap side
// product of triangulation anyway, allocate storage for them. // product of triangulation anyway, allocate storage for them.
if (!pMesh->mNormals && get_normals) { if (!pMesh->mNormals && getNormals) {
// XXX need a mechanism to inform the GenVertexNormals process to treat these normals as preprocessed per-face normals // XXX need a mechanism to inform the GenVertexNormals process to treat these normals as preprocessed per-face normals
// nor_out = pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; // nor_out = pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
} }
// the output mesh will contain triangles, but no polys anymore // the output mesh will contain triangles, but no polys anymore
pMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; pMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
pMesh->mPrimitiveTypes &= ~aiPrimitiveType_POLYGON; pMesh->mPrimitiveTypes &= ~aiPrimitiveType_POLYGON;
aiFace* out = new aiFace[numOut](), *curOut = out; aiFace *out = new aiFace[numOut](), *curOut = out;
std::vector<aiVector3D> temp_verts3d(max_out+2); /* temporary storage for vertices */ const size_t Capa = max_out + 2;
std::vector<aiVector2D> temp_verts(max_out+2); std::vector<aiVector3D> temp_verts3d(max_out + 2); /* temporary storage for vertices */
std::vector<aiVector2D> temp_verts(max_out + 2);
// Apply vertex colors to represent the face winding? // Apply vertex colors to represent the face winding?
#ifdef AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING #ifdef AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING
if (!pMesh->mColors[0]) if (!pMesh->mColors[0])
pMesh->mColors[0] = new aiColor4D[pMesh->mNumVertices]; pMesh->mColors[0] = new aiColor4D[pMesh->mNumVertices];
else else
new(pMesh->mColors[0]) aiColor4D[pMesh->mNumVertices]; new (pMesh->mColors[0]) aiColor4D[pMesh->mNumVertices];
aiColor4D* clr = pMesh->mColors[0]; aiColor4D *clr = pMesh->mColors[0];
#endif #endif
#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS #ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
FILE* fout = fopen(POLY_OUTPUT_FILE,"a"); FILE *fout = fopen(POLY_OUTPUT_FILE, "a");
#endif #endif
const aiVector3D* verts = pMesh->mVertices; const aiVector3D *verts = pMesh->mVertices;
// use std::unique_ptr to avoid slow std::vector<bool> specialiations // use std::unique_ptr to avoid slow std::vector<bool> specialiations
std::unique_ptr<bool[]> done(new bool[max_out]); std::unique_ptr<bool[]> done(new bool[max_out]);
for( unsigned int a = 0; a < pMesh->mNumFaces; a++) { for (unsigned int a = 0; a < pMesh->mNumFaces; a++) {
aiFace& face = pMesh->mFaces[a]; aiFace &face = pMesh->mFaces[a];
unsigned int* idx = face.mIndices; unsigned int *idx = face.mIndices;
int num = (int)face.mNumIndices, ear = 0, tmp, prev = num-1, next = 0, max = num; int num = (int)face.mNumIndices, ear = 0, tmp, prev = num - 1, next = 0, max = num;
// Apply vertex colors to represent the face winding? // Apply vertex colors to represent the face winding?
#ifdef AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING #ifdef AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING
for (unsigned int i = 0; i < face.mNumIndices; ++i) { for (unsigned int i = 0; i < face.mNumIndices; ++i) {
aiColor4D& c = clr[idx[i]]; aiColor4D &c = clr[idx[i]];
c.r = (i+1) / (float)max; c.r = (i + 1) / (float)max;
c.b = 1.f - c.r; c.b = 1.f - c.r;
} }
#endif #endif
aiFace* const last_face = curOut; aiFace *const last_face = curOut;
// if it's a simple point,line or triangle: just copy it // if it's a simple point,line or triangle: just copy it
if( face.mNumIndices <= 3) if (face.mNumIndices <= 3) {
{ aiFace &nface = *curOut++;
aiFace& nface = *curOut++;
nface.mNumIndices = face.mNumIndices; nface.mNumIndices = face.mNumIndices;
nface.mIndices = face.mIndices; nface.mIndices = face.mIndices;
face.mIndices = nullptr; face.mIndices = nullptr;
continue; continue;
} }
// optimized code for quadrilaterals // optimized code for quadrilaterals
else if ( face.mNumIndices == 4) { else if (face.mNumIndices == 4) {
// quads can have at maximum one concave vertex. Determine // quads can have at maximum one concave vertex. Determine
// this vertex (if it exists) and start tri-fanning from // this vertex (if it exists) and start tri-fanning from
// it. // it.
unsigned int start_vertex = 0; unsigned int start_vertex = 0;
for (unsigned int i = 0; i < 4; ++i) { for (unsigned int i = 0; i < 4; ++i) {
const aiVector3D& v0 = verts[face.mIndices[(i+3) % 4]]; const aiVector3D &v0 = verts[face.mIndices[(i + 3) % 4]];
const aiVector3D& v1 = verts[face.mIndices[(i+2) % 4]]; const aiVector3D &v1 = verts[face.mIndices[(i + 2) % 4]];
const aiVector3D& v2 = verts[face.mIndices[(i+1) % 4]]; const aiVector3D &v2 = verts[face.mIndices[(i + 1) % 4]];
const aiVector3D& v = verts[face.mIndices[i]]; const aiVector3D &v = verts[face.mIndices[i]];
aiVector3D left = (v0-v); aiVector3D left = (v0 - v);
aiVector3D diag = (v1-v); aiVector3D diag = (v1 - v);
aiVector3D right = (v2-v); aiVector3D right = (v2 - v);
left.Normalize(); left.Normalize();
diag.Normalize(); diag.Normalize();
right.Normalize(); right.Normalize();
const float angle = std::acos(left*diag) + std::acos(right*diag); const float angle = std::acos(left * diag) + std::acos(right * diag);
if (angle > AI_MATH_PI_F) { if (angle > AI_MATH_PI_F) {
// this is the concave point // this is the concave point
start_vertex = i; start_vertex = i;
@ -254,9 +259,9 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
} }
} }
const unsigned int temp[] = {face.mIndices[0], face.mIndices[1], face.mIndices[2], face.mIndices[3]}; const unsigned int temp[] = { face.mIndices[0], face.mIndices[1], face.mIndices[2], face.mIndices[3] };
aiFace& nface = *curOut++; aiFace &nface = *curOut++;
nface.mNumIndices = 3; nface.mNumIndices = 3;
nface.mIndices = face.mIndices; nface.mIndices = face.mIndices;
@ -264,7 +269,7 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
nface.mIndices[1] = temp[(start_vertex + 1) % 4]; nface.mIndices[1] = temp[(start_vertex + 1) % 4];
nface.mIndices[2] = temp[(start_vertex + 2) % 4]; nface.mIndices[2] = temp[(start_vertex + 2) % 4];
aiFace& sface = *curOut++; aiFace &sface = *curOut++;
sface.mNumIndices = 3; sface.mNumIndices = 3;
sface.mIndices = new unsigned int[3]; sface.mIndices = new unsigned int[3];
@ -275,9 +280,7 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
// prevent double deletion of the indices field // prevent double deletion of the indices field
face.mIndices = nullptr; face.mIndices = nullptr;
continue; continue;
} } else {
else
{
// A polygon with more than 3 vertices can be either concave or convex. // A polygon with more than 3 vertices can be either concave or convex.
// Usually everything we're getting is convex and we could easily // Usually everything we're getting is convex and we could easily
// triangulate by tri-fanning. However, LightWave is probably the only // triangulate by tri-fanning. However, LightWave is probably the only
@ -288,42 +291,43 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
// We project it onto a plane to get a 2d triangle. // We project it onto a plane to get a 2d triangle.
// Collect all vertices of of the polygon. // Collect all vertices of of the polygon.
for (tmp = 0; tmp < max; ++tmp) { for (tmp = 0; tmp < max; ++tmp) {
temp_verts3d[tmp] = verts[idx[tmp]]; temp_verts3d[tmp] = verts[idx[tmp]];
} }
// Get newell normal of the polygon. Store it for future use if it's a polygon-only mesh // Get Newell-Normal of the polygon. Store it for future use if it's a polygon-only mesh
aiVector3D n; aiVector3D n;
NewellNormal<3,3,3>(n,max,&temp_verts3d.front().x,&temp_verts3d.front().y,&temp_verts3d.front().z); NewellNormal<3, 3, 3>(n, max, &temp_verts3d.front().x, &temp_verts3d.front().y, &temp_verts3d.front().z, Capa);
if (nor_out) { if (nor_out) {
for (tmp = 0; tmp < max; ++tmp) for (tmp = 0; tmp < max; ++tmp)
nor_out[idx[tmp]] = n; nor_out[idx[tmp]] = n;
} }
// Select largest normal coordinate to ignore for projection // Select largest normal coordinate to ignore for projection
const float ax = (n.x>0 ? n.x : -n.x); const float ax = (n.x > 0 ? n.x : -n.x);
const float ay = (n.y>0 ? n.y : -n.y); const float ay = (n.y > 0 ? n.y : -n.y);
const float az = (n.z>0 ? n.z : -n.z); const float az = (n.z > 0 ? n.z : -n.z);
unsigned int ac = 0, bc = 1; /* no z coord. projection to xy */ unsigned int ac = 0, bc = 1; // no z coord. projection to xy
float inv = n.z; float inv = n.z;
if (ax > ay) { if (ax > ay) {
if (ax > az) { /* no x coord. projection to yz */ if (ax > az) { // no x coord. projection to yz
ac = 1; bc = 2; ac = 1;
bc = 2;
inv = n.x; inv = n.x;
} }
} } else if (ay > az) { // no y coord. projection to zy
else if (ay > az) { /* no y coord. projection to zy */ ac = 2;
ac = 2; bc = 0; bc = 0;
inv = n.y; inv = n.y;
} }
// Swap projection axes to take the negated projection vector into account // Swap projection axes to take the negated projection vector into account
if (inv < 0.f) { if (inv < 0.f) {
std::swap(ac,bc); std::swap(ac, bc);
} }
for (tmp =0; tmp < max; ++tmp) { for (tmp = 0; tmp < max; ++tmp) {
temp_verts[tmp].x = verts[idx[tmp]][ac]; temp_verts[tmp].x = verts[idx[tmp]][ac];
temp_verts[tmp].y = verts[idx[tmp]][bc]; temp_verts[tmp].y = verts[idx[tmp]][bc];
done[tmp] = false; done[tmp] = false;
@ -331,30 +335,30 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS #ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
// plot the plane onto which we mapped the polygon to a 2D ASCII pic // plot the plane onto which we mapped the polygon to a 2D ASCII pic
aiVector2D bmin,bmax; aiVector2D bmin, bmax;
ArrayBounds(&temp_verts[0],max,bmin,bmax); ArrayBounds(&temp_verts[0], max, bmin, bmax);
char grid[POLY_GRID_Y][POLY_GRID_X+POLY_GRID_XPAD]; char grid[POLY_GRID_Y][POLY_GRID_X + POLY_GRID_XPAD];
std::fill_n((char*)grid,POLY_GRID_Y*(POLY_GRID_X+POLY_GRID_XPAD),' '); std::fill_n((char *)grid, POLY_GRID_Y * (POLY_GRID_X + POLY_GRID_XPAD), ' ');
for (int i =0; i < max; ++i) { for (int i = 0; i < max; ++i) {
const aiVector2D& v = (temp_verts[i] - bmin) / (bmax-bmin); const aiVector2D &v = (temp_verts[i] - bmin) / (bmax - bmin);
const size_t x = static_cast<size_t>(v.x*(POLY_GRID_X-1)), y = static_cast<size_t>(v.y*(POLY_GRID_Y-1)); const size_t x = static_cast<size_t>(v.x * (POLY_GRID_X - 1)), y = static_cast<size_t>(v.y * (POLY_GRID_Y - 1));
char* loc = grid[y]+x; char *loc = grid[y] + x;
if (grid[y][x] != ' ') { if (grid[y][x] != ' ') {
for(;*loc != ' '; ++loc); for (; *loc != ' '; ++loc)
;
*loc++ = '_'; *loc++ = '_';
} }
*(loc+::ai_snprintf(loc, POLY_GRID_XPAD,"%i",i)) = ' '; *(loc + ::ai_snprintf(loc, POLY_GRID_XPAD, "%i", i)) = ' ';
} }
for (size_t y = 0; y < POLY_GRID_Y; ++y) {
for(size_t y = 0; y < POLY_GRID_Y; ++y) { grid[y][POLY_GRID_X + POLY_GRID_XPAD - 1] = '\0';
grid[y][POLY_GRID_X+POLY_GRID_XPAD-1] = '\0'; fprintf(fout, "%s\n", grid[y]);
fprintf(fout,"%s\n",grid[y]);
} }
fprintf(fout,"\ntriangulation sequence: "); fprintf(fout, "\ntriangulation sequence: ");
#endif #endif
// //
@ -364,26 +368,27 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
// Find the next ear of the polygon // Find the next ear of the polygon
int num_found = 0; int num_found = 0;
for (ear = next;;prev = ear,ear = next) { for (ear = next;; prev = ear, ear = next) {
// break after we looped two times without a positive match // break after we looped two times without a positive match
for (next=ear+1;done[(next>=max?next=0:next)];++next); for (next = ear + 1; done[(next >= max ? next = 0 : next)]; ++next)
;
if (next < ear) { if (next < ear) {
if (++num_found == 2) { if (++num_found == 2) {
break; break;
} }
} }
const aiVector2D* pnt1 = &temp_verts[ear], const aiVector2D *pnt1 = &temp_verts[ear],
*pnt0 = &temp_verts[prev], *pnt0 = &temp_verts[prev],
*pnt2 = &temp_verts[next]; *pnt2 = &temp_verts[next];
// Must be a convex point. Assuming ccw winding, it must be on the right of the line between p-1 and p+1. // Must be a convex point. Assuming ccw winding, it must be on the right of the line between p-1 and p+1.
if (OnLeftSideOfLine2D(*pnt0,*pnt2,*pnt1)) { if (OnLeftSideOfLine2D(*pnt0, *pnt2, *pnt1)) {
continue; continue;
} }
// and no other point may be contained in this triangle // and no other point may be contained in this triangle
for ( tmp = 0; tmp < max; ++tmp) { for (tmp = 0; tmp < max; ++tmp) {
// We need to compare the actual values because it's possible that multiple indexes in // We need to compare the actual values because it's possible that multiple indexes in
// the polygon are referring to the same position. concave_polygon.obj is a sample // the polygon are referring to the same position. concave_polygon.obj is a sample
@ -392,8 +397,8 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
// PointInTriangle() I'm guessing that it's actually possible to construct // PointInTriangle() I'm guessing that it's actually possible to construct
// input data that would cause us to end up with no ears. The problem is, // input data that would cause us to end up with no ears. The problem is,
// which epsilon? If we chose a too large value, we'd get wrong results // which epsilon? If we chose a too large value, we'd get wrong results
const aiVector2D& vtmp = temp_verts[tmp]; const aiVector2D &vtmp = temp_verts[tmp];
if ( vtmp != *pnt1 && vtmp != *pnt2 && vtmp != *pnt0 && PointInTriangle2D(*pnt0,*pnt1,*pnt2,vtmp)) { if (vtmp != *pnt1 && vtmp != *pnt2 && vtmp != *pnt0 && PointInTriangle2D(*pnt0, *pnt1, *pnt2, vtmp)) {
break; break;
} }
} }
@ -415,29 +420,13 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
ASSIMP_LOG_ERROR("Failed to triangulate polygon (no ear found). Probably not a simple polygon?"); ASSIMP_LOG_ERROR("Failed to triangulate polygon (no ear found). Probably not a simple polygon?");
#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS #ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
fprintf(fout,"critical error here, no ear found! "); fprintf(fout, "critical error here, no ear found! ");
#endif #endif
num = 0; num = 0;
break; break;
/*curOut -= (max-num); // undo all previous work
for (tmp = 0; tmp < max-2; ++tmp) {
aiFace& nface = *curOut++;
nface.mNumIndices = 3;
if (!nface.mIndices)
nface.mIndices = new unsigned int[3];
nface.mIndices[0] = 0;
nface.mIndices[1] = tmp+1;
nface.mIndices[2] = tmp+2;
}
num = 0;
break;*/
} }
aiFace& nface = *curOut++; aiFace &nface = *curOut++;
nface.mNumIndices = 3; nface.mNumIndices = 3;
if (!nface.mIndices) { if (!nface.mIndices) {
@ -455,56 +444,40 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
} }
if (num > 0) { if (num > 0) {
// We have three indices forming the last 'ear' remaining. Collect them. // We have three indices forming the last 'ear' remaining. Collect them.
aiFace& nface = *curOut++; aiFace &nface = *curOut++;
nface.mNumIndices = 3; nface.mNumIndices = 3;
if (!nface.mIndices) { if (!nface.mIndices) {
nface.mIndices = new unsigned int[3]; nface.mIndices = new unsigned int[3];
} }
for (tmp = 0; done[tmp]; ++tmp); for (tmp = 0; done[tmp]; ++tmp)
;
nface.mIndices[0] = tmp; nface.mIndices[0] = tmp;
for (++tmp; done[tmp]; ++tmp); for (++tmp; done[tmp]; ++tmp)
;
nface.mIndices[1] = tmp; nface.mIndices[1] = tmp;
for (++tmp; done[tmp]; ++tmp); for (++tmp; done[tmp]; ++tmp)
;
nface.mIndices[2] = tmp; nface.mIndices[2] = tmp;
} }
} }
#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS #ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
for(aiFace* f = last_face; f != curOut; ++f) { for (aiFace *f = last_face; f != curOut; ++f) {
unsigned int* i = f->mIndices; unsigned int *i = f->mIndices;
fprintf(fout," (%i %i %i)",i[0],i[1],i[2]); fprintf(fout, " (%i %i %i)", i[0], i[1], i[2]);
} }
fprintf(fout,"\n*********************************************************************\n"); fprintf(fout, "\n*********************************************************************\n");
fflush(fout); fflush(fout);
#endif #endif
for(aiFace* f = last_face; f != curOut; ) { for (aiFace *f = last_face; f != curOut;) {
unsigned int* i = f->mIndices; unsigned int *i = f->mIndices;
// drop dumb 0-area triangles - deactivated for now:
//FindDegenerates post processing step can do the same thing
//if (std::fabs(GetArea2D(temp_verts[i[0]],temp_verts[i[1]],temp_verts[i[2]])) < 1e-5f) {
// ASSIMP_LOG_VERBOSE_DEBUG("Dropping triangle with area 0");
// --curOut;
// delete[] f->mIndices;
// f->mIndices = nullptr;
// for(aiFace* ff = f; ff != curOut; ++ff) {
// ff->mNumIndices = (ff+1)->mNumIndices;
// ff->mIndices = (ff+1)->mIndices;
// (ff+1)->mIndices = nullptr;
// }
// continue;
//}
i[0] = idx[i[0]]; i[0] = idx[i[0]];
i[1] = idx[i[1]]; i[1] = idx[i[1]];
i[2] = idx[i[2]]; i[2] = idx[i[2]];
@ -520,11 +493,11 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
#endif #endif
// kill the old faces // kill the old faces
delete [] pMesh->mFaces; delete[] pMesh->mFaces;
// ... and store the new ones // ... and store the new ones
pMesh->mFaces = out; pMesh->mFaces = out;
pMesh->mNumFaces = (unsigned int)(curOut-out); /* not necessarily equal to numOut */ pMesh->mNumFaces = (unsigned int)(curOut - out); /* not necessarily equal to numOut */
return true; return true;
} }

View File

@ -96,6 +96,7 @@ SET( COMMON
unit/Common/utSpatialSort.cpp unit/Common/utSpatialSort.cpp
unit/Common/utAssertHandler.cpp unit/Common/utAssertHandler.cpp
unit/Common/utXmlParser.cpp unit/Common/utXmlParser.cpp
unit/Common/utPolyTools.cpp
) )
SET( IMPORTERS SET( IMPORTERS

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,

View File

@ -43,9 +43,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef AV_ANIMEVALUATOR_H_INCLUDED #ifndef AV_ANIMEVALUATOR_H_INCLUDED
#define AV_ANIMEVALUATOR_H_INCLUDED #define AV_ANIMEVALUATOR_H_INCLUDED
#include <assimp/matrix4x4.h>
#include <tuple> #include <tuple>
#include <vector> #include <vector>
struct aiAnimation;
namespace AssimpView { namespace AssimpView {
/** /**
@ -74,7 +78,7 @@ public:
* the aiAnimation. */ * the aiAnimation. */
const std::vector<aiMatrix4x4> &GetTransformations() const { return mTransforms; } const std::vector<aiMatrix4x4> &GetTransformations() const { return mTransforms; }
protected: private:
const aiAnimation *mAnim; const aiAnimation *mAnim;
double mLastTime; double mLastTime;
std::vector<std::tuple<unsigned int, unsigned int, unsigned int>> mLastPositions; std::vector<std::tuple<unsigned int, unsigned int, unsigned int>> mLastPositions;

File diff suppressed because it is too large Load Diff

View File

@ -47,7 +47,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef AV_SCENEANIMATOR_H_INCLUDED #ifndef AV_SCENEANIMATOR_H_INCLUDED
#define AV_SCENEANIMATOR_H_INCLUDED #define AV_SCENEANIMATOR_H_INCLUDED
#include <assimp/scene.h>
#include <map> #include <map>
#include <string>
namespace AssimpView { namespace AssimpView {
@ -59,7 +62,7 @@ namespace AssimpView {
struct SceneAnimNode { struct SceneAnimNode {
std::string mName; std::string mName;
SceneAnimNode *mParent; SceneAnimNode *mParent;
std::vector<SceneAnimNode *> mChildren; std::vector<SceneAnimNode*> mChildren;
//! most recently calculated local transform //! most recently calculated local transform
aiMatrix4x4 mLocalTransform; aiMatrix4x4 mLocalTransform;
@ -72,13 +75,23 @@ struct SceneAnimNode {
//! Default construction //! Default construction
SceneAnimNode() : SceneAnimNode() :
mName(), mParent(nullptr), mChildren(), mLocalTransform(), mGlobalTransform(), mChannelIndex(-1) { mName(),
mParent(nullptr),
mChildren(),
mLocalTransform(),
mGlobalTransform(),
mChannelIndex(-1) {
// empty // empty
} }
//! Construction from a given name //! Construction from a given name
SceneAnimNode(const std::string &pName) : SceneAnimNode(const std::string &pName) :
mName(pName), mParent(nullptr), mChildren(), mLocalTransform(), mGlobalTransform(), mChannelIndex(-1) { mName(pName),
mParent(nullptr),
mChildren(),
mLocalTransform(),
mGlobalTransform(),
mChannelIndex(-1) {
// empty // empty
} }
@ -125,7 +138,7 @@ public:
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** Calculates the node transformations for the scene. Call this to get /** Calculates the node transformations for the scene. Call this to get
* uptodate results before calling one of the getters. * up-to-date results before calling one of the getters.
* @param pTime Current time. Can be an arbitrary range. * @param pTime Current time. Can be an arbitrary range.
*/ */
void Calculate(double pTime); void Calculate(double pTime);
@ -136,7 +149,7 @@ public:
* The returned matrix is in the node's parent's local space, just like the * The returned matrix is in the node's parent's local space, just like the
* original node's transformation matrix. If the node is not animated, the * original node's transformation matrix. If the node is not animated, the
* node's original transformation is returned so that you can safely use or * node's original transformation is returned so that you can safely use or
* assign it to the node itsself. If there is no node with the given name, * assign it to the node itself. If there is no node with the given name,
* the identity matrix is returned. All transformations are updated whenever * the identity matrix is returned. All transformations are updated whenever
* Calculate() is called. * Calculate() is called.
* @param pNodeName Name of the node * @param pNodeName Name of the node
@ -151,7 +164,7 @@ public:
* The returned matrix is in world space, which is the same coordinate space * The returned matrix is in world space, which is the same coordinate space
* as the transformation of the scene's root node. If the node is not animated, * as the transformation of the scene's root node. If the node is not animated,
* the node's original transformation is returned so that you can safely use or * the node's original transformation is returned so that you can safely use or
* assign it to the node itsself. If there is no node with the given name, the * assign it to the node itself. If there is no node with the given name, the
* identity matrix is returned. All transformations are updated whenever * identity matrix is returned. All transformations are updated whenever
* Calculate() is called. * Calculate() is called.
* @param pNodeName Name of the node * @param pNodeName Name of the node
@ -190,7 +203,7 @@ public:
/** @brief Get the current animation or NULL /** @brief Get the current animation or NULL
*/ */
aiAnimation *CurrentAnim() const { aiAnimation *CurrentAnim() const {
return static_cast<unsigned int>(mCurrentAnimIndex) < mScene->mNumAnimations ? mScene->mAnimations[mCurrentAnimIndex] : NULL; return static_cast<unsigned int>(mCurrentAnimIndex) < mScene->mNumAnimations ? mScene->mAnimations[mCurrentAnimIndex] : nullptr;
} }
protected: protected: