Compare commits
3 Commits
master
...
issue_1044
Author | SHA1 | Date |
---|---|---|
Kim Kulling | 8e4ee11bf3 | |
Kim Kulling | 4bb2006325 | |
Kim Kulling | 456b54988a |
|
@ -123,20 +123,20 @@ const aiImporterDesc *FBXImporter::GetInfo() const {
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
// Setup configuration properties for the loader
|
||||
void FBXImporter::SetupProperties(const Importer *pImp) {
|
||||
settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
|
||||
settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
|
||||
settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
|
||||
settings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
|
||||
settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
|
||||
settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
|
||||
settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
|
||||
settings.readWeights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_WEIGHTS, true);
|
||||
settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
|
||||
settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
|
||||
settings.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);
|
||||
settings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
|
||||
settings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
|
||||
mSettings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
|
||||
mSettings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
|
||||
mSettings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
|
||||
mSettings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
|
||||
mSettings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
|
||||
mSettings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
|
||||
mSettings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
|
||||
mSettings.readWeights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_WEIGHTS, true);
|
||||
mSettings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
|
||||
mSettings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
|
||||
mSettings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
|
||||
mSettings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
|
||||
mSettings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
|
||||
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);
|
||||
|
||||
// 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
|
||||
ConvertToAssimpScene(pScene, doc, settings.removeEmptyBones);
|
||||
ConvertToAssimpScene(pScene, doc, mSettings.removeEmptyBones);
|
||||
|
||||
// size relative to cm
|
||||
float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor();
|
||||
|
|
|
@ -70,27 +70,16 @@ typedef class basic_formatter<char, std::char_traits<char>, std::allocator<char>
|
|||
class FBXImporter : public BaseImporter, public LogFunctions<FBXImporter> {
|
||||
public:
|
||||
FBXImporter();
|
||||
virtual ~FBXImporter();
|
||||
|
||||
// --------------------
|
||||
bool CanRead(const std::string &pFile,
|
||||
IOSystem *pIOHandler,
|
||||
bool checkSig) const;
|
||||
~FBXImporter() override;
|
||||
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const;
|
||||
|
||||
protected:
|
||||
// --------------------
|
||||
const aiImporterDesc *GetInfo() const;
|
||||
|
||||
// --------------------
|
||||
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:
|
||||
FBX::ImportSettings settings;
|
||||
FBX::ImportSettings mSettings;
|
||||
}; // !class FBXImporter
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
|
|
@ -48,12 +48,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include <functional>
|
||||
|
||||
#include "FBXMeshGeometry.h"
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXImporter.h"
|
||||
#include "FBXImportSettings.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
|
||||
#include "FBXImportSettings.h"
|
||||
#include "FBXImporter.h"
|
||||
#include "FBXMeshGeometry.h"
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
@ -61,17 +60,15 @@ namespace FBX {
|
|||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Geometry::Geometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
|
||||
: Object(id, element, name)
|
||||
, skin()
|
||||
{
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
|
||||
for(const Connection* con : conns) {
|
||||
const Skin* const sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
|
||||
if(sk) {
|
||||
Geometry::Geometry(uint64_t id, const Element &element, const std::string &name, const Document &doc) :
|
||||
Object(id, element, name), skin() {
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer");
|
||||
for (const Connection *con : conns) {
|
||||
const Skin *const sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
|
||||
if (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) {
|
||||
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
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<const BlendShape*>& Geometry::GetBlendShapes() const {
|
||||
const std::vector<const BlendShape *> &Geometry::GetBlendShapes() const {
|
||||
return blendShapes;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const Skin* Geometry::DeformerSkin() const {
|
||||
const Skin *Geometry::DeformerSkin() const {
|
||||
return skin;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
|
||||
: Geometry(id, element,name, doc)
|
||||
{
|
||||
const Scope* sc = element.Compound();
|
||||
MeshGeometry::MeshGeometry(uint64_t id, const Element &element, const std::string &name, const Document &doc) :
|
||||
Geometry(id, element, name, doc) {
|
||||
const Scope *sc = element.Compound();
|
||||
if (!sc) {
|
||||
DOMError("failed to read Geometry object (class: Mesh), no data scope found");
|
||||
}
|
||||
|
||||
// must have Mesh elements:
|
||||
const Element& Vertices = GetRequiredElement(*sc,"Vertices",&element);
|
||||
const Element& PolygonVertexIndex = GetRequiredElement(*sc,"PolygonVertexIndex",&element);
|
||||
const Element &Vertices = GetRequiredElement(*sc, "Vertices", &element);
|
||||
const Element &PolygonVertexIndex = GetRequiredElement(*sc, "PolygonVertexIndex", &element);
|
||||
|
||||
// optional Mesh elements:
|
||||
const ElementCollection& Layer = sc->GetCollection("Layer");
|
||||
const ElementCollection &Layer = sc->GetCollection("Layer");
|
||||
|
||||
std::vector<aiVector3D> tempVerts;
|
||||
ParseVectorDataArray(tempVerts,Vertices);
|
||||
ParseVectorDataArray(tempVerts, Vertices);
|
||||
|
||||
if(tempVerts.empty()) {
|
||||
if (tempVerts.empty()) {
|
||||
FBXImporter::LogWarn("encountered mesh with no vertices");
|
||||
}
|
||||
|
||||
std::vector<int> tempFaces;
|
||||
ParseVectorDataArray(tempFaces,PolygonVertexIndex);
|
||||
ParseVectorDataArray(tempFaces, PolygonVertexIndex);
|
||||
|
||||
if(tempFaces.empty()) {
|
||||
if (tempFaces.empty()) {
|
||||
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_mapping_offsets.resize(tempVerts.size());
|
||||
m_mapping_counts.resize(tempVerts.size(),0);
|
||||
m_mapping_counts.resize(tempVerts.size(), 0);
|
||||
m_mappings.resize(tempFaces.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
|
||||
// preserve the mapping from fbx indices to *this* indexing.
|
||||
unsigned int count = 0;
|
||||
for(int index : tempFaces) {
|
||||
for (int index : tempFaces) {
|
||||
const int absi = index < 0 ? (-index - 1) : index;
|
||||
if(static_cast<size_t>(absi) >= vertex_count) {
|
||||
DOMError("polygon vertex index out of range",&PolygonVertexIndex);
|
||||
if (static_cast<size_t>(absi) >= vertex_count) {
|
||||
DOMError("polygon vertex index out of range", &PolygonVertexIndex);
|
||||
}
|
||||
|
||||
m_vertices.push_back(tempVerts[absi]);
|
||||
|
@ -162,7 +157,7 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
|
|||
}
|
||||
|
||||
cursor = 0;
|
||||
for(int index : tempFaces) {
|
||||
for (int index : tempFaces) {
|
||||
const int absi = index < 0 ? (-index - 1) : index;
|
||||
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:
|
||||
// * read only the layer with index 0, but warn about any further layers
|
||||
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);
|
||||
if(err) {
|
||||
DOMError(err,&element);
|
||||
if (err) {
|
||||
DOMError(err, &element);
|
||||
}
|
||||
|
||||
if(doc.Settings().readAllLayers || index == 0) {
|
||||
const Scope& layer = GetRequiredScope(*(*it).second);
|
||||
if (doc.Settings().readAllLayers || index == 0) {
|
||||
const Scope &layer = GetRequiredScope(*(*it).second);
|
||||
ReadLayer(layer);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<aiVector3D>& MeshGeometry::GetNormals() const {
|
||||
const std::vector<aiVector3D> &MeshGeometry::GetNormals() const {
|
||||
return m_normals;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<aiVector3D>& MeshGeometry::GetTangents() const {
|
||||
const std::vector<aiVector3D> &MeshGeometry::GetTangents() const {
|
||||
return m_tangents;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<aiVector3D>& MeshGeometry::GetBinormals() const {
|
||||
const std::vector<aiVector3D> &MeshGeometry::GetBinormals() const {
|
||||
return m_binormals;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<unsigned int>& MeshGeometry::GetFaceIndexCounts() const {
|
||||
const std::vector<unsigned int> &MeshGeometry::GetFaceIndexCounts() const {
|
||||
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;
|
||||
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 {
|
||||
return index >= AI_MAX_NUMBER_OF_TEXTURECOORDS ? "" : m_uvNames[ index ];
|
||||
std::string MeshGeometry::GetTextureCoordChannelName(unsigned int index) const {
|
||||
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;
|
||||
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;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const unsigned int* MeshGeometry::ToOutputVertexIndex( unsigned int in_index, unsigned int& count ) const {
|
||||
if ( in_index >= m_mapping_counts.size() ) {
|
||||
const unsigned int *MeshGeometry::ToOutputVertexIndex(unsigned int in_index, unsigned int &count) const {
|
||||
if (in_index >= m_mapping_counts.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ai_assert( m_mapping_counts.size() == m_mapping_offsets.size() );
|
||||
count = m_mapping_counts[ in_index ];
|
||||
ai_assert(m_mapping_counts.size() == m_mapping_offsets.size());
|
||||
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 {
|
||||
ai_assert( in_index < m_vertices.size() );
|
||||
unsigned int MeshGeometry::FaceForVertexIndex(unsigned int in_index) const {
|
||||
ai_assert(in_index < m_vertices.size());
|
||||
|
||||
// in the current conversion pattern this will only be needed if
|
||||
// weights are present, so no need to always pre-compute this table
|
||||
if ( m_facesVertexStartIndices.empty() ) {
|
||||
m_facesVertexStartIndices.resize( m_faces.size() + 1, 0 );
|
||||
if (m_facesVertexStartIndices.empty()) {
|
||||
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();
|
||||
}
|
||||
|
||||
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(
|
||||
m_facesVertexStartIndices.begin(),
|
||||
m_facesVertexStartIndices.end(),
|
||||
in_index
|
||||
);
|
||||
m_facesVertexStartIndices.begin(),
|
||||
m_facesVertexStartIndices.end(),
|
||||
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)
|
||||
{
|
||||
const ElementCollection& LayerElement = layer.GetCollection("LayerElement");
|
||||
void MeshGeometry::ReadLayer(const Scope &layer) {
|
||||
const ElementCollection &LayerElement = layer.GetCollection("LayerElement");
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MeshGeometry::ReadLayerElement(const Scope& layerElement)
|
||||
{
|
||||
const Element& Type = GetRequiredElement(layerElement,"Type");
|
||||
const Element& TypedIndex = GetRequiredElement(layerElement,"TypedIndex");
|
||||
void MeshGeometry::ReadLayerElement(const Scope &layerElement) {
|
||||
const Element &Type = GetRequiredElement(layerElement, "Type");
|
||||
const Element &TypedIndex = GetRequiredElement(layerElement, "TypedIndex");
|
||||
|
||||
const std::string& type = ParseTokenAsString(GetRequiredToken(Type,0));
|
||||
const int typedIndex = ParseTokenAsInt(GetRequiredToken(TypedIndex,0));
|
||||
const std::string &type = ParseTokenAsString(GetRequiredToken(Type, 0));
|
||||
const int typedIndex = ParseTokenAsInt(GetRequiredToken(TypedIndex, 0));
|
||||
|
||||
const Scope& top = GetRequiredScope(element);
|
||||
const Scope &top = GetRequiredScope(element);
|
||||
const ElementCollection candidates = top.GetCollection(type);
|
||||
|
||||
for (ElementMap::const_iterator it = candidates.first; it != candidates.second; ++it) {
|
||||
const int index = ParseTokenAsInt(GetRequiredToken(*(*it).second,0));
|
||||
if(index == typedIndex) {
|
||||
ReadVertexData(type,typedIndex,GetRequiredScope(*(*it).second));
|
||||
const int index = ParseTokenAsInt(GetRequiredToken(*(*it).second, 0));
|
||||
if (index == typedIndex) {
|
||||
ReadVertexData(type, typedIndex, GetRequiredScope(*(*it).second));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
const std::string& MappingInformationType = ParseTokenAsString(GetRequiredToken(
|
||||
GetRequiredElement(source,"MappingInformationType"),0)
|
||||
);
|
||||
void MeshGeometry::ReadVertexData(const std::string &type, int index, const Scope &source) {
|
||||
const std::string &MappingInformationType = ParseTokenAsString(GetRequiredToken(
|
||||
GetRequiredElement(source, "MappingInformationType"), 0));
|
||||
|
||||
const std::string& ReferenceInformationType = ParseTokenAsString(GetRequiredToken(
|
||||
GetRequiredElement(source,"ReferenceInformationType"),0)
|
||||
);
|
||||
const std::string &ReferenceInformationType = ParseTokenAsString(GetRequiredToken(
|
||||
GetRequiredElement(source, "ReferenceInformationType"), 0));
|
||||
|
||||
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: ")
|
||||
<< index << " (limit is " << AI_MAX_NUMBER_OF_TEXTURECOORDS << ")" );
|
||||
<< index << " (limit is " << AI_MAX_NUMBER_OF_TEXTURECOORDS << ")");
|
||||
return;
|
||||
}
|
||||
|
||||
const Element* Name = source["Name"];
|
||||
const Element *Name = source["Name"];
|
||||
m_uvNames[index] = "";
|
||||
if(Name) {
|
||||
m_uvNames[index] = ParseTokenAsString(GetRequiredToken(*Name,0));
|
||||
if (Name) {
|
||||
m_uvNames[index] = ParseTokenAsString(GetRequiredToken(*Name, 0));
|
||||
}
|
||||
|
||||
ReadVertexDataUV(m_uvs[index],source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType
|
||||
);
|
||||
}
|
||||
else if (type == "LayerElementMaterial") {
|
||||
ReadVertexDataUV(m_uvs[index], source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType);
|
||||
} else if (type == "LayerElementMaterial") {
|
||||
if (m_materials.size() > 0) {
|
||||
FBXImporter::LogError("ignoring additional material layer");
|
||||
return;
|
||||
|
@ -348,10 +333,9 @@ void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scop
|
|||
|
||||
std::vector<int> temp_materials;
|
||||
|
||||
ReadVertexDataMaterials(temp_materials,source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType
|
||||
);
|
||||
ReadVertexDataMaterials(temp_materials, source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType);
|
||||
|
||||
// sometimes, there will be only negative entries. Drop the material
|
||||
// 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
|
||||
// coming of which at least one contains actual data (did observe
|
||||
// that with one test file).
|
||||
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()) {
|
||||
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()) {
|
||||
FBXImporter::LogWarn("ignoring dummy material layer (all entries -1)");
|
||||
return;
|
||||
}
|
||||
|
||||
std::swap(temp_materials, m_materials);
|
||||
}
|
||||
else if (type == "LayerElementNormal") {
|
||||
} else if (type == "LayerElementNormal") {
|
||||
if (m_normals.size() > 0) {
|
||||
FBXImporter::LogError("ignoring additional normal layer");
|
||||
return;
|
||||
}
|
||||
|
||||
ReadVertexDataNormals(m_normals,source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType
|
||||
);
|
||||
}
|
||||
else if (type == "LayerElementTangent") {
|
||||
ReadVertexDataNormals(m_normals, source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType);
|
||||
} else if (type == "LayerElementTangent") {
|
||||
if (m_tangents.size() > 0) {
|
||||
FBXImporter::LogError("ignoring additional tangent layer");
|
||||
return;
|
||||
}
|
||||
|
||||
ReadVertexDataTangents(m_tangents,source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType
|
||||
);
|
||||
}
|
||||
else if (type == "LayerElementBinormal") {
|
||||
ReadVertexDataTangents(m_tangents, source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType);
|
||||
} else if (type == "LayerElementBinormal") {
|
||||
if (m_binormals.size() > 0) {
|
||||
FBXImporter::LogError("ignoring additional binormal layer");
|
||||
return;
|
||||
}
|
||||
|
||||
ReadVertexDataBinormals(m_binormals,source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType
|
||||
);
|
||||
}
|
||||
else if (type == "LayerElementColor") {
|
||||
if(index >= AI_MAX_NUMBER_OF_COLOR_SETS) {
|
||||
ReadVertexDataBinormals(m_binormals, source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType);
|
||||
} 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: ")
|
||||
<< index << " (limit is " << AI_MAX_NUMBER_OF_COLOR_SETS << ")" );
|
||||
<< index << " (limit is " << AI_MAX_NUMBER_OF_COLOR_SETS << ")");
|
||||
return;
|
||||
}
|
||||
|
||||
ReadVertexDataColors(m_colors[index],source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType
|
||||
);
|
||||
ReadVertexDataColors(m_colors[index], source,
|
||||
MappingInformationType,
|
||||
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,
|
||||
// tangents ..
|
||||
template <typename T>
|
||||
void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType,
|
||||
const char* dataElementName,
|
||||
const char* indexDataElementName,
|
||||
size_t vertex_count,
|
||||
const std::vector<unsigned int>& mapping_counts,
|
||||
const std::vector<unsigned int>& mapping_offsets,
|
||||
const std::vector<unsigned int>& mappings)
|
||||
{
|
||||
void ResolveVertexDataArray(std::vector<T> &data_out, const Scope &source,
|
||||
const std::string &MappingInformationType,
|
||||
const std::string &ReferenceInformationType,
|
||||
const char *dataElementName,
|
||||
const char *indexDataElementName,
|
||||
size_t vertex_count,
|
||||
const std::vector<unsigned int> &mapping_counts,
|
||||
const std::vector<unsigned int> &mapping_offsets,
|
||||
const std::vector<unsigned int> &mappings) {
|
||||
bool isDirect = ReferenceInformationType == "Direct";
|
||||
bool isIndexToDirect = ReferenceInformationType == "IndexToDirect";
|
||||
|
||||
// fall-back to direct data if there is no index data element
|
||||
if ( isIndexToDirect && !HasElement( source, indexDataElementName ) ) {
|
||||
if (isIndexToDirect && !HasElement(source, indexDataElementName)) {
|
||||
isDirect = true;
|
||||
isIndexToDirect = false;
|
||||
}
|
||||
|
@ -461,13 +436,12 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
|
|||
data_out[mappings[j]] = tempData[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (MappingInformationType == "ByVertice" && isIndexToDirect) {
|
||||
std::vector<T> tempData;
|
||||
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
|
||||
} else if (MappingInformationType == "ByVertice" && isIndexToDirect) {
|
||||
std::vector<T> tempData;
|
||||
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
|
||||
|
||||
std::vector<int> uvIndices;
|
||||
ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
|
||||
ParseVectorDataArray(uvIndices, GetRequiredElement(source, indexDataElementName));
|
||||
|
||||
if (uvIndices.size() != vertex_count) {
|
||||
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];
|
||||
for (unsigned int j = istart; j < iend; ++j) {
|
||||
if (static_cast<size_t>(uvIndices[i]) >= tempData.size()) {
|
||||
DOMError("index out of range",&GetRequiredElement(source,indexDataElementName));
|
||||
if (static_cast<size_t>(uvIndices[i]) >= tempData.size()) {
|
||||
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) {
|
||||
std::vector<T> tempData;
|
||||
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
|
||||
} else if (MappingInformationType == "ByPolygonVertex" && isDirect) {
|
||||
std::vector<T> tempData;
|
||||
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: ")
|
||||
<< tempData.size() << ", expected " << vertex_count
|
||||
);
|
||||
<< tempData.size() << ", expected " << vertex_count);
|
||||
return;
|
||||
}
|
||||
|
||||
data_out.swap(tempData);
|
||||
}
|
||||
else if (MappingInformationType == "ByPolygonVertex" && isIndexToDirect) {
|
||||
std::vector<T> tempData;
|
||||
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
|
||||
data_out.swap(tempData);
|
||||
} else if (MappingInformationType == "ByPolygonVertex" && isIndexToDirect) {
|
||||
std::vector<T> tempData;
|
||||
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
|
||||
|
||||
std::vector<int> uvIndices;
|
||||
ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
|
||||
ParseVectorDataArray(uvIndices, GetRequiredElement(source, indexDataElementName));
|
||||
|
||||
if (uvIndices.size() != vertex_count) {
|
||||
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;
|
||||
unsigned int next = 0;
|
||||
for(int i : uvIndices) {
|
||||
if ( -1 == i ) {
|
||||
data_out[ next++ ] = empty;
|
||||
for (int i : uvIndices) {
|
||||
if (-1 == i) {
|
||||
data_out[next++] = empty;
|
||||
continue;
|
||||
}
|
||||
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: ")
|
||||
<< MappingInformationType << "," << ReferenceInformationType);
|
||||
<< MappingInformationType << "," << ReferenceInformationType);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MeshGeometry::ReadVertexDataNormals(std::vector<aiVector3D>& normals_out, const Scope& source,
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType)
|
||||
{
|
||||
ResolveVertexDataArray(normals_out,source,MappingInformationType,ReferenceInformationType,
|
||||
"Normals",
|
||||
"NormalsIndex",
|
||||
m_vertices.size(),
|
||||
m_mapping_counts,
|
||||
m_mapping_offsets,
|
||||
m_mappings);
|
||||
void MeshGeometry::ReadVertexDataNormals(std::vector<aiVector3D> &normals_out, const Scope &source,
|
||||
const std::string &MappingInformationType,
|
||||
const std::string &ReferenceInformationType) {
|
||||
ResolveVertexDataArray(normals_out, source, MappingInformationType, ReferenceInformationType,
|
||||
"Normals",
|
||||
"NormalsIndex",
|
||||
m_vertices.size(),
|
||||
m_mapping_counts,
|
||||
m_mapping_offsets,
|
||||
m_mappings);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MeshGeometry::ReadVertexDataUV(std::vector<aiVector2D>& uv_out, const Scope& source,
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType)
|
||||
{
|
||||
ResolveVertexDataArray(uv_out,source,MappingInformationType,ReferenceInformationType,
|
||||
"UV",
|
||||
"UVIndex",
|
||||
m_vertices.size(),
|
||||
m_mapping_counts,
|
||||
m_mapping_offsets,
|
||||
m_mappings);
|
||||
void MeshGeometry::ReadVertexDataUV(std::vector<aiVector2D> &uv_out, const Scope &source,
|
||||
const std::string &MappingInformationType,
|
||||
const std::string &ReferenceInformationType) {
|
||||
ResolveVertexDataArray(uv_out, source, MappingInformationType, ReferenceInformationType,
|
||||
"UV",
|
||||
"UVIndex",
|
||||
m_vertices.size(),
|
||||
m_mapping_counts,
|
||||
m_mapping_offsets,
|
||||
m_mappings);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MeshGeometry::ReadVertexDataColors(std::vector<aiColor4D>& colors_out, const Scope& source,
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType)
|
||||
{
|
||||
ResolveVertexDataArray(colors_out,source,MappingInformationType,ReferenceInformationType,
|
||||
"Colors",
|
||||
"ColorIndex",
|
||||
m_vertices.size(),
|
||||
m_mapping_counts,
|
||||
m_mapping_offsets,
|
||||
m_mappings);
|
||||
void MeshGeometry::ReadVertexDataColors(std::vector<aiColor4D> &colors_out, const Scope &source,
|
||||
const std::string &MappingInformationType,
|
||||
const std::string &ReferenceInformationType) {
|
||||
ResolveVertexDataArray(colors_out, source, MappingInformationType, ReferenceInformationType,
|
||||
"Colors",
|
||||
"ColorIndex",
|
||||
m_vertices.size(),
|
||||
m_mapping_counts,
|
||||
m_mapping_offsets,
|
||||
m_mappings);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static const char *TangentIndexToken = "TangentIndex";
|
||||
static const char *TangentsIndexToken = "TangentsIndex";
|
||||
|
||||
void MeshGeometry::ReadVertexDataTangents(std::vector<aiVector3D>& tangents_out, const Scope& source,
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType)
|
||||
{
|
||||
const char * str = source.Elements().count( "Tangents" ) > 0 ? "Tangents" : "Tangent";
|
||||
const char * strIdx = source.Elements().count( "Tangents" ) > 0 ? TangentsIndexToken : TangentIndexToken;
|
||||
ResolveVertexDataArray(tangents_out,source,MappingInformationType,ReferenceInformationType,
|
||||
str,
|
||||
strIdx,
|
||||
m_vertices.size(),
|
||||
m_mapping_counts,
|
||||
m_mapping_offsets,
|
||||
m_mappings);
|
||||
void MeshGeometry::ReadVertexDataTangents(std::vector<aiVector3D> &tangents_out, const Scope &source,
|
||||
const std::string &MappingInformationType,
|
||||
const std::string &ReferenceInformationType) {
|
||||
const char *str = source.Elements().count("Tangents") > 0 ? "Tangents" : "Tangent";
|
||||
const char *strIdx = source.Elements().count("Tangents") > 0 ? TangentsIndexToken : TangentIndexToken;
|
||||
ResolveVertexDataArray(tangents_out, source, MappingInformationType, ReferenceInformationType,
|
||||
str,
|
||||
strIdx,
|
||||
m_vertices.size(),
|
||||
m_mapping_counts,
|
||||
m_mapping_offsets,
|
||||
m_mappings);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static const std::string BinormalIndexToken = "BinormalIndex";
|
||||
static const std::string BinormalsIndexToken = "BinormalsIndex";
|
||||
|
||||
void MeshGeometry::ReadVertexDataBinormals(std::vector<aiVector3D>& binormals_out, const Scope& source,
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType)
|
||||
{
|
||||
const char * str = source.Elements().count( "Binormals" ) > 0 ? "Binormals" : "Binormal";
|
||||
const char * strIdx = source.Elements().count( "Binormals" ) > 0 ? BinormalsIndexToken.c_str() : BinormalIndexToken.c_str();
|
||||
ResolveVertexDataArray(binormals_out,source,MappingInformationType,ReferenceInformationType,
|
||||
str,
|
||||
strIdx,
|
||||
m_vertices.size(),
|
||||
m_mapping_counts,
|
||||
m_mapping_offsets,
|
||||
m_mappings);
|
||||
void MeshGeometry::ReadVertexDataBinormals(std::vector<aiVector3D> &binormals_out, const Scope &source,
|
||||
const std::string &MappingInformationType,
|
||||
const std::string &ReferenceInformationType) {
|
||||
const char *str = source.Elements().count("Binormals") > 0 ? "Binormals" : "Binormal";
|
||||
const char *strIdx = source.Elements().count("Binormals") > 0 ? BinormalsIndexToken.c_str() : BinormalIndexToken.c_str();
|
||||
ResolveVertexDataArray(binormals_out, source, MappingInformationType, ReferenceInformationType,
|
||||
str,
|
||||
strIdx,
|
||||
m_vertices.size(),
|
||||
m_mapping_counts,
|
||||
m_mapping_offsets,
|
||||
m_mappings);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MeshGeometry::ReadVertexDataMaterials(std::vector<int>& materials_out, const Scope& source,
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType)
|
||||
{
|
||||
void MeshGeometry::ReadVertexDataMaterials(std::vector<int> &materials_out, const Scope &source,
|
||||
const std::string &MappingInformationType,
|
||||
const std::string &ReferenceInformationType) {
|
||||
const size_t face_count = m_faces.size();
|
||||
if( 0 == face_count )
|
||||
{
|
||||
if (0 == face_count) {
|
||||
return;
|
||||
}
|
||||
|
||||
// materials are handled separately. First of all, they are assigned per-face
|
||||
// and not per polyvert. Secondly, ReferenceInformationType=IndexToDirect
|
||||
// has a slightly different meaning for materials.
|
||||
ParseVectorDataArray(materials_out,GetRequiredElement(source,"Materials"));
|
||||
ParseVectorDataArray(materials_out, GetRequiredElement(source, "Materials"));
|
||||
|
||||
if (MappingInformationType == "AllSame") {
|
||||
// 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") {
|
||||
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: ")
|
||||
<< materials_out.size() << ", expected " << face_count
|
||||
);
|
||||
<< materials_out.size() << ", expected " << face_count);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
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)
|
||||
: Geometry(id, element, name, doc) {
|
||||
ShapeGeometry::ShapeGeometry(uint64_t id, const Element &element, const std::string &name, const Document &doc) :
|
||||
Geometry(id, element, name, doc) {
|
||||
const Scope *sc = element.Compound();
|
||||
if (nullptr == sc) {
|
||||
DOMError("failed to read Geometry object (class: Shape), no data scope found");
|
||||
}
|
||||
const Element& Indexes = GetRequiredElement(*sc, "Indexes", &element);
|
||||
const Element& Normals = GetRequiredElement(*sc, "Normals", &element);
|
||||
const Element& Vertices = GetRequiredElement(*sc, "Vertices", &element);
|
||||
const Element &Indexes = GetRequiredElement(*sc, "Indexes", &element);
|
||||
const Element &Normals = GetRequiredElement(*sc, "Normals", &element);
|
||||
const Element &Vertices = GetRequiredElement(*sc, "Vertices", &element);
|
||||
ParseVectorDataArray(m_indices, Indexes);
|
||||
ParseVectorDataArray(m_vertices, Vertices);
|
||||
ParseVectorDataArray(m_normals, Normals);
|
||||
|
@ -679,27 +640,26 @@ ShapeGeometry::~ShapeGeometry() {
|
|||
// empty
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<aiVector3D>& ShapeGeometry::GetVertices() const {
|
||||
const std::vector<aiVector3D> &ShapeGeometry::GetVertices() const {
|
||||
return m_vertices;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<aiVector3D>& ShapeGeometry::GetNormals() const {
|
||||
const std::vector<aiVector3D> &ShapeGeometry::GetNormals() const {
|
||||
return m_normals;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<unsigned int>& ShapeGeometry::GetIndices() const {
|
||||
const std::vector<unsigned int> &ShapeGeometry::GetIndices() const {
|
||||
return m_indices;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LineGeometry::LineGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
|
||||
: Geometry(id, element, name, doc)
|
||||
{
|
||||
const Scope* sc = element.Compound();
|
||||
LineGeometry::LineGeometry(uint64_t id, const Element &element, const std::string &name, const Document &doc) :
|
||||
Geometry(id, element, name, doc) {
|
||||
const Scope *sc = element.Compound();
|
||||
if (!sc) {
|
||||
DOMError("failed to read Geometry object (class: Line), no data scope found");
|
||||
}
|
||||
const Element& Points = GetRequiredElement(*sc, "Points", &element);
|
||||
const Element& PointsIndex = GetRequiredElement(*sc, "PointsIndex", &element);
|
||||
const Element &Points = GetRequiredElement(*sc, "Points", &element);
|
||||
const Element &PointsIndex = GetRequiredElement(*sc, "PointsIndex", &element);
|
||||
ParseVectorDataArray(m_vertices, Points);
|
||||
ParseVectorDataArray(m_indices, PointsIndex);
|
||||
}
|
||||
|
@ -709,14 +669,13 @@ LineGeometry::~LineGeometry() {
|
|||
// empty
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<aiVector3D>& LineGeometry::GetVertices() const {
|
||||
const std::vector<aiVector3D> &LineGeometry::GetVertices() const {
|
||||
return m_vertices;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<int>& LineGeometry::GetIndices() const {
|
||||
const std::vector<int> &LineGeometry::GetIndices() const {
|
||||
return m_indices;
|
||||
}
|
||||
} // !FBX
|
||||
} // !Assimp
|
||||
} // namespace FBX
|
||||
} // namespace Assimp
|
||||
#endif
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -55,20 +55,19 @@ namespace Assimp {
|
|||
namespace IFC {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TempOpening::Transform(const IfcMatrix4& mat) {
|
||||
if(profileMesh) {
|
||||
void TempOpening::Transform(const IfcMatrix4 &mat) {
|
||||
if (profileMesh) {
|
||||
profileMesh->Transform(mat);
|
||||
}
|
||||
if(profileMesh2D) {
|
||||
if (profileMesh2D) {
|
||||
profileMesh2D->Transform(mat);
|
||||
}
|
||||
extrusionDir *= IfcMatrix3(mat);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiMesh* TempMesh::ToMesh()
|
||||
{
|
||||
ai_assert(mVerts.size() == std::accumulate(mVertcnt.begin(),mVertcnt.end(),size_t(0)));
|
||||
aiMesh *TempMesh::ToMesh() {
|
||||
ai_assert(mVerts.size() == std::accumulate(mVertcnt.begin(), mVertcnt.end(), size_t(0)));
|
||||
|
||||
if (mVerts.empty()) {
|
||||
return nullptr;
|
||||
|
@ -79,14 +78,14 @@ aiMesh* TempMesh::ToMesh()
|
|||
// copy vertices
|
||||
mesh->mNumVertices = static_cast<unsigned int>(mVerts.size());
|
||||
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
|
||||
mesh->mNumFaces = static_cast<unsigned int>(mVertcnt.size());
|
||||
mesh->mFaces = new aiFace[mesh->mNumFaces];
|
||||
|
||||
for(unsigned int i = 0,n=0, acc = 0; i < mesh->mNumFaces; ++n) {
|
||||
aiFace& f = mesh->mFaces[i];
|
||||
for (unsigned int i = 0, n = 0, acc = 0; i < mesh->mNumFaces; ++n) {
|
||||
aiFace &f = mesh->mFaces[i];
|
||||
if (!mVertcnt[n]) {
|
||||
--mesh->mNumFaces;
|
||||
continue;
|
||||
|
@ -94,7 +93,7 @@ aiMesh* TempMesh::ToMesh()
|
|||
|
||||
f.mNumIndices = mVertcnt[n];
|
||||
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++;
|
||||
}
|
||||
|
||||
|
@ -105,36 +104,31 @@ aiMesh* TempMesh::ToMesh()
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TempMesh::Clear()
|
||||
{
|
||||
void TempMesh::Clear() {
|
||||
mVerts.clear();
|
||||
mVertcnt.clear();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TempMesh::Transform(const IfcMatrix4& mat)
|
||||
{
|
||||
for(IfcVector3& v : mVerts) {
|
||||
void TempMesh::Transform(const IfcMatrix4 &mat) {
|
||||
for (IfcVector3 &v : mVerts) {
|
||||
v *= mat;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
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()));
|
||||
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()));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TempMesh::Append(const TempMesh& other)
|
||||
{
|
||||
mVerts.insert(mVerts.end(),other.mVerts.begin(),other.mVerts.end());
|
||||
mVertcnt.insert(mVertcnt.end(),other.mVertcnt.begin(),other.mVertcnt.end());
|
||||
void TempMesh::Append(const TempMesh &other) {
|
||||
mVerts.insert(mVerts.end(), other.mVerts.begin(), other.mVerts.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
|
||||
// Newell's algorithm. The length of the normals gives the area
|
||||
// of the polygons, which is close to zero for lines.
|
||||
|
@ -161,52 +155,48 @@ void TempMesh::RemoveDegenerates()
|
|||
++it;
|
||||
}
|
||||
|
||||
if(drop) {
|
||||
if (drop) {
|
||||
IFCImporter::LogVerboseDebug("removing degenerate faces");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
IfcVector3 TempMesh::ComputePolygonNormal(const IfcVector3* vtcs, size_t cnt, bool normalize)
|
||||
{
|
||||
std::vector<IfcFloat> temp((cnt+2)*3);
|
||||
for( size_t vofs = 0, i = 0; vofs < cnt; ++vofs )
|
||||
{
|
||||
const IfcVector3& v = vtcs[vofs];
|
||||
IfcVector3 TempMesh::ComputePolygonNormal(const IfcVector3 *vtcs, size_t cnt, bool normalize) {
|
||||
const size_t Capa = cnt + 2;
|
||||
std::vector<IfcFloat> temp((Capa)*3);
|
||||
for (size_t vofs = 0, i = 0; vofs < cnt; ++vofs) {
|
||||
const IfcVector3 &v = vtcs[vofs];
|
||||
temp[i++] = v.x;
|
||||
temp[i++] = v.y;
|
||||
temp[i++] = v.z;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TempMesh::ComputePolygonNormals(std::vector<IfcVector3>& normals,
|
||||
bool normalize,
|
||||
size_t ofs) const
|
||||
{
|
||||
void TempMesh::ComputePolygonNormals(std::vector<IfcVector3> &normals, bool normalize, size_t ofs) const {
|
||||
size_t max_vcount = 0;
|
||||
std::vector<unsigned int>::const_iterator begin = mVertcnt.begin()+ofs, end = mVertcnt.end(), iit;
|
||||
for(iit = begin; iit != end; ++iit) {
|
||||
max_vcount = std::max(max_vcount,static_cast<size_t>(*iit));
|
||||
std::vector<unsigned int>::const_iterator begin = mVertcnt.begin() + ofs, end = mVertcnt.end(), iit;
|
||||
for (iit = begin; iit != end; ++iit) {
|
||||
max_vcount = std::max(max_vcount, static_cast<size_t>(*iit));
|
||||
}
|
||||
|
||||
std::vector<IfcFloat> temp((max_vcount+2)*4);
|
||||
normals.reserve( normals.size() + mVertcnt.size()-ofs );
|
||||
const size_t Capa = max_vcount + 2;
|
||||
std::vector<IfcFloat> temp(Capa * 4);
|
||||
normals.reserve(normals.size() + mVertcnt.size() - ofs);
|
||||
|
||||
// `NewellNormal()` currently has a relatively strange interface and need to
|
||||
// re-structure things a bit to meet them.
|
||||
size_t vidx = std::accumulate(mVertcnt.begin(),begin,0);
|
||||
for(iit = begin; iit != end; vidx += *iit++) {
|
||||
size_t vidx = std::accumulate(mVertcnt.begin(), begin, 0);
|
||||
for (iit = begin; iit != end; vidx += *iit++) {
|
||||
if (!*iit) {
|
||||
normals.push_back(IfcVector3());
|
||||
normals.emplace_back();
|
||||
continue;
|
||||
}
|
||||
for(size_t vofs = 0, cnt = 0; vofs < *iit; ++vofs) {
|
||||
const IfcVector3& v = mVerts[vidx+vofs];
|
||||
for (size_t vofs = 0, cnt = 0; vofs < *iit; ++vofs) {
|
||||
const IfcVector3 &v = mVerts[vidx + vofs];
|
||||
temp[cnt++] = v.x;
|
||||
temp[cnt++] = v.y;
|
||||
temp[cnt++] = v.z;
|
||||
|
@ -216,12 +206,12 @@ void TempMesh::ComputePolygonNormals(std::vector<IfcVector3>& normals,
|
|||
++cnt;
|
||||
}
|
||||
|
||||
normals.push_back(IfcVector3());
|
||||
NewellNormal<4,4,4>(normals.back(),*iit,&temp[0],&temp[1],&temp[2]);
|
||||
normals.emplace_back();
|
||||
NewellNormal<4, 4, 4>(normals.back(), *iit, &temp[0], &temp[1], &temp[2], Capa);
|
||||
}
|
||||
|
||||
if(normalize) {
|
||||
for(IfcVector3& n : normals) {
|
||||
if (normalize) {
|
||||
for (IfcVector3 &n : normals) {
|
||||
n.Normalize();
|
||||
}
|
||||
}
|
||||
|
@ -229,62 +219,55 @@ void TempMesh::ComputePolygonNormals(std::vector<IfcVector3>& normals,
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// 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);
|
||||
}
|
||||
|
||||
struct CompareVector
|
||||
{
|
||||
bool operator () (const IfcVector3& a, const IfcVector3& b) const
|
||||
{
|
||||
struct CompareVector {
|
||||
bool operator()(const IfcVector3 &a, const IfcVector3 &b) const {
|
||||
IfcVector3 d = a - b;
|
||||
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);
|
||||
}
|
||||
};
|
||||
struct FindVector
|
||||
{
|
||||
struct FindVector {
|
||||
IfcVector3 v;
|
||||
FindVector(const IfcVector3& p) : v(p) { }
|
||||
bool operator () (const IfcVector3& p) { return FuzzyVectorCompare(1e-6)(p, v); }
|
||||
FindVector(const IfcVector3 &p) :
|
||||
v(p) {}
|
||||
bool operator()(const IfcVector3 &p) { return FuzzyVectorCompare(1e-6)(p, v); }
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TempMesh::FixupFaceOrientation()
|
||||
{
|
||||
void TempMesh::FixupFaceOrientation() {
|
||||
const IfcVector3 vavg = Center();
|
||||
|
||||
// create a list of start indices for all faces to allow random access to faces
|
||||
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;
|
||||
|
||||
// list all faces on a vertex
|
||||
std::map<IfcVector3, std::vector<size_t>, CompareVector> facesByVertex;
|
||||
for( size_t a = 0; a < mVertcnt.size(); ++a )
|
||||
{
|
||||
for( size_t b = 0; b < mVertcnt[a]; ++b )
|
||||
for (size_t a = 0; a < mVertcnt.size(); ++a) {
|
||||
for (size_t b = 0; b < mVertcnt[a]; ++b)
|
||||
facesByVertex[mVerts[faceStartIndices[a] + b]].push_back(a);
|
||||
}
|
||||
// determine neighbourhood for all polys
|
||||
std::vector<size_t> neighbour(mVerts.size(), SIZE_MAX);
|
||||
std::vector<size_t> tempIntersect(10);
|
||||
for( size_t a = 0; a < mVertcnt.size(); ++a )
|
||||
{
|
||||
for( size_t b = 0; b < mVertcnt[a]; ++b )
|
||||
{
|
||||
for (size_t a = 0; a < mVertcnt.size(); ++a) {
|
||||
for (size_t b = 0; b < mVertcnt[a]; ++b) {
|
||||
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>& facesOnNB = facesByVertex[mVerts[nib]];
|
||||
const std::vector<size_t> &facesOnB = facesByVertex[mVerts[ib]];
|
||||
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
|
||||
std::vector<size_t>::iterator sectstart = tempIntersect.begin();
|
||||
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;
|
||||
if( *sectstart == a )
|
||||
if (*sectstart == a)
|
||||
++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
|
||||
// faces to have the same winding until all faces have been tested.
|
||||
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
|
||||
size_t farthestIndex = SIZE_MAX;
|
||||
IfcFloat farthestDistance = -1.0;
|
||||
for( size_t a = 0; a < mVertcnt.size(); ++a )
|
||||
{
|
||||
if( faceDone[a] )
|
||||
for (size_t a = 0; a < mVertcnt.size(); ++a) {
|
||||
if (faceDone[a])
|
||||
continue;
|
||||
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();
|
||||
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
|
||||
IfcVector3 farthestNormal = ComputePolygonNormal(mVerts.data() + faceStartIndices[farthestIndex], mVertcnt[farthestIndex]);
|
||||
IfcVector3 farthestCenter = std::accumulate(mVerts.begin() + faceStartIndices[farthestIndex],
|
||||
mVerts.begin() + faceStartIndices[farthestIndex] + mVertcnt[farthestIndex], IfcVector3(0.0))
|
||||
/ IfcFloat(mVertcnt[farthestIndex]);
|
||||
mVerts.begin() + faceStartIndices[farthestIndex] + mVertcnt[farthestIndex], IfcVector3(0.0)) /
|
||||
IfcFloat(mVertcnt[farthestIndex]);
|
||||
// We accept a bit of negative orientation without reversing. In case of doubt, prefer the orientation given in
|
||||
// the file.
|
||||
if( (farthestNormal * (farthestCenter - vavg).Normalize()) < -0.4 )
|
||||
{
|
||||
if ((farthestNormal * (farthestCenter - vavg).Normalize()) < -0.4) {
|
||||
size_t fsi = faceStartIndices[farthestIndex], fvc = mVertcnt[farthestIndex];
|
||||
std::reverse(mVerts.begin() + fsi, mVerts.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
|
||||
// After: points D - C - B - A, reversed neighbours are s - r - q - p, but the should be
|
||||
// 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]);
|
||||
}
|
||||
faceDone[farthestIndex] = true;
|
||||
|
@ -334,21 +318,19 @@ void TempMesh::FixupFaceOrientation()
|
|||
todo.push_back(farthestIndex);
|
||||
|
||||
// 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 vsi = faceStartIndices[tdf], vc = mVertcnt[tdf];
|
||||
todo.pop_back();
|
||||
|
||||
// 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
|
||||
size_t nbi = neighbour[vsi + a];
|
||||
if( nbi == SIZE_MAX || faceDone[nbi] )
|
||||
if (nbi == SIZE_MAX || faceDone[nbi])
|
||||
continue;
|
||||
|
||||
const IfcVector3& vp = mVerts[vsi + a];
|
||||
const IfcVector3 &vp = mVerts[vsi + a];
|
||||
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));
|
||||
ai_assert(it != mVerts.begin() + nbvsi + nbvc);
|
||||
|
@ -358,8 +340,7 @@ void TempMesh::FixupFaceOrientation()
|
|||
// to reverse the neighbour
|
||||
nb_vidx = (nb_vidx + 1) % nbvc;
|
||||
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(neighbour.begin() + nbvsi, neighbour.begin() + nbvsi + nbvc);
|
||||
for (size_t aa = 0; aa < nbvc - 1; ++aa) {
|
||||
|
@ -381,17 +362,16 @@ void TempMesh::FixupFaceOrientation()
|
|||
void TempMesh::RemoveAdjacentDuplicates() {
|
||||
bool drop = false;
|
||||
std::vector<IfcVector3>::iterator base = mVerts.begin();
|
||||
for(unsigned int& cnt : mVertcnt) {
|
||||
if (cnt < 2){
|
||||
for (unsigned int &cnt : mVertcnt) {
|
||||
if (cnt < 2) {
|
||||
base += cnt;
|
||||
continue;
|
||||
}
|
||||
|
||||
IfcVector3 vmin,vmax;
|
||||
ArrayBounds(&*base, cnt ,vmin,vmax);
|
||||
IfcVector3 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;
|
||||
|
||||
//// 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
|
||||
// of the previous pass as a side-effect.
|
||||
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) {
|
||||
cnt -= static_cast<unsigned int>(std::distance(e, end));
|
||||
mVerts.erase(e,end);
|
||||
drop = true;
|
||||
mVerts.erase(e, end);
|
||||
drop = true;
|
||||
}
|
||||
|
||||
// check front and back vertices for this polygon
|
||||
if (cnt > 1 && fz(*base,*(base+cnt-1))) {
|
||||
mVerts.erase(base+ --cnt);
|
||||
drop = true;
|
||||
if (cnt > 1 && fz(*base, *(base + cnt - 1))) {
|
||||
mVerts.erase(base + --cnt);
|
||||
drop = true;
|
||||
}
|
||||
|
||||
// removing adjacent duplicates shouldn't erase everything :-)
|
||||
ai_assert(cnt>0);
|
||||
ai_assert(cnt > 0);
|
||||
base += cnt;
|
||||
}
|
||||
if(drop) {
|
||||
if (drop) {
|
||||
IFCImporter::LogVerboseDebug("removing duplicate vertices");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TempMesh::Swap(TempMesh& other)
|
||||
{
|
||||
void TempMesh::Swap(TempMesh &other) {
|
||||
mVertcnt.swap(other.mVertcnt);
|
||||
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";
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
IfcFloat ConvertSIPrefix(const std::string& prefix)
|
||||
{
|
||||
IfcFloat ConvertSIPrefix(const std::string &prefix) {
|
||||
if (prefix == "EXA") {
|
||||
return 1e18f;
|
||||
}
|
||||
else if (prefix == "PETA") {
|
||||
} else if (prefix == "PETA") {
|
||||
return 1e15f;
|
||||
}
|
||||
else if (prefix == "TERA") {
|
||||
} else if (prefix == "TERA") {
|
||||
return 1e12f;
|
||||
}
|
||||
else if (prefix == "GIGA") {
|
||||
} else if (prefix == "GIGA") {
|
||||
return 1e9f;
|
||||
}
|
||||
else if (prefix == "MEGA") {
|
||||
} else if (prefix == "MEGA") {
|
||||
return 1e6f;
|
||||
}
|
||||
else if (prefix == "KILO") {
|
||||
} else if (prefix == "KILO") {
|
||||
return 1e3f;
|
||||
}
|
||||
else if (prefix == "HECTO") {
|
||||
} else if (prefix == "HECTO") {
|
||||
return 1e2f;
|
||||
}
|
||||
else if (prefix == "DECA") {
|
||||
} else if (prefix == "DECA") {
|
||||
return 1e-0f;
|
||||
}
|
||||
else if (prefix == "DECI") {
|
||||
} else if (prefix == "DECI") {
|
||||
return 1e-1f;
|
||||
}
|
||||
else if (prefix == "CENTI") {
|
||||
} else if (prefix == "CENTI") {
|
||||
return 1e-2f;
|
||||
}
|
||||
else if (prefix == "MILLI") {
|
||||
} else if (prefix == "MILLI") {
|
||||
return 1e-3f;
|
||||
}
|
||||
else if (prefix == "MICRO") {
|
||||
} else if (prefix == "MICRO") {
|
||||
return 1e-6f;
|
||||
}
|
||||
else if (prefix == "NANO") {
|
||||
} else if (prefix == "NANO") {
|
||||
return 1e-9f;
|
||||
}
|
||||
else if (prefix == "PICO") {
|
||||
} else if (prefix == "PICO") {
|
||||
return 1e-12f;
|
||||
}
|
||||
else if (prefix == "FEMTO") {
|
||||
} else if (prefix == "FEMTO") {
|
||||
return 1e-15f;
|
||||
}
|
||||
else if (prefix == "ATTO") {
|
||||
} else if (prefix == "ATTO") {
|
||||
return 1e-18f;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
IFCImporter::LogError("Unrecognized SI prefix: " + prefix);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertColor(aiColor4D& out, const Schema_2x3::IfcColourRgb& in)
|
||||
{
|
||||
out.r = static_cast<float>( in.Red );
|
||||
out.g = static_cast<float>( in.Green );
|
||||
out.b = static_cast<float>( in.Blue );
|
||||
out.a = static_cast<float>( 1.f );
|
||||
void ConvertColor(aiColor4D &out, const Schema_2x3::IfcColourRgb &in) {
|
||||
out.r = static_cast<float>(in.Red);
|
||||
out.g = static_cast<float>(in.Green);
|
||||
out.b = static_cast<float>(in.Blue);
|
||||
out.a = static_cast<float>(1.f);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
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>()) {
|
||||
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>()) {
|
||||
out.r = out.g = out.b = static_cast<float>(*r);
|
||||
if(base) {
|
||||
out.r *= static_cast<float>( base->r );
|
||||
out.g *= static_cast<float>( base->g );
|
||||
out.b *= static_cast<float>( base->b );
|
||||
out.a = static_cast<float>( base->a );
|
||||
}
|
||||
else out.a = 1.0;
|
||||
}
|
||||
else if (const Schema_2x3::IfcColourRgb* const rgb = in.ResolveSelectPtr<Schema_2x3::IfcColourRgb>(conv.db)) {
|
||||
ConvertColor(out,*rgb);
|
||||
}
|
||||
else {
|
||||
if (base) {
|
||||
out.r *= static_cast<float>(base->r);
|
||||
out.g *= static_cast<float>(base->g);
|
||||
out.b *= static_cast<float>(base->b);
|
||||
out.a = static_cast<float>(base->a);
|
||||
} else
|
||||
out.a = 1.0;
|
||||
} else if (const Schema_2x3::IfcColourRgb *const rgb = in.ResolveSelectPtr<Schema_2x3::IfcColourRgb>(conv.db)) {
|
||||
ConvertColor(out, *rgb);
|
||||
} else {
|
||||
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();
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertVector(IfcVector3& out, const Schema_2x3::IfcVector& in)
|
||||
{
|
||||
ConvertDirection(out,in.Orientation);
|
||||
void ConvertVector(IfcVector3 &out, const Schema_2x3::IfcVector &in) {
|
||||
ConvertDirection(out, in.Orientation);
|
||||
out *= in.Magnitude;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertDirection(IfcVector3& out, const Schema_2x3::IfcDirection& in)
|
||||
{
|
||||
void ConvertDirection(IfcVector3 &out, const Schema_2x3::IfcDirection &in) {
|
||||
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];
|
||||
}
|
||||
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");
|
||||
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.b1 = x.y;
|
||||
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;
|
||||
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) {
|
||||
ConvertDirection(z,*in.Axis.Get());
|
||||
ConvertDirection(z, *in.Axis.Get());
|
||||
}
|
||||
if (in.RefDirection) {
|
||||
ConvertDirection(r,*in.RefDirection.Get());
|
||||
ConvertDirection(r, *in.RefDirection.Get());
|
||||
}
|
||||
|
||||
IfcVector3 v = r.Normalize();
|
||||
IfcVector3 tmpx = z * (v*z);
|
||||
IfcVector3 tmpx = z * (v * z);
|
||||
|
||||
x = (v-tmpx).Normalize();
|
||||
IfcVector3 y = (z^x);
|
||||
x = (v - tmpx).Normalize();
|
||||
IfcVector3 y = (z ^ x);
|
||||
|
||||
IfcMatrix4::Translation(loc,out);
|
||||
AssignMatrixAxes(out,x,y,z);
|
||||
IfcMatrix4::Translation(loc, out);
|
||||
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;
|
||||
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) {
|
||||
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);
|
||||
AssignMatrixAxes(out,x,y,IfcVector3(0.f,0.f,1.f));
|
||||
IfcMatrix4::Translation(loc, out);
|
||||
AssignMatrixAxes(out, x, y, IfcVector3(0.f, 0.f, 1.f));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertAxisPlacement(IfcVector3& axis, IfcVector3& pos, const Schema_2x3::IfcAxis1Placement& in)
|
||||
{
|
||||
ConvertCartesianPoint(pos,in.Location);
|
||||
void ConvertAxisPlacement(IfcVector3 &axis, IfcVector3 &pos, const Schema_2x3::IfcAxis1Placement &in) {
|
||||
ConvertCartesianPoint(pos, in.Location);
|
||||
if (in.Axis) {
|
||||
ConvertDirection(axis,in.Axis.Get());
|
||||
}
|
||||
else {
|
||||
axis = IfcVector3(0.f,0.f,1.f);
|
||||
ConvertDirection(axis, in.Axis.Get());
|
||||
} else {
|
||||
axis = IfcVector3(0.f, 0.f, 1.f);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement& in, ConversionData& conv)
|
||||
{
|
||||
if(const Schema_2x3::IfcAxis2Placement3D* pl3 = in.ResolveSelectPtr<Schema_2x3::IfcAxis2Placement3D>(conv.db)) {
|
||||
ConvertAxisPlacement(out,*pl3);
|
||||
}
|
||||
else if(const Schema_2x3::IfcAxis2Placement2D* pl2 = in.ResolveSelectPtr<Schema_2x3::IfcAxis2Placement2D>(conv.db)) {
|
||||
ConvertAxisPlacement(out,*pl2);
|
||||
}
|
||||
else {
|
||||
void ConvertAxisPlacement(IfcMatrix4 &out, const Schema_2x3::IfcAxis2Placement &in, ConversionData &conv) {
|
||||
if (const Schema_2x3::IfcAxis2Placement3D *pl3 = in.ResolveSelectPtr<Schema_2x3::IfcAxis2Placement3D>(conv.db)) {
|
||||
ConvertAxisPlacement(out, *pl3);
|
||||
} else if (const Schema_2x3::IfcAxis2Placement2D *pl2 = in.ResolveSelectPtr<Schema_2x3::IfcAxis2Placement2D>(conv.db)) {
|
||||
ConvertAxisPlacement(out, *pl2);
|
||||
} else {
|
||||
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;
|
||||
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) {
|
||||
ConvertDirection(x,*op.Axis1.Get());
|
||||
ConvertDirection(x, *op.Axis1.Get());
|
||||
}
|
||||
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(op2->Axis3) {
|
||||
ConvertDirection(z,*op2->Axis3.Get());
|
||||
if (const Schema_2x3::IfcCartesianTransformationOperator3D *op2 = op.ToPtr<Schema_2x3::IfcCartesianTransformationOperator3D>()) {
|
||||
if (op2->Axis3) {
|
||||
ConvertDirection(z, *op2->Axis3.Get());
|
||||
}
|
||||
}
|
||||
|
||||
IfcMatrix4 locm;
|
||||
IfcMatrix4::Translation(loc,locm);
|
||||
AssignMatrixAxes(out,x,y,z);
|
||||
|
||||
IfcMatrix4::Translation(loc, locm);
|
||||
AssignMatrixAxes(out, x, y, z);
|
||||
|
||||
IfcVector3 vscale;
|
||||
if (const Schema_2x3::IfcCartesianTransformationOperator3DnonUniform* nuni = op.ToPtr<Schema_2x3::IfcCartesianTransformationOperator3DnonUniform>()) {
|
||||
vscale.x = nuni->Scale?op.Scale.Get():1.f;
|
||||
vscale.y = nuni->Scale2?nuni->Scale2.Get():1.f;
|
||||
vscale.z = nuni->Scale3?nuni->Scale3.Get():1.f;
|
||||
}
|
||||
else {
|
||||
const IfcFloat sc = op.Scale?op.Scale.Get():1.f;
|
||||
vscale = IfcVector3(sc,sc,sc);
|
||||
if (const Schema_2x3::IfcCartesianTransformationOperator3DnonUniform *nuni = op.ToPtr<Schema_2x3::IfcCartesianTransformationOperator3DnonUniform>()) {
|
||||
vscale.x = nuni->Scale ? op.Scale.Get() : 1.f;
|
||||
vscale.y = nuni->Scale2 ? nuni->Scale2.Get() : 1.f;
|
||||
vscale.z = nuni->Scale3 ? nuni->Scale3.Get() : 1.f;
|
||||
} else {
|
||||
const IfcFloat sc = op.Scale ? op.Scale.Get() : 1.f;
|
||||
vscale = IfcVector3(sc, sc, sc);
|
||||
}
|
||||
|
||||
IfcMatrix4 s;
|
||||
IfcMatrix4::Scaling(vscale,s);
|
||||
IfcMatrix4::Scaling(vscale, s);
|
||||
|
||||
out = locm * out * s;
|
||||
}
|
||||
|
||||
|
||||
} // ! IFC
|
||||
} // ! Assimp
|
||||
} // namespace IFC
|
||||
} // namespace Assimp
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
|
|||
|
||||
Copyright (c) 2006-2020, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
|
@ -47,40 +46,37 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#ifndef INCLUDED_IFCUTIL_H
|
||||
#define INCLUDED_IFCUTIL_H
|
||||
|
||||
#include "AssetLib/IFC/IFCReaderGen_2x3.h"
|
||||
#include "AssetLib/IFC/IFCLoader.h"
|
||||
#include "AssetLib/IFC/IFCReaderGen_2x3.h"
|
||||
#include "AssetLib/Step/STEPFile.h"
|
||||
|
||||
#include <assimp/mesh.h>
|
||||
#include <assimp/material.h>
|
||||
#include <assimp/mesh.h>
|
||||
|
||||
struct aiNode;
|
||||
|
||||
namespace Assimp {
|
||||
namespace IFC {
|
||||
|
||||
typedef double IfcFloat;
|
||||
|
||||
// IfcFloat-precision math data types
|
||||
typedef aiVector2t<IfcFloat> IfcVector2;
|
||||
typedef aiVector3t<IfcFloat> IfcVector3;
|
||||
typedef aiMatrix4x4t<IfcFloat> IfcMatrix4;
|
||||
typedef aiMatrix3x3t<IfcFloat> IfcMatrix3;
|
||||
typedef aiColor4t<IfcFloat> IfcColor4;
|
||||
using IfcFloat = double;
|
||||
|
||||
// IfcFloat-precision math data types
|
||||
using IfcVector2 = aiVector2t<IfcFloat>;
|
||||
using IfcVector3 = aiVector3t<IfcFloat>;
|
||||
using IfcMatrix4 = aiMatrix4x4t<IfcFloat>;
|
||||
using IfcMatrix3 = aiMatrix3x3t<IfcFloat>;
|
||||
using IfcColor4 = aiColor4t<IfcFloat>;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Helper for std::for_each to delete all heap-allocated items in a container
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
struct delete_fun {
|
||||
void operator()(T* del) {
|
||||
void operator()(T *del) {
|
||||
delete del;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Helper used during mesh construction. Aids at creating aiMesh'es out of relatively few polygons.
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -89,32 +85,29 @@ struct TempMesh {
|
|||
std::vector<unsigned int> mVertcnt;
|
||||
|
||||
// utilities
|
||||
aiMesh* ToMesh();
|
||||
aiMesh *ToMesh();
|
||||
void Clear();
|
||||
void Transform(const IfcMatrix4& mat);
|
||||
void Transform(const IfcMatrix4 &mat);
|
||||
IfcVector3 Center() const;
|
||||
void Append(const TempMesh& other);
|
||||
void Append(const TempMesh &other);
|
||||
bool IsEmpty() const;
|
||||
void RemoveAdjacentDuplicates();
|
||||
void RemoveDegenerates();
|
||||
void FixupFaceOrientation();
|
||||
static IfcVector3 ComputePolygonNormal(const IfcVector3* vtcs, size_t cnt, bool normalize = true);
|
||||
static IfcVector3 ComputePolygonNormal(const IfcVector3 *vtcs, size_t cnt, bool normalize = true);
|
||||
IfcVector3 ComputeLastPolygonNormal(bool normalize = true) const;
|
||||
void ComputePolygonNormals(std::vector<IfcVector3>& normals, bool normalize = true, size_t ofs = 0) const;
|
||||
void Swap(TempMesh& other);
|
||||
void ComputePolygonNormals(std::vector<IfcVector3> &normals, bool normalize = true, size_t ofs = 0) const;
|
||||
void Swap(TempMesh &other);
|
||||
};
|
||||
|
||||
inline
|
||||
bool TempMesh::IsEmpty() const {
|
||||
inline bool TempMesh::IsEmpty() const {
|
||||
return mVerts.empty() && mVertcnt.empty();
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Temporary representation of an opening in a wall or a floor
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
struct TempOpening
|
||||
{
|
||||
struct TempOpening {
|
||||
const IFC::Schema_2x3::IfcSolidModel *solid;
|
||||
IfcVector3 extrusionDir;
|
||||
|
||||
|
@ -129,90 +122,98 @@ struct TempOpening
|
|||
std::vector<IfcVector3> wallPoints;
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
TempOpening()
|
||||
: solid()
|
||||
, extrusionDir()
|
||||
, profileMesh()
|
||||
{
|
||||
TempOpening() :
|
||||
solid(),
|
||||
extrusionDir(),
|
||||
profileMesh() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
TempOpening(const IFC::Schema_2x3::IfcSolidModel* solid,IfcVector3 extrusionDir,
|
||||
std::shared_ptr<TempMesh> profileMesh,
|
||||
std::shared_ptr<TempMesh> profileMesh2D)
|
||||
: solid(solid)
|
||||
, extrusionDir(extrusionDir)
|
||||
, profileMesh(profileMesh)
|
||||
, profileMesh2D(profileMesh2D)
|
||||
{
|
||||
TempOpening(const IFC::Schema_2x3::IfcSolidModel *solid, IfcVector3 extrusionDir,
|
||||
std::shared_ptr<TempMesh> profileMesh,
|
||||
std::shared_ptr<TempMesh> profileMesh2D) :
|
||||
solid(solid),
|
||||
extrusionDir(extrusionDir),
|
||||
profileMesh(profileMesh),
|
||||
profileMesh2D(profileMesh2D) {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
void Transform(const IfcMatrix4& mat); // defined later since TempMesh is not complete yet
|
||||
|
||||
|
||||
void Transform(const IfcMatrix4 &mat); // defined later since TempMesh is not complete yet
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Helper to sort openings by distance from a given base point
|
||||
struct DistanceSorter {
|
||||
|
||||
DistanceSorter(const IfcVector3& base) : base(base) {}
|
||||
DistanceSorter(const IfcVector3 &base) :
|
||||
base(base) {}
|
||||
|
||||
bool operator () (const TempOpening& a, const TempOpening& b) const {
|
||||
return (a.profileMesh->Center()-base).SquareLength() < (b.profileMesh->Center()-base).SquareLength();
|
||||
bool operator()(const TempOpening &a, const TempOpening &b) const {
|
||||
return (a.profileMesh->Center() - base).SquareLength() < (b.profileMesh->Center() - base).SquareLength();
|
||||
}
|
||||
|
||||
IfcVector3 base;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Intermediate data storage during conversion. Keeps everything and a bit more.
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
struct ConversionData
|
||||
{
|
||||
ConversionData(const STEP::DB& db, const IFC::Schema_2x3::IfcProject& proj, aiScene* out,const IFCImporter::Settings& settings)
|
||||
: len_scale(1.0)
|
||||
, angle_scale(-1.0)
|
||||
, db(db)
|
||||
, proj(proj)
|
||||
, out(out)
|
||||
, settings(settings)
|
||||
, apply_openings()
|
||||
, collect_openings()
|
||||
{}
|
||||
struct ConversionData {
|
||||
ConversionData(const STEP::DB &db, const IFC::Schema_2x3::IfcProject &proj, aiScene *out, const IFCImporter::Settings &settings) :
|
||||
len_scale(1.0),
|
||||
angle_scale(-1.0),
|
||||
plane_angle_in_radians(true),
|
||||
db(db),
|
||||
proj(proj),
|
||||
out(out),
|
||||
wcs(),
|
||||
meshes(),
|
||||
materials(),
|
||||
cached_meshes(),
|
||||
cached_materials(),
|
||||
settings(settings),
|
||||
apply_openings(nullptr),
|
||||
collect_openings(nullptr),
|
||||
already_processed() {
|
||||
// empty
|
||||
}
|
||||
|
||||
~ConversionData() {
|
||||
std::for_each(meshes.begin(),meshes.end(),delete_fun<aiMesh>());
|
||||
std::for_each(materials.begin(),materials.end(),delete_fun<aiMaterial>());
|
||||
std::for_each(meshes.begin(), meshes.end(), delete_fun<aiMesh>());
|
||||
std::for_each(materials.begin(), materials.end(), delete_fun<aiMaterial>());
|
||||
}
|
||||
|
||||
IfcFloat len_scale, angle_scale;
|
||||
bool plane_angle_in_radians;
|
||||
|
||||
const STEP::DB& db;
|
||||
const IFC::Schema_2x3::IfcProject& proj;
|
||||
aiScene* out;
|
||||
const STEP::DB &db;
|
||||
const IFC::Schema_2x3::IfcProject &proj;
|
||||
aiScene *out;
|
||||
|
||||
IfcMatrix4 wcs;
|
||||
std::vector<aiMesh*> meshes;
|
||||
std::vector<aiMaterial*> materials;
|
||||
std::vector<aiMesh *> meshes;
|
||||
std::vector<aiMaterial *> materials;
|
||||
|
||||
struct MeshCacheIndex {
|
||||
const IFC::Schema_2x3::IfcRepresentationItem* item; unsigned int matindex;
|
||||
MeshCacheIndex() : item(nullptr), matindex(0) { }
|
||||
MeshCacheIndex(const IFC::Schema_2x3::IfcRepresentationItem* i, unsigned int mi) : item(i), matindex(mi) { }
|
||||
bool operator == (const MeshCacheIndex& o) const { return item == o.item && matindex == o.matindex; }
|
||||
bool operator < (const MeshCacheIndex& o) const { return item < o.item || (item == o.item && matindex < o.matindex); }
|
||||
const IFC::Schema_2x3::IfcRepresentationItem *item;
|
||||
unsigned int matindex;
|
||||
MeshCacheIndex() :
|
||||
item(nullptr), matindex(0) {}
|
||||
MeshCacheIndex(const IFC::Schema_2x3::IfcRepresentationItem *i, unsigned int mi) :
|
||||
item(i), matindex(mi) {}
|
||||
bool operator==(const MeshCacheIndex &o) const { return item == o.item && matindex == o.matindex; }
|
||||
bool operator<(const MeshCacheIndex &o) const { return item < o.item || (item == o.item && matindex < o.matindex); }
|
||||
};
|
||||
typedef std::map<MeshCacheIndex, std::set<unsigned int> > MeshCache;
|
||||
using MeshCache = std::map<MeshCacheIndex, std::set<unsigned int>>;
|
||||
MeshCache cached_meshes;
|
||||
|
||||
typedef std::map<const IFC::Schema_2x3::IfcSurfaceStyle*, unsigned int> MaterialCache;
|
||||
using MaterialCache = std::map<const IFC::Schema_2x3::IfcSurfaceStyle *, unsigned int>;
|
||||
MaterialCache cached_materials;
|
||||
|
||||
const IFCImporter::Settings& settings;
|
||||
const IFCImporter::Settings &settings;
|
||||
|
||||
// Intermediate arrays used to resolve openings in walls: only one of them
|
||||
// can be given at a time. apply_openings if present if the current element
|
||||
|
@ -220,34 +221,33 @@ struct ConversionData
|
|||
// collect_openings is present only if the current element is an
|
||||
// IfcOpeningElement, for which all the geometry needs to be preserved
|
||||
// for later processing by a parent, which is a wall.
|
||||
std::vector<TempOpening>* apply_openings;
|
||||
std::vector<TempOpening>* collect_openings;
|
||||
std::vector<TempOpening> *apply_openings;
|
||||
std::vector<TempOpening> *collect_openings;
|
||||
|
||||
std::set<uint64_t> already_processed;
|
||||
};
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Binary predicate to compare vectors with a given, quadratic epsilon.
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
struct FuzzyVectorCompare {
|
||||
|
||||
FuzzyVectorCompare(IfcFloat epsilon) : epsilon(epsilon) {}
|
||||
bool operator()(const IfcVector3& a, const IfcVector3& b) {
|
||||
return std::abs((a-b).SquareLength()) < epsilon;
|
||||
FuzzyVectorCompare(IfcFloat epsilon) :
|
||||
epsilon(epsilon) {}
|
||||
bool operator()(const IfcVector3 &a, const IfcVector3 &b) {
|
||||
return std::abs((a - b).SquareLength()) < epsilon;
|
||||
}
|
||||
|
||||
const IfcFloat epsilon;
|
||||
};
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Ordering predicate to totally order R^2 vectors first by x and then by y
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
struct XYSorter {
|
||||
|
||||
// sort first by X coordinates, then by Y coordinates
|
||||
bool operator () (const IfcVector2&a, const IfcVector2& b) const {
|
||||
bool operator()(const IfcVector2 &a, const IfcVector2 &b) const {
|
||||
if (a.x == b.x) {
|
||||
return a.y < b.y;
|
||||
}
|
||||
|
@ -255,67 +255,61 @@ struct XYSorter {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// conversion routines for common IFC entities, implemented in IFCUtil.cpp
|
||||
void ConvertColor(aiColor4D& out, const Schema_2x3::IfcColourRgb& in);
|
||||
void ConvertColor(aiColor4D& out, const Schema_2x3::IfcColourOrFactor& in,ConversionData& conv,const aiColor4D* base);
|
||||
void ConvertCartesianPoint(IfcVector3& out, const Schema_2x3::IfcCartesianPoint& in);
|
||||
void ConvertDirection(IfcVector3& out, const Schema_2x3::IfcDirection& in);
|
||||
void ConvertVector(IfcVector3& out, const Schema_2x3::IfcVector& in);
|
||||
void AssignMatrixAxes(IfcMatrix4& out, const IfcVector3& x, const IfcVector3& y, const IfcVector3& z);
|
||||
void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement3D& in);
|
||||
void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement2D& in);
|
||||
void ConvertAxisPlacement(IfcVector3& axis, IfcVector3& pos, const IFC::Schema_2x3::IfcAxis1Placement& in);
|
||||
void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement& in, ConversionData& conv);
|
||||
void ConvertTransformOperator(IfcMatrix4& out, const Schema_2x3::IfcCartesianTransformationOperator& op);
|
||||
bool IsTrue(const Assimp::STEP::EXPRESS::BOOLEAN& in);
|
||||
IfcFloat ConvertSIPrefix(const std::string& prefix);
|
||||
|
||||
void ConvertColor(aiColor4D &out, const Schema_2x3::IfcColourRgb &in);
|
||||
void ConvertColor(aiColor4D &out, const Schema_2x3::IfcColourOrFactor &in, ConversionData &conv, const aiColor4D *base);
|
||||
void ConvertCartesianPoint(IfcVector3 &out, const Schema_2x3::IfcCartesianPoint &in);
|
||||
void ConvertDirection(IfcVector3 &out, const Schema_2x3::IfcDirection &in);
|
||||
void ConvertVector(IfcVector3 &out, const Schema_2x3::IfcVector &in);
|
||||
void AssignMatrixAxes(IfcMatrix4 &out, const IfcVector3 &x, const IfcVector3 &y, const IfcVector3 &z);
|
||||
void ConvertAxisPlacement(IfcMatrix4 &out, const Schema_2x3::IfcAxis2Placement3D &in);
|
||||
void ConvertAxisPlacement(IfcMatrix4 &out, const Schema_2x3::IfcAxis2Placement2D &in);
|
||||
void ConvertAxisPlacement(IfcVector3 &axis, IfcVector3 &pos, const IFC::Schema_2x3::IfcAxis1Placement &in);
|
||||
void ConvertAxisPlacement(IfcMatrix4 &out, const Schema_2x3::IfcAxis2Placement &in, ConversionData &conv);
|
||||
void ConvertTransformOperator(IfcMatrix4 &out, const Schema_2x3::IfcCartesianTransformationOperator &op);
|
||||
bool IsTrue(const Assimp::STEP::EXPRESS::BOOLEAN &in);
|
||||
IfcFloat ConvertSIPrefix(const std::string &prefix);
|
||||
|
||||
// IFCProfile.cpp
|
||||
bool ProcessProfile(const Schema_2x3::IfcProfileDef& prof, TempMesh& meshout, ConversionData& conv);
|
||||
bool ProcessCurve(const Schema_2x3::IfcCurve& curve, TempMesh& meshout, ConversionData& conv);
|
||||
bool ProcessProfile(const Schema_2x3::IfcProfileDef &prof, TempMesh &meshout, ConversionData &conv);
|
||||
bool ProcessCurve(const Schema_2x3::IfcCurve &curve, TempMesh &meshout, ConversionData &conv);
|
||||
|
||||
// IFCMaterial.cpp
|
||||
unsigned int ProcessMaterials(uint64_t id, unsigned int prevMatId, ConversionData& conv, bool forceDefaultMat);
|
||||
unsigned int ProcessMaterials(uint64_t id, unsigned int prevMatId, ConversionData &conv, bool forceDefaultMat);
|
||||
|
||||
// IFCGeometry.cpp
|
||||
IfcMatrix3 DerivePlaneCoordinateSpace(const TempMesh& curmesh, bool& ok, IfcVector3& norOut);
|
||||
bool ProcessRepresentationItem(const Schema_2x3::IfcRepresentationItem& item, unsigned int matid, std::set<unsigned int>& mesh_indices, ConversionData& conv);
|
||||
void AssignAddedMeshes(std::set<unsigned int>& mesh_indices,aiNode* nd,ConversionData& /*conv*/);
|
||||
IfcMatrix3 DerivePlaneCoordinateSpace(const TempMesh &curmesh, bool &ok, IfcVector3 &norOut);
|
||||
bool ProcessRepresentationItem(const Schema_2x3::IfcRepresentationItem &item, unsigned int matid, std::set<unsigned int> &mesh_indices, ConversionData &conv);
|
||||
void AssignAddedMeshes(std::set<unsigned int> &mesh_indices, aiNode *nd, ConversionData & /*conv*/);
|
||||
|
||||
void ProcessSweptAreaSolid(const Schema_2x3::IfcSweptAreaSolid& swept, TempMesh& meshout,
|
||||
ConversionData& conv);
|
||||
void ProcessSweptAreaSolid(const Schema_2x3::IfcSweptAreaSolid &swept, TempMesh &meshout,
|
||||
ConversionData &conv);
|
||||
|
||||
void ProcessExtrudedAreaSolid(const Schema_2x3::IfcExtrudedAreaSolid& solid, TempMesh& result,
|
||||
ConversionData& conv, bool collect_openings);
|
||||
void ProcessExtrudedAreaSolid(const Schema_2x3::IfcExtrudedAreaSolid &solid, TempMesh &result,
|
||||
ConversionData &conv, bool collect_openings);
|
||||
|
||||
// IFCBoolean.cpp
|
||||
|
||||
void ProcessBoolean(const Schema_2x3::IfcBooleanResult& boolean, TempMesh& result, ConversionData& conv);
|
||||
void ProcessBooleanHalfSpaceDifference(const Schema_2x3::IfcHalfSpaceSolid* hs, TempMesh& result,
|
||||
const TempMesh& first_operand,
|
||||
ConversionData& conv);
|
||||
|
||||
void ProcessPolygonalBoundedBooleanHalfSpaceDifference(const Schema_2x3::IfcPolygonalBoundedHalfSpace* hs, TempMesh& result,
|
||||
const TempMesh& first_operand,
|
||||
ConversionData& conv);
|
||||
void ProcessBooleanExtrudedAreaSolidDifference(const Schema_2x3::IfcExtrudedAreaSolid* as, TempMesh& result,
|
||||
const TempMesh& first_operand,
|
||||
ConversionData& conv);
|
||||
void ProcessBoolean(const Schema_2x3::IfcBooleanResult &boolean, TempMesh &result, ConversionData &conv);
|
||||
void ProcessBooleanHalfSpaceDifference(const Schema_2x3::IfcHalfSpaceSolid *hs, TempMesh &result,
|
||||
const TempMesh &first_operand,
|
||||
ConversionData &conv);
|
||||
|
||||
void ProcessPolygonalBoundedBooleanHalfSpaceDifference(const Schema_2x3::IfcPolygonalBoundedHalfSpace *hs, TempMesh &result,
|
||||
const TempMesh &first_operand,
|
||||
ConversionData &conv);
|
||||
void ProcessBooleanExtrudedAreaSolidDifference(const Schema_2x3::IfcExtrudedAreaSolid *as, TempMesh &result,
|
||||
const TempMesh &first_operand,
|
||||
ConversionData &conv);
|
||||
|
||||
// IFCOpenings.cpp
|
||||
|
||||
bool GenerateOpenings(std::vector<TempOpening>& openings,
|
||||
const std::vector<IfcVector3>& nors,
|
||||
TempMesh& curmesh,
|
||||
bool check_intersection,
|
||||
bool generate_connection_geometry,
|
||||
const IfcVector3& wall_extrusion_axis = IfcVector3(0,1,0));
|
||||
|
||||
|
||||
bool GenerateOpenings(std::vector<TempOpening> &openings,
|
||||
const std::vector<IfcVector3> &nors,
|
||||
TempMesh &curmesh,
|
||||
bool check_intersection,
|
||||
bool generate_connection_geometry,
|
||||
const IfcVector3 &wall_extrusion_axis = IfcVector3(0, 1, 0));
|
||||
|
||||
// IFCCurve.cpp
|
||||
|
||||
|
@ -324,8 +318,8 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
class CurveError {
|
||||
public:
|
||||
CurveError(const std::string& s)
|
||||
: mStr(s) {
|
||||
CurveError(const std::string &s) :
|
||||
mStr(s) {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
@ -338,18 +332,17 @@ public:
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
class Curve {
|
||||
protected:
|
||||
Curve(const Schema_2x3::IfcCurve& base_entity, ConversionData& conv)
|
||||
: base_entity(base_entity)
|
||||
, conv(conv) {
|
||||
Curve(const Schema_2x3::IfcCurve &base_entity, ConversionData &conv) :
|
||||
base_entity(base_entity),
|
||||
conv(conv) {
|
||||
// empty
|
||||
}
|
||||
|
||||
public:
|
||||
typedef std::pair<IfcFloat, IfcFloat> ParamRange;
|
||||
using ParamRange = std::pair<IfcFloat, IfcFloat>;
|
||||
|
||||
virtual ~Curve() {}
|
||||
|
||||
|
||||
// check if a curve is closed
|
||||
virtual bool IsClosed() const = 0;
|
||||
|
||||
|
@ -359,56 +352,53 @@ public:
|
|||
// try to match a point on the curve to a given parameter
|
||||
// for self-intersecting curves, the result is not ambiguous and
|
||||
// it is undefined which parameter is returned.
|
||||
virtual bool ReverseEval(const IfcVector3& val, IfcFloat& paramOut) const;
|
||||
virtual bool ReverseEval(const IfcVector3 &val, IfcFloat ¶mOut) const;
|
||||
|
||||
// get the range of the curve (both inclusive).
|
||||
// +inf and -inf are valid return values, the curve is not bounded in such a case.
|
||||
virtual std::pair<IfcFloat,IfcFloat> GetParametricRange() const = 0;
|
||||
virtual std::pair<IfcFloat, IfcFloat> GetParametricRange() const = 0;
|
||||
IfcFloat GetParametricRangeDelta() const;
|
||||
|
||||
// estimate the number of sample points that this curve will require
|
||||
virtual size_t EstimateSampleCount(IfcFloat start,IfcFloat end) const;
|
||||
virtual size_t EstimateSampleCount(IfcFloat start, IfcFloat end) const;
|
||||
|
||||
// intelligently sample the curve based on the current settings
|
||||
// and append the result to the mesh
|
||||
virtual void SampleDiscrete(TempMesh& out,IfcFloat start,IfcFloat end) const;
|
||||
virtual void SampleDiscrete(TempMesh &out, IfcFloat start, IfcFloat end) const;
|
||||
|
||||
#ifdef ASSIMP_BUILD_DEBUG
|
||||
// check if a particular parameter value lies within the well-defined range
|
||||
bool InRange(IfcFloat) const;
|
||||
#endif
|
||||
static Curve* Convert(const IFC::Schema_2x3::IfcCurve&,ConversionData& conv);
|
||||
static Curve *Convert(const IFC::Schema_2x3::IfcCurve &, ConversionData &conv);
|
||||
|
||||
protected:
|
||||
const Schema_2x3::IfcCurve& base_entity;
|
||||
ConversionData& conv;
|
||||
const Schema_2x3::IfcCurve &base_entity;
|
||||
ConversionData &conv;
|
||||
};
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// A BoundedCurve always holds the invariant that GetParametricRange()
|
||||
// never returns infinite values.
|
||||
// --------------------------------------------------------------------------------
|
||||
class BoundedCurve : public Curve {
|
||||
public:
|
||||
BoundedCurve(const Schema_2x3::IfcBoundedCurve& entity, ConversionData& conv)
|
||||
: Curve(entity,conv)
|
||||
{}
|
||||
BoundedCurve(const Schema_2x3::IfcBoundedCurve &entity, ConversionData &conv) :
|
||||
Curve(entity, conv) {}
|
||||
|
||||
public:
|
||||
|
||||
bool IsClosed() const;
|
||||
bool IsClosed() const override;
|
||||
|
||||
public:
|
||||
|
||||
// sample the entire curve
|
||||
void SampleDiscrete(TempMesh& out) const;
|
||||
void SampleDiscrete(TempMesh &out) const;
|
||||
using Curve::SampleDiscrete;
|
||||
};
|
||||
|
||||
// IfcProfile.cpp
|
||||
bool ProcessCurve(const Schema_2x3::IfcCurve& curve, TempMesh& meshout, ConversionData& conv);
|
||||
}
|
||||
}
|
||||
bool ProcessCurve(const Schema_2x3::IfcCurve &curve, TempMesh &meshout, ConversionData &conv);
|
||||
|
||||
} // namespace IFC
|
||||
} // namespace Assimp
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -44,20 +44,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#ifndef INCLUDED_AI_IMPORTER_H
|
||||
#define INCLUDED_AI_IMPORTER_H
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <assimp/matrix4x4.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct aiScene;
|
||||
|
||||
namespace Assimp {
|
||||
class ProgressHandler;
|
||||
class IOSystem;
|
||||
class BaseImporter;
|
||||
class BaseProcess;
|
||||
class SharedPostProcessInfo;
|
||||
|
||||
namespace Assimp {
|
||||
class ProgressHandler;
|
||||
class IOSystem;
|
||||
class BaseImporter;
|
||||
class BaseProcess;
|
||||
class SharedPostProcessInfo;
|
||||
|
||||
//! @cond never
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -70,7 +69,7 @@ namespace Assimp {
|
|||
class ImporterPimpl {
|
||||
public:
|
||||
// Data type to store the key hash
|
||||
typedef unsigned int KeyType;
|
||||
using KeyType = unsigned int;
|
||||
|
||||
// typedefs for our four configuration maps.
|
||||
// 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;
|
||||
|
||||
/** IO handler to use for all file accesses. */
|
||||
IOSystem* mIOHandler;
|
||||
IOSystem *mIOHandler;
|
||||
bool mIsDefaultHandler;
|
||||
|
||||
/** Progress handler for feedback. */
|
||||
ProgressHandler* mProgressHandler;
|
||||
ProgressHandler *mProgressHandler;
|
||||
bool mIsDefaultProgressHandler;
|
||||
|
||||
/** 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. */
|
||||
std::vector< BaseProcess* > mPostProcessingSteps;
|
||||
std::vector<BaseProcess *> mPostProcessingSteps;
|
||||
|
||||
/** 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,
|
||||
* mException will carry the full details. */
|
||||
|
@ -120,29 +119,27 @@ public:
|
|||
bool bExtraVerbose;
|
||||
|
||||
/** Used by post-process steps to share data */
|
||||
SharedPostProcessInfo* mPPShared;
|
||||
SharedPostProcessInfo *mPPShared;
|
||||
|
||||
/// The default class constructor.
|
||||
ImporterPimpl() AI_NO_EXCEPT;
|
||||
};
|
||||
|
||||
inline
|
||||
ImporterPimpl::ImporterPimpl() AI_NO_EXCEPT :
|
||||
mIOHandler( nullptr ),
|
||||
mIsDefaultHandler( false ),
|
||||
mProgressHandler( nullptr ),
|
||||
mIsDefaultProgressHandler( false ),
|
||||
mImporter(),
|
||||
mPostProcessingSteps(),
|
||||
mScene( nullptr ),
|
||||
mErrorString(),
|
||||
mException(),
|
||||
mIntProperties(),
|
||||
mFloatProperties(),
|
||||
mStringProperties(),
|
||||
mMatrixProperties(),
|
||||
bExtraVerbose( false ),
|
||||
mPPShared( nullptr ) {
|
||||
inline ImporterPimpl::ImporterPimpl() AI_NO_EXCEPT : mIOHandler(nullptr),
|
||||
mIsDefaultHandler(false),
|
||||
mProgressHandler(nullptr),
|
||||
mIsDefaultProgressHandler(false),
|
||||
mImporter(),
|
||||
mPostProcessingSteps(),
|
||||
mScene(nullptr),
|
||||
mErrorString(),
|
||||
mException(),
|
||||
mIntProperties(),
|
||||
mFloatProperties(),
|
||||
mStringProperties(),
|
||||
mMatrixProperties(),
|
||||
bExtraVerbose(false),
|
||||
mPPShared(nullptr) {
|
||||
// empty
|
||||
}
|
||||
//! @endcond
|
||||
|
@ -164,17 +161,17 @@ public:
|
|||
/** Wraps a full list of configuration properties for an importer.
|
||||
* Properties can be set using SetGenericProperty */
|
||||
struct PropertyMap {
|
||||
ImporterPimpl::IntPropertyMap ints;
|
||||
ImporterPimpl::FloatPropertyMap floats;
|
||||
ImporterPimpl::StringPropertyMap strings;
|
||||
ImporterPimpl::MatrixPropertyMap matrices;
|
||||
ImporterPimpl::IntPropertyMap ints;
|
||||
ImporterPimpl::FloatPropertyMap floats;
|
||||
ImporterPimpl::StringPropertyMap strings;
|
||||
ImporterPimpl::MatrixPropertyMap matrices;
|
||||
|
||||
bool operator == (const PropertyMap& prop) const {
|
||||
bool operator==(const PropertyMap &prop) const {
|
||||
// fixme: really isocpp? gcc complains
|
||||
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();
|
||||
}
|
||||
};
|
||||
|
@ -184,7 +181,7 @@ public:
|
|||
/** Construct a batch loader from a given IO system to be used
|
||||
* to access external files
|
||||
*/
|
||||
explicit BatchLoader(IOSystem* pIO, bool validate = false );
|
||||
explicit BatchLoader(IOSystem *pIO, bool validate = false);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** The class destructor.
|
||||
|
@ -195,7 +192,7 @@ public:
|
|||
/** Sets the validation step. True for enable validation during postprocess.
|
||||
* @param enable True for validation.
|
||||
*/
|
||||
void setValidation( bool enabled );
|
||||
void setValidation(bool enabled);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns the current validation step.
|
||||
|
@ -211,11 +208,10 @@ public:
|
|||
* @return 'Load request channel' - an unique ID that can later
|
||||
* be used to access the imported file data.
|
||||
* @see GetImport */
|
||||
unsigned int AddLoadRequest (
|
||||
const std::string& file,
|
||||
unsigned int steps = 0,
|
||||
const PropertyMap *map = nullptr
|
||||
);
|
||||
unsigned int AddLoadRequest(
|
||||
const std::string &file,
|
||||
unsigned int steps = 0,
|
||||
const PropertyMap *map = nullptr);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Get an imported scene.
|
||||
|
@ -226,9 +222,8 @@ public:
|
|||
* @param which LRWC returned by AddLoadRequest().
|
||||
* @return nullptr if there is no scene with this file name
|
||||
* in the queue of the scene hasn't been loaded yet. */
|
||||
aiScene* GetImport(
|
||||
unsigned int which
|
||||
);
|
||||
aiScene *GetImport(
|
||||
unsigned int which);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Waits until all scenes have been loaded. This returns
|
||||
|
|
|
@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
|
|||
|
||||
Copyright (c) 2006-2020, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
|
@ -45,185 +44,147 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#ifndef AI_POLYTOOLS_H_INCLUDED
|
||||
#define AI_POLYTOOLS_H_INCLUDED
|
||||
|
||||
#include <assimp/material.h>
|
||||
#include <assimp/ai_assert.h>
|
||||
#include <assimp/material.h>
|
||||
#include <assimp/vector3.h>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/** Compute the signed area of a triangle.
|
||||
* The function accepts an unconstrained template parameter for use with
|
||||
* both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/
|
||||
template <typename T>
|
||||
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));
|
||||
}
|
||||
template<class T>
|
||||
class TBoundingBox2D {
|
||||
T mMin, mMax;
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/** Test if a given point p2 is on the left side of the line formed by p0-p1.
|
||||
* The function accepts an unconstrained template parameter for use with
|
||||
* both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/
|
||||
template <typename T>
|
||||
inline bool OnLeftSideOfLine2D(const T& p0, const T& p1,const T& p2)
|
||||
{
|
||||
return GetArea2D(p0,p2,p1) > 0;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/** Test if a given point is inside a given triangle in R2.
|
||||
* The function accepts an unconstrained template parameter for use with
|
||||
* both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/
|
||||
template <typename T>
|
||||
inline bool PointInTriangle2D(const T& p0, const T& p1,const T& p2, const T& pp)
|
||||
{
|
||||
// Point in triangle test using baryzentric coordinates
|
||||
const aiVector2D v0 = p1 - p0;
|
||||
const aiVector2D v1 = p2 - p0;
|
||||
const aiVector2D v2 = pp - p0;
|
||||
|
||||
double dot00 = v0 * v0;
|
||||
double dot01 = v0 * v1;
|
||||
double dot02 = v0 * v2;
|
||||
double dot11 = v1 * v1;
|
||||
double dot12 = v1 * v2;
|
||||
|
||||
const double invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
|
||||
dot11 = (dot11 * dot02 - dot01 * dot12) * invDenom;
|
||||
dot00 = (dot00 * dot12 - dot01 * dot02) * invDenom;
|
||||
|
||||
return (dot11 > 0) && (dot00 > 0) && (dot11 + dot00 < 1);
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/** Check whether the winding order of a given polygon is counter-clockwise.
|
||||
* The function accepts an unconstrained template parameter, but is intended
|
||||
* to be used only with aiVector2D and aiVector3D (z axis is ignored, only
|
||||
* x and y are taken into account).
|
||||
* @note Code taken from http://cgm.cs.mcgill.ca/~godfried/teaching/cg-projects/97/Ian/applet1.html and translated to C++
|
||||
*/
|
||||
template <typename T>
|
||||
inline bool IsCCW(T* in, size_t npoints) {
|
||||
double aa, bb, cc, b, c, theta;
|
||||
double convex_turn;
|
||||
double convex_sum = 0;
|
||||
|
||||
ai_assert(npoints >= 3);
|
||||
|
||||
for (size_t i = 0; i < npoints - 2; i++) {
|
||||
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));
|
||||
|
||||
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));
|
||||
|
||||
cc = ((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));
|
||||
|
||||
b = std::sqrt(bb);
|
||||
c = std::sqrt(cc);
|
||||
theta = std::acos((bb + cc - aa) / (2 * b * c));
|
||||
|
||||
if (OnLeftSideOfLine2D(in[i],in[i+2],in[i+1])) {
|
||||
// if (convex(in[i].x, in[i].y,
|
||||
// in[i+1].x, in[i+1].y,
|
||||
// in[i+2].x, in[i+2].y)) {
|
||||
convex_turn = AI_MATH_PI_F - theta;
|
||||
convex_sum += convex_turn;
|
||||
}
|
||||
else {
|
||||
convex_sum -= AI_MATH_PI_F - theta;
|
||||
}
|
||||
TBoundingBox2D( const T &min, const T &max ) :
|
||||
mMin( min ),
|
||||
mMax( max ) {
|
||||
// empty
|
||||
}
|
||||
aa = ((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));
|
||||
};
|
||||
|
||||
bb = ((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));
|
||||
using BoundingBox2D = TBoundingBox2D<aiVector2D>;
|
||||
|
||||
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));
|
||||
// -------------------------------------------------------------------------------
|
||||
/// Compute the normal of an arbitrary polygon in R3.
|
||||
///
|
||||
/// The code is based on Newell's formula, that is a polygons normal is the ratio
|
||||
/// of its area when projected onto the three coordinate axes.
|
||||
///
|
||||
/// @param out Receives the output normal
|
||||
/// @param num Number of input vertices
|
||||
/// @param x X data source. x[ofs_x*n] is the n'th element.
|
||||
/// @param y Y data source. y[ofs_y*n] is the y'th element
|
||||
/// @param z Z data source. z[ofs_z*n] is the z'th element
|
||||
///
|
||||
/// @note The data arrays must have storage for at least num+2 elements. Using
|
||||
/// this method is much faster than the 'other' NewellNormal()
|
||||
// -------------------------------------------------------------------------------
|
||||
template <size_t ofs_x, size_t ofs_y, size_t ofs_z, typename TReal>
|
||||
inline void NewellNormal(aiVector3t<TReal> &out, size_t num, TReal *x, TReal *y, TReal *z, size_t bufferSize) {
|
||||
ai_assert(bufferSize > num);
|
||||
|
||||
b = std::sqrt(bb);
|
||||
c = std::sqrt(cc);
|
||||
theta = std::acos((bb + cc - aa) / (2 * b * c));
|
||||
|
||||
//if (convex(in[npoints-2].x, in[npoints-2].y,
|
||||
// in[0].x, in[0].y,
|
||||
// in[1].x, in[1].y)) {
|
||||
if (OnLeftSideOfLine2D(in[npoints-2],in[1],in[0])) {
|
||||
convex_turn = AI_MATH_PI_F - theta;
|
||||
convex_sum += convex_turn;
|
||||
}
|
||||
else {
|
||||
convex_sum -= AI_MATH_PI_F - theta;
|
||||
if (nullptr == x || nullptr == y || nullptr == z || 0 == bufferSize || 0 == num) {
|
||||
return;
|
||||
}
|
||||
|
||||
return convex_sum >= (2 * AI_MATH_PI_F);
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/** Compute the normal of an arbitrary polygon in R3.
|
||||
*
|
||||
* The code is based on Newell's formula, that is a polygons normal is the ratio
|
||||
* of its area when projected onto the three coordinate axes.
|
||||
*
|
||||
* @param out Receives the output normal
|
||||
* @param num Number of input vertices
|
||||
* @param x X data source. x[ofs_x*n] is the n'th element.
|
||||
* @param y Y data source. y[ofs_y*n] is the y'th element
|
||||
* @param z Z data source. z[ofs_z*n] is the z'th element
|
||||
*
|
||||
* @note The data arrays must have storage for at least num+2 elements. Using
|
||||
* this method is much faster than the 'other' NewellNormal()
|
||||
*/
|
||||
template <int ofs_x, int ofs_y, int ofs_z, typename TReal>
|
||||
inline void NewellNormal (aiVector3t<TReal>& out, int num, TReal* x, TReal* y, TReal* z)
|
||||
{
|
||||
// Duplicate the first two vertices at the end
|
||||
x[(num+0)*ofs_x] = x[0];
|
||||
x[(num+1)*ofs_x] = x[ofs_x];
|
||||
x[(num + 0) * ofs_x] = x[0];
|
||||
x[(num + 1) * ofs_x] = x[ofs_x];
|
||||
|
||||
y[(num+0)*ofs_y] = y[0];
|
||||
y[(num+1)*ofs_y] = y[ofs_y];
|
||||
y[(num + 0) * ofs_y] = y[0];
|
||||
y[(num + 1) * ofs_y] = y[ofs_y];
|
||||
|
||||
z[(num+0)*ofs_z] = z[0];
|
||||
z[(num+1)*ofs_z] = z[ofs_z];
|
||||
z[(num + 0) * ofs_z] = z[0];
|
||||
z[(num + 1) * ofs_z] = z[ofs_z];
|
||||
|
||||
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 *yptr = y +ofs_y, *ylow = y, *yhigh = y + ofs_y*2;
|
||||
TReal *zptr = z +ofs_z, *zlow = z, *zhigh = z + ofs_z*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 *zptr = z + ofs_z, *zlow = z, *zhigh = z + ofs_z * 2;
|
||||
|
||||
for (int tmp=0; tmp < num; tmp++) {
|
||||
sum_xy += (*xptr) * ( (*yhigh) - (*ylow) );
|
||||
sum_yz += (*yptr) * ( (*zhigh) - (*zlow) );
|
||||
sum_zx += (*zptr) * ( (*xhigh) - (*xlow) );
|
||||
for (size_t tmp = 0; tmp < num; ++tmp ) {
|
||||
sum_xy += (*xptr) * ((*yhigh) - (*ylow));
|
||||
sum_yz += (*yptr) * ((*zhigh) - (*zlow));
|
||||
sum_zx += (*zptr) * ((*xhigh) - (*xlow));
|
||||
|
||||
xptr += ofs_x;
|
||||
xlow += ofs_x;
|
||||
xptr += ofs_x;
|
||||
xlow += ofs_x;
|
||||
xhigh += ofs_x;
|
||||
|
||||
yptr += ofs_y;
|
||||
ylow += ofs_y;
|
||||
yptr += ofs_y;
|
||||
ylow += ofs_y;
|
||||
yhigh += ofs_y;
|
||||
|
||||
zptr += ofs_z;
|
||||
zlow += ofs_z;
|
||||
zptr += ofs_z;
|
||||
zlow += ofs_z;
|
||||
zhigh += ofs_z;
|
||||
}
|
||||
out = aiVector3t<TReal>(sum_yz,sum_zx,sum_xy);
|
||||
out = aiVector3t<TReal>(sum_yz, sum_zx, sum_xy);
|
||||
}
|
||||
|
||||
} // ! Assimp
|
||||
// -------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
inline aiMatrix4x4t<T> DerivePlaneCoordinateSpace(const aiVector3t<T> *vertices, size_t numVertices, bool &ok, aiVector3t<T> &norOut) {
|
||||
const aiVector3t<T> *out = vertices;
|
||||
aiMatrix4x4t<T> m;
|
||||
|
||||
ok = true;
|
||||
|
||||
const size_t s = numVertices;
|
||||
|
||||
const aiVector3t<T> &any_point = out[numVertices - 1u];
|
||||
aiVector3t<T> nor;
|
||||
|
||||
// The input polygon is arbitrarily shaped, therefore we might need some tries
|
||||
// until we find a suitable normal. Note that Newell's algorithm would give
|
||||
// a more robust result, but this variant also gives us a suitable first
|
||||
// axis for the 2D coordinate space on the polygon plane, exploiting the
|
||||
// fact that the input polygon is nearly always a quad.
|
||||
bool done = false;
|
||||
size_t idx = 0;
|
||||
for (size_t i = 0; !done && i < s - 2; done || ++i) {
|
||||
idx = i;
|
||||
for (size_t j = i + 1; j < s - 1; ++j) {
|
||||
nor = -((out[i] - any_point) ^ (out[j] - any_point));
|
||||
if (std::fabs(nor.Length()) > 1e-8f) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!done) {
|
||||
ok = false;
|
||||
return m;
|
||||
}
|
||||
|
||||
nor.Normalize();
|
||||
norOut = nor;
|
||||
|
||||
aiVector3t<T> r = (out[idx] - any_point);
|
||||
r.Normalize();
|
||||
|
||||
// Reconstruct orthonormal basis
|
||||
// XXX use Gram Schmidt for increased robustness
|
||||
aiVector3t<T> u = r ^ nor;
|
||||
u.Normalize();
|
||||
|
||||
m.a1 = r.x;
|
||||
m.a2 = r.y;
|
||||
m.a3 = r.z;
|
||||
|
||||
m.b1 = u.x;
|
||||
m.b2 = u.y;
|
||||
m.b3 = u.z;
|
||||
|
||||
m.c1 = -nor.x;
|
||||
m.c2 = -nor.y;
|
||||
m.c3 = -nor.z;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
} // namespace Assimp
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
|
|||
|
||||
Copyright (c) 2006-2020, assimp team
|
||||
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
|
@ -45,25 +43,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
* @brief Implementation of the FindDegenerates post-process step.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
// internal headers
|
||||
#include "ProcessHelper.h"
|
||||
#include "FindDegenerates.h"
|
||||
#include "ProcessHelper.h"
|
||||
#include <assimp/Exceptional.h>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
//remove mesh at position 'index' from the scene
|
||||
static void removeMesh(aiScene* pScene, unsigned const index);
|
||||
static void removeMesh(aiScene *pScene, unsigned const index);
|
||||
//correct node indices to meshes and remove references to deleted mesh
|
||||
static void updateSceneGraph(aiNode* pNode, unsigned const index);
|
||||
static void updateSceneGraph(aiNode *pNode, unsigned const index);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
FindDegeneratesProcess::FindDegeneratesProcess()
|
||||
: mConfigRemoveDegenerates( false )
|
||||
, mConfigCheckAreaOfTriangle( false ){
|
||||
FindDegeneratesProcess::FindDegeneratesProcess() :
|
||||
mConfigRemoveDegenerates(false),
|
||||
mConfigCheckAreaOfTriangle(false) {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
@ -75,24 +71,23 @@ FindDegeneratesProcess::~FindDegeneratesProcess() {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool FindDegeneratesProcess::IsActive( unsigned int pFlags) const {
|
||||
bool FindDegeneratesProcess::IsActive(unsigned int pFlags) const {
|
||||
return 0 != (pFlags & aiProcess_FindDegenerates);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Setup import configuration
|
||||
void FindDegeneratesProcess::SetupProperties(const Importer* pImp) {
|
||||
void FindDegeneratesProcess::SetupProperties(const Importer *pImp) {
|
||||
// Get the current value of AI_CONFIG_PP_FD_REMOVE
|
||||
mConfigRemoveDegenerates = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_REMOVE,0));
|
||||
mConfigCheckAreaOfTriangle = ( 0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_CHECKAREA) );
|
||||
mConfigRemoveDegenerates = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_REMOVE, 0));
|
||||
mConfigCheckAreaOfTriangle = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_CHECKAREA));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void FindDegeneratesProcess::Execute( aiScene* pScene) {
|
||||
void FindDegeneratesProcess::Execute(aiScene *pScene) {
|
||||
ASSIMP_LOG_DEBUG("FindDegeneratesProcess begin");
|
||||
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
|
||||
{
|
||||
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
||||
//Do not process point cloud, ExecuteOnMesh works only with faces data
|
||||
if ((pScene->mMeshes[i]->mPrimitiveTypes != aiPrimitiveType::aiPrimitiveType_POINT) && ExecuteOnMesh(pScene->mMeshes[i])) {
|
||||
removeMesh(pScene, i);
|
||||
|
@ -102,12 +97,12 @@ void FindDegeneratesProcess::Execute( aiScene* pScene) {
|
|||
ASSIMP_LOG_DEBUG("FindDegeneratesProcess finished");
|
||||
}
|
||||
|
||||
static void removeMesh(aiScene* pScene, unsigned const index) {
|
||||
static void removeMesh(aiScene *pScene, unsigned const index) {
|
||||
//we start at index and copy the pointers one position forward
|
||||
//save the mesh pointer to delete it later
|
||||
auto delete_me = pScene->mMeshes[index];
|
||||
for (unsigned i = index; i < pScene->mNumMeshes - 1; ++i) {
|
||||
pScene->mMeshes[i] = pScene->mMeshes[i+1];
|
||||
pScene->mMeshes[i] = pScene->mMeshes[i + 1];
|
||||
}
|
||||
pScene->mMeshes[pScene->mNumMeshes - 1] = nullptr;
|
||||
--(pScene->mNumMeshes);
|
||||
|
@ -117,15 +112,15 @@ static void removeMesh(aiScene* pScene, unsigned const index) {
|
|||
updateSceneGraph(pScene->mRootNode, index);
|
||||
}
|
||||
|
||||
static void updateSceneGraph(aiNode* pNode, unsigned const index) {
|
||||
static void updateSceneGraph(aiNode *pNode, unsigned const index) {
|
||||
for (unsigned i = 0; i < pNode->mNumMeshes; ++i) {
|
||||
if (pNode->mMeshes[i] > index) {
|
||||
--(pNode->mMeshes[i]);
|
||||
continue;
|
||||
}
|
||||
if (pNode->mMeshes[i] == index) {
|
||||
for (unsigned j = i; j < pNode->mNumMeshes -1; ++j) {
|
||||
pNode->mMeshes[j] = pNode->mMeshes[j+1];
|
||||
for (unsigned j = i; j < pNode->mNumMeshes - 1; ++j) {
|
||||
pNode->mMeshes[j] = pNode->mMeshes[j + 1];
|
||||
}
|
||||
--(pNode->mNumMeshes);
|
||||
--i;
|
||||
|
@ -138,50 +133,50 @@ static void updateSceneGraph(aiNode* pNode, unsigned const index) {
|
|||
}
|
||||
}
|
||||
|
||||
static ai_real heron( ai_real a, ai_real b, ai_real c ) {
|
||||
static ai_real heron(ai_real a, ai_real b, ai_real c) {
|
||||
ai_real s = (a + b + c) / 2;
|
||||
ai_real area = pow((s * ( s - a ) * ( s - b ) * ( s - c ) ), (ai_real)0.5 );
|
||||
ai_real area = pow((s * (s - a) * (s - b) * (s - c)), (ai_real)0.5);
|
||||
return area;
|
||||
}
|
||||
|
||||
static ai_real distance3D( const aiVector3D &vA, aiVector3D &vB ) {
|
||||
const ai_real lx = ( vB.x - vA.x );
|
||||
const ai_real ly = ( vB.y - vA.y );
|
||||
const ai_real lz = ( vB.z - vA.z );
|
||||
ai_real a = lx*lx + ly*ly + lz*lz;
|
||||
ai_real d = pow( a, (ai_real)0.5 );
|
||||
static ai_real distance3D(const aiVector3D &vA, aiVector3D &vB) {
|
||||
const ai_real lx = (vB.x - vA.x);
|
||||
const ai_real ly = (vB.y - vA.y);
|
||||
const ai_real lz = (vB.z - vA.z);
|
||||
ai_real a = lx * lx + ly * ly + lz * lz;
|
||||
ai_real d = pow(a, (ai_real)0.5);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
static ai_real calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh ) {
|
||||
static ai_real calculateAreaOfTriangle(const aiFace &face, aiMesh *mesh) {
|
||||
ai_real area = 0;
|
||||
|
||||
aiVector3D vA( mesh->mVertices[ face.mIndices[ 0 ] ] );
|
||||
aiVector3D vB( mesh->mVertices[ face.mIndices[ 1 ] ] );
|
||||
aiVector3D vC( mesh->mVertices[ face.mIndices[ 2 ] ] );
|
||||
aiVector3D vA(mesh->mVertices[face.mIndices[0]]);
|
||||
aiVector3D vB(mesh->mVertices[face.mIndices[1]]);
|
||||
aiVector3D vC(mesh->mVertices[face.mIndices[2]]);
|
||||
|
||||
ai_real a( distance3D( vA, vB ) );
|
||||
ai_real b( distance3D( vB, vC ) );
|
||||
ai_real c( distance3D( vC, vA ) );
|
||||
area = heron( a, b, c );
|
||||
ai_real a(distance3D(vA, vB));
|
||||
ai_real b(distance3D(vB, vC));
|
||||
ai_real c(distance3D(vC, vA));
|
||||
area = heron(a, b, c);
|
||||
|
||||
return area;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported mesh
|
||||
bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
|
||||
bool FindDegeneratesProcess::ExecuteOnMesh(aiMesh *mesh) {
|
||||
mesh->mPrimitiveTypes = 0;
|
||||
|
||||
std::vector<bool> remove_me;
|
||||
if (mConfigRemoveDegenerates) {
|
||||
remove_me.resize( mesh->mNumFaces, false );
|
||||
remove_me.resize(mesh->mNumFaces, false);
|
||||
}
|
||||
|
||||
unsigned int deg = 0, limit;
|
||||
for ( unsigned int a = 0; a < mesh->mNumFaces; ++a ) {
|
||||
aiFace& face = mesh->mFaces[a];
|
||||
for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
|
||||
aiFace &face = mesh->mFaces[a];
|
||||
bool first = true;
|
||||
|
||||
// check whether the face contains degenerated entries
|
||||
|
@ -191,43 +186,43 @@ bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
|
|||
// double points may not come directly after another.
|
||||
limit = face.mNumIndices;
|
||||
if (face.mNumIndices > 4) {
|
||||
limit = std::min( limit, i+2 );
|
||||
limit = std::min(limit, i + 2);
|
||||
}
|
||||
|
||||
for (unsigned int t = i+1; t < limit; ++t) {
|
||||
if (mesh->mVertices[face.mIndices[ i ] ] == mesh->mVertices[ face.mIndices[ t ] ]) {
|
||||
for (unsigned int t = i + 1; t < limit; ++t) {
|
||||
if (mesh->mVertices[face.mIndices[i]] == mesh->mVertices[face.mIndices[t]]) {
|
||||
// we have found a matching vertex position
|
||||
// remove the corresponding index from the array
|
||||
--face.mNumIndices;
|
||||
--limit;
|
||||
for (unsigned int m = t; m < face.mNumIndices; ++m) {
|
||||
face.mIndices[ m ] = face.mIndices[ m+1 ];
|
||||
face.mIndices[m] = face.mIndices[m + 1];
|
||||
}
|
||||
--t;
|
||||
|
||||
// NOTE: we set the removed vertex index to an unique value
|
||||
// to make sure the developer gets notified when his
|
||||
// application attempts to access this data.
|
||||
face.mIndices[ face.mNumIndices ] = 0xdeadbeef;
|
||||
face.mIndices[face.mNumIndices] = 0xdeadbeef;
|
||||
|
||||
if(first) {
|
||||
if (first) {
|
||||
++deg;
|
||||
first = false;
|
||||
}
|
||||
|
||||
if ( mConfigRemoveDegenerates ) {
|
||||
remove_me[ a ] = true;
|
||||
if (mConfigRemoveDegenerates) {
|
||||
remove_me[a] = true;
|
||||
goto evil_jump_outside; // hrhrhrh ... yeah, this rocks baby!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( mConfigCheckAreaOfTriangle ) {
|
||||
if ( face.mNumIndices == 3 ) {
|
||||
ai_real area = calculateAreaOfTriangle( face, mesh );
|
||||
if ( area < 1e-6 ) {
|
||||
if ( mConfigRemoveDegenerates ) {
|
||||
remove_me[ a ] = true;
|
||||
if (mConfigCheckAreaOfTriangle) {
|
||||
if (face.mNumIndices == 3) {
|
||||
ai_real area = calculateAreaOfTriangle(face, mesh);
|
||||
if (area < 1e-6) {
|
||||
if (mConfigRemoveDegenerates) {
|
||||
remove_me[a] = true;
|
||||
++deg;
|
||||
goto evil_jump_outside;
|
||||
}
|
||||
|
@ -239,8 +234,7 @@ bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
|
|||
}
|
||||
|
||||
// We need to update the primitive flags array of the mesh.
|
||||
switch (face.mNumIndices)
|
||||
{
|
||||
switch (face.mNumIndices) {
|
||||
case 1u:
|
||||
mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
|
||||
break;
|
||||
|
@ -254,30 +248,28 @@ bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
|
|||
mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
|
||||
break;
|
||||
};
|
||||
evil_jump_outside:
|
||||
evil_jump_outside:
|
||||
continue;
|
||||
}
|
||||
|
||||
// If AI_CONFIG_PP_FD_REMOVE is true, remove degenerated faces from the import
|
||||
if (mConfigRemoveDegenerates && deg) {
|
||||
unsigned int n = 0;
|
||||
for (unsigned int a = 0; a < mesh->mNumFaces; ++a)
|
||||
{
|
||||
aiFace& face_src = mesh->mFaces[a];
|
||||
for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
|
||||
aiFace &face_src = mesh->mFaces[a];
|
||||
if (!remove_me[a]) {
|
||||
aiFace& face_dest = mesh->mFaces[n++];
|
||||
aiFace &face_dest = mesh->mFaces[n++];
|
||||
|
||||
// Do a manual copy, keep the index array
|
||||
face_dest.mNumIndices = face_src.mNumIndices;
|
||||
face_dest.mIndices = face_src.mIndices;
|
||||
face_dest.mIndices = face_src.mIndices;
|
||||
|
||||
if (&face_src != &face_dest) {
|
||||
// clear source
|
||||
face_src.mNumIndices = 0;
|
||||
face_src.mIndices = nullptr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Otherwise delete it if we don't need this face
|
||||
delete[] face_src.mIndices;
|
||||
face_src.mIndices = nullptr;
|
||||
|
@ -295,7 +287,7 @@ evil_jump_outside:
|
|||
}
|
||||
|
||||
if (deg && !DefaultLogger::isNullLogger()) {
|
||||
ASSIMP_LOG_WARN_F( "Found ", deg, " degenerated primitives");
|
||||
ASSIMP_LOG_WARN_F("Found ", deg, " degenerated primitives");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -47,485 +47,294 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
* The triangulation algorithm will handle concave or convex polygons.
|
||||
* Self-intersecting or non-planar polygons are not rejected, but
|
||||
* they're probably not triangulated correctly.
|
||||
*
|
||||
* DEBUG SWITCHES - do not enable any of them in release builds:
|
||||
*
|
||||
* AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING
|
||||
* - generates vertex colors to represent the face winding order.
|
||||
* the first vertex of a polygon becomes red, the last blue.
|
||||
* AI_BUILD_TRIANGULATE_DEBUG_POLYS
|
||||
* - dump all polygons and their triangulation sequences to
|
||||
* a file
|
||||
*/
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_TRIANGULATE_PROCESS
|
||||
|
||||
#include "PostProcessing/TriangulateProcess.h"
|
||||
#include "PostProcessing/ProcessHelper.h"
|
||||
#include "Common/PolyTools.h"
|
||||
#include "PostProcessing/ProcessHelper.h"
|
||||
|
||||
#include "contrib/poly2tri/poly2tri/poly2tri.h"
|
||||
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
//#define AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING
|
||||
//#define AI_BUILD_TRIANGULATE_DEBUG_POLYS
|
||||
|
||||
#define POLY_GRID_Y 40
|
||||
#define POLY_GRID_X 70
|
||||
#define POLY_GRID_XPAD 20
|
||||
#define POLY_OUTPUT_FILE "assimp_polygons_debug.txt"
|
||||
|
||||
using namespace Assimp;
|
||||
namespace Assimp {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
TriangulateProcess::TriangulateProcess()
|
||||
{
|
||||
TriangulateProcess::TriangulateProcess() {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
TriangulateProcess::~TriangulateProcess()
|
||||
{
|
||||
TriangulateProcess::~TriangulateProcess() {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// 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;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// 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");
|
||||
|
||||
bool bHas = false;
|
||||
for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
|
||||
{
|
||||
if (pScene->mMeshes[ a ]) {
|
||||
if ( TriangulateMesh( pScene->mMeshes[ a ] ) ) {
|
||||
for (unsigned int a = 0; a < pScene->mNumMeshes; a++) {
|
||||
if (pScene->mMeshes[a]) {
|
||||
if (TriangulateMesh(pScene->mMeshes[a])) {
|
||||
bHas = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( bHas ) {
|
||||
ASSIMP_LOG_INFO( "TriangulateProcess finished. All polygons have been triangulated." );
|
||||
if (bHas) {
|
||||
ASSIMP_LOG_INFO("TriangulateProcess finished. All polygons have been triangulated.");
|
||||
} else {
|
||||
ASSIMP_LOG_DEBUG( "TriangulateProcess finished. There was nothing to be done." );
|
||||
ASSIMP_LOG_DEBUG("TriangulateProcess finished. There was nothing to be done.");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Triangulates the given mesh.
|
||||
bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
|
||||
{
|
||||
// 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++) {
|
||||
const aiFace& face = pMesh->mFaces[a];
|
||||
|
||||
if( face.mNumIndices != 3) {
|
||||
bNeed = true;
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (!bNeed)
|
||||
return false;
|
||||
}
|
||||
else if (!(pMesh->mPrimitiveTypes & aiPrimitiveType_POLYGON)) {
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static void quad2Triangles(const aiFace &face, const aiVector3D *verts, aiFace *curOut) {
|
||||
// quads can have at maximum one concave vertex. Determine
|
||||
// this vertex (if it exists) and start tri-fanning from
|
||||
// it.
|
||||
unsigned int start_vertex = 0;
|
||||
for (unsigned int i = 0; i < 4; ++i) {
|
||||
const aiVector3D &v0 = verts[face.mIndices[(i + 3) % 4]];
|
||||
const aiVector3D &v1 = verts[face.mIndices[(i + 2) % 4]];
|
||||
const aiVector3D &v2 = verts[face.mIndices[(i + 1) % 4]];
|
||||
|
||||
const aiVector3D &v = verts[face.mIndices[i]];
|
||||
|
||||
aiVector3D left = (v0 - v);
|
||||
aiVector3D diag = (v1 - v);
|
||||
aiVector3D right = (v2 - v);
|
||||
|
||||
left.Normalize();
|
||||
diag.Normalize();
|
||||
right.Normalize();
|
||||
|
||||
const float angle = std::acos(left * diag) + std::acos(right * diag);
|
||||
if (angle > AI_MATH_PI_F) {
|
||||
// this is the concave point
|
||||
start_vertex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const unsigned int temp[] = { face.mIndices[0], face.mIndices[1], face.mIndices[2], face.mIndices[3] };
|
||||
|
||||
aiFace &nface = *curOut++;
|
||||
nface.mNumIndices = 3;
|
||||
nface.mIndices = face.mIndices;
|
||||
|
||||
nface.mIndices[0] = temp[start_vertex];
|
||||
nface.mIndices[1] = temp[(start_vertex + 1) % 4];
|
||||
nface.mIndices[2] = temp[(start_vertex + 2) % 4];
|
||||
|
||||
aiFace &sface = *curOut++;
|
||||
sface.mNumIndices = 3;
|
||||
sface.mIndices = new unsigned int[3];
|
||||
|
||||
sface.mIndices[0] = temp[start_vertex];
|
||||
sface.mIndices[1] = temp[(start_vertex + 2) % 4];
|
||||
sface.mIndices[2] = temp[(start_vertex + 3) % 4];
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool getContourFromePolyline(aiFace &face, aiMesh *pMesh, std::vector<p2t::Point *> &contour,
|
||||
aiMatrix4x4 &m, aiVector3D &vmin, aiVector3D &vmax, ai_real &zcoord) {
|
||||
aiVector3D normal;
|
||||
bool ok = true;
|
||||
m = DerivePlaneCoordinateSpace<ai_real>(pMesh->mVertices, pMesh->mNumVertices, ok, normal);
|
||||
if (!ok) {
|
||||
false;
|
||||
}
|
||||
for (unsigned int i = 0; i < face.mNumIndices; ++i) {
|
||||
unsigned int index = face.mIndices[i];
|
||||
|
||||
const aiVector3D vv = m * pMesh->mVertices[index];
|
||||
// keep Z offset in the plane coordinate system. Ignoring precision issues
|
||||
// (which are present, of course), this should be the same value for
|
||||
// all polygon vertices (assuming the polygon is planar).
|
||||
|
||||
// XXX this should be guarded, but we somehow need to pick a suitable
|
||||
// epsilon
|
||||
// if(coord != -1.0f) {
|
||||
// assert(std::fabs(coord - vv.z) < 1e-3f);
|
||||
// }
|
||||
zcoord += vv.z;
|
||||
vmin = std::min(vv, vmin);
|
||||
vmax = std::max(vv, vmax);
|
||||
|
||||
contour.push_back(new p2t::Point(vv.x, vv.y));
|
||||
}
|
||||
|
||||
zcoord /= pMesh->mNumVertices;
|
||||
|
||||
// Further improve the projection by mapping the entire working set into
|
||||
// [0,1] range. This gives us a consistent data range so all epsilons
|
||||
// used below can be constants.
|
||||
vmax -= vmin;
|
||||
const aiVector2D one_vec(1, 1);
|
||||
|
||||
for (p2t::Point* &vv : contour) {
|
||||
vv->x = (vv->x - vmin.x) / vmax.x;
|
||||
vv->y = (vv->y - vmin.y) / vmax.y;
|
||||
|
||||
// sanity rounding
|
||||
aiVector2D cur_vv((ai_real) vv->x, (ai_real)vv->y);
|
||||
cur_vv = std::max(cur_vv, aiVector2D());
|
||||
cur_vv = std::min(cur_vv, one_vec);
|
||||
}
|
||||
|
||||
aiMatrix4x4 mult;
|
||||
mult.a1 = static_cast<ai_real>(1.0) / vmax.x;
|
||||
mult.b2 = static_cast<ai_real>(1.0) / vmax.y;
|
||||
|
||||
mult.a4 = -vmin.x * mult.a1;
|
||||
mult.b4 = -vmin.y * mult.b2;
|
||||
mult.c4 = -zcoord;
|
||||
m = mult * m;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Triangulates the given mesh.
|
||||
bool TriangulateProcess::TriangulateMesh(aiMesh *pMesh) {
|
||||
// Now we have aiMesh::mPrimitiveTypes, so this is only here for test cases
|
||||
|
||||
if (!pMesh->mPrimitiveTypes) {
|
||||
if (!validateNumIndices(pMesh)) {
|
||||
ASSIMP_LOG_DEBUG("Error while validating number of indices.");
|
||||
return false;
|
||||
}
|
||||
} else if (!(pMesh->mPrimitiveTypes & aiPrimitiveType_POLYGON)) {
|
||||
ASSIMP_LOG_DEBUG("???!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find out how many output faces we'll get
|
||||
uint32_t numOut = 0, max_out = 0;
|
||||
bool get_normals = true;
|
||||
for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
|
||||
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
|
||||
ai_assert(numOut != pMesh->mNumFaces);
|
||||
|
||||
aiVector3D *nor_out = nullptr;
|
||||
|
||||
// if we don't have normals yet, but expect them to be a cheap side
|
||||
// product of triangulation anyway, allocate storage for them.
|
||||
if (!pMesh->mNormals && get_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];
|
||||
size_t numOut = 0, max_out = 0;
|
||||
bool getNormals = true;
|
||||
calulateNumOutputFaces(pMesh, numOut, max_out, getNormals);
|
||||
if (numOut == pMesh->mNumFaces) {
|
||||
ASSIMP_LOG_DEBUG("Error while generating contour.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// the output mesh will contain triangles, but no polys anymore
|
||||
pMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
|
||||
pMesh->mPrimitiveTypes &= ~aiPrimitiveType_POLYGON;
|
||||
|
||||
aiFace* out = new aiFace[numOut](), *curOut = out;
|
||||
std::vector<aiVector3D> temp_verts3d(max_out+2); /* temporary storage for vertices */
|
||||
std::vector<aiVector2D> temp_verts(max_out+2);
|
||||
aiFace *out = new aiFace[numOut](), *curOut = out;
|
||||
const size_t Capa = 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?
|
||||
#ifdef AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING
|
||||
if (!pMesh->mColors[0])
|
||||
pMesh->mColors[0] = new aiColor4D[pMesh->mNumVertices];
|
||||
else
|
||||
new(pMesh->mColors[0]) aiColor4D[pMesh->mNumVertices];
|
||||
|
||||
aiColor4D* clr = pMesh->mColors[0];
|
||||
#endif
|
||||
|
||||
#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
|
||||
FILE* fout = fopen(POLY_OUTPUT_FILE,"a");
|
||||
#endif
|
||||
|
||||
const aiVector3D* verts = pMesh->mVertices;
|
||||
const aiVector3D *verts = pMesh->mVertices;
|
||||
|
||||
// use std::unique_ptr to avoid slow std::vector<bool> specialiations
|
||||
std::unique_ptr<bool[]> done(new bool[max_out]);
|
||||
for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
|
||||
aiFace& face = pMesh->mFaces[a];
|
||||
|
||||
unsigned int* idx = face.mIndices;
|
||||
int num = (int)face.mNumIndices, ear = 0, tmp, prev = num-1, next = 0, max = num;
|
||||
|
||||
// Apply vertex colors to represent the face winding?
|
||||
#ifdef AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING
|
||||
for (unsigned int i = 0; i < face.mNumIndices; ++i) {
|
||||
aiColor4D& c = clr[idx[i]];
|
||||
c.r = (i+1) / (float)max;
|
||||
c.b = 1.f - c.r;
|
||||
}
|
||||
#endif
|
||||
|
||||
aiFace* const last_face = curOut;
|
||||
for (unsigned int a = 0; a < pMesh->mNumFaces; a++) {
|
||||
aiFace &face = pMesh->mFaces[a];
|
||||
|
||||
// if it's a simple point,line or triangle: just copy it
|
||||
if( face.mNumIndices <= 3)
|
||||
{
|
||||
aiFace& nface = *curOut++;
|
||||
if (face.mNumIndices <= 3) {
|
||||
aiFace &nface = *curOut++;
|
||||
nface.mNumIndices = face.mNumIndices;
|
||||
nface.mIndices = face.mIndices;
|
||||
|
||||
face.mIndices = nullptr;
|
||||
continue;
|
||||
}
|
||||
// optimized code for quadrilaterals
|
||||
else if ( face.mNumIndices == 4) {
|
||||
|
||||
// quads can have at maximum one concave vertex. Determine
|
||||
// this vertex (if it exists) and start tri-fanning from
|
||||
// it.
|
||||
unsigned int start_vertex = 0;
|
||||
for (unsigned int i = 0; i < 4; ++i) {
|
||||
const aiVector3D& v0 = verts[face.mIndices[(i+3) % 4]];
|
||||
const aiVector3D& v1 = verts[face.mIndices[(i+2) % 4]];
|
||||
const aiVector3D& v2 = verts[face.mIndices[(i+1) % 4]];
|
||||
|
||||
const aiVector3D& v = verts[face.mIndices[i]];
|
||||
|
||||
aiVector3D left = (v0-v);
|
||||
aiVector3D diag = (v1-v);
|
||||
aiVector3D right = (v2-v);
|
||||
|
||||
left.Normalize();
|
||||
diag.Normalize();
|
||||
right.Normalize();
|
||||
|
||||
const float angle = std::acos(left*diag) + std::acos(right*diag);
|
||||
if (angle > AI_MATH_PI_F) {
|
||||
// this is the concave point
|
||||
start_vertex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const unsigned int temp[] = {face.mIndices[0], face.mIndices[1], face.mIndices[2], face.mIndices[3]};
|
||||
|
||||
aiFace& nface = *curOut++;
|
||||
nface.mNumIndices = 3;
|
||||
nface.mIndices = face.mIndices;
|
||||
|
||||
nface.mIndices[0] = temp[start_vertex];
|
||||
nface.mIndices[1] = temp[(start_vertex + 1) % 4];
|
||||
nface.mIndices[2] = temp[(start_vertex + 2) % 4];
|
||||
|
||||
aiFace& sface = *curOut++;
|
||||
sface.mNumIndices = 3;
|
||||
sface.mIndices = new unsigned int[3];
|
||||
|
||||
sface.mIndices[0] = temp[start_vertex];
|
||||
sface.mIndices[1] = temp[(start_vertex + 2) % 4];
|
||||
sface.mIndices[2] = temp[(start_vertex + 3) % 4];
|
||||
|
||||
// prevent double deletion of the indices field
|
||||
face.mIndices = nullptr;
|
||||
continue;
|
||||
} else if (face.mNumIndices == 4) {
|
||||
// optimized code for quadrilaterals
|
||||
quad2Triangles(face, verts, curOut);
|
||||
face.mIndices = nullptr;
|
||||
} else {
|
||||
std::vector<p2t::Point *> contour;
|
||||
aiMatrix4x4 m;
|
||||
aiVector3D vmin, vmax;
|
||||
ai_real zcoord = -1;
|
||||
if (!getContourFromePolyline(face, pMesh, contour, m, vmin, vmax, zcoord)) {
|
||||
ASSIMP_LOG_DEBUG("Error while generating contour.");
|
||||
continue;
|
||||
}
|
||||
p2t::CDT cdt(contour);
|
||||
cdt.Triangulate();
|
||||
const std::vector<p2t::Triangle *> tris = cdt.GetTriangles();
|
||||
const aiMatrix4x4 matInv = m.Inverse();
|
||||
for (p2t::Triangle *tri : tris) {
|
||||
curOut->mNumIndices = 3;
|
||||
curOut->mIndices = new unsigned int[curOut->mNumIndices];
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
const aiVector2D v = aiVector2D(static_cast<ai_real>(tri->GetPoint(i)->x), static_cast<ai_real>(tri->GetPoint(i)->y));
|
||||
// ai_assert(v.x <= 1.0 && v.x >= 0.0 && v.y <= 1.0 && v.y >= 0.0);
|
||||
const aiVector3D v3 = matInv * aiVector3D(vmin.x + v.x * vmax.x, vmin.y + v.y * vmax.y, zcoord);
|
||||
temp_verts3d.emplace_back(v3);
|
||||
curOut->mIndices[i] = (unsigned int) temp_verts3d.size()-1;
|
||||
}
|
||||
curOut++;
|
||||
}
|
||||
face.mIndices = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// A polygon with more than 3 vertices can be either concave or convex.
|
||||
// Usually everything we're getting is convex and we could easily
|
||||
// triangulate by tri-fanning. However, LightWave is probably the only
|
||||
// modeling suite to make extensive use of highly concave, monster polygons ...
|
||||
// so we need to apply the full 'ear cutting' algorithm to get it right.
|
||||
|
||||
// RERQUIREMENT: polygon is expected to be simple and *nearly* planar.
|
||||
// We project it onto a plane to get a 2d triangle.
|
||||
|
||||
// Collect all vertices of of the polygon.
|
||||
for (tmp = 0; tmp < max; ++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
|
||||
aiVector3D n;
|
||||
NewellNormal<3,3,3>(n,max,&temp_verts3d.front().x,&temp_verts3d.front().y,&temp_verts3d.front().z);
|
||||
if (nor_out) {
|
||||
for (tmp = 0; tmp < max; ++tmp)
|
||||
nor_out[idx[tmp]] = n;
|
||||
}
|
||||
|
||||
// Select largest normal coordinate to ignore for projection
|
||||
const float ax = (n.x>0 ? n.x : -n.x);
|
||||
const float ay = (n.y>0 ? n.y : -n.y);
|
||||
const float az = (n.z>0 ? n.z : -n.z);
|
||||
|
||||
unsigned int ac = 0, bc = 1; /* no z coord. projection to xy */
|
||||
float inv = n.z;
|
||||
if (ax > ay) {
|
||||
if (ax > az) { /* no x coord. projection to yz */
|
||||
ac = 1; bc = 2;
|
||||
inv = n.x;
|
||||
}
|
||||
}
|
||||
else if (ay > az) { /* no y coord. projection to zy */
|
||||
ac = 2; bc = 0;
|
||||
inv = n.y;
|
||||
}
|
||||
|
||||
// Swap projection axes to take the negated projection vector into account
|
||||
if (inv < 0.f) {
|
||||
std::swap(ac,bc);
|
||||
}
|
||||
|
||||
for (tmp =0; tmp < max; ++tmp) {
|
||||
temp_verts[tmp].x = verts[idx[tmp]][ac];
|
||||
temp_verts[tmp].y = verts[idx[tmp]][bc];
|
||||
done[tmp] = false;
|
||||
}
|
||||
|
||||
#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
|
||||
// plot the plane onto which we mapped the polygon to a 2D ASCII pic
|
||||
aiVector2D bmin,bmax;
|
||||
ArrayBounds(&temp_verts[0],max,bmin,bmax);
|
||||
|
||||
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) {
|
||||
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));
|
||||
char* loc = grid[y]+x;
|
||||
if (grid[y][x] != ' ') {
|
||||
for(;*loc != ' '; ++loc);
|
||||
*loc++ = '_';
|
||||
}
|
||||
*(loc+::ai_snprintf(loc, POLY_GRID_XPAD,"%i",i)) = ' ';
|
||||
}
|
||||
|
||||
|
||||
for(size_t y = 0; y < POLY_GRID_Y; ++y) {
|
||||
grid[y][POLY_GRID_X+POLY_GRID_XPAD-1] = '\0';
|
||||
fprintf(fout,"%s\n",grid[y]);
|
||||
}
|
||||
|
||||
fprintf(fout,"\ntriangulation sequence: ");
|
||||
#endif
|
||||
|
||||
//
|
||||
// FIXME: currently this is the slow O(kn) variant with a worst case
|
||||
// complexity of O(n^2) (I think). Can be done in O(n).
|
||||
while (num > 3) {
|
||||
|
||||
// Find the next ear of the polygon
|
||||
int num_found = 0;
|
||||
for (ear = next;;prev = ear,ear = next) {
|
||||
|
||||
// break after we looped two times without a positive match
|
||||
for (next=ear+1;done[(next>=max?next=0:next)];++next);
|
||||
if (next < ear) {
|
||||
if (++num_found == 2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
const aiVector2D* pnt1 = &temp_verts[ear],
|
||||
*pnt0 = &temp_verts[prev],
|
||||
*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.
|
||||
if (OnLeftSideOfLine2D(*pnt0,*pnt2,*pnt1)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// and no other point may be contained in this triangle
|
||||
for ( tmp = 0; tmp < max; ++tmp) {
|
||||
|
||||
// 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
|
||||
//
|
||||
// FIXME: Use 'epsiloned' comparisons instead? Due to numeric inaccuracies in
|
||||
// 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,
|
||||
// which epsilon? If we chose a too large value, we'd get wrong results
|
||||
const aiVector2D& vtmp = temp_verts[tmp];
|
||||
if ( vtmp != *pnt1 && vtmp != *pnt2 && vtmp != *pnt0 && PointInTriangle2D(*pnt0,*pnt1,*pnt2,vtmp)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (tmp != max) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// this vertex is an ear
|
||||
break;
|
||||
}
|
||||
if (num_found == 2) {
|
||||
|
||||
// Due to the 'two ear theorem', every simple polygon with more than three points must
|
||||
// have 2 'ears'. Here's definitely something wrong ... but we don't give up yet.
|
||||
//
|
||||
|
||||
// Instead we're continuing with the standard tri-fanning algorithm which we'd
|
||||
// use if we had only convex polygons. That's life.
|
||||
ASSIMP_LOG_ERROR("Failed to triangulate polygon (no ear found). Probably not a simple polygon?");
|
||||
|
||||
#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
|
||||
fprintf(fout,"critical error here, no ear found! ");
|
||||
#endif
|
||||
num = 0;
|
||||
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++;
|
||||
nface.mNumIndices = 3;
|
||||
|
||||
if (!nface.mIndices) {
|
||||
nface.mIndices = new unsigned int[3];
|
||||
}
|
||||
|
||||
// setup indices for the new triangle ...
|
||||
nface.mIndices[0] = prev;
|
||||
nface.mIndices[1] = ear;
|
||||
nface.mIndices[2] = next;
|
||||
|
||||
// exclude the ear from most further processing
|
||||
done[ear] = true;
|
||||
--num;
|
||||
}
|
||||
if (num > 0) {
|
||||
// We have three indices forming the last 'ear' remaining. Collect them.
|
||||
aiFace& nface = *curOut++;
|
||||
nface.mNumIndices = 3;
|
||||
if (!nface.mIndices) {
|
||||
nface.mIndices = new unsigned int[3];
|
||||
}
|
||||
|
||||
for (tmp = 0; done[tmp]; ++tmp);
|
||||
nface.mIndices[0] = tmp;
|
||||
|
||||
for (++tmp; done[tmp]; ++tmp);
|
||||
nface.mIndices[1] = tmp;
|
||||
|
||||
for (++tmp; done[tmp]; ++tmp);
|
||||
nface.mIndices[2] = tmp;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
|
||||
|
||||
for(aiFace* f = last_face; f != curOut; ++f) {
|
||||
unsigned int* i = f->mIndices;
|
||||
fprintf(fout," (%i %i %i)",i[0],i[1],i[2]);
|
||||
}
|
||||
|
||||
fprintf(fout,"\n*********************************************************************\n");
|
||||
fflush(fout);
|
||||
|
||||
#endif
|
||||
|
||||
for(aiFace* f = last_face; f != curOut; ) {
|
||||
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[1] = idx[i[1]];
|
||||
i[2] = idx[i[2]];
|
||||
++f;
|
||||
}
|
||||
|
||||
delete[] face.mIndices;
|
||||
face.mIndices = nullptr;
|
||||
}
|
||||
|
||||
#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
|
||||
fclose(fout);
|
||||
#endif
|
||||
delete[] pMesh->mFaces;
|
||||
pMesh->mFaces = out;
|
||||
pMesh->mNumVertices = (unsigned int)temp_verts3d.size();
|
||||
delete[] pMesh->mVertices;
|
||||
pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
|
||||
for (size_t i = 0; i < temp_verts3d.size(); ++i) {
|
||||
pMesh->mVertices[i] = temp_verts3d[i];
|
||||
}
|
||||
pMesh->mNumFaces = (unsigned int)(curOut - out); /* not necessarily equal to numOut */
|
||||
|
||||
// kill the old faces
|
||||
delete [] pMesh->mFaces;
|
||||
|
||||
// ... and store the new ones
|
||||
pMesh->mFaces = out;
|
||||
pMesh->mNumFaces = (unsigned int)(curOut-out); /* not necessarily equal to numOut */
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Assimp
|
||||
|
||||
#endif // !! ASSIMP_BUILD_NO_TRIANGULATE_PROCESS
|
||||
|
|
Binary file not shown.
|
@ -1,5 +1,8 @@
|
|||
find_package( Doxygen REQUIRED )
|
||||
|
||||
set(SPHINX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(SPHINX_BUILD ${CMAKE_CURRENT_BINARY_DIR}/docs/sphinx)
|
||||
|
||||
set( HTML_OUTPUT "AssimpDoc_Html" CACHE STRING "Output directory for generated HTML documentation. Defaults to AssimpDoc_Html." )
|
||||
|
||||
# Enable Microsoft CHM help style only on Windows
|
||||
|
|
|
@ -1484,7 +1484,7 @@ MAN_LINKS = NO
|
|||
# generate an XML file that captures the structure of
|
||||
# the code including all documentation.
|
||||
|
||||
GENERATE_XML = NO
|
||||
GENERATE_XML = YES
|
||||
|
||||
# The XML_OUTPUT tag is used to specify where the XML pages will be put.
|
||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||
|
|
|
@ -47,8 +47,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Hashing function taken from
|
||||
|
@ -74,8 +74,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
inline uint32_t SuperFastHash (const char * data, uint32_t len = 0, uint32_t hash = 0) {
|
||||
uint32_t tmp;
|
||||
int rem;
|
||||
uint32_t tmp;
|
||||
int rem;
|
||||
|
||||
if (!data) return 0;
|
||||
if (!len)len = (uint32_t)::strlen(data);
|
||||
|
|
|
@ -49,12 +49,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#define INCLUDED_LINE_SPLITTER_H
|
||||
|
||||
#ifdef __GNUC__
|
||||
# pragma GCC system_header
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include <stdexcept>
|
||||
#include <assimp/StreamReader.h>
|
||||
#include <assimp/ParsingUtils.h>
|
||||
#include <assimp/StreamReader.h>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
|
@ -79,37 +79,37 @@ for(LineSplitter splitter(stream);splitter;++splitter) {
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
class LineSplitter {
|
||||
public:
|
||||
typedef size_t line_idx;
|
||||
using line_idx = size_t;
|
||||
|
||||
// -----------------------------------------
|
||||
/** construct from existing stream reader
|
||||
note: trim is *always* assumed true if skyp_empty_lines==true
|
||||
*/
|
||||
LineSplitter(StreamReaderLE& stream, bool skip_empty_lines = true, bool trim = true);
|
||||
LineSplitter(StreamReaderLE &stream, bool skip_empty_lines = true, bool trim = true);
|
||||
|
||||
~LineSplitter();
|
||||
|
||||
// -----------------------------------------
|
||||
/** pseudo-iterator increment */
|
||||
LineSplitter& operator++();
|
||||
LineSplitter &operator++();
|
||||
|
||||
// -----------------------------------------
|
||||
LineSplitter& operator++(int);
|
||||
LineSplitter &operator++(int);
|
||||
|
||||
// -----------------------------------------
|
||||
/** get a pointer to the beginning of a particular token */
|
||||
const char* operator[] (size_t idx) const;
|
||||
const char *operator[](size_t idx) const;
|
||||
|
||||
// -----------------------------------------
|
||||
/** extract the start positions of N tokens from the current line*/
|
||||
template <size_t N>
|
||||
void get_tokens(const char* (&tokens)[N]) const;
|
||||
void get_tokens(const char *(&tokens)[N]) const;
|
||||
|
||||
// -----------------------------------------
|
||||
/** member access */
|
||||
const std::string* operator -> () const;
|
||||
const std::string *operator->() const;
|
||||
|
||||
std::string operator* () const;
|
||||
std::string operator*() const;
|
||||
|
||||
// -----------------------------------------
|
||||
/** boolean context */
|
||||
|
@ -123,47 +123,45 @@ public:
|
|||
|
||||
// -----------------------------------------
|
||||
/** access the underlying stream object */
|
||||
StreamReaderLE& get_stream();
|
||||
StreamReaderLE &get_stream();
|
||||
|
||||
// -----------------------------------------
|
||||
/** !strcmp((*this)->substr(0,strlen(check)),check) */
|
||||
bool match_start(const char* check);
|
||||
bool match_start(const char *check);
|
||||
|
||||
// -----------------------------------------
|
||||
/** swallow the next call to ++, return the previous value. */
|
||||
void swallow_next_increment();
|
||||
|
||||
LineSplitter( const LineSplitter & ) = delete;
|
||||
LineSplitter(const LineSplitter &) = delete;
|
||||
LineSplitter(LineSplitter &&) = delete;
|
||||
LineSplitter &operator = ( const LineSplitter & ) = delete;
|
||||
LineSplitter &operator=(const LineSplitter &) = delete;
|
||||
|
||||
private:
|
||||
line_idx mIdx;
|
||||
std::string mCur;
|
||||
StreamReaderLE& mStream;
|
||||
StreamReaderLE &mStream;
|
||||
bool mSwallow, mSkip_empty_lines, mTrim;
|
||||
};
|
||||
|
||||
AI_FORCE_INLINE
|
||||
LineSplitter::LineSplitter(StreamReaderLE& stream, bool skip_empty_lines, bool trim )
|
||||
: mIdx(0)
|
||||
, mCur()
|
||||
, mStream(stream)
|
||||
, mSwallow()
|
||||
, mSkip_empty_lines(skip_empty_lines)
|
||||
, mTrim(trim) {
|
||||
AI_FORCE_INLINE LineSplitter::LineSplitter(StreamReaderLE &stream, bool skip_empty_lines, bool trim) :
|
||||
mIdx(0),
|
||||
mCur(),
|
||||
mStream(stream),
|
||||
mSwallow(),
|
||||
mSkip_empty_lines(skip_empty_lines),
|
||||
mTrim(trim) {
|
||||
mCur.reserve(1024);
|
||||
operator++();
|
||||
mIdx = 0;
|
||||
}
|
||||
|
||||
AI_FORCE_INLINE
|
||||
LineSplitter::~LineSplitter() {
|
||||
AI_FORCE_INLINE LineSplitter::~LineSplitter() {
|
||||
// empty
|
||||
}
|
||||
|
||||
AI_FORCE_INLINE
|
||||
LineSplitter& LineSplitter::operator++() {
|
||||
LineSplitter &LineSplitter::operator++() {
|
||||
if (mSwallow) {
|
||||
mSwallow = false;
|
||||
return *this;
|
||||
|
@ -178,7 +176,8 @@ LineSplitter& LineSplitter::operator++() {
|
|||
while (mStream.GetRemainingSize() && (s = mStream.GetI1(), 1)) {
|
||||
if (s == '\n' || s == '\r') {
|
||||
if (mSkip_empty_lines) {
|
||||
while (mStream.GetRemainingSize() && ((s = mStream.GetI1()) == ' ' || s == '\r' || s == '\n'));
|
||||
while (mStream.GetRemainingSize() && ((s = mStream.GetI1()) == ' ' || s == '\r' || s == '\n'))
|
||||
;
|
||||
if (mStream.GetRemainingSize()) {
|
||||
mStream.IncPtr(-1);
|
||||
}
|
||||
|
@ -188,7 +187,8 @@ LineSplitter& LineSplitter::operator++() {
|
|||
mStream.IncPtr(-1);
|
||||
}
|
||||
if (mTrim) {
|
||||
while (mStream.GetRemainingSize() && ((s = mStream.GetI1()) == ' ' || s == '\t'));
|
||||
while (mStream.GetRemainingSize() && ((s = mStream.GetI1()) == ' ' || s == '\t'))
|
||||
;
|
||||
if (mStream.GetRemainingSize()) {
|
||||
mStream.IncPtr(-1);
|
||||
}
|
||||
|
@ -203,14 +203,13 @@ LineSplitter& LineSplitter::operator++() {
|
|||
return *this;
|
||||
}
|
||||
|
||||
AI_FORCE_INLINE
|
||||
LineSplitter &LineSplitter::operator++(int) {
|
||||
AI_FORCE_INLINE LineSplitter &LineSplitter::operator++(int) {
|
||||
return ++(*this);
|
||||
}
|
||||
|
||||
AI_FORCE_INLINE
|
||||
const char *LineSplitter::operator[] (size_t idx) const {
|
||||
const char* s = operator->()->c_str();
|
||||
const char *LineSplitter::operator[](size_t idx) const {
|
||||
const char *s = operator->()->c_str();
|
||||
|
||||
SkipSpaces(&s);
|
||||
for (size_t i = 0; i < idx; ++i) {
|
||||
|
@ -226,9 +225,8 @@ const char *LineSplitter::operator[] (size_t idx) const {
|
|||
}
|
||||
|
||||
template <size_t N>
|
||||
AI_FORCE_INLINE
|
||||
void LineSplitter::get_tokens(const char* (&tokens)[N]) const {
|
||||
const char* s = operator->()->c_str();
|
||||
AI_FORCE_INLINE void LineSplitter::get_tokens(const char *(&tokens)[N]) const {
|
||||
const char *s = operator->()->c_str();
|
||||
|
||||
SkipSpaces(&s);
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
|
@ -237,18 +235,19 @@ void LineSplitter::get_tokens(const char* (&tokens)[N]) const {
|
|||
}
|
||||
tokens[i] = s;
|
||||
|
||||
for (; *s && !IsSpace(*s); ++s);
|
||||
for (; *s && !IsSpace(*s); ++s)
|
||||
;
|
||||
SkipSpaces(&s);
|
||||
}
|
||||
}
|
||||
|
||||
AI_FORCE_INLINE
|
||||
const std::string* LineSplitter::operator -> () const {
|
||||
const std::string *LineSplitter::operator->() const {
|
||||
return &mCur;
|
||||
}
|
||||
|
||||
AI_FORCE_INLINE
|
||||
std::string LineSplitter::operator* () const {
|
||||
std::string LineSplitter::operator*() const {
|
||||
return mCur;
|
||||
}
|
||||
|
||||
|
@ -273,7 +272,7 @@ StreamReaderLE &LineSplitter::get_stream() {
|
|||
}
|
||||
|
||||
AI_FORCE_INLINE
|
||||
bool LineSplitter::match_start(const char* check) {
|
||||
bool LineSplitter::match_start(const char *check) {
|
||||
const size_t len = ::strlen(check);
|
||||
|
||||
return len <= mCur.length() && std::equal(check, check + len, mCur.begin());
|
||||
|
|
|
@ -119,7 +119,7 @@ public:
|
|||
/** @brief Normalize the vector with extra check for zero vectors */
|
||||
aiVector3t& NormalizeSafe();
|
||||
|
||||
/** @brief Componentwise multiplication of two vectors
|
||||
/** @brief Component-wise multiplication of two vectors
|
||||
*
|
||||
* Note that vec*vec yields the dot product.
|
||||
* @param o Second factor */
|
||||
|
@ -129,7 +129,7 @@ public:
|
|||
};
|
||||
|
||||
|
||||
typedef aiVector3t<ai_real> aiVector3D;
|
||||
using aiVector3D = aiVector3t<ai_real>;
|
||||
|
||||
#else
|
||||
|
||||
|
|
|
@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
|
|||
|
||||
Copyright (c) 2006-2020, assimp team
|
||||
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
|
@ -306,4 +304,5 @@ aiVector3t<TReal> operator - ( const aiVector3t<TReal>& v) {
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // AI_VECTOR3D_INL_INC
|
||||
|
|
|
@ -96,6 +96,7 @@ SET( COMMON
|
|||
unit/Common/utSpatialSort.cpp
|
||||
unit/Common/utAssertHandler.cpp
|
||||
unit/Common/utXmlParser.cpp
|
||||
unit/Common/utPolyTools.cpp
|
||||
)
|
||||
|
||||
SET( IMPORTERS
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2020, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
#include "UnitTestPCH.h"
|
||||
#include "Common/PolyTools.h"
|
||||
#include <assimp/defs.h>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
class utPolyTools : public ::testing::Test {
|
||||
// empty
|
||||
};
|
||||
|
||||
TEST_F( utPolyTools, NewellNormalTest ) {
|
||||
aiVector3t<ai_real> out;
|
||||
static const size_t Num = 4;
|
||||
static const size_t Capa = Num + 2;
|
||||
ai_real x[Capa], y[Capa], z[Capa];
|
||||
|
||||
x[0] = 0;
|
||||
x[1] = 1;
|
||||
x[2] = 2;
|
||||
x[3] = 3;
|
||||
y[0] = 1;
|
||||
y[1] = 2;
|
||||
y[2] = 3;
|
||||
y[3] = 4;
|
||||
z[0] = z[1] = z[2] = z[3] = 0;
|
||||
NewellNormal<3, 3, 3>(out, 4, x, y, z, Capa);
|
||||
}
|
||||
|
||||
TEST_F(utPolyTools, DerivePlaneCoordinateSpaceTest) {
|
||||
const aiVector3D vertices_ok[3] = {
|
||||
aiVector3D(-1, -1, 0),
|
||||
aiVector3D(0, 1, 0),
|
||||
aiVector3D(1, -1, 0)
|
||||
|
||||
};
|
||||
aiVector3D normal;
|
||||
bool ok = true;
|
||||
aiMatrix4x4 m_ok = DerivePlaneCoordinateSpace<ai_real>(vertices_ok, 3, ok, normal);
|
||||
EXPECT_TRUE(ok);
|
||||
EXPECT_FLOAT_EQ(normal.x, 0.0f);
|
||||
EXPECT_FLOAT_EQ(normal.y, 0.0f);
|
||||
EXPECT_FLOAT_EQ(normal.z, 1.0f);
|
||||
|
||||
const aiVector3D vertices_not_ok[3] = {
|
||||
aiVector3D(-1, -1, 0),
|
||||
aiVector3D(-1, -1, 0),
|
||||
aiVector3D(-1, -1, 0)
|
||||
|
||||
};
|
||||
aiMatrix4x4 m_not_ok = DerivePlaneCoordinateSpace<ai_real>(vertices_not_ok, 3, ok, normal);
|
||||
EXPECT_FALSE(ok);
|
||||
}
|
|
@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
|
|||
|
||||
Copyright (c) 2006-2020, assimp team
|
||||
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
|
|
|
@ -49,8 +49,8 @@ using namespace Assimp;
|
|||
|
||||
class TriangulateProcessTest : public ::testing::Test {
|
||||
public:
|
||||
virtual void SetUp();
|
||||
virtual void TearDown();
|
||||
void SetUp() override;
|
||||
void TearDown() override;
|
||||
|
||||
protected:
|
||||
aiMesh *pcMesh;
|
||||
|
@ -132,6 +132,6 @@ TEST_F(TriangulateProcessTest, testTriangulation) {
|
|||
}
|
||||
}
|
||||
|
||||
// we should have no valid normal vectors now necause we aren't a pure polygon mesh
|
||||
// we should have no valid normal vectors now because we aren't a pure polygon mesh
|
||||
EXPECT_TRUE(pcMesh->mNormals == NULL);
|
||||
}
|
||||
|
|
|
@ -43,9 +43,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#ifndef AV_ANIMEVALUATOR_H_INCLUDED
|
||||
#define AV_ANIMEVALUATOR_H_INCLUDED
|
||||
|
||||
#include <assimp/matrix4x4.h>
|
||||
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
struct aiAnimation;
|
||||
|
||||
namespace AssimpView {
|
||||
|
||||
/**
|
||||
|
@ -74,7 +78,7 @@ public:
|
|||
* the aiAnimation. */
|
||||
const std::vector<aiMatrix4x4> &GetTransformations() const { return mTransforms; }
|
||||
|
||||
protected:
|
||||
private:
|
||||
const aiAnimation *mAnim;
|
||||
double mLastTime;
|
||||
std::vector<std::tuple<unsigned int, unsigned int, unsigned int>> mLastPositions;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -47,7 +47,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#ifndef AV_SCENEANIMATOR_H_INCLUDED
|
||||
#define AV_SCENEANIMATOR_H_INCLUDED
|
||||
|
||||
#include <assimp/scene.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace AssimpView {
|
||||
|
||||
|
@ -59,7 +62,7 @@ namespace AssimpView {
|
|||
struct SceneAnimNode {
|
||||
std::string mName;
|
||||
SceneAnimNode *mParent;
|
||||
std::vector<SceneAnimNode *> mChildren;
|
||||
std::vector<SceneAnimNode*> mChildren;
|
||||
|
||||
//! most recently calculated local transform
|
||||
aiMatrix4x4 mLocalTransform;
|
||||
|
@ -72,13 +75,23 @@ struct SceneAnimNode {
|
|||
|
||||
//! Default construction
|
||||
SceneAnimNode() :
|
||||
mName(), mParent(nullptr), mChildren(), mLocalTransform(), mGlobalTransform(), mChannelIndex(-1) {
|
||||
mName(),
|
||||
mParent(nullptr),
|
||||
mChildren(),
|
||||
mLocalTransform(),
|
||||
mGlobalTransform(),
|
||||
mChannelIndex(-1) {
|
||||
// empty
|
||||
}
|
||||
|
||||
//! Construction from a given name
|
||||
SceneAnimNode(const std::string &pName) :
|
||||
mName(pName), mParent(nullptr), mChildren(), mLocalTransform(), mGlobalTransform(), mChannelIndex(-1) {
|
||||
mName(pName),
|
||||
mParent(nullptr),
|
||||
mChildren(),
|
||||
mLocalTransform(),
|
||||
mGlobalTransform(),
|
||||
mChannelIndex(-1) {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
@ -125,7 +138,7 @@ public:
|
|||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** 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.
|
||||
*/
|
||||
void Calculate(double pTime);
|
||||
|
@ -136,7 +149,7 @@ public:
|
|||
* 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
|
||||
* 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
|
||||
* Calculate() is called.
|
||||
* @param pNodeName Name of the node
|
||||
|
@ -151,7 +164,7 @@ public:
|
|||
* 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,
|
||||
* 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
|
||||
* Calculate() is called.
|
||||
* @param pNodeName Name of the node
|
||||
|
@ -190,7 +203,7 @@ public:
|
|||
/** @brief Get the current animation or NULL
|
||||
*/
|
||||
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:
|
||||
|
|
Loading…
Reference in New Issue