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
|
// Setup configuration properties for the loader
|
||||||
void FBXImporter::SetupProperties(const Importer *pImp) {
|
void FBXImporter::SetupProperties(const Importer *pImp) {
|
||||||
settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
|
mSettings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
|
||||||
settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
|
mSettings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
|
||||||
settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
|
mSettings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
|
||||||
settings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
|
mSettings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
|
||||||
settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
|
mSettings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
|
||||||
settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
|
mSettings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
|
||||||
settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
|
mSettings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
|
||||||
settings.readWeights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_WEIGHTS, true);
|
mSettings.readWeights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_WEIGHTS, true);
|
||||||
settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
|
mSettings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
|
||||||
settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
|
mSettings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
|
||||||
settings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
|
mSettings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
|
||||||
settings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
|
mSettings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
|
||||||
settings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
|
mSettings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
|
||||||
settings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
|
mSettings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -181,10 +181,10 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
||||||
Parser parser(tokens, is_binary);
|
Parser parser(tokens, is_binary);
|
||||||
|
|
||||||
// take the raw parse-tree and convert it to a FBX DOM
|
// take the raw parse-tree and convert it to a FBX DOM
|
||||||
Document doc(parser, settings);
|
Document doc(parser, mSettings);
|
||||||
|
|
||||||
// convert the FBX DOM to aiScene
|
// convert the FBX DOM to aiScene
|
||||||
ConvertToAssimpScene(pScene, doc, settings.removeEmptyBones);
|
ConvertToAssimpScene(pScene, doc, mSettings.removeEmptyBones);
|
||||||
|
|
||||||
// size relative to cm
|
// size relative to cm
|
||||||
float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor();
|
float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor();
|
||||||
|
|
|
@ -70,27 +70,16 @@ typedef class basic_formatter<char, std::char_traits<char>, std::allocator<char>
|
||||||
class FBXImporter : public BaseImporter, public LogFunctions<FBXImporter> {
|
class FBXImporter : public BaseImporter, public LogFunctions<FBXImporter> {
|
||||||
public:
|
public:
|
||||||
FBXImporter();
|
FBXImporter();
|
||||||
virtual ~FBXImporter();
|
~FBXImporter() override;
|
||||||
|
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const;
|
||||||
// --------------------
|
|
||||||
bool CanRead(const std::string &pFile,
|
|
||||||
IOSystem *pIOHandler,
|
|
||||||
bool checkSig) const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// --------------------
|
|
||||||
const aiImporterDesc *GetInfo() const;
|
const aiImporterDesc *GetInfo() const;
|
||||||
|
|
||||||
// --------------------
|
|
||||||
void SetupProperties(const Importer *pImp);
|
void SetupProperties(const Importer *pImp);
|
||||||
|
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler);
|
||||||
// --------------------
|
|
||||||
void InternReadFile(const std::string &pFile,
|
|
||||||
aiScene *pScene,
|
|
||||||
IOSystem *pIOHandler);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FBX::ImportSettings settings;
|
FBX::ImportSettings mSettings;
|
||||||
}; // !class FBXImporter
|
}; // !class FBXImporter
|
||||||
|
|
||||||
} // end of namespace Assimp
|
} // end of namespace Assimp
|
||||||
|
|
|
@ -48,12 +48,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
#include "FBXMeshGeometry.h"
|
|
||||||
#include "FBXDocument.h"
|
#include "FBXDocument.h"
|
||||||
#include "FBXImporter.h"
|
|
||||||
#include "FBXImportSettings.h"
|
|
||||||
#include "FBXDocumentUtil.h"
|
#include "FBXDocumentUtil.h"
|
||||||
|
#include "FBXImportSettings.h"
|
||||||
|
#include "FBXImporter.h"
|
||||||
|
#include "FBXMeshGeometry.h"
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
namespace FBX {
|
namespace FBX {
|
||||||
|
@ -61,10 +60,8 @@ namespace FBX {
|
||||||
using namespace Util;
|
using namespace Util;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Geometry::Geometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
|
Geometry::Geometry(uint64_t id, const Element &element, const std::string &name, const Document &doc) :
|
||||||
: Object(id, element, name)
|
Object(id, element, name), skin() {
|
||||||
, skin()
|
|
||||||
{
|
|
||||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer");
|
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer");
|
||||||
for (const Connection *con : conns) {
|
for (const Connection *con : conns) {
|
||||||
const Skin *const sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
|
const Skin *const sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
|
||||||
|
@ -79,8 +76,7 @@ Geometry::Geometry(uint64_t id, const Element& element, const std::string& name,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Geometry::~Geometry()
|
Geometry::~Geometry() {
|
||||||
{
|
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,9 +91,8 @@ const Skin* Geometry::DeformerSkin() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
|
MeshGeometry::MeshGeometry(uint64_t id, const Element &element, const std::string &name, const Document &doc) :
|
||||||
: Geometry(id, element,name, doc)
|
Geometry(id, element, name, doc) {
|
||||||
{
|
|
||||||
const Scope *sc = element.Compound();
|
const Scope *sc = element.Compound();
|
||||||
if (!sc) {
|
if (!sc) {
|
||||||
DOMError("failed to read Geometry object (class: Mesh), no data scope found");
|
DOMError("failed to read Geometry object (class: Mesh), no data scope found");
|
||||||
|
@ -183,8 +178,7 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
|
||||||
if (doc.Settings().readAllLayers || index == 0) {
|
if (doc.Settings().readAllLayers || index == 0) {
|
||||||
const Scope &layer = GetRequiredScope(*(*it).second);
|
const Scope &layer = GetRequiredScope(*(*it).second);
|
||||||
ReadLayer(layer);
|
ReadLayer(layer);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
FBXImporter::LogWarn("ignoring additional geometry layers");
|
FBXImporter::LogWarn("ignoring additional geometry layers");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -269,15 +263,13 @@ unsigned int MeshGeometry::FaceForVertexIndex( unsigned int in_index ) const {
|
||||||
const std::vector<unsigned int>::iterator it = std::upper_bound(
|
const std::vector<unsigned int>::iterator it = std::upper_bound(
|
||||||
m_facesVertexStartIndices.begin(),
|
m_facesVertexStartIndices.begin(),
|
||||||
m_facesVertexStartIndices.end(),
|
m_facesVertexStartIndices.end(),
|
||||||
in_index
|
in_index);
|
||||||
);
|
|
||||||
|
|
||||||
return static_cast<unsigned int>(std::distance(m_facesVertexStartIndices.begin(), it - 1));
|
return static_cast<unsigned int>(std::distance(m_facesVertexStartIndices.begin(), it - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void MeshGeometry::ReadLayer(const Scope& layer)
|
void MeshGeometry::ReadLayer(const Scope &layer) {
|
||||||
{
|
|
||||||
const ElementCollection &LayerElement = layer.GetCollection("LayerElement");
|
const ElementCollection &LayerElement = layer.GetCollection("LayerElement");
|
||||||
for (ElementMap::const_iterator eit = LayerElement.first; eit != LayerElement.second; ++eit) {
|
for (ElementMap::const_iterator eit = LayerElement.first; eit != LayerElement.second; ++eit) {
|
||||||
const Scope &elayer = GetRequiredScope(*(*eit).second);
|
const Scope &elayer = GetRequiredScope(*(*eit).second);
|
||||||
|
@ -286,10 +278,8 @@ void MeshGeometry::ReadLayer(const Scope& layer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void MeshGeometry::ReadLayerElement(const Scope& layerElement)
|
void MeshGeometry::ReadLayerElement(const Scope &layerElement) {
|
||||||
{
|
|
||||||
const Element &Type = GetRequiredElement(layerElement, "Type");
|
const Element &Type = GetRequiredElement(layerElement, "Type");
|
||||||
const Element &TypedIndex = GetRequiredElement(layerElement, "TypedIndex");
|
const Element &TypedIndex = GetRequiredElement(layerElement, "TypedIndex");
|
||||||
|
|
||||||
|
@ -312,15 +302,12 @@ void MeshGeometry::ReadLayerElement(const Scope& layerElement)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scope& source)
|
void MeshGeometry::ReadVertexData(const std::string &type, int index, const Scope &source) {
|
||||||
{
|
|
||||||
const std::string &MappingInformationType = ParseTokenAsString(GetRequiredToken(
|
const std::string &MappingInformationType = ParseTokenAsString(GetRequiredToken(
|
||||||
GetRequiredElement(source,"MappingInformationType"),0)
|
GetRequiredElement(source, "MappingInformationType"), 0));
|
||||||
);
|
|
||||||
|
|
||||||
const std::string &ReferenceInformationType = ParseTokenAsString(GetRequiredToken(
|
const std::string &ReferenceInformationType = ParseTokenAsString(GetRequiredToken(
|
||||||
GetRequiredElement(source,"ReferenceInformationType"),0)
|
GetRequiredElement(source, "ReferenceInformationType"), 0));
|
||||||
);
|
|
||||||
|
|
||||||
if (type == "LayerElementUV") {
|
if (type == "LayerElementUV") {
|
||||||
if (index >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
|
if (index >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
|
||||||
|
@ -337,10 +324,8 @@ void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scop
|
||||||
|
|
||||||
ReadVertexDataUV(m_uvs[index], source,
|
ReadVertexDataUV(m_uvs[index], source,
|
||||||
MappingInformationType,
|
MappingInformationType,
|
||||||
ReferenceInformationType
|
ReferenceInformationType);
|
||||||
);
|
} else if (type == "LayerElementMaterial") {
|
||||||
}
|
|
||||||
else if (type == "LayerElementMaterial") {
|
|
||||||
if (m_materials.size() > 0) {
|
if (m_materials.size() > 0) {
|
||||||
FBXImporter::LogError("ignoring additional material layer");
|
FBXImporter::LogError("ignoring additional material layer");
|
||||||
return;
|
return;
|
||||||
|
@ -350,8 +335,7 @@ void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scop
|
||||||
|
|
||||||
ReadVertexDataMaterials(temp_materials, source,
|
ReadVertexDataMaterials(temp_materials, source,
|
||||||
MappingInformationType,
|
MappingInformationType,
|
||||||
ReferenceInformationType
|
ReferenceInformationType);
|
||||||
);
|
|
||||||
|
|
||||||
// sometimes, there will be only negative entries. Drop the material
|
// sometimes, there will be only negative entries. Drop the material
|
||||||
// layer in such a case (I guess it means a default material should
|
// layer in such a case (I guess it means a default material should
|
||||||
|
@ -366,8 +350,7 @@ void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scop
|
||||||
}
|
}
|
||||||
|
|
||||||
std::swap(temp_materials, m_materials);
|
std::swap(temp_materials, m_materials);
|
||||||
}
|
} else if (type == "LayerElementNormal") {
|
||||||
else if (type == "LayerElementNormal") {
|
|
||||||
if (m_normals.size() > 0) {
|
if (m_normals.size() > 0) {
|
||||||
FBXImporter::LogError("ignoring additional normal layer");
|
FBXImporter::LogError("ignoring additional normal layer");
|
||||||
return;
|
return;
|
||||||
|
@ -375,10 +358,8 @@ void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scop
|
||||||
|
|
||||||
ReadVertexDataNormals(m_normals, source,
|
ReadVertexDataNormals(m_normals, source,
|
||||||
MappingInformationType,
|
MappingInformationType,
|
||||||
ReferenceInformationType
|
ReferenceInformationType);
|
||||||
);
|
} else if (type == "LayerElementTangent") {
|
||||||
}
|
|
||||||
else if (type == "LayerElementTangent") {
|
|
||||||
if (m_tangents.size() > 0) {
|
if (m_tangents.size() > 0) {
|
||||||
FBXImporter::LogError("ignoring additional tangent layer");
|
FBXImporter::LogError("ignoring additional tangent layer");
|
||||||
return;
|
return;
|
||||||
|
@ -386,10 +367,8 @@ void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scop
|
||||||
|
|
||||||
ReadVertexDataTangents(m_tangents, source,
|
ReadVertexDataTangents(m_tangents, source,
|
||||||
MappingInformationType,
|
MappingInformationType,
|
||||||
ReferenceInformationType
|
ReferenceInformationType);
|
||||||
);
|
} else if (type == "LayerElementBinormal") {
|
||||||
}
|
|
||||||
else if (type == "LayerElementBinormal") {
|
|
||||||
if (m_binormals.size() > 0) {
|
if (m_binormals.size() > 0) {
|
||||||
FBXImporter::LogError("ignoring additional binormal layer");
|
FBXImporter::LogError("ignoring additional binormal layer");
|
||||||
return;
|
return;
|
||||||
|
@ -397,10 +376,8 @@ void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scop
|
||||||
|
|
||||||
ReadVertexDataBinormals(m_binormals, source,
|
ReadVertexDataBinormals(m_binormals, source,
|
||||||
MappingInformationType,
|
MappingInformationType,
|
||||||
ReferenceInformationType
|
ReferenceInformationType);
|
||||||
);
|
} else if (type == "LayerElementColor") {
|
||||||
}
|
|
||||||
else if (type == "LayerElementColor") {
|
|
||||||
if (index >= AI_MAX_NUMBER_OF_COLOR_SETS) {
|
if (index >= AI_MAX_NUMBER_OF_COLOR_SETS) {
|
||||||
FBXImporter::LogError(Formatter::format("ignoring vertex color layer, maximum number of color sets exceeded: ")
|
FBXImporter::LogError(Formatter::format("ignoring vertex color layer, maximum number of color sets exceeded: ")
|
||||||
<< index << " (limit is " << AI_MAX_NUMBER_OF_COLOR_SETS << ")");
|
<< index << " (limit is " << AI_MAX_NUMBER_OF_COLOR_SETS << ")");
|
||||||
|
@ -409,8 +386,7 @@ void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scop
|
||||||
|
|
||||||
ReadVertexDataColors(m_colors[index], source,
|
ReadVertexDataColors(m_colors[index], source,
|
||||||
MappingInformationType,
|
MappingInformationType,
|
||||||
ReferenceInformationType
|
ReferenceInformationType);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -427,8 +403,7 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
|
||||||
size_t vertex_count,
|
size_t vertex_count,
|
||||||
const std::vector<unsigned int> &mapping_counts,
|
const std::vector<unsigned int> &mapping_counts,
|
||||||
const std::vector<unsigned int> &mapping_offsets,
|
const std::vector<unsigned int> &mapping_offsets,
|
||||||
const std::vector<unsigned int>& mappings)
|
const std::vector<unsigned int> &mappings) {
|
||||||
{
|
|
||||||
bool isDirect = ReferenceInformationType == "Direct";
|
bool isDirect = ReferenceInformationType == "Direct";
|
||||||
bool isIndexToDirect = ReferenceInformationType == "IndexToDirect";
|
bool isIndexToDirect = ReferenceInformationType == "IndexToDirect";
|
||||||
|
|
||||||
|
@ -461,8 +436,7 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
|
||||||
data_out[mappings[j]] = tempData[i];
|
data_out[mappings[j]] = tempData[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else if (MappingInformationType == "ByVertice" && isIndexToDirect) {
|
||||||
else if (MappingInformationType == "ByVertice" && isIndexToDirect) {
|
|
||||||
std::vector<T> tempData;
|
std::vector<T> tempData;
|
||||||
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
|
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
|
||||||
|
|
||||||
|
@ -487,21 +461,18 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
|
||||||
data_out[mappings[j]] = tempData[uvIndices[i]];
|
data_out[mappings[j]] = tempData[uvIndices[i]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else if (MappingInformationType == "ByPolygonVertex" && isDirect) {
|
||||||
else if (MappingInformationType == "ByPolygonVertex" && isDirect) {
|
|
||||||
std::vector<T> tempData;
|
std::vector<T> tempData;
|
||||||
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
|
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
|
||||||
|
|
||||||
if (tempData.size() != vertex_count) {
|
if (tempData.size() != vertex_count) {
|
||||||
FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ")
|
FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ")
|
||||||
<< tempData.size() << ", expected " << vertex_count
|
<< tempData.size() << ", expected " << vertex_count);
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
data_out.swap(tempData);
|
data_out.swap(tempData);
|
||||||
}
|
} else if (MappingInformationType == "ByPolygonVertex" && isIndexToDirect) {
|
||||||
else if (MappingInformationType == "ByPolygonVertex" && isIndexToDirect) {
|
|
||||||
std::vector<T> tempData;
|
std::vector<T> tempData;
|
||||||
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
|
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
|
||||||
|
|
||||||
|
@ -529,8 +500,7 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
|
||||||
|
|
||||||
data_out[next++] = tempData[i];
|
data_out[next++] = tempData[i];
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
FBXImporter::LogError(Formatter::format("ignoring vertex data channel, access type not implemented: ")
|
FBXImporter::LogError(Formatter::format("ignoring vertex data channel, access type not implemented: ")
|
||||||
<< MappingInformationType << "," << ReferenceInformationType);
|
<< MappingInformationType << "," << ReferenceInformationType);
|
||||||
}
|
}
|
||||||
|
@ -539,8 +509,7 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void MeshGeometry::ReadVertexDataNormals(std::vector<aiVector3D> &normals_out, const Scope &source,
|
void MeshGeometry::ReadVertexDataNormals(std::vector<aiVector3D> &normals_out, const Scope &source,
|
||||||
const std::string &MappingInformationType,
|
const std::string &MappingInformationType,
|
||||||
const std::string& ReferenceInformationType)
|
const std::string &ReferenceInformationType) {
|
||||||
{
|
|
||||||
ResolveVertexDataArray(normals_out, source, MappingInformationType, ReferenceInformationType,
|
ResolveVertexDataArray(normals_out, source, MappingInformationType, ReferenceInformationType,
|
||||||
"Normals",
|
"Normals",
|
||||||
"NormalsIndex",
|
"NormalsIndex",
|
||||||
|
@ -553,8 +522,7 @@ void MeshGeometry::ReadVertexDataNormals(std::vector<aiVector3D>& normals_out, c
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void MeshGeometry::ReadVertexDataUV(std::vector<aiVector2D> &uv_out, const Scope &source,
|
void MeshGeometry::ReadVertexDataUV(std::vector<aiVector2D> &uv_out, const Scope &source,
|
||||||
const std::string &MappingInformationType,
|
const std::string &MappingInformationType,
|
||||||
const std::string& ReferenceInformationType)
|
const std::string &ReferenceInformationType) {
|
||||||
{
|
|
||||||
ResolveVertexDataArray(uv_out, source, MappingInformationType, ReferenceInformationType,
|
ResolveVertexDataArray(uv_out, source, MappingInformationType, ReferenceInformationType,
|
||||||
"UV",
|
"UV",
|
||||||
"UVIndex",
|
"UVIndex",
|
||||||
|
@ -567,8 +535,7 @@ void MeshGeometry::ReadVertexDataUV(std::vector<aiVector2D>& uv_out, const Scope
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void MeshGeometry::ReadVertexDataColors(std::vector<aiColor4D> &colors_out, const Scope &source,
|
void MeshGeometry::ReadVertexDataColors(std::vector<aiColor4D> &colors_out, const Scope &source,
|
||||||
const std::string &MappingInformationType,
|
const std::string &MappingInformationType,
|
||||||
const std::string& ReferenceInformationType)
|
const std::string &ReferenceInformationType) {
|
||||||
{
|
|
||||||
ResolveVertexDataArray(colors_out, source, MappingInformationType, ReferenceInformationType,
|
ResolveVertexDataArray(colors_out, source, MappingInformationType, ReferenceInformationType,
|
||||||
"Colors",
|
"Colors",
|
||||||
"ColorIndex",
|
"ColorIndex",
|
||||||
|
@ -584,8 +551,7 @@ static const char *TangentsIndexToken = "TangentsIndex";
|
||||||
|
|
||||||
void MeshGeometry::ReadVertexDataTangents(std::vector<aiVector3D> &tangents_out, const Scope &source,
|
void MeshGeometry::ReadVertexDataTangents(std::vector<aiVector3D> &tangents_out, const Scope &source,
|
||||||
const std::string &MappingInformationType,
|
const std::string &MappingInformationType,
|
||||||
const std::string& ReferenceInformationType)
|
const std::string &ReferenceInformationType) {
|
||||||
{
|
|
||||||
const char *str = source.Elements().count("Tangents") > 0 ? "Tangents" : "Tangent";
|
const char *str = source.Elements().count("Tangents") > 0 ? "Tangents" : "Tangent";
|
||||||
const char *strIdx = source.Elements().count("Tangents") > 0 ? TangentsIndexToken : TangentIndexToken;
|
const char *strIdx = source.Elements().count("Tangents") > 0 ? TangentsIndexToken : TangentIndexToken;
|
||||||
ResolveVertexDataArray(tangents_out, source, MappingInformationType, ReferenceInformationType,
|
ResolveVertexDataArray(tangents_out, source, MappingInformationType, ReferenceInformationType,
|
||||||
|
@ -603,8 +569,7 @@ static const std::string BinormalsIndexToken = "BinormalsIndex";
|
||||||
|
|
||||||
void MeshGeometry::ReadVertexDataBinormals(std::vector<aiVector3D> &binormals_out, const Scope &source,
|
void MeshGeometry::ReadVertexDataBinormals(std::vector<aiVector3D> &binormals_out, const Scope &source,
|
||||||
const std::string &MappingInformationType,
|
const std::string &MappingInformationType,
|
||||||
const std::string& ReferenceInformationType)
|
const std::string &ReferenceInformationType) {
|
||||||
{
|
|
||||||
const char *str = source.Elements().count("Binormals") > 0 ? "Binormals" : "Binormal";
|
const char *str = source.Elements().count("Binormals") > 0 ? "Binormals" : "Binormal";
|
||||||
const char *strIdx = source.Elements().count("Binormals") > 0 ? BinormalsIndexToken.c_str() : BinormalIndexToken.c_str();
|
const char *strIdx = source.Elements().count("Binormals") > 0 ? BinormalsIndexToken.c_str() : BinormalIndexToken.c_str();
|
||||||
ResolveVertexDataArray(binormals_out, source, MappingInformationType, ReferenceInformationType,
|
ResolveVertexDataArray(binormals_out, source, MappingInformationType, ReferenceInformationType,
|
||||||
|
@ -616,15 +581,12 @@ void MeshGeometry::ReadVertexDataBinormals(std::vector<aiVector3D>& binormals_ou
|
||||||
m_mappings);
|
m_mappings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void MeshGeometry::ReadVertexDataMaterials(std::vector<int> &materials_out, const Scope &source,
|
void MeshGeometry::ReadVertexDataMaterials(std::vector<int> &materials_out, const Scope &source,
|
||||||
const std::string &MappingInformationType,
|
const std::string &MappingInformationType,
|
||||||
const std::string& ReferenceInformationType)
|
const std::string &ReferenceInformationType) {
|
||||||
{
|
|
||||||
const size_t face_count = m_faces.size();
|
const size_t face_count = m_faces.size();
|
||||||
if( 0 == face_count )
|
if (0 == face_count) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -650,8 +612,7 @@ void MeshGeometry::ReadVertexDataMaterials(std::vector<int>& materials_out, cons
|
||||||
|
|
||||||
if (materials_out.size() != face_count) {
|
if (materials_out.size() != face_count) {
|
||||||
FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ")
|
FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ")
|
||||||
<< materials_out.size() << ", expected " << face_count
|
<< materials_out.size() << ", expected " << face_count);
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -660,8 +621,8 @@ void MeshGeometry::ReadVertexDataMaterials(std::vector<int>& materials_out, cons
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
ShapeGeometry::ShapeGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
|
ShapeGeometry::ShapeGeometry(uint64_t id, const Element &element, const std::string &name, const Document &doc) :
|
||||||
: Geometry(id, element, name, doc) {
|
Geometry(id, element, name, doc) {
|
||||||
const Scope *sc = element.Compound();
|
const Scope *sc = element.Compound();
|
||||||
if (nullptr == sc) {
|
if (nullptr == sc) {
|
||||||
DOMError("failed to read Geometry object (class: Shape), no data scope found");
|
DOMError("failed to read Geometry object (class: Shape), no data scope found");
|
||||||
|
@ -691,9 +652,8 @@ const std::vector<unsigned int>& ShapeGeometry::GetIndices() const {
|
||||||
return m_indices;
|
return m_indices;
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
LineGeometry::LineGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
|
LineGeometry::LineGeometry(uint64_t id, const Element &element, const std::string &name, const Document &doc) :
|
||||||
: Geometry(id, element, name, doc)
|
Geometry(id, element, name, doc) {
|
||||||
{
|
|
||||||
const Scope *sc = element.Compound();
|
const Scope *sc = element.Compound();
|
||||||
if (!sc) {
|
if (!sc) {
|
||||||
DOMError("failed to read Geometry object (class: Line), no data scope found");
|
DOMError("failed to read Geometry object (class: Line), no data scope found");
|
||||||
|
@ -716,7 +676,6 @@ const std::vector<aiVector3D>& LineGeometry::GetVertices() const {
|
||||||
const std::vector<int> &LineGeometry::GetIndices() const {
|
const std::vector<int> &LineGeometry::GetIndices() const {
|
||||||
return m_indices;
|
return m_indices;
|
||||||
}
|
}
|
||||||
} // !FBX
|
} // namespace FBX
|
||||||
} // !Assimp
|
} // namespace Assimp
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -52,13 +52,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "../contrib/zlib/zlib.h"
|
#include "../contrib/zlib/zlib.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "FBXTokenizer.h"
|
|
||||||
#include "FBXParser.h"
|
#include "FBXParser.h"
|
||||||
|
#include "FBXTokenizer.h"
|
||||||
#include "FBXUtil.h"
|
#include "FBXUtil.h"
|
||||||
|
|
||||||
|
#include <assimp/ByteSwapper.h>
|
||||||
#include <assimp/ParsingUtils.h>
|
#include <assimp/ParsingUtils.h>
|
||||||
#include <assimp/fast_atof.h>
|
#include <assimp/fast_atof.h>
|
||||||
#include <assimp/ByteSwapper.h>
|
|
||||||
#include <assimp/DefaultLogger.hpp>
|
#include <assimp/DefaultLogger.hpp>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -71,25 +71,21 @@ namespace {
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// signal parse error, this is always unrecoverable. Throws DeadlyImportError.
|
// signal parse error, this is always unrecoverable. Throws DeadlyImportError.
|
||||||
AI_WONT_RETURN void ParseError(const std::string &message, const Token &token) AI_WONT_RETURN_SUFFIX;
|
AI_WONT_RETURN void ParseError(const std::string &message, const Token &token) AI_WONT_RETURN_SUFFIX;
|
||||||
AI_WONT_RETURN void ParseError(const std::string& message, const Token& token)
|
AI_WONT_RETURN void ParseError(const std::string &message, const Token &token) {
|
||||||
{
|
|
||||||
throw DeadlyImportError("FBX-Parser", Util::GetTokenText(&token), message);
|
throw DeadlyImportError("FBX-Parser", Util::GetTokenText(&token), message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
AI_WONT_RETURN void ParseError(const std::string &message, const Element *element = nullptr) AI_WONT_RETURN_SUFFIX;
|
AI_WONT_RETURN void ParseError(const std::string &message, const Element *element = nullptr) AI_WONT_RETURN_SUFFIX;
|
||||||
AI_WONT_RETURN void ParseError(const std::string& message, const Element* element)
|
AI_WONT_RETURN void ParseError(const std::string &message, const Element *element) {
|
||||||
{
|
|
||||||
if (element) {
|
if (element) {
|
||||||
ParseError(message, element->KeyToken());
|
ParseError(message, element->KeyToken());
|
||||||
}
|
}
|
||||||
throw DeadlyImportError("FBX-Parser ", message);
|
throw DeadlyImportError("FBX-Parser ", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ParseError(const std::string& message, TokenPtr token)
|
void ParseError(const std::string &message, TokenPtr token) {
|
||||||
{
|
|
||||||
if (token) {
|
if (token) {
|
||||||
ParseError(message, *token);
|
ParseError(message, *token);
|
||||||
}
|
}
|
||||||
|
@ -109,15 +105,14 @@ namespace {
|
||||||
::memcpy(&result, data, sizeof(T));
|
::memcpy(&result, data, sizeof(T));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
} // namespace
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
namespace FBX {
|
namespace FBX {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Element::Element(const Token& key_token, Parser& parser)
|
Element::Element(const Token &key_token, Parser &parser) :
|
||||||
: key_token(key_token)
|
key_token(key_token) {
|
||||||
{
|
|
||||||
TokenPtr n = nullptr;
|
TokenPtr n = nullptr;
|
||||||
do {
|
do {
|
||||||
n = parser.AdvanceToNextToken();
|
n = parser.AdvanceToNextToken();
|
||||||
|
@ -160,19 +155,16 @@ Element::Element(const Token& key_token, Parser& parser)
|
||||||
parser.AdvanceToNextToken();
|
parser.AdvanceToNextToken();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
} while (n->Type() != TokenType_KEY && n->Type() != TokenType_CLOSE_BRACKET);
|
||||||
while(n->Type() != TokenType_KEY && n->Type() != TokenType_CLOSE_BRACKET);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Element::~Element()
|
Element::~Element() {
|
||||||
{
|
|
||||||
// no need to delete tokens, they are owned by the parser
|
// no need to delete tokens, they are owned by the parser
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Scope::Scope(Parser& parser,bool topLevel)
|
Scope::Scope(Parser &parser, bool topLevel) {
|
||||||
{
|
|
||||||
if (!topLevel) {
|
if (!topLevel) {
|
||||||
TokenPtr t = parser.CurrentToken();
|
TokenPtr t = parser.CurrentToken();
|
||||||
if (t->Type() != TokenType_OPEN_BRACKET) {
|
if (t->Type() != TokenType_OPEN_BRACKET) {
|
||||||
|
@ -206,34 +198,26 @@ Scope::Scope(Parser& parser,bool topLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Scope::~Scope()
|
Scope::~Scope() {
|
||||||
{
|
|
||||||
for (ElementMap::value_type &v : elements) {
|
for (ElementMap::value_type &v : elements) {
|
||||||
delete v.second;
|
delete v.second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Parser::Parser (const TokenList& tokens, bool is_binary)
|
Parser::Parser(const TokenList &tokens, bool is_binary) :
|
||||||
: tokens(tokens)
|
tokens(tokens), last(), current(), cursor(tokens.begin()), is_binary(is_binary) {
|
||||||
, last()
|
|
||||||
, current()
|
|
||||||
, cursor(tokens.begin())
|
|
||||||
, is_binary(is_binary)
|
|
||||||
{
|
|
||||||
ASSIMP_LOG_DEBUG("Parsing FBX tokens");
|
ASSIMP_LOG_DEBUG("Parsing FBX tokens");
|
||||||
root.reset(new Scope(*this, true));
|
root.reset(new Scope(*this, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Parser::~Parser()
|
Parser::~Parser() {
|
||||||
{
|
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
TokenPtr Parser::AdvanceToNextToken()
|
TokenPtr Parser::AdvanceToNextToken() {
|
||||||
{
|
|
||||||
last = current;
|
last = current;
|
||||||
if (cursor == tokens.end()) {
|
if (cursor == tokens.end()) {
|
||||||
current = nullptr;
|
current = nullptr;
|
||||||
|
@ -244,20 +228,17 @@ TokenPtr Parser::AdvanceToNextToken()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
TokenPtr Parser::CurrentToken() const
|
TokenPtr Parser::CurrentToken() const {
|
||||||
{
|
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
TokenPtr Parser::LastToken() const
|
TokenPtr Parser::LastToken() const {
|
||||||
{
|
|
||||||
return last;
|
return last;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
uint64_t ParseTokenAsID(const Token& t, const char*& err_out)
|
uint64_t ParseTokenAsID(const Token &t, const char *&err_out) {
|
||||||
{
|
|
||||||
err_out = nullptr;
|
err_out = nullptr;
|
||||||
|
|
||||||
if (t.Type() != TokenType_DATA) {
|
if (t.Type() != TokenType_DATA) {
|
||||||
|
@ -265,8 +246,7 @@ uint64_t ParseTokenAsID(const Token& t, const char*& err_out)
|
||||||
return 0L;
|
return 0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(t.IsBinary())
|
if (t.IsBinary()) {
|
||||||
{
|
|
||||||
const char *data = t.begin();
|
const char *data = t.begin();
|
||||||
if (data[0] != 'L') {
|
if (data[0] != 'L') {
|
||||||
err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)";
|
err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)";
|
||||||
|
@ -293,8 +273,7 @@ uint64_t ParseTokenAsID(const Token& t, const char*& err_out)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
size_t ParseTokenAsDim(const Token& t, const char*& err_out)
|
size_t ParseTokenAsDim(const Token &t, const char *&err_out) {
|
||||||
{
|
|
||||||
// same as ID parsing, except there is a trailing asterisk
|
// same as ID parsing, except there is a trailing asterisk
|
||||||
err_out = nullptr;
|
err_out = nullptr;
|
||||||
|
|
||||||
|
@ -303,8 +282,7 @@ size_t ParseTokenAsDim(const Token& t, const char*& err_out)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(t.IsBinary())
|
if (t.IsBinary()) {
|
||||||
{
|
|
||||||
const char *data = t.begin();
|
const char *data = t.begin();
|
||||||
if (data[0] != 'L') {
|
if (data[0] != 'L') {
|
||||||
err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)";
|
err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)";
|
||||||
|
@ -338,10 +316,8 @@ size_t ParseTokenAsDim(const Token& t, const char*& err_out)
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
float ParseTokenAsFloat(const Token& t, const char*& err_out)
|
float ParseTokenAsFloat(const Token &t, const char *&err_out) {
|
||||||
{
|
|
||||||
err_out = nullptr;
|
err_out = nullptr;
|
||||||
|
|
||||||
if (t.Type() != TokenType_DATA) {
|
if (t.Type() != TokenType_DATA) {
|
||||||
|
@ -349,8 +325,7 @@ float ParseTokenAsFloat(const Token& t, const char*& err_out)
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(t.IsBinary())
|
if (t.IsBinary()) {
|
||||||
{
|
|
||||||
const char *data = t.begin();
|
const char *data = t.begin();
|
||||||
if (data[0] != 'F' && data[0] != 'D') {
|
if (data[0] != 'F' && data[0] != 'D') {
|
||||||
err_out = "failed to parse F(loat) or D(ouble), unexpected data type (binary)";
|
err_out = "failed to parse F(loat) or D(ouble), unexpected data type (binary)";
|
||||||
|
@ -359,8 +334,7 @@ float ParseTokenAsFloat(const Token& t, const char*& err_out)
|
||||||
|
|
||||||
if (data[0] == 'F') {
|
if (data[0] == 'F') {
|
||||||
return SafeParse<float>(data + 1, t.end());
|
return SafeParse<float>(data + 1, t.end());
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return static_cast<float>(SafeParse<double>(data + 1, t.end()));
|
return static_cast<float>(SafeParse<double>(data + 1, t.end()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -381,10 +355,8 @@ float ParseTokenAsFloat(const Token& t, const char*& err_out)
|
||||||
return fast_atof(temp);
|
return fast_atof(temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
int ParseTokenAsInt(const Token& t, const char*& err_out)
|
int ParseTokenAsInt(const Token &t, const char *&err_out) {
|
||||||
{
|
|
||||||
err_out = nullptr;
|
err_out = nullptr;
|
||||||
|
|
||||||
if (t.Type() != TokenType_DATA) {
|
if (t.Type() != TokenType_DATA) {
|
||||||
|
@ -392,8 +364,7 @@ int ParseTokenAsInt(const Token& t, const char*& err_out)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(t.IsBinary())
|
if (t.IsBinary()) {
|
||||||
{
|
|
||||||
const char *data = t.begin();
|
const char *data = t.begin();
|
||||||
if (data[0] != 'I') {
|
if (data[0] != 'I') {
|
||||||
err_out = "failed to parse I(nt), unexpected data type (binary)";
|
err_out = "failed to parse I(nt), unexpected data type (binary)";
|
||||||
|
@ -417,10 +388,8 @@ int ParseTokenAsInt(const Token& t, const char*& err_out)
|
||||||
return intval;
|
return intval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
int64_t ParseTokenAsInt64(const Token& t, const char*& err_out)
|
int64_t ParseTokenAsInt64(const Token &t, const char *&err_out) {
|
||||||
{
|
|
||||||
err_out = nullptr;
|
err_out = nullptr;
|
||||||
|
|
||||||
if (t.Type() != TokenType_DATA) {
|
if (t.Type() != TokenType_DATA) {
|
||||||
|
@ -428,8 +397,7 @@ int64_t ParseTokenAsInt64(const Token& t, const char*& err_out)
|
||||||
return 0L;
|
return 0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t.IsBinary())
|
if (t.IsBinary()) {
|
||||||
{
|
|
||||||
const char *data = t.begin();
|
const char *data = t.begin();
|
||||||
if (data[0] != 'L') {
|
if (data[0] != 'L') {
|
||||||
err_out = "failed to parse Int64, unexpected data type";
|
err_out = "failed to parse Int64, unexpected data type";
|
||||||
|
@ -456,8 +424,7 @@ int64_t ParseTokenAsInt64(const Token& t, const char*& err_out)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
std::string ParseTokenAsString(const Token& t, const char*& err_out)
|
std::string ParseTokenAsString(const Token &t, const char *&err_out) {
|
||||||
{
|
|
||||||
err_out = nullptr;
|
err_out = nullptr;
|
||||||
|
|
||||||
if (t.Type() != TokenType_DATA) {
|
if (t.Type() != TokenType_DATA) {
|
||||||
|
@ -465,8 +432,7 @@ std::string ParseTokenAsString(const Token& t, const char*& err_out)
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if(t.IsBinary())
|
if (t.IsBinary()) {
|
||||||
{
|
|
||||||
const char *data = t.begin();
|
const char *data = t.begin();
|
||||||
if (data[0] != 'S') {
|
if (data[0] != 'S') {
|
||||||
err_out = "failed to parse S(tring), unexpected data type (binary)";
|
err_out = "failed to parse S(tring), unexpected data type (binary)";
|
||||||
|
@ -496,14 +462,12 @@ std::string ParseTokenAsString(const Token& t, const char*& err_out)
|
||||||
return std::string(s + 1, length - 2);
|
return std::string(s + 1, length - 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// read the type code and element count of a binary data array and stop there
|
// read the type code and element count of a binary data array and stop there
|
||||||
void ReadBinaryDataArrayHead(const char *&data, const char *end, char &type, uint32_t &count,
|
void ReadBinaryDataArrayHead(const char *&data, const char *end, char &type, uint32_t &count,
|
||||||
const Element& el)
|
const Element &el) {
|
||||||
{
|
|
||||||
if (static_cast<size_t>(end - data) < 5) {
|
if (static_cast<size_t>(end - data) < 5) {
|
||||||
ParseError("binary data array is too short, need five (5) bytes for type signature and element count", &el);
|
ParseError("binary data array is too short, need five (5) bytes for type signature and element count", &el);
|
||||||
}
|
}
|
||||||
|
@ -519,13 +483,11 @@ void ReadBinaryDataArrayHead(const char*& data, const char* end, char& type, uin
|
||||||
data += 5;
|
data += 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// read binary data array, assume cursor points to the 'compression mode' field (i.e. behind the header)
|
// read binary data array, assume cursor points to the 'compression mode' field (i.e. behind the header)
|
||||||
void ReadBinaryDataArray(char type, uint32_t count, const char *&data, const char *end,
|
void ReadBinaryDataArray(char type, uint32_t count, const char *&data, const char *end,
|
||||||
std::vector<char> &buff,
|
std::vector<char> &buff,
|
||||||
const Element& /*el*/)
|
const Element & /*el*/) {
|
||||||
{
|
|
||||||
BE_NCONST uint32_t encmode = SafeParse<uint32_t>(data, end);
|
BE_NCONST uint32_t encmode = SafeParse<uint32_t>(data, end);
|
||||||
AI_SWAP4(encmode);
|
AI_SWAP4(encmode);
|
||||||
data += 4;
|
data += 4;
|
||||||
|
@ -539,8 +501,7 @@ void ReadBinaryDataArray(char type, uint32_t count, const char*& data, const cha
|
||||||
|
|
||||||
// determine the length of the uncompressed data by looking at the type signature
|
// determine the length of the uncompressed data by looking at the type signature
|
||||||
uint32_t stride = 0;
|
uint32_t stride = 0;
|
||||||
switch(type)
|
switch (type) {
|
||||||
{
|
|
||||||
case 'f':
|
case 'f':
|
||||||
case 'i':
|
case 'i':
|
||||||
stride = 4;
|
stride = 4;
|
||||||
|
@ -563,8 +524,7 @@ void ReadBinaryDataArray(char type, uint32_t count, const char*& data, const cha
|
||||||
|
|
||||||
// plain data, no compression
|
// plain data, no compression
|
||||||
std::copy(data, end, buff.begin());
|
std::copy(data, end, buff.begin());
|
||||||
}
|
} else if (encmode == 1) {
|
||||||
else if(encmode == 1) {
|
|
||||||
// zlib/deflate, next comes ZIP head (0x78 0x01)
|
// zlib/deflate, next comes ZIP head (0x78 0x01)
|
||||||
// see http://www.ietf.org/rfc/rfc1950.txt
|
// see http://www.ietf.org/rfc/rfc1950.txt
|
||||||
|
|
||||||
|
@ -604,13 +564,11 @@ void ReadBinaryDataArray(char type, uint32_t count, const char*& data, const cha
|
||||||
ai_assert(data == end);
|
ai_assert(data == end);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // !anon
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// read an array of float3 tuples
|
// read an array of float3 tuples
|
||||||
void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el)
|
void ParseVectorDataArray(std::vector<aiVector3D> &out, const Element &el) {
|
||||||
{
|
|
||||||
out.resize(0);
|
out.resize(0);
|
||||||
|
|
||||||
const TokenList &tok = el.Tokens();
|
const TokenList &tok = el.Tokens();
|
||||||
|
@ -660,8 +618,7 @@ void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el)
|
||||||
stream << " vec3.x = " << vec3.x << " vec3.y = " << vec3.y << " vec3.z = " << vec3.z << std::endl;
|
stream << " vec3.x = " << vec3.x << " vec3.y = " << vec3.y << " vec3.z = " << vec3.z << std::endl;
|
||||||
DefaultLogger::get()->info( stream.str() );
|
DefaultLogger::get()->info( stream.str() );
|
||||||
}*/
|
}*/
|
||||||
}
|
} else if (type == 'f') {
|
||||||
else if (type == 'f') {
|
|
||||||
const float *f = reinterpret_cast<const float *>(&buff[0]);
|
const float *f = reinterpret_cast<const float *>(&buff[0]);
|
||||||
for (unsigned int i = 0; i < count3; ++i, f += 3) {
|
for (unsigned int i = 0; i < count3; ++i, f += 3) {
|
||||||
out.push_back(aiVector3D(f[0], f[1], f[2]));
|
out.push_back(aiVector3D(f[0], f[1], f[2]));
|
||||||
|
@ -694,11 +651,9 @@ void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// read an array of color4 tuples
|
// read an array of color4 tuples
|
||||||
void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el)
|
void ParseVectorDataArray(std::vector<aiColor4D> &out, const Element &el) {
|
||||||
{
|
|
||||||
out.resize(0);
|
out.resize(0);
|
||||||
const TokenList &tok = el.Tokens();
|
const TokenList &tok = el.Tokens();
|
||||||
if (tok.empty()) {
|
if (tok.empty()) {
|
||||||
|
@ -741,8 +696,7 @@ void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el)
|
||||||
static_cast<float>(d[2]),
|
static_cast<float>(d[2]),
|
||||||
static_cast<float>(d[3])));
|
static_cast<float>(d[3])));
|
||||||
}
|
}
|
||||||
}
|
} else if (type == 'f') {
|
||||||
else if (type == 'f') {
|
|
||||||
const float *f = reinterpret_cast<const float *>(&buff[0]);
|
const float *f = reinterpret_cast<const float *>(&buff[0]);
|
||||||
for (unsigned int i = 0; i < count4; ++i, f += 4) {
|
for (unsigned int i = 0; i < count4; ++i, f += 4) {
|
||||||
out.push_back(aiColor4D(f[0], f[1], f[2], f[3]));
|
out.push_back(aiColor4D(f[0], f[1], f[2], f[3]));
|
||||||
|
@ -773,11 +727,9 @@ void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// read an array of float2 tuples
|
// read an array of float2 tuples
|
||||||
void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el)
|
void ParseVectorDataArray(std::vector<aiVector2D> &out, const Element &el) {
|
||||||
{
|
|
||||||
out.resize(0);
|
out.resize(0);
|
||||||
const TokenList &tok = el.Tokens();
|
const TokenList &tok = el.Tokens();
|
||||||
if (tok.empty()) {
|
if (tok.empty()) {
|
||||||
|
@ -818,8 +770,7 @@ void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el)
|
||||||
out.push_back(aiVector2D(static_cast<float>(d[0]),
|
out.push_back(aiVector2D(static_cast<float>(d[0]),
|
||||||
static_cast<float>(d[1])));
|
static_cast<float>(d[1])));
|
||||||
}
|
}
|
||||||
}
|
} else if (type == 'f') {
|
||||||
else if (type == 'f') {
|
|
||||||
const float *f = reinterpret_cast<const float *>(&buff[0]);
|
const float *f = reinterpret_cast<const float *>(&buff[0]);
|
||||||
for (unsigned int i = 0; i < count2; ++i, f += 2) {
|
for (unsigned int i = 0; i < count2; ++i, f += 2) {
|
||||||
out.push_back(aiVector2D(f[0], f[1]));
|
out.push_back(aiVector2D(f[0], f[1]));
|
||||||
|
@ -849,11 +800,9 @@ void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// read an array of ints
|
// read an array of ints
|
||||||
void ParseVectorDataArray(std::vector<int>& out, const Element& el)
|
void ParseVectorDataArray(std::vector<int> &out, const Element &el) {
|
||||||
{
|
|
||||||
out.resize(0);
|
out.resize(0);
|
||||||
const TokenList &tok = el.Tokens();
|
const TokenList &tok = el.Tokens();
|
||||||
if (tok.empty()) {
|
if (tok.empty()) {
|
||||||
|
@ -907,11 +856,9 @@ void ParseVectorDataArray(std::vector<int>& out, const Element& el)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// read an array of floats
|
// read an array of floats
|
||||||
void ParseVectorDataArray(std::vector<float>& out, const Element& el)
|
void ParseVectorDataArray(std::vector<float> &out, const Element &el) {
|
||||||
{
|
|
||||||
out.resize(0);
|
out.resize(0);
|
||||||
const TokenList &tok = el.Tokens();
|
const TokenList &tok = el.Tokens();
|
||||||
if (tok.empty()) {
|
if (tok.empty()) {
|
||||||
|
@ -944,8 +891,7 @@ void ParseVectorDataArray(std::vector<float>& out, const Element& el)
|
||||||
for (unsigned int i = 0; i < count; ++i, ++d) {
|
for (unsigned int i = 0; i < count; ++i, ++d) {
|
||||||
out.push_back(static_cast<float>(*d));
|
out.push_back(static_cast<float>(*d));
|
||||||
}
|
}
|
||||||
}
|
} else if (type == 'f') {
|
||||||
else if (type == 'f') {
|
|
||||||
const float *f = reinterpret_cast<const float *>(&buff[0]);
|
const float *f = reinterpret_cast<const float *>(&buff[0]);
|
||||||
for (unsigned int i = 0; i < count; ++i, ++f) {
|
for (unsigned int i = 0; i < count; ++i, ++f) {
|
||||||
out.push_back(*f);
|
out.push_back(*f);
|
||||||
|
@ -971,8 +917,7 @@ void ParseVectorDataArray(std::vector<float>& out, const Element& el)
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// read an array of uints
|
// read an array of uints
|
||||||
void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el)
|
void ParseVectorDataArray(std::vector<unsigned int> &out, const Element &el) {
|
||||||
{
|
|
||||||
out.resize(0);
|
out.resize(0);
|
||||||
const TokenList &tok = el.Tokens();
|
const TokenList &tok = el.Tokens();
|
||||||
if (tok.empty()) {
|
if (tok.empty()) {
|
||||||
|
@ -1033,11 +978,9 @@ void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// read an array of uint64_ts
|
// read an array of uint64_ts
|
||||||
void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& el)
|
void ParseVectorDataArray(std::vector<uint64_t> &out, const Element &el) {
|
||||||
{
|
|
||||||
out.resize(0);
|
out.resize(0);
|
||||||
const TokenList &tok = el.Tokens();
|
const TokenList &tok = el.Tokens();
|
||||||
if (tok.empty()) {
|
if (tok.empty()) {
|
||||||
|
@ -1094,8 +1037,7 @@ void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& el)
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// read an array of int64_ts
|
// read an array of int64_ts
|
||||||
void ParseVectorDataArray(std::vector<int64_t>& out, const Element& el)
|
void ParseVectorDataArray(std::vector<int64_t> &out, const Element &el) {
|
||||||
{
|
|
||||||
out.resize(0);
|
out.resize(0);
|
||||||
const TokenList &tok = el.Tokens();
|
const TokenList &tok = el.Tokens();
|
||||||
if (tok.empty()) {
|
if (tok.empty()) {
|
||||||
|
@ -1151,8 +1093,7 @@ void ParseVectorDataArray(std::vector<int64_t>& out, const Element& el)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
aiMatrix4x4 ReadMatrix(const Element& element)
|
aiMatrix4x4 ReadMatrix(const Element &element) {
|
||||||
{
|
|
||||||
std::vector<float> values;
|
std::vector<float> values;
|
||||||
ParseVectorDataArray(values, element);
|
ParseVectorDataArray(values, element);
|
||||||
|
|
||||||
|
@ -1162,7 +1103,6 @@ aiMatrix4x4 ReadMatrix(const Element& element)
|
||||||
|
|
||||||
aiMatrix4x4 result;
|
aiMatrix4x4 result;
|
||||||
|
|
||||||
|
|
||||||
result.a1 = values[0];
|
result.a1 = values[0];
|
||||||
result.a2 = values[1];
|
result.a2 = values[1];
|
||||||
result.a3 = values[2];
|
result.a3 = values[2];
|
||||||
|
@ -1187,11 +1127,9 @@ aiMatrix4x4 ReadMatrix(const Element& element)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// wrapper around ParseTokenAsString() with ParseError handling
|
// wrapper around ParseTokenAsString() with ParseError handling
|
||||||
std::string ParseTokenAsString(const Token& t)
|
std::string ParseTokenAsString(const Token &t) {
|
||||||
{
|
|
||||||
const char *err;
|
const char *err;
|
||||||
const std::string &i = ParseTokenAsString(t, err);
|
const std::string &i = ParseTokenAsString(t, err);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -1211,8 +1149,7 @@ bool HasElement( const Scope& sc, const std::string& index ) {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// extract a required element from a scope, abort if the element cannot be found
|
// extract a required element from a scope, abort if the element cannot be found
|
||||||
const Element& GetRequiredElement(const Scope& sc, const std::string& index, const Element* element /*= nullptr*/)
|
const Element &GetRequiredElement(const Scope &sc, const std::string &index, const Element *element /*= nullptr*/) {
|
||||||
{
|
|
||||||
const Element *el = sc[index];
|
const Element *el = sc[index];
|
||||||
if (!el) {
|
if (!el) {
|
||||||
ParseError("did not find required element \"" + index + "\"", element);
|
ParseError("did not find required element \"" + index + "\"", element);
|
||||||
|
@ -1220,11 +1157,9 @@ const Element& GetRequiredElement(const Scope& sc, const std::string& index, con
|
||||||
return *el;
|
return *el;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// extract required compound scope
|
// extract required compound scope
|
||||||
const Scope& GetRequiredScope(const Element& el)
|
const Scope &GetRequiredScope(const Element &el) {
|
||||||
{
|
|
||||||
const Scope *const s = el.Compound();
|
const Scope *const s = el.Compound();
|
||||||
if (!s) {
|
if (!s) {
|
||||||
ParseError("expected compound scope", &el);
|
ParseError("expected compound scope", &el);
|
||||||
|
@ -1233,11 +1168,9 @@ const Scope& GetRequiredScope(const Element& el)
|
||||||
return *s;
|
return *s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// get token at a particular index
|
// get token at a particular index
|
||||||
const Token& GetRequiredToken(const Element& el, unsigned int index)
|
const Token &GetRequiredToken(const Element &el, unsigned int index) {
|
||||||
{
|
|
||||||
const TokenList &t = el.Tokens();
|
const TokenList &t = el.Tokens();
|
||||||
if (index >= t.size()) {
|
if (index >= t.size()) {
|
||||||
ParseError(Formatter::format("missing token at index ") << index, &el);
|
ParseError(Formatter::format("missing token at index ") << index, &el);
|
||||||
|
@ -1246,11 +1179,9 @@ const Token& GetRequiredToken(const Element& el, unsigned int index)
|
||||||
return *t[index];
|
return *t[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// wrapper around ParseTokenAsID() with ParseError handling
|
// wrapper around ParseTokenAsID() with ParseError handling
|
||||||
uint64_t ParseTokenAsID(const Token& t)
|
uint64_t ParseTokenAsID(const Token &t) {
|
||||||
{
|
|
||||||
const char *err;
|
const char *err;
|
||||||
const uint64_t i = ParseTokenAsID(t, err);
|
const uint64_t i = ParseTokenAsID(t, err);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -1259,11 +1190,9 @@ uint64_t ParseTokenAsID(const Token& t)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// wrapper around ParseTokenAsDim() with ParseError handling
|
// wrapper around ParseTokenAsDim() with ParseError handling
|
||||||
size_t ParseTokenAsDim(const Token& t)
|
size_t ParseTokenAsDim(const Token &t) {
|
||||||
{
|
|
||||||
const char *err;
|
const char *err;
|
||||||
const size_t i = ParseTokenAsDim(t, err);
|
const size_t i = ParseTokenAsDim(t, err);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -1272,11 +1201,9 @@ size_t ParseTokenAsDim(const Token& t)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// wrapper around ParseTokenAsFloat() with ParseError handling
|
// wrapper around ParseTokenAsFloat() with ParseError handling
|
||||||
float ParseTokenAsFloat(const Token& t)
|
float ParseTokenAsFloat(const Token &t) {
|
||||||
{
|
|
||||||
const char *err;
|
const char *err;
|
||||||
const float i = ParseTokenAsFloat(t, err);
|
const float i = ParseTokenAsFloat(t, err);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -1287,8 +1214,7 @@ float ParseTokenAsFloat(const Token& t)
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// wrapper around ParseTokenAsInt() with ParseError handling
|
// wrapper around ParseTokenAsInt() with ParseError handling
|
||||||
int ParseTokenAsInt(const Token& t)
|
int ParseTokenAsInt(const Token &t) {
|
||||||
{
|
|
||||||
const char *err;
|
const char *err;
|
||||||
const int i = ParseTokenAsInt(t, err);
|
const int i = ParseTokenAsInt(t, err);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -1299,8 +1225,7 @@ int ParseTokenAsInt(const Token& t)
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// wrapper around ParseTokenAsInt64() with ParseError handling
|
// wrapper around ParseTokenAsInt64() with ParseError handling
|
||||||
int64_t ParseTokenAsInt64(const Token& t)
|
int64_t ParseTokenAsInt64(const Token &t) {
|
||||||
{
|
|
||||||
const char *err;
|
const char *err;
|
||||||
const int64_t i = ParseTokenAsInt64(t, err);
|
const int64_t i = ParseTokenAsInt64(t, err);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -1309,7 +1234,7 @@ int64_t ParseTokenAsInt64(const Token& t)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // !FBX
|
} // namespace FBX
|
||||||
} // !Assimp
|
} // namespace Assimp
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -43,18 +43,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* holes for windows and doors into walls.
|
* holes for windows and doors into walls.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef ASSIMP_BUILD_NO_IFC_IMPORTER
|
#ifndef ASSIMP_BUILD_NO_IFC_IMPORTER
|
||||||
#include "IFCUtil.h"
|
|
||||||
#include "Common/PolyTools.h"
|
#include "Common/PolyTools.h"
|
||||||
|
#include "IFCUtil.h"
|
||||||
#include "PostProcessing/ProcessHelper.h"
|
#include "PostProcessing/ProcessHelper.h"
|
||||||
|
|
||||||
#ifdef ASSIMP_USE_HUNTER
|
#ifdef ASSIMP_USE_HUNTER
|
||||||
#include <poly2tri/poly2tri.h>
|
#include <poly2tri/poly2tri.h>
|
||||||
#include <polyclipping/clipper.hpp>
|
#include <polyclipping/clipper.hpp>
|
||||||
#else
|
#else
|
||||||
# include "../contrib/poly2tri/poly2tri/poly2tri.h"
|
|
||||||
#include "../contrib/clipper/clipper.hpp"
|
#include "../contrib/clipper/clipper.hpp"
|
||||||
|
#include "../contrib/poly2tri/poly2tri/poly2tri.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
@ -71,21 +70,17 @@ namespace Assimp {
|
||||||
#define from_int64(p) (static_cast<IfcFloat>((p)) / max_ulong64)
|
#define from_int64(p) (static_cast<IfcFloat>((p)) / max_ulong64)
|
||||||
#define one_vec (IfcVector2(static_cast<IfcFloat>(1.0), static_cast<IfcFloat>(1.0)))
|
#define one_vec (IfcVector2(static_cast<IfcFloat>(1.0), static_cast<IfcFloat>(1.0)))
|
||||||
|
|
||||||
|
|
||||||
// fallback method to generate wall openings
|
// fallback method to generate wall openings
|
||||||
bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening> &openings, const std::vector<IfcVector3> &nors,
|
bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening> &openings, const std::vector<IfcVector3> &nors,
|
||||||
TempMesh &curmesh);
|
TempMesh &curmesh);
|
||||||
|
|
||||||
|
using BoundingBox = std::pair<IfcVector2, IfcVector2>;
|
||||||
typedef std::pair< IfcVector2, IfcVector2 > BoundingBox;
|
using XYSortedField = std::map<IfcVector2, size_t, XYSorter>;
|
||||||
typedef std::map<IfcVector2,size_t,XYSorter> XYSortedField;
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void QuadrifyPart(const IfcVector2 &pmin, const IfcVector2 &pmax, XYSortedField &field,
|
void QuadrifyPart(const IfcVector2 &pmin, const IfcVector2 &pmax, XYSortedField &field,
|
||||||
const std::vector<BoundingBox> &bbs,
|
const std::vector<BoundingBox> &bbs,
|
||||||
std::vector<IfcVector2>& out)
|
std::vector<IfcVector2> &out) {
|
||||||
{
|
|
||||||
if (!(pmin.x - pmax.x) || !(pmin.y - pmax.y)) {
|
if (!(pmin.x - pmax.x) || !(pmin.y - pmax.y)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -111,10 +106,10 @@ void QuadrifyPart(const IfcVector2& pmin, const IfcVector2& pmax, XYSortedField&
|
||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
// the rectangle [pmin,pend] is opaque, fill it
|
// the rectangle [pmin,pend] is opaque, fill it
|
||||||
out.push_back(pmin);
|
out.emplace_back(pmin);
|
||||||
out.push_back(IfcVector2(pmin.x,pmax.y));
|
out.emplace_back(pmin.x, pmax.y);
|
||||||
out.push_back(pmax);
|
out.emplace_back(pmax);
|
||||||
out.push_back(IfcVector2(pmax.x,pmin.y));
|
out.emplace_back(pmax.x, pmin.y);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,10 +118,10 @@ void QuadrifyPart(const IfcVector2& pmin, const IfcVector2& pmax, XYSortedField&
|
||||||
|
|
||||||
// see if there's an offset to fill at the top of our quad
|
// see if there's an offset to fill at the top of our quad
|
||||||
if (xs - pmin.x) {
|
if (xs - pmin.x) {
|
||||||
out.push_back(pmin);
|
out.emplace_back(pmin);
|
||||||
out.push_back(IfcVector2(pmin.x,pmax.y));
|
out.emplace_back(pmin.x, pmax.y);
|
||||||
out.push_back(IfcVector2(xs,pmax.y));
|
out.emplace_back(xs, pmax.y);
|
||||||
out.push_back(IfcVector2(xs,pmin.y));
|
out.emplace_back(xs, pmin.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// search along the y-axis for all openings that overlap xs and our quad
|
// search along the y-axis for all openings that overlap xs and our quad
|
||||||
|
@ -157,10 +152,10 @@ void QuadrifyPart(const IfcVector2& pmin, const IfcVector2& pmax, XYSortedField&
|
||||||
}
|
}
|
||||||
if (!found) {
|
if (!found) {
|
||||||
// the rectangle [pmin,pend] is opaque, fill it
|
// the rectangle [pmin,pend] is opaque, fill it
|
||||||
out.push_back(IfcVector2(xs,pmin.y));
|
out.emplace_back(IfcVector2(xs, pmin.y));
|
||||||
out.push_back(IfcVector2(xs,pmax.y));
|
out.emplace_back(xs, pmax.y);
|
||||||
out.push_back(IfcVector2(xe,pmax.y));
|
out.emplace_back(xe, pmax.y);
|
||||||
out.push_back(IfcVector2(xe,pmin.y));
|
out.emplace_back(xe, pmin.y);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ylast < pmax.y) {
|
if (ylast < pmax.y) {
|
||||||
|
@ -173,23 +168,17 @@ void QuadrifyPart(const IfcVector2& pmin, const IfcVector2& pmax, XYSortedField&
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef std::vector<IfcVector2> Contour;
|
using Contour = std::vector<IfcVector2>;
|
||||||
typedef std::vector<bool> SkipList; // should probably use int for performance reasons
|
using SkipList = std::vector<bool>; // should probably use int for performance reasons
|
||||||
|
|
||||||
struct ProjectedWindowContour
|
struct ProjectedWindowContour {
|
||||||
{
|
|
||||||
Contour contour;
|
Contour contour;
|
||||||
BoundingBox bb;
|
BoundingBox bb;
|
||||||
SkipList skiplist;
|
SkipList skiplist;
|
||||||
bool is_rectangular;
|
bool is_rectangular;
|
||||||
|
|
||||||
|
ProjectedWindowContour(const Contour &contour, const BoundingBox &bb, bool is_rectangular) :
|
||||||
ProjectedWindowContour(const Contour& contour, const BoundingBox& bb, bool is_rectangular)
|
contour(contour), bb(bb), is_rectangular(is_rectangular) {}
|
||||||
: contour(contour)
|
|
||||||
, bb(bb)
|
|
||||||
, is_rectangular(is_rectangular)
|
|
||||||
{}
|
|
||||||
|
|
||||||
|
|
||||||
bool IsInvalid() const {
|
bool IsInvalid() const {
|
||||||
return contour.empty();
|
return contour.empty();
|
||||||
|
@ -204,19 +193,17 @@ struct ProjectedWindowContour
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector< ProjectedWindowContour > ContourVector;
|
using ContourVector = std::vector<ProjectedWindowContour>;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
bool BoundingBoxesOverlapping( const BoundingBox &ibb, const BoundingBox &bb )
|
bool BoundingBoxesOverlapping(const BoundingBox &ibb, const BoundingBox &bb) {
|
||||||
{
|
|
||||||
// count the '=' case as non-overlapping but as adjacent to each other
|
// count the '=' case as non-overlapping but as adjacent to each other
|
||||||
return ibb.first.x < bb.second.x && ibb.second.x > bb.first.x &&
|
return ibb.first.x < bb.second.x && ibb.second.x > bb.first.x &&
|
||||||
ibb.first.y < bb.second.y && ibb.second.y > bb.first.y;
|
ibb.first.y < bb.second.y && ibb.second.y > bb.first.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
bool IsDuplicateVertex(const IfcVector2& vv, const std::vector<IfcVector2>& temp_contour)
|
bool IsDuplicateVertex(const IfcVector2 &vv, const std::vector<IfcVector2> &temp_contour) {
|
||||||
{
|
|
||||||
// sanity check for duplicate vertices
|
// sanity check for duplicate vertices
|
||||||
for (const IfcVector2 &cp : temp_contour) {
|
for (const IfcVector2 &cp : temp_contour) {
|
||||||
if ((cp - vv).SquareLength() < 1e-5f) {
|
if ((cp - vv).SquareLength() < 1e-5f) {
|
||||||
|
@ -228,8 +215,7 @@ bool IsDuplicateVertex(const IfcVector2& vv, const std::vector<IfcVector2>& temp
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ExtractVerticesFromClipper(const ClipperLib::Polygon &poly, std::vector<IfcVector2> &temp_contour,
|
void ExtractVerticesFromClipper(const ClipperLib::Polygon &poly, std::vector<IfcVector2> &temp_contour,
|
||||||
bool filter_duplicates = false)
|
bool filter_duplicates = false) {
|
||||||
{
|
|
||||||
temp_contour.clear();
|
temp_contour.clear();
|
||||||
for (const ClipperLib::IntPoint &point : poly) {
|
for (const ClipperLib::IntPoint &point : poly) {
|
||||||
IfcVector2 vv = IfcVector2(from_int64(point.X), from_int64(point.Y));
|
IfcVector2 vv = IfcVector2(from_int64(point.X), from_int64(point.Y));
|
||||||
|
@ -243,8 +229,7 @@ void ExtractVerticesFromClipper(const ClipperLib::Polygon& poly, std::vector<Ifc
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
BoundingBox GetBoundingBox(const ClipperLib::Polygon& poly)
|
BoundingBox GetBoundingBox2D(const ClipperLib::Polygon &poly) {
|
||||||
{
|
|
||||||
IfcVector2 newbb_min, newbb_max;
|
IfcVector2 newbb_min, newbb_max;
|
||||||
MinMaxChooser<IfcVector2>()(newbb_min, newbb_max);
|
MinMaxChooser<IfcVector2>()(newbb_min, newbb_max);
|
||||||
|
|
||||||
|
@ -264,8 +249,7 @@ BoundingBox GetBoundingBox(const ClipperLib::Polygon& poly)
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void InsertWindowContours(const ContourVector &contours,
|
void InsertWindowContours(const ContourVector &contours,
|
||||||
const std::vector<TempOpening> & /*openings*/,
|
const std::vector<TempOpening> & /*openings*/,
|
||||||
TempMesh& curmesh)
|
TempMesh &curmesh) {
|
||||||
{
|
|
||||||
// fix windows - we need to insert the real, polygonal shapes into the quadratic holes that we have now
|
// fix windows - we need to insert the real, polygonal shapes into the quadratic holes that we have now
|
||||||
for (size_t i = 0; i < contours.size(); ++i) {
|
for (size_t i = 0; i < contours.size(); ++i) {
|
||||||
const BoundingBox &bb = contours[i].bb;
|
const BoundingBox &bb = contours[i].bb;
|
||||||
|
@ -282,10 +266,7 @@ void InsertWindowContours(const ContourVector& contours,
|
||||||
verts.insert(contour[n]);
|
verts.insert(contour[n]);
|
||||||
}
|
}
|
||||||
const std::set<IfcVector2, XYSorter>::const_iterator end = verts.end();
|
const std::set<IfcVector2, XYSorter>::const_iterator end = verts.end();
|
||||||
if (verts.find(bb.first)!=end && verts.find(bb.second)!=end
|
if (verts.find(bb.first) != end && verts.find(bb.second) != end && verts.find(IfcVector2(bb.first.x, bb.second.y)) != end && verts.find(IfcVector2(bb.second.x, bb.first.y)) != end) {
|
||||||
&& verts.find(IfcVector2(bb.first.x,bb.second.y))!=end
|
|
||||||
&& verts.find(IfcVector2(bb.second.x,bb.first.y))!=end
|
|
||||||
) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -310,8 +291,7 @@ void InsertWindowContours(const ContourVector& contours,
|
||||||
if (std::fabs(v.x - bb.first.x) < epsilon) {
|
if (std::fabs(v.x - bb.first.x) < epsilon) {
|
||||||
edge.x = bb.first.x;
|
edge.x = bb.first.x;
|
||||||
hit = true;
|
hit = true;
|
||||||
}
|
} else if (std::fabs(v.x - bb.second.x) < epsilon) {
|
||||||
else if (std::fabs(v.x-bb.second.x)<epsilon) {
|
|
||||||
edge.x = bb.second.x;
|
edge.x = bb.second.x;
|
||||||
hit = true;
|
hit = true;
|
||||||
}
|
}
|
||||||
|
@ -319,8 +299,7 @@ void InsertWindowContours(const ContourVector& contours,
|
||||||
if (std::fabs(v.y - bb.first.y) < epsilon) {
|
if (std::fabs(v.y - bb.first.y) < epsilon) {
|
||||||
edge.y = bb.first.y;
|
edge.y = bb.first.y;
|
||||||
hit = true;
|
hit = true;
|
||||||
}
|
} else if (std::fabs(v.y - bb.second.y) < epsilon) {
|
||||||
else if (std::fabs(v.y-bb.second.y)<epsilon) {
|
|
||||||
edge.y = bb.second.y;
|
edge.y = bb.second.y;
|
||||||
hit = true;
|
hit = true;
|
||||||
}
|
}
|
||||||
|
@ -349,21 +328,18 @@ void InsertWindowContours(const ContourVector& contours,
|
||||||
|
|
||||||
if (std::fabs(contour[last_hit].x - bb.first.x) < epsilon) {
|
if (std::fabs(contour[last_hit].x - bb.first.x) < epsilon) {
|
||||||
corner.x = bb.first.x;
|
corner.x = bb.first.x;
|
||||||
}
|
} else if (std::fabs(contour[last_hit].x - bb.second.x) < epsilon) {
|
||||||
else if (std::fabs(contour[last_hit].x-bb.second.x)<epsilon) {
|
|
||||||
corner.x = bb.second.x;
|
corner.x = bb.second.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::fabs(contour[last_hit].y - bb.first.y) < epsilon) {
|
if (std::fabs(contour[last_hit].y - bb.first.y) < epsilon) {
|
||||||
corner.y = bb.first.y;
|
corner.y = bb.first.y;
|
||||||
}
|
} else if (std::fabs(contour[last_hit].y - bb.second.y) < epsilon) {
|
||||||
else if (std::fabs(contour[last_hit].y-bb.second.y)<epsilon) {
|
|
||||||
corner.y = bb.second.y;
|
corner.y = bb.second.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
curmesh.mVerts.push_back(IfcVector3(corner.x, corner.y, 0.0f));
|
curmesh.mVerts.push_back(IfcVector3(corner.x, corner.y, 0.0f));
|
||||||
}
|
} else if (cnt == 1) {
|
||||||
else if (cnt == 1) {
|
|
||||||
// avoid degenerate polygons (also known as lines or points)
|
// avoid degenerate polygons (also known as lines or points)
|
||||||
curmesh.mVerts.erase(curmesh.mVerts.begin() + old, curmesh.mVerts.end());
|
curmesh.mVerts.erase(curmesh.mVerts.begin() + old, curmesh.mVerts.end());
|
||||||
}
|
}
|
||||||
|
@ -375,8 +351,7 @@ void InsertWindowContours(const ContourVector& contours,
|
||||||
if (n == very_first_hit) {
|
if (n == very_first_hit) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
very_first_hit = n;
|
very_first_hit = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,8 +364,7 @@ void InsertWindowContours(const ContourVector& contours,
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void MergeWindowContours(const std::vector<IfcVector2> &a,
|
void MergeWindowContours(const std::vector<IfcVector2> &a,
|
||||||
const std::vector<IfcVector2> &b,
|
const std::vector<IfcVector2> &b,
|
||||||
ClipperLib::ExPolygons& out)
|
ClipperLib::ExPolygons &out) {
|
||||||
{
|
|
||||||
out.clear();
|
out.clear();
|
||||||
|
|
||||||
ClipperLib::Clipper clipper;
|
ClipperLib::Clipper clipper;
|
||||||
|
@ -423,8 +397,7 @@ void MergeWindowContours (const std::vector<IfcVector2>& a,
|
||||||
// Subtract a from b
|
// Subtract a from b
|
||||||
void MakeDisjunctWindowContours(const std::vector<IfcVector2> &a,
|
void MakeDisjunctWindowContours(const std::vector<IfcVector2> &a,
|
||||||
const std::vector<IfcVector2> &b,
|
const std::vector<IfcVector2> &b,
|
||||||
ClipperLib::ExPolygons& out)
|
ClipperLib::ExPolygons &out) {
|
||||||
{
|
|
||||||
out.clear();
|
out.clear();
|
||||||
|
|
||||||
ClipperLib::Clipper clipper;
|
ClipperLib::Clipper clipper;
|
||||||
|
@ -454,8 +427,7 @@ void MakeDisjunctWindowContours (const std::vector<IfcVector2>& a,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void CleanupWindowContour(ProjectedWindowContour& window)
|
void CleanupWindowContour(ProjectedWindowContour &window) {
|
||||||
{
|
|
||||||
std::vector<IfcVector2> scratch;
|
std::vector<IfcVector2> scratch;
|
||||||
std::vector<IfcVector2> &contour = window.contour;
|
std::vector<IfcVector2> &contour = window.contour;
|
||||||
|
|
||||||
|
@ -489,23 +461,19 @@ void CleanupWindowContour(ProjectedWindowContour& window)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void CleanupWindowContours(ContourVector& contours)
|
void CleanupWindowContours(ContourVector &contours) {
|
||||||
{
|
|
||||||
// Use PolyClipper to clean up window contours
|
// Use PolyClipper to clean up window contours
|
||||||
try {
|
try {
|
||||||
for (ProjectedWindowContour &window : contours) {
|
for (ProjectedWindowContour &window : contours) {
|
||||||
CleanupWindowContour(window);
|
CleanupWindowContour(window);
|
||||||
}
|
}
|
||||||
}
|
} catch (const char *sx) {
|
||||||
catch (const char* sx) {
|
IFCImporter::LogError("error during polygon clipping, window shape may be wrong: (Clipper: " + std::string(sx) + ")");
|
||||||
IFCImporter::LogError("error during polygon clipping, window shape may be wrong: (Clipper: "
|
|
||||||
+ std::string(sx) + ")");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void CleanupOuterContour(const std::vector<IfcVector2>& contour_flat, TempMesh& curmesh)
|
void CleanupOuterContour(const std::vector<IfcVector2> &contour_flat, TempMesh &curmesh) {
|
||||||
{
|
|
||||||
std::vector<IfcVector3> vold;
|
std::vector<IfcVector3> vold;
|
||||||
std::vector<unsigned int> iold;
|
std::vector<unsigned int> iold;
|
||||||
|
|
||||||
|
@ -568,10 +536,8 @@ void CleanupOuterContour(const std::vector<IfcVector2>& contour_flat, TempMesh&
|
||||||
clipper.Clear();
|
clipper.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} catch (const char *sx) {
|
||||||
catch (const char* sx) {
|
IFCImporter::LogError("Ifc: error during polygon clipping, wall contour line may be wrong: (Clipper: " + std::string(sx) + ")");
|
||||||
IFCImporter::LogError("Ifc: error during polygon clipping, wall contour line may be wrong: (Clipper: "
|
|
||||||
+ std::string(sx) + ")");
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -586,12 +552,11 @@ typedef std::vector<OpeningRefs > OpeningRefVector;
|
||||||
|
|
||||||
typedef std::vector<std::pair<
|
typedef std::vector<std::pair<
|
||||||
ContourVector::const_iterator,
|
ContourVector::const_iterator,
|
||||||
Contour::const_iterator>
|
Contour::const_iterator>>
|
||||||
> ContourRefVector;
|
ContourRefVector;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
bool BoundingBoxesAdjacent(const BoundingBox& bb, const BoundingBox& ibb)
|
bool BoundingBoxesAdjacent(const BoundingBox &bb, const BoundingBox &ibb) {
|
||||||
{
|
|
||||||
// TODO: I'm pretty sure there is a much more compact way to check this
|
// TODO: I'm pretty sure there is a much more compact way to check this
|
||||||
const IfcFloat epsilon = Math::getEpsilon<float>();
|
const IfcFloat epsilon = Math::getEpsilon<float>();
|
||||||
return (std::fabs(bb.second.x - ibb.first.x) < epsilon && bb.first.y <= ibb.second.y && bb.second.y >= ibb.first.y) ||
|
return (std::fabs(bb.second.x - ibb.first.x) < epsilon && bb.first.y <= ibb.second.y && bb.second.y >= ibb.first.y) ||
|
||||||
|
@ -605,8 +570,7 @@ bool BoundingBoxesAdjacent(const BoundingBox& bb, const BoundingBox& ibb)
|
||||||
// output the intersection points on n0,n1
|
// output the intersection points on n0,n1
|
||||||
bool IntersectingLineSegments(const IfcVector2 &n0, const IfcVector2 &n1,
|
bool IntersectingLineSegments(const IfcVector2 &n0, const IfcVector2 &n1,
|
||||||
const IfcVector2 &m0, const IfcVector2 &m1,
|
const IfcVector2 &m0, const IfcVector2 &m1,
|
||||||
IfcVector2& out0, IfcVector2& out1)
|
IfcVector2 &out0, IfcVector2 &out1) {
|
||||||
{
|
|
||||||
const IfcVector2 n0_to_n1 = n1 - n0;
|
const IfcVector2 n0_to_n1 = n1 - n0;
|
||||||
|
|
||||||
const IfcVector2 n0_to_m0 = m0 - n0;
|
const IfcVector2 n0_to_m0 = m0 - n0;
|
||||||
|
@ -645,8 +609,7 @@ bool IntersectingLineSegments(const IfcVector2& n0, const IfcVector2& n1,
|
||||||
if (std::fabs(s1) == inf && std::fabs(n0_to_m1.x) < smalle) {
|
if (std::fabs(s1) == inf && std::fabs(n0_to_m1.x) < smalle) {
|
||||||
s1 = 0.;
|
s1 = 0.;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
s0 = n0_to_m0.y / n0_to_n1.y;
|
s0 = n0_to_m0.y / n0_to_n1.y;
|
||||||
s1 = n0_to_m1.y / n0_to_n1.y;
|
s1 = n0_to_m1.y / n0_to_n1.y;
|
||||||
|
|
||||||
|
@ -679,8 +642,7 @@ bool IntersectingLineSegments(const IfcVector2& n0, const IfcVector2& n1,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void FindAdjacentContours(ContourVector::iterator current, const ContourVector& contours)
|
void FindAdjacentContours(ContourVector::iterator current, const ContourVector &contours) {
|
||||||
{
|
|
||||||
const IfcFloat sqlen_epsilon = static_cast<IfcFloat>(Math::getEpsilon<float>());
|
const IfcFloat sqlen_epsilon = static_cast<IfcFloat>(Math::getEpsilon<float>());
|
||||||
const BoundingBox &bb = (*current).bb;
|
const BoundingBox &bb = (*current).bb;
|
||||||
|
|
||||||
|
@ -737,8 +699,7 @@ void FindAdjacentContours(ContourVector::iterator current, const ContourVector&
|
||||||
|
|
||||||
ncontour.insert(ncontour.begin() + n, isect0);
|
ncontour.insert(ncontour.begin() + n, isect0);
|
||||||
skiplist.insert(skiplist.begin() + n, true);
|
skiplist.insert(skiplist.begin() + n, true);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
skiplist[n] = true;
|
skiplist[n] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -756,15 +717,13 @@ void FindAdjacentContours(ContourVector::iterator current, const ContourVector&
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
AI_FORCE_INLINE bool LikelyBorder(const IfcVector2& vdelta)
|
AI_FORCE_INLINE bool LikelyBorder(const IfcVector2 &vdelta) {
|
||||||
{
|
|
||||||
const IfcFloat dot_point_epsilon = static_cast<IfcFloat>(Math::getEpsilon<float>());
|
const IfcFloat dot_point_epsilon = static_cast<IfcFloat>(Math::getEpsilon<float>());
|
||||||
return std::fabs(vdelta.x * vdelta.y) < dot_point_epsilon;
|
return std::fabs(vdelta.x * vdelta.y) < dot_point_epsilon;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void FindBorderContours(ContourVector::iterator current)
|
void FindBorderContours(ContourVector::iterator current) {
|
||||||
{
|
|
||||||
const IfcFloat border_epsilon_upper = static_cast<IfcFloat>(1 - 1e-4);
|
const IfcFloat border_epsilon_upper = static_cast<IfcFloat>(1 - 1e-4);
|
||||||
const IfcFloat border_epsilon_lower = static_cast<IfcFloat>(1e-4);
|
const IfcFloat border_epsilon_lower = static_cast<IfcFloat>(1e-4);
|
||||||
|
|
||||||
|
@ -790,14 +749,12 @@ void FindBorderContours(ContourVector::iterator current)
|
||||||
if (LikelyBorder(proj_point - last_proj_point)) {
|
if (LikelyBorder(proj_point - last_proj_point)) {
|
||||||
skiplist[std::distance(cbegin, cit) - 1] = true;
|
skiplist[std::distance(cbegin, cit) - 1] = true;
|
||||||
}
|
}
|
||||||
}
|
} else if (cit == cbegin) {
|
||||||
else if (cit == cbegin) {
|
|
||||||
start_on_outer_border = true;
|
start_on_outer_border = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
outer_border = true;
|
outer_border = true;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
outer_border = false;
|
outer_border = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -814,16 +771,14 @@ void FindBorderContours(ContourVector::iterator current)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
AI_FORCE_INLINE bool LikelyDiagonal(IfcVector2 vdelta)
|
AI_FORCE_INLINE bool LikelyDiagonal(IfcVector2 vdelta) {
|
||||||
{
|
|
||||||
vdelta.x = std::fabs(vdelta.x);
|
vdelta.x = std::fabs(vdelta.x);
|
||||||
vdelta.y = std::fabs(vdelta.y);
|
vdelta.y = std::fabs(vdelta.y);
|
||||||
return (std::fabs(vdelta.x - vdelta.y) < 0.8 * std::max(vdelta.x, vdelta.y));
|
return (std::fabs(vdelta.x - vdelta.y) < 0.8 * std::max(vdelta.x, vdelta.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void FindLikelyCrossingLines(ContourVector::iterator current)
|
void FindLikelyCrossingLines(ContourVector::iterator current) {
|
||||||
{
|
|
||||||
SkipList &skiplist = (*current).skiplist;
|
SkipList &skiplist = (*current).skiplist;
|
||||||
IfcVector2 last_proj_point;
|
IfcVector2 last_proj_point;
|
||||||
|
|
||||||
|
@ -851,8 +806,7 @@ void FindLikelyCrossingLines(ContourVector::iterator current)
|
||||||
size_t CloseWindows(ContourVector &contours,
|
size_t CloseWindows(ContourVector &contours,
|
||||||
const IfcMatrix4 &minv,
|
const IfcMatrix4 &minv,
|
||||||
OpeningRefVector &contours_to_openings,
|
OpeningRefVector &contours_to_openings,
|
||||||
TempMesh& curmesh)
|
TempMesh &curmesh) {
|
||||||
{
|
|
||||||
size_t closed = 0;
|
size_t closed = 0;
|
||||||
// For all contour points, check if one of the assigned openings does
|
// For all contour points, check if one of the assigned openings does
|
||||||
// already have points assigned to it. In this case, assume this is
|
// already have points assigned to it. In this case, assume this is
|
||||||
|
@ -961,8 +915,7 @@ size_t CloseWindows(ContourVector& contours,
|
||||||
if (drop_this_edge) {
|
if (drop_this_edge) {
|
||||||
curmesh.mVerts.pop_back();
|
curmesh.mVerts.pop_back();
|
||||||
curmesh.mVerts.pop_back();
|
curmesh.mVerts.pop_back();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
curmesh.mVerts.push_back(((cit == cbegin) != reverseCountourFaces) ? world_point : bestv);
|
curmesh.mVerts.push_back(((cit == cbegin) != reverseCountourFaces) ? world_point : bestv);
|
||||||
curmesh.mVerts.push_back(((cit == cbegin) != reverseCountourFaces) ? bestv : world_point);
|
curmesh.mVerts.push_back(((cit == cbegin) != reverseCountourFaces) ? bestv : world_point);
|
||||||
|
|
||||||
|
@ -989,15 +942,13 @@ size_t CloseWindows(ContourVector& contours,
|
||||||
curmesh.mVertcnt.pop_back();
|
curmesh.mVertcnt.pop_back();
|
||||||
curmesh.mVerts.pop_back();
|
curmesh.mVerts.pop_back();
|
||||||
curmesh.mVerts.pop_back();
|
curmesh.mVerts.pop_back();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
curmesh.mVerts.push_back(reverseCountourFaces ? start0 : start1);
|
curmesh.mVerts.push_back(reverseCountourFaces ? start0 : start1);
|
||||||
curmesh.mVerts.push_back(reverseCountourFaces ? start1 : start0);
|
curmesh.mVerts.push_back(reverseCountourFaces ? start1 : start0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
|
|
||||||
const Contour::const_iterator cbegin = (*it).contour.begin(), cend = (*it).contour.end();
|
const Contour::const_iterator cbegin = (*it).contour.begin(), cend = (*it).contour.end();
|
||||||
for (TempOpening *opening : refs) {
|
for (TempOpening *opening : refs) {
|
||||||
|
@ -1015,8 +966,7 @@ size_t CloseWindows(ContourVector& contours,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Quadrify(const std::vector< BoundingBox >& bbs, TempMesh& curmesh)
|
void Quadrify(const std::vector<BoundingBox> &bbs, TempMesh &curmesh) {
|
||||||
{
|
|
||||||
ai_assert(curmesh.IsEmpty());
|
ai_assert(curmesh.IsEmpty());
|
||||||
|
|
||||||
std::vector<IfcVector2> quads;
|
std::vector<IfcVector2> quads;
|
||||||
|
@ -1042,8 +992,7 @@ void Quadrify(const std::vector< BoundingBox >& bbs, TempMesh& curmesh)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Quadrify(const ContourVector& contours, TempMesh& curmesh)
|
void Quadrify(const ContourVector &contours, TempMesh &curmesh) {
|
||||||
{
|
|
||||||
std::vector<BoundingBox> bbs;
|
std::vector<BoundingBox> bbs;
|
||||||
bbs.reserve(contours.size());
|
bbs.reserve(contours.size());
|
||||||
|
|
||||||
|
@ -1056,8 +1005,7 @@ void Quadrify(const ContourVector& contours, TempMesh& curmesh)
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
IfcMatrix4 ProjectOntoPlane(std::vector<IfcVector2> &out_contour, const TempMesh &in_mesh,
|
IfcMatrix4 ProjectOntoPlane(std::vector<IfcVector2> &out_contour, const TempMesh &in_mesh,
|
||||||
bool &ok, IfcVector3& nor_out)
|
bool &ok, IfcVector3 &nor_out) {
|
||||||
{
|
|
||||||
const std::vector<IfcVector3> &in_verts = in_mesh.mVerts;
|
const std::vector<IfcVector3> &in_verts = in_mesh.mVerts;
|
||||||
ok = true;
|
ok = true;
|
||||||
|
|
||||||
|
@ -1073,7 +1021,6 @@ IfcMatrix4 ProjectOntoPlane(std::vector<IfcVector2>& out_contour, const TempMesh
|
||||||
IfcFloat zcoord = 0;
|
IfcFloat zcoord = 0;
|
||||||
out_contour.reserve(in_verts.size());
|
out_contour.reserve(in_verts.size());
|
||||||
|
|
||||||
|
|
||||||
IfcVector3 vmin, vmax;
|
IfcVector3 vmin, vmax;
|
||||||
MinMaxChooser<IfcVector3>()(vmin, vmax);
|
MinMaxChooser<IfcVector3>()(vmin, vmax);
|
||||||
|
|
||||||
|
@ -1144,8 +1091,7 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
|
||||||
TempMesh &curmesh,
|
TempMesh &curmesh,
|
||||||
bool check_intersection,
|
bool check_intersection,
|
||||||
bool generate_connection_geometry,
|
bool generate_connection_geometry,
|
||||||
const IfcVector3& wall_extrusion_axis)
|
const IfcVector3 &wall_extrusion_axis) {
|
||||||
{
|
|
||||||
OpeningRefVector contours_to_openings;
|
OpeningRefVector contours_to_openings;
|
||||||
|
|
||||||
// Try to derive a solid base plane within the current surface for use as
|
// Try to derive a solid base plane within the current surface for use as
|
||||||
|
@ -1163,14 +1109,12 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Obtain inverse transform for getting back to world space later on
|
// Obtain inverse transform for getting back to world space later on
|
||||||
const IfcMatrix4 minv = IfcMatrix4(m).Inverse();
|
const IfcMatrix4 mInverse = IfcMatrix4(m).Inverse();
|
||||||
|
|
||||||
// Compute bounding boxes for all 2D openings in projection space
|
// Compute bounding boxes for all 2D openings in projection space
|
||||||
ContourVector contours;
|
ContourVector contours;
|
||||||
|
|
||||||
std::vector<IfcVector2> temp_contour;
|
std::vector<IfcVector2> temp_contour, temp_contour2;
|
||||||
std::vector<IfcVector2> temp_contour2;
|
|
||||||
|
|
||||||
IfcVector3 wall_extrusion_axis_norm = wall_extrusion_axis;
|
IfcVector3 wall_extrusion_axis_norm = wall_extrusion_axis;
|
||||||
wall_extrusion_axis_norm.Normalize();
|
wall_extrusion_axis_norm.Normalize();
|
||||||
|
|
||||||
|
@ -1181,8 +1125,7 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
|
||||||
IfcVector3 norm_extrusion_dir = opening.extrusionDir;
|
IfcVector3 norm_extrusion_dir = opening.extrusionDir;
|
||||||
if (norm_extrusion_dir.SquareLength() > 1e-10) {
|
if (norm_extrusion_dir.SquareLength() > 1e-10) {
|
||||||
norm_extrusion_dir.Normalize();
|
norm_extrusion_dir.Normalize();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
norm_extrusion_dir = IfcVector3();
|
norm_extrusion_dir = IfcVector3();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1196,8 +1139,7 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
|
||||||
profile_data = opening.profileMesh2D.get();
|
profile_data = opening.profileMesh2D.get();
|
||||||
is_2d_source = true;
|
is_2d_source = true;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// vertical extrusion
|
// vertical extrusion
|
||||||
if (std::fabs(norm_extrusion_dir * nor) > 0.9) {
|
if (std::fabs(norm_extrusion_dir * nor) > 0.9) {
|
||||||
profile_data = opening.profileMesh2D.get();
|
profile_data = opening.profileMesh2D.get();
|
||||||
|
@ -1241,7 +1183,8 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
|
||||||
bool side_flag = true;
|
bool side_flag = true;
|
||||||
if (!is_2d_source) {
|
if (!is_2d_source) {
|
||||||
const IfcVector3 face_nor = ((profile_verts[vi_total + 2] - profile_verts[vi_total]) ^
|
const IfcVector3 face_nor = ((profile_verts[vi_total + 2] - profile_verts[vi_total]) ^
|
||||||
(profile_verts[vi_total+1] - profile_verts[vi_total])).Normalize();
|
(profile_verts[vi_total + 1] - profile_verts[vi_total]))
|
||||||
|
.Normalize();
|
||||||
|
|
||||||
const IfcFloat abs_dot_face_nor = std::abs(nor * face_nor);
|
const IfcFloat abs_dot_face_nor = std::abs(nor * face_nor);
|
||||||
if (abs_dot_face_nor < 0.9) {
|
if (abs_dot_face_nor < 0.9) {
|
||||||
|
@ -1270,8 +1213,7 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
|
||||||
if (side_flag) {
|
if (side_flag) {
|
||||||
vpmin = std::min(vpmin, vv);
|
vpmin = std::min(vpmin, vv);
|
||||||
vpmax = std::max(vpmax, vv);
|
vpmax = std::max(vpmax, vv);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
vpmin2 = std::min(vpmin2, vv);
|
vpmin2 = std::min(vpmin2, vv);
|
||||||
vpmax2 = std::max(vpmax2, vv);
|
vpmax2 = std::max(vpmax2, vv);
|
||||||
}
|
}
|
||||||
|
@ -1335,7 +1277,7 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
|
||||||
MakeDisjunctWindowContours(other, temp_contour, poly);
|
MakeDisjunctWindowContours(other, temp_contour, poly);
|
||||||
if (poly.size() == 1) {
|
if (poly.size() == 1) {
|
||||||
|
|
||||||
const BoundingBox newbb = GetBoundingBox(poly[0].outer);
|
const BoundingBox newbb = GetBoundingBox2D(poly[0].outer);
|
||||||
if (!BoundingBoxesOverlapping(ibb, newbb)) {
|
if (!BoundingBoxesOverlapping(ibb, newbb)) {
|
||||||
// Good guy bounding box
|
// Good guy bounding box
|
||||||
bb = newbb;
|
bb = newbb;
|
||||||
|
@ -1352,13 +1294,11 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
|
||||||
|
|
||||||
if (poly.size() > 1) {
|
if (poly.size() > 1) {
|
||||||
return TryAddOpenings_Poly2Tri(openings, nors, curmesh);
|
return TryAddOpenings_Poly2Tri(openings, nors, curmesh);
|
||||||
}
|
} else if (poly.size() == 0) {
|
||||||
else if (poly.size() == 0) {
|
|
||||||
IFCImporter::LogWarn("ignoring duplicate opening");
|
IFCImporter::LogWarn("ignoring duplicate opening");
|
||||||
temp_contour.clear();
|
temp_contour.clear();
|
||||||
break;
|
break;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
IFCImporter::LogVerboseDebug("merging overlapping openings");
|
IFCImporter::LogVerboseDebug("merging overlapping openings");
|
||||||
ExtractVerticesFromClipper(poly[0].outer, temp_contour, false);
|
ExtractVerticesFromClipper(poly[0].outer, temp_contour, false);
|
||||||
|
|
||||||
|
@ -1427,21 +1367,20 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
|
||||||
|
|
||||||
// Undo the projection and get back to world (or local object) space
|
// Undo the projection and get back to world (or local object) space
|
||||||
for (IfcVector3 &v3 : curmesh.mVerts) {
|
for (IfcVector3 &v3 : curmesh.mVerts) {
|
||||||
v3 = minv * v3;
|
v3 = mInverse * v3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate window caps to connect the symmetric openings on both sides
|
// Generate window caps to connect the symmetric openings on both sides
|
||||||
// of the wall.
|
// of the wall.
|
||||||
if (generate_connection_geometry) {
|
if (generate_connection_geometry) {
|
||||||
CloseWindows(contours, minv, contours_to_openings, curmesh);
|
CloseWindows(contours, mInverse, contours_to_openings, curmesh);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening> &openings, const std::vector<IfcVector3> &nors,
|
bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening> &openings, const std::vector<IfcVector3> &nors,
|
||||||
TempMesh& curmesh)
|
TempMesh &curmesh) {
|
||||||
{
|
|
||||||
IFCImporter::LogWarn("forced to use poly2tri fallback method to generate wall openings");
|
IFCImporter::LogWarn("forced to use poly2tri fallback method to generate wall openings");
|
||||||
std::vector<IfcVector3> &out = curmesh.mVerts;
|
std::vector<IfcVector3> &out = curmesh.mVerts;
|
||||||
|
|
||||||
|
@ -1456,8 +1395,7 @@ bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,const std:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const IfcMatrix3 minv = IfcMatrix3(m).Inverse();
|
const IfcMatrix3 mInverse = IfcMatrix3(m).Inverse();
|
||||||
|
|
||||||
|
|
||||||
IfcFloat coord = -1;
|
IfcFloat coord = -1;
|
||||||
|
|
||||||
|
@ -1475,7 +1413,6 @@ bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,const std:
|
||||||
// (which are present, of course), this should be the same value for
|
// (which are present, of course), this should be the same value for
|
||||||
// all polygon vertices (assuming the polygon is planar).
|
// all polygon vertices (assuming the polygon is planar).
|
||||||
|
|
||||||
|
|
||||||
// XXX this should be guarded, but we somehow need to pick a suitable
|
// XXX this should be guarded, but we somehow need to pick a suitable
|
||||||
// epsilon
|
// epsilon
|
||||||
// if(coord != -1.0f) {
|
// if(coord != -1.0f) {
|
||||||
|
@ -1502,7 +1439,6 @@ bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,const std:
|
||||||
ClipperLib::ExPolygons clipped;
|
ClipperLib::ExPolygons clipped;
|
||||||
ClipperLib::Polygons holes_union;
|
ClipperLib::Polygons holes_union;
|
||||||
|
|
||||||
|
|
||||||
IfcVector3 wall_extrusion;
|
IfcVector3 wall_extrusion;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
|
||||||
|
@ -1597,10 +1533,8 @@ bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,const std:
|
||||||
ClipperLib::pftNonZero);
|
ClipperLib::pftNonZero);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} catch (const char *sx) {
|
||||||
catch (const char* sx) {
|
IFCImporter::LogError("Ifc: error during polygon clipping, skipping openings for this face: (Clipper: " + std::string(sx) + ")");
|
||||||
IFCImporter::LogError("Ifc: error during polygon clipping, skipping openings for this face: (Clipper: "
|
|
||||||
+ std::string(sx) + ")");
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1629,14 +1563,11 @@ bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,const std:
|
||||||
// happen in production use if the input data is broken. An assertion would be
|
// happen in production use if the input data is broken. An assertion would be
|
||||||
// inappropriate.
|
// inappropriate.
|
||||||
cdt = new p2t::CDT(contour_points);
|
cdt = new p2t::CDT(contour_points);
|
||||||
}
|
} catch (const std::exception &e) {
|
||||||
catch(const std::exception& e) {
|
IFCImporter::LogError("Ifc: error during polygon triangulation, skipping some openings: (poly2tri: " + std::string(e.what()) + ")");
|
||||||
IFCImporter::LogError("Ifc: error during polygon triangulation, skipping some openings: (poly2tri: "
|
|
||||||
+ std::string(e.what()) + ")");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Build the poly2tri inner contours for all holes we got from ClipperLib
|
// Build the poly2tri inner contours for all holes we got from ClipperLib
|
||||||
for (ClipperLib::Polygon &opening : clip.holes) {
|
for (ClipperLib::Polygon &opening : clip.holes) {
|
||||||
|
|
||||||
|
@ -1653,10 +1584,8 @@ bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,const std:
|
||||||
try {
|
try {
|
||||||
// Note: See above
|
// Note: See above
|
||||||
cdt->Triangulate();
|
cdt->Triangulate();
|
||||||
}
|
} catch (const std::exception &e) {
|
||||||
catch(const std::exception& e) {
|
IFCImporter::LogError("Ifc: error during polygon triangulation, skipping some openings: (poly2tri: " + std::string(e.what()) + ")");
|
||||||
IFCImporter::LogError("Ifc: error during polygon triangulation, skipping some openings: (poly2tri: "
|
|
||||||
+ std::string(e.what()) + ")");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1668,11 +1597,10 @@ bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,const std:
|
||||||
|
|
||||||
const IfcVector2 v = IfcVector2(
|
const IfcVector2 v = IfcVector2(
|
||||||
static_cast<IfcFloat>(tri->GetPoint(i)->x),
|
static_cast<IfcFloat>(tri->GetPoint(i)->x),
|
||||||
static_cast<IfcFloat>( tri->GetPoint(i)->y )
|
static_cast<IfcFloat>(tri->GetPoint(i)->y));
|
||||||
);
|
|
||||||
|
|
||||||
ai_assert(v.x <= 1.0 && v.x >= 0.0 && v.y <= 1.0 && v.y >= 0.0);
|
ai_assert(v.x <= 1.0 && v.x >= 0.0 && v.y <= 1.0 && v.y >= 0.0);
|
||||||
const IfcVector3 v3 = minv * IfcVector3(vmin.x + v.x * vmax.x, vmin.y + v.y * vmax.y,coord) ;
|
const IfcVector3 v3 = mInverse * IfcVector3(vmin.x + v.x * vmax.x, vmin.y + v.y * vmax.y, coord);
|
||||||
|
|
||||||
curmesh.mVerts.push_back(v3);
|
curmesh.mVerts.push_back(v3);
|
||||||
}
|
}
|
||||||
|
@ -1693,9 +1621,8 @@ bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,const std:
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace IFC
|
||||||
} // ! IFC
|
} // namespace Assimp
|
||||||
} // ! Assimp
|
|
||||||
|
|
||||||
#undef to_int64
|
#undef to_int64
|
||||||
#undef from_int64
|
#undef from_int64
|
||||||
|
|
|
@ -66,8 +66,7 @@ void TempOpening::Transform(const IfcMatrix4& mat) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
aiMesh* TempMesh::ToMesh()
|
aiMesh *TempMesh::ToMesh() {
|
||||||
{
|
|
||||||
ai_assert(mVerts.size() == std::accumulate(mVertcnt.begin(), mVertcnt.end(), size_t(0)));
|
ai_assert(mVerts.size() == std::accumulate(mVertcnt.begin(), mVertcnt.end(), size_t(0)));
|
||||||
|
|
||||||
if (mVerts.empty()) {
|
if (mVerts.empty()) {
|
||||||
|
@ -105,36 +104,31 @@ aiMesh* TempMesh::ToMesh()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void TempMesh::Clear()
|
void TempMesh::Clear() {
|
||||||
{
|
|
||||||
mVerts.clear();
|
mVerts.clear();
|
||||||
mVertcnt.clear();
|
mVertcnt.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void TempMesh::Transform(const IfcMatrix4& mat)
|
void TempMesh::Transform(const IfcMatrix4 &mat) {
|
||||||
{
|
|
||||||
for (IfcVector3 &v : mVerts) {
|
for (IfcVector3 &v : mVerts) {
|
||||||
v *= mat;
|
v *= mat;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------
|
||||||
IfcVector3 TempMesh::Center() const
|
IfcVector3 TempMesh::Center() const {
|
||||||
{
|
|
||||||
return (mVerts.size() == 0) ? IfcVector3(0.0f, 0.0f, 0.0f) : (std::accumulate(mVerts.begin(), mVerts.end(), IfcVector3()) / static_cast<IfcFloat>(mVerts.size()));
|
return (mVerts.size() == 0) ? IfcVector3(0.0f, 0.0f, 0.0f) : (std::accumulate(mVerts.begin(), mVerts.end(), IfcVector3()) / static_cast<IfcFloat>(mVerts.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void TempMesh::Append(const TempMesh& other)
|
void TempMesh::Append(const TempMesh &other) {
|
||||||
{
|
|
||||||
mVerts.insert(mVerts.end(), other.mVerts.begin(), other.mVerts.end());
|
mVerts.insert(mVerts.end(), other.mVerts.begin(), other.mVerts.end());
|
||||||
mVertcnt.insert(mVertcnt.end(), other.mVertcnt.begin(), other.mVertcnt.end());
|
mVertcnt.insert(mVertcnt.end(), other.mVertcnt.begin(), other.mVertcnt.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void TempMesh::RemoveDegenerates()
|
void TempMesh::RemoveDegenerates() {
|
||||||
{
|
|
||||||
// The strategy is simple: walk the mesh and compute normals using
|
// The strategy is simple: walk the mesh and compute normals using
|
||||||
// Newell's algorithm. The length of the normals gives the area
|
// Newell's algorithm. The length of the normals gives the area
|
||||||
// of the polygons, which is close to zero for lines.
|
// of the polygons, which is close to zero for lines.
|
||||||
|
@ -167,11 +161,10 @@ void TempMesh::RemoveDegenerates()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
IfcVector3 TempMesh::ComputePolygonNormal(const IfcVector3* vtcs, size_t cnt, bool normalize)
|
IfcVector3 TempMesh::ComputePolygonNormal(const IfcVector3 *vtcs, size_t cnt, bool normalize) {
|
||||||
{
|
const size_t Capa = cnt + 2;
|
||||||
std::vector<IfcFloat> temp((cnt+2)*3);
|
std::vector<IfcFloat> temp((Capa)*3);
|
||||||
for( size_t vofs = 0, i = 0; vofs < cnt; ++vofs )
|
for (size_t vofs = 0, i = 0; vofs < cnt; ++vofs) {
|
||||||
{
|
|
||||||
const IfcVector3 &v = vtcs[vofs];
|
const IfcVector3 &v = vtcs[vofs];
|
||||||
temp[i++] = v.x;
|
temp[i++] = v.x;
|
||||||
temp[i++] = v.y;
|
temp[i++] = v.y;
|
||||||
|
@ -179,22 +172,19 @@ IfcVector3 TempMesh::ComputePolygonNormal(const IfcVector3* vtcs, size_t cnt, bo
|
||||||
}
|
}
|
||||||
|
|
||||||
IfcVector3 nor;
|
IfcVector3 nor;
|
||||||
NewellNormal<3, 3, 3>(nor, static_cast<int>(cnt), &temp[0], &temp[1], &temp[2]);
|
NewellNormal<3, 3, 3>(nor, static_cast<int>(cnt), &temp[0], &temp[1], &temp[2], Capa);
|
||||||
return normalize ? nor.Normalize() : nor;
|
return normalize ? nor.Normalize() : nor;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void TempMesh::ComputePolygonNormals(std::vector<IfcVector3>& normals,
|
void TempMesh::ComputePolygonNormals(std::vector<IfcVector3> &normals, bool normalize, size_t ofs) const {
|
||||||
bool normalize,
|
|
||||||
size_t ofs) const
|
|
||||||
{
|
|
||||||
size_t max_vcount = 0;
|
size_t max_vcount = 0;
|
||||||
std::vector<unsigned int>::const_iterator begin = mVertcnt.begin() + ofs, end = mVertcnt.end(), iit;
|
std::vector<unsigned int>::const_iterator begin = mVertcnt.begin() + ofs, end = mVertcnt.end(), iit;
|
||||||
for (iit = begin; iit != end; ++iit) {
|
for (iit = begin; iit != end; ++iit) {
|
||||||
max_vcount = std::max(max_vcount, static_cast<size_t>(*iit));
|
max_vcount = std::max(max_vcount, static_cast<size_t>(*iit));
|
||||||
}
|
}
|
||||||
|
const size_t Capa = max_vcount + 2;
|
||||||
std::vector<IfcFloat> temp((max_vcount+2)*4);
|
std::vector<IfcFloat> temp(Capa * 4);
|
||||||
normals.reserve(normals.size() + mVertcnt.size() - ofs);
|
normals.reserve(normals.size() + mVertcnt.size() - ofs);
|
||||||
|
|
||||||
// `NewellNormal()` currently has a relatively strange interface and need to
|
// `NewellNormal()` currently has a relatively strange interface and need to
|
||||||
|
@ -202,7 +192,7 @@ void TempMesh::ComputePolygonNormals(std::vector<IfcVector3>& normals,
|
||||||
size_t vidx = std::accumulate(mVertcnt.begin(), begin, 0);
|
size_t vidx = std::accumulate(mVertcnt.begin(), begin, 0);
|
||||||
for (iit = begin; iit != end; vidx += *iit++) {
|
for (iit = begin; iit != end; vidx += *iit++) {
|
||||||
if (!*iit) {
|
if (!*iit) {
|
||||||
normals.push_back(IfcVector3());
|
normals.emplace_back();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (size_t vofs = 0, cnt = 0; vofs < *iit; ++vofs) {
|
for (size_t vofs = 0, cnt = 0; vofs < *iit; ++vofs) {
|
||||||
|
@ -216,8 +206,8 @@ void TempMesh::ComputePolygonNormals(std::vector<IfcVector3>& normals,
|
||||||
++cnt;
|
++cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
normals.push_back(IfcVector3());
|
normals.emplace_back();
|
||||||
NewellNormal<4,4,4>(normals.back(),*iit,&temp[0],&temp[1],&temp[2]);
|
NewellNormal<4, 4, 4>(normals.back(), *iit, &temp[0], &temp[1], &temp[2], Capa);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalize) {
|
if (normalize) {
|
||||||
|
@ -229,30 +219,26 @@ void TempMesh::ComputePolygonNormals(std::vector<IfcVector3>& normals,
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Compute the normal of the last polygon in the given mesh
|
// Compute the normal of the last polygon in the given mesh
|
||||||
IfcVector3 TempMesh::ComputeLastPolygonNormal(bool normalize) const
|
IfcVector3 TempMesh::ComputeLastPolygonNormal(bool normalize) const {
|
||||||
{
|
|
||||||
return ComputePolygonNormal(&mVerts[mVerts.size() - mVertcnt.back()], mVertcnt.back(), normalize);
|
return ComputePolygonNormal(&mVerts[mVerts.size() - mVertcnt.back()], mVertcnt.back(), normalize);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CompareVector
|
struct CompareVector {
|
||||||
{
|
bool operator()(const IfcVector3 &a, const IfcVector3 &b) const {
|
||||||
bool operator () (const IfcVector3& a, const IfcVector3& b) const
|
|
||||||
{
|
|
||||||
IfcVector3 d = a - b;
|
IfcVector3 d = a - b;
|
||||||
IfcFloat eps = 1e-6;
|
IfcFloat eps = 1e-6;
|
||||||
return d.x < -eps || (std::abs(d.x) < eps && d.y < -eps) || (std::abs(d.x) < eps && std::abs(d.y) < eps && d.z < -eps);
|
return d.x < -eps || (std::abs(d.x) < eps && d.y < -eps) || (std::abs(d.x) < eps && std::abs(d.y) < eps && d.z < -eps);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
struct FindVector
|
struct FindVector {
|
||||||
{
|
|
||||||
IfcVector3 v;
|
IfcVector3 v;
|
||||||
FindVector(const IfcVector3& p) : v(p) { }
|
FindVector(const IfcVector3 &p) :
|
||||||
|
v(p) {}
|
||||||
bool operator()(const IfcVector3 &p) { return FuzzyVectorCompare(1e-6)(p, v); }
|
bool operator()(const IfcVector3 &p) { return FuzzyVectorCompare(1e-6)(p, v); }
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void TempMesh::FixupFaceOrientation()
|
void TempMesh::FixupFaceOrientation() {
|
||||||
{
|
|
||||||
const IfcVector3 vavg = Center();
|
const IfcVector3 vavg = Center();
|
||||||
|
|
||||||
// create a list of start indices for all faces to allow random access to faces
|
// create a list of start indices for all faces to allow random access to faces
|
||||||
|
@ -262,18 +248,15 @@ void TempMesh::FixupFaceOrientation()
|
||||||
|
|
||||||
// list all faces on a vertex
|
// list all faces on a vertex
|
||||||
std::map<IfcVector3, std::vector<size_t>, CompareVector> facesByVertex;
|
std::map<IfcVector3, std::vector<size_t>, CompareVector> facesByVertex;
|
||||||
for( size_t a = 0; a < mVertcnt.size(); ++a )
|
for (size_t a = 0; a < mVertcnt.size(); ++a) {
|
||||||
{
|
|
||||||
for (size_t b = 0; b < mVertcnt[a]; ++b)
|
for (size_t b = 0; b < mVertcnt[a]; ++b)
|
||||||
facesByVertex[mVerts[faceStartIndices[a] + b]].push_back(a);
|
facesByVertex[mVerts[faceStartIndices[a] + b]].push_back(a);
|
||||||
}
|
}
|
||||||
// determine neighbourhood for all polys
|
// determine neighbourhood for all polys
|
||||||
std::vector<size_t> neighbour(mVerts.size(), SIZE_MAX);
|
std::vector<size_t> neighbour(mVerts.size(), SIZE_MAX);
|
||||||
std::vector<size_t> tempIntersect(10);
|
std::vector<size_t> tempIntersect(10);
|
||||||
for( size_t a = 0; a < mVertcnt.size(); ++a )
|
for (size_t a = 0; a < mVertcnt.size(); ++a) {
|
||||||
{
|
for (size_t b = 0; b < mVertcnt[a]; ++b) {
|
||||||
for( size_t b = 0; b < mVertcnt[a]; ++b )
|
|
||||||
{
|
|
||||||
size_t ib = faceStartIndices[a] + b, nib = faceStartIndices[a] + (b + 1) % mVertcnt[a];
|
size_t ib = faceStartIndices[a] + b, nib = faceStartIndices[a] + (b + 1) % mVertcnt[a];
|
||||||
const std::vector<size_t> &facesOnB = facesByVertex[mVerts[ib]];
|
const std::vector<size_t> &facesOnB = facesByVertex[mVerts[ib]];
|
||||||
const std::vector<size_t> &facesOnNB = facesByVertex[mVerts[nib]];
|
const std::vector<size_t> &facesOnNB = facesByVertex[mVerts[nib]];
|
||||||
|
@ -294,30 +277,31 @@ void TempMesh::FixupFaceOrientation()
|
||||||
// facing outwards. So we reverse this face to point outwards in relation to the center. Then we adapt neighbouring
|
// facing outwards. So we reverse this face to point outwards in relation to the center. Then we adapt neighbouring
|
||||||
// faces to have the same winding until all faces have been tested.
|
// faces to have the same winding until all faces have been tested.
|
||||||
std::vector<bool> faceDone(mVertcnt.size(), false);
|
std::vector<bool> faceDone(mVertcnt.size(), false);
|
||||||
while( std::count(faceDone.begin(), faceDone.end(), false) != 0 )
|
while (std::count(faceDone.begin(), faceDone.end(), false) != 0) {
|
||||||
{
|
|
||||||
// find the farthest of the remaining faces
|
// find the farthest of the remaining faces
|
||||||
size_t farthestIndex = SIZE_MAX;
|
size_t farthestIndex = SIZE_MAX;
|
||||||
IfcFloat farthestDistance = -1.0;
|
IfcFloat farthestDistance = -1.0;
|
||||||
for( size_t a = 0; a < mVertcnt.size(); ++a )
|
for (size_t a = 0; a < mVertcnt.size(); ++a) {
|
||||||
{
|
|
||||||
if (faceDone[a])
|
if (faceDone[a])
|
||||||
continue;
|
continue;
|
||||||
IfcVector3 faceCenter = std::accumulate(mVerts.begin() + faceStartIndices[a],
|
IfcVector3 faceCenter = std::accumulate(mVerts.begin() + faceStartIndices[a],
|
||||||
mVerts.begin() + faceStartIndices[a] + mVertcnt[a], IfcVector3(0.0)) / IfcFloat(mVertcnt[a]);
|
mVerts.begin() + faceStartIndices[a] + mVertcnt[a], IfcVector3(0.0)) /
|
||||||
|
IfcFloat(mVertcnt[a]);
|
||||||
IfcFloat dst = (faceCenter - vavg).SquareLength();
|
IfcFloat dst = (faceCenter - vavg).SquareLength();
|
||||||
if( dst > farthestDistance ) { farthestDistance = dst; farthestIndex = a; }
|
if (dst > farthestDistance) {
|
||||||
|
farthestDistance = dst;
|
||||||
|
farthestIndex = a;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate its normal and reverse the poly if its facing towards the mesh center
|
// calculate its normal and reverse the poly if its facing towards the mesh center
|
||||||
IfcVector3 farthestNormal = ComputePolygonNormal(mVerts.data() + faceStartIndices[farthestIndex], mVertcnt[farthestIndex]);
|
IfcVector3 farthestNormal = ComputePolygonNormal(mVerts.data() + faceStartIndices[farthestIndex], mVertcnt[farthestIndex]);
|
||||||
IfcVector3 farthestCenter = std::accumulate(mVerts.begin() + faceStartIndices[farthestIndex],
|
IfcVector3 farthestCenter = std::accumulate(mVerts.begin() + faceStartIndices[farthestIndex],
|
||||||
mVerts.begin() + faceStartIndices[farthestIndex] + mVertcnt[farthestIndex], IfcVector3(0.0))
|
mVerts.begin() + faceStartIndices[farthestIndex] + mVertcnt[farthestIndex], IfcVector3(0.0)) /
|
||||||
/ IfcFloat(mVertcnt[farthestIndex]);
|
IfcFloat(mVertcnt[farthestIndex]);
|
||||||
// We accept a bit of negative orientation without reversing. In case of doubt, prefer the orientation given in
|
// We accept a bit of negative orientation without reversing. In case of doubt, prefer the orientation given in
|
||||||
// the file.
|
// the file.
|
||||||
if( (farthestNormal * (farthestCenter - vavg).Normalize()) < -0.4 )
|
if ((farthestNormal * (farthestCenter - vavg).Normalize()) < -0.4) {
|
||||||
{
|
|
||||||
size_t fsi = faceStartIndices[farthestIndex], fvc = mVertcnt[farthestIndex];
|
size_t fsi = faceStartIndices[farthestIndex], fvc = mVertcnt[farthestIndex];
|
||||||
std::reverse(mVerts.begin() + fsi, mVerts.begin() + fsi + fvc);
|
std::reverse(mVerts.begin() + fsi, mVerts.begin() + fsi + fvc);
|
||||||
std::reverse(neighbour.begin() + fsi, neighbour.begin() + fsi + fvc);
|
std::reverse(neighbour.begin() + fsi, neighbour.begin() + fsi + fvc);
|
||||||
|
@ -334,15 +318,13 @@ void TempMesh::FixupFaceOrientation()
|
||||||
todo.push_back(farthestIndex);
|
todo.push_back(farthestIndex);
|
||||||
|
|
||||||
// go over its neighbour faces recursively and adapt their winding order to match the farthest face
|
// go over its neighbour faces recursively and adapt their winding order to match the farthest face
|
||||||
while( !todo.empty() )
|
while (!todo.empty()) {
|
||||||
{
|
|
||||||
size_t tdf = todo.back();
|
size_t tdf = todo.back();
|
||||||
size_t vsi = faceStartIndices[tdf], vc = mVertcnt[tdf];
|
size_t vsi = faceStartIndices[tdf], vc = mVertcnt[tdf];
|
||||||
todo.pop_back();
|
todo.pop_back();
|
||||||
|
|
||||||
// check its neighbours
|
// check its neighbours
|
||||||
for( size_t a = 0; a < vc; ++a )
|
for (size_t a = 0; a < vc; ++a) {
|
||||||
{
|
|
||||||
// ignore neighbours if we already checked them
|
// ignore neighbours if we already checked them
|
||||||
size_t nbi = neighbour[vsi + a];
|
size_t nbi = neighbour[vsi + a];
|
||||||
if (nbi == SIZE_MAX || faceDone[nbi])
|
if (nbi == SIZE_MAX || faceDone[nbi])
|
||||||
|
@ -358,8 +340,7 @@ void TempMesh::FixupFaceOrientation()
|
||||||
// to reverse the neighbour
|
// to reverse the neighbour
|
||||||
nb_vidx = (nb_vidx + 1) % nbvc;
|
nb_vidx = (nb_vidx + 1) % nbvc;
|
||||||
size_t oursideidx = (a + 1) % vc;
|
size_t oursideidx = (a + 1) % vc;
|
||||||
if( FuzzyVectorCompare(1e-6)(mVerts[vsi + oursideidx], mVerts[nbvsi + nb_vidx]) )
|
if (FuzzyVectorCompare(1e-6)(mVerts[vsi + oursideidx], mVerts[nbvsi + nb_vidx])) {
|
||||||
{
|
|
||||||
std::reverse(mVerts.begin() + nbvsi, mVerts.begin() + nbvsi + nbvc);
|
std::reverse(mVerts.begin() + nbvsi, mVerts.begin() + nbvsi + nbvc);
|
||||||
std::reverse(neighbour.begin() + nbvsi, neighbour.begin() + nbvsi + nbvc);
|
std::reverse(neighbour.begin() + nbvsi, neighbour.begin() + nbvsi + nbvc);
|
||||||
for (size_t aa = 0; aa < nbvc - 1; ++aa) {
|
for (size_t aa = 0; aa < nbvc - 1; ++aa) {
|
||||||
|
@ -390,7 +371,6 @@ void TempMesh::RemoveAdjacentDuplicates() {
|
||||||
IfcVector3 vmin, vmax;
|
IfcVector3 vmin, vmax;
|
||||||
ArrayBounds(&*base, cnt, vmin, vmax);
|
ArrayBounds(&*base, cnt, vmin, vmax);
|
||||||
|
|
||||||
|
|
||||||
const IfcFloat epsilon = (vmax - vmin).SquareLength() / static_cast<IfcFloat>(1e9);
|
const IfcFloat epsilon = (vmax - vmin).SquareLength() / static_cast<IfcFloat>(1e9);
|
||||||
//const IfcFloat dotepsilon = 1e-9;
|
//const IfcFloat dotepsilon = 1e-9;
|
||||||
|
|
||||||
|
@ -442,78 +422,58 @@ void TempMesh::RemoveAdjacentDuplicates() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void TempMesh::Swap(TempMesh& other)
|
void TempMesh::Swap(TempMesh &other) {
|
||||||
{
|
|
||||||
mVertcnt.swap(other.mVertcnt);
|
mVertcnt.swap(other.mVertcnt);
|
||||||
mVerts.swap(other.mVerts);
|
mVerts.swap(other.mVerts);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
bool IsTrue(const ::Assimp::STEP::EXPRESS::BOOLEAN& in)
|
bool IsTrue(const ::Assimp::STEP::EXPRESS::BOOLEAN &in) {
|
||||||
{
|
|
||||||
return (std::string)in == "TRUE" || (std::string)in == "T";
|
return (std::string)in == "TRUE" || (std::string)in == "T";
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
IfcFloat ConvertSIPrefix(const std::string& prefix)
|
IfcFloat ConvertSIPrefix(const std::string &prefix) {
|
||||||
{
|
|
||||||
if (prefix == "EXA") {
|
if (prefix == "EXA") {
|
||||||
return 1e18f;
|
return 1e18f;
|
||||||
}
|
} else if (prefix == "PETA") {
|
||||||
else if (prefix == "PETA") {
|
|
||||||
return 1e15f;
|
return 1e15f;
|
||||||
}
|
} else if (prefix == "TERA") {
|
||||||
else if (prefix == "TERA") {
|
|
||||||
return 1e12f;
|
return 1e12f;
|
||||||
}
|
} else if (prefix == "GIGA") {
|
||||||
else if (prefix == "GIGA") {
|
|
||||||
return 1e9f;
|
return 1e9f;
|
||||||
}
|
} else if (prefix == "MEGA") {
|
||||||
else if (prefix == "MEGA") {
|
|
||||||
return 1e6f;
|
return 1e6f;
|
||||||
}
|
} else if (prefix == "KILO") {
|
||||||
else if (prefix == "KILO") {
|
|
||||||
return 1e3f;
|
return 1e3f;
|
||||||
}
|
} else if (prefix == "HECTO") {
|
||||||
else if (prefix == "HECTO") {
|
|
||||||
return 1e2f;
|
return 1e2f;
|
||||||
}
|
} else if (prefix == "DECA") {
|
||||||
else if (prefix == "DECA") {
|
|
||||||
return 1e-0f;
|
return 1e-0f;
|
||||||
}
|
} else if (prefix == "DECI") {
|
||||||
else if (prefix == "DECI") {
|
|
||||||
return 1e-1f;
|
return 1e-1f;
|
||||||
}
|
} else if (prefix == "CENTI") {
|
||||||
else if (prefix == "CENTI") {
|
|
||||||
return 1e-2f;
|
return 1e-2f;
|
||||||
}
|
} else if (prefix == "MILLI") {
|
||||||
else if (prefix == "MILLI") {
|
|
||||||
return 1e-3f;
|
return 1e-3f;
|
||||||
}
|
} else if (prefix == "MICRO") {
|
||||||
else if (prefix == "MICRO") {
|
|
||||||
return 1e-6f;
|
return 1e-6f;
|
||||||
}
|
} else if (prefix == "NANO") {
|
||||||
else if (prefix == "NANO") {
|
|
||||||
return 1e-9f;
|
return 1e-9f;
|
||||||
}
|
} else if (prefix == "PICO") {
|
||||||
else if (prefix == "PICO") {
|
|
||||||
return 1e-12f;
|
return 1e-12f;
|
||||||
}
|
} else if (prefix == "FEMTO") {
|
||||||
else if (prefix == "FEMTO") {
|
|
||||||
return 1e-15f;
|
return 1e-15f;
|
||||||
}
|
} else if (prefix == "ATTO") {
|
||||||
else if (prefix == "ATTO") {
|
|
||||||
return 1e-18f;
|
return 1e-18f;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
IFCImporter::LogError("Unrecognized SI prefix: " + prefix);
|
IFCImporter::LogError("Unrecognized SI prefix: " + prefix);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ConvertColor(aiColor4D& out, const Schema_2x3::IfcColourRgb& in)
|
void ConvertColor(aiColor4D &out, const Schema_2x3::IfcColourRgb &in) {
|
||||||
{
|
|
||||||
out.r = static_cast<float>(in.Red);
|
out.r = static_cast<float>(in.Red);
|
||||||
out.g = static_cast<float>(in.Green);
|
out.g = static_cast<float>(in.Green);
|
||||||
out.b = static_cast<float>(in.Blue);
|
out.b = static_cast<float>(in.Blue);
|
||||||
|
@ -521,8 +481,7 @@ void ConvertColor(aiColor4D& out, const Schema_2x3::IfcColourRgb& in)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ConvertColor(aiColor4D& out, const Schema_2x3::IfcColourOrFactor& in,ConversionData& conv,const aiColor4D* base)
|
void ConvertColor(aiColor4D &out, const Schema_2x3::IfcColourOrFactor &in, ConversionData &conv, const aiColor4D *base) {
|
||||||
{
|
|
||||||
if (const ::Assimp::STEP::EXPRESS::REAL *const r = in.ToPtr<::Assimp::STEP::EXPRESS::REAL>()) {
|
if (const ::Assimp::STEP::EXPRESS::REAL *const r = in.ToPtr<::Assimp::STEP::EXPRESS::REAL>()) {
|
||||||
out.r = out.g = out.b = static_cast<float>(*r);
|
out.r = out.g = out.b = static_cast<float>(*r);
|
||||||
if (base) {
|
if (base) {
|
||||||
|
@ -530,20 +489,17 @@ void ConvertColor(aiColor4D& out, const Schema_2x3::IfcColourOrFactor& in,Conver
|
||||||
out.g *= static_cast<float>(base->g);
|
out.g *= static_cast<float>(base->g);
|
||||||
out.b *= static_cast<float>(base->b);
|
out.b *= static_cast<float>(base->b);
|
||||||
out.a = static_cast<float>(base->a);
|
out.a = static_cast<float>(base->a);
|
||||||
}
|
} else
|
||||||
else out.a = 1.0;
|
out.a = 1.0;
|
||||||
}
|
} else if (const Schema_2x3::IfcColourRgb *const rgb = in.ResolveSelectPtr<Schema_2x3::IfcColourRgb>(conv.db)) {
|
||||||
else if (const Schema_2x3::IfcColourRgb* const rgb = in.ResolveSelectPtr<Schema_2x3::IfcColourRgb>(conv.db)) {
|
|
||||||
ConvertColor(out, *rgb);
|
ConvertColor(out, *rgb);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
IFCImporter::LogWarn("skipping unknown IfcColourOrFactor entity");
|
IFCImporter::LogWarn("skipping unknown IfcColourOrFactor entity");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ConvertCartesianPoint(IfcVector3& out, const Schema_2x3::IfcCartesianPoint& in)
|
void ConvertCartesianPoint(IfcVector3 &out, const Schema_2x3::IfcCartesianPoint &in) {
|
||||||
{
|
|
||||||
out = IfcVector3();
|
out = IfcVector3();
|
||||||
for (size_t i = 0; i < in.Coordinates.size(); ++i) {
|
for (size_t i = 0; i < in.Coordinates.size(); ++i) {
|
||||||
out[static_cast<unsigned int>(i)] = in.Coordinates[i];
|
out[static_cast<unsigned int>(i)] = in.Coordinates[i];
|
||||||
|
@ -551,15 +507,13 @@ void ConvertCartesianPoint(IfcVector3& out, const Schema_2x3::IfcCartesianPoint&
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ConvertVector(IfcVector3& out, const Schema_2x3::IfcVector& in)
|
void ConvertVector(IfcVector3 &out, const Schema_2x3::IfcVector &in) {
|
||||||
{
|
|
||||||
ConvertDirection(out, in.Orientation);
|
ConvertDirection(out, in.Orientation);
|
||||||
out *= in.Magnitude;
|
out *= in.Magnitude;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ConvertDirection(IfcVector3& out, const Schema_2x3::IfcDirection& in)
|
void ConvertDirection(IfcVector3 &out, const Schema_2x3::IfcDirection &in) {
|
||||||
{
|
|
||||||
out = IfcVector3();
|
out = IfcVector3();
|
||||||
for (size_t i = 0; i < in.DirectionRatios.size(); ++i) {
|
for (size_t i = 0; i < in.DirectionRatios.size(); ++i) {
|
||||||
out[static_cast<unsigned int>(i)] = in.DirectionRatios[i];
|
out[static_cast<unsigned int>(i)] = in.DirectionRatios[i];
|
||||||
|
@ -573,8 +527,7 @@ void ConvertDirection(IfcVector3& out, const Schema_2x3::IfcDirection& in)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void AssignMatrixAxes(IfcMatrix4& out, const IfcVector3& x, const IfcVector3& y, const IfcVector3& z)
|
void AssignMatrixAxes(IfcMatrix4 &out, const IfcVector3 &x, const IfcVector3 &y, const IfcVector3 &z) {
|
||||||
{
|
|
||||||
out.a1 = x.x;
|
out.a1 = x.x;
|
||||||
out.b1 = x.y;
|
out.b1 = x.y;
|
||||||
out.c1 = x.z;
|
out.c1 = x.z;
|
||||||
|
@ -589,8 +542,7 @@ void AssignMatrixAxes(IfcMatrix4& out, const IfcVector3& x, const IfcVector3& y,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement3D& in)
|
void ConvertAxisPlacement(IfcMatrix4 &out, const Schema_2x3::IfcAxis2Placement3D &in) {
|
||||||
{
|
|
||||||
IfcVector3 loc;
|
IfcVector3 loc;
|
||||||
ConvertCartesianPoint(loc, in.Location);
|
ConvertCartesianPoint(loc, in.Location);
|
||||||
|
|
||||||
|
@ -614,8 +566,7 @@ void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement3D
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement2D& in)
|
void ConvertAxisPlacement(IfcMatrix4 &out, const Schema_2x3::IfcAxis2Placement2D &in) {
|
||||||
{
|
|
||||||
IfcVector3 loc;
|
IfcVector3 loc;
|
||||||
ConvertCartesianPoint(loc, in.Location);
|
ConvertCartesianPoint(loc, in.Location);
|
||||||
|
|
||||||
|
@ -631,34 +582,28 @@ void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement2D
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ConvertAxisPlacement(IfcVector3& axis, IfcVector3& pos, const Schema_2x3::IfcAxis1Placement& in)
|
void ConvertAxisPlacement(IfcVector3 &axis, IfcVector3 &pos, const Schema_2x3::IfcAxis1Placement &in) {
|
||||||
{
|
|
||||||
ConvertCartesianPoint(pos, in.Location);
|
ConvertCartesianPoint(pos, in.Location);
|
||||||
if (in.Axis) {
|
if (in.Axis) {
|
||||||
ConvertDirection(axis, in.Axis.Get());
|
ConvertDirection(axis, in.Axis.Get());
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
axis = IfcVector3(0.f, 0.f, 1.f);
|
axis = IfcVector3(0.f, 0.f, 1.f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement& in, ConversionData& conv)
|
void ConvertAxisPlacement(IfcMatrix4 &out, const Schema_2x3::IfcAxis2Placement &in, ConversionData &conv) {
|
||||||
{
|
|
||||||
if (const Schema_2x3::IfcAxis2Placement3D *pl3 = in.ResolveSelectPtr<Schema_2x3::IfcAxis2Placement3D>(conv.db)) {
|
if (const Schema_2x3::IfcAxis2Placement3D *pl3 = in.ResolveSelectPtr<Schema_2x3::IfcAxis2Placement3D>(conv.db)) {
|
||||||
ConvertAxisPlacement(out, *pl3);
|
ConvertAxisPlacement(out, *pl3);
|
||||||
}
|
} else if (const Schema_2x3::IfcAxis2Placement2D *pl2 = in.ResolveSelectPtr<Schema_2x3::IfcAxis2Placement2D>(conv.db)) {
|
||||||
else if(const Schema_2x3::IfcAxis2Placement2D* pl2 = in.ResolveSelectPtr<Schema_2x3::IfcAxis2Placement2D>(conv.db)) {
|
|
||||||
ConvertAxisPlacement(out, *pl2);
|
ConvertAxisPlacement(out, *pl2);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
IFCImporter::LogWarn("skipping unknown IfcAxis2Placement entity");
|
IFCImporter::LogWarn("skipping unknown IfcAxis2Placement entity");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ConvertTransformOperator(IfcMatrix4& out, const Schema_2x3::IfcCartesianTransformationOperator& op)
|
void ConvertTransformOperator(IfcMatrix4 &out, const Schema_2x3::IfcCartesianTransformationOperator &op) {
|
||||||
{
|
|
||||||
IfcVector3 loc;
|
IfcVector3 loc;
|
||||||
ConvertCartesianPoint(loc, op.LocalOrigin);
|
ConvertCartesianPoint(loc, op.LocalOrigin);
|
||||||
|
|
||||||
|
@ -679,14 +624,12 @@ void ConvertTransformOperator(IfcMatrix4& out, const Schema_2x3::IfcCartesianTra
|
||||||
IfcMatrix4::Translation(loc, locm);
|
IfcMatrix4::Translation(loc, locm);
|
||||||
AssignMatrixAxes(out, x, y, z);
|
AssignMatrixAxes(out, x, y, z);
|
||||||
|
|
||||||
|
|
||||||
IfcVector3 vscale;
|
IfcVector3 vscale;
|
||||||
if (const Schema_2x3::IfcCartesianTransformationOperator3DnonUniform *nuni = op.ToPtr<Schema_2x3::IfcCartesianTransformationOperator3DnonUniform>()) {
|
if (const Schema_2x3::IfcCartesianTransformationOperator3DnonUniform *nuni = op.ToPtr<Schema_2x3::IfcCartesianTransformationOperator3DnonUniform>()) {
|
||||||
vscale.x = nuni->Scale ? op.Scale.Get() : 1.f;
|
vscale.x = nuni->Scale ? op.Scale.Get() : 1.f;
|
||||||
vscale.y = nuni->Scale2 ? nuni->Scale2.Get() : 1.f;
|
vscale.y = nuni->Scale2 ? nuni->Scale2.Get() : 1.f;
|
||||||
vscale.z = nuni->Scale3 ? nuni->Scale3.Get() : 1.f;
|
vscale.z = nuni->Scale3 ? nuni->Scale3.Get() : 1.f;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
const IfcFloat sc = op.Scale ? op.Scale.Get() : 1.f;
|
const IfcFloat sc = op.Scale ? op.Scale.Get() : 1.f;
|
||||||
vscale = IfcVector3(sc, sc, sc);
|
vscale = IfcVector3(sc, sc, sc);
|
||||||
}
|
}
|
||||||
|
@ -697,8 +640,7 @@ void ConvertTransformOperator(IfcMatrix4& out, const Schema_2x3::IfcCartesianTra
|
||||||
out = locm * out * s;
|
out = locm * out * s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace IFC
|
||||||
} // ! IFC
|
} // namespace Assimp
|
||||||
} // ! Assimp
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
|
||||||
|
|
||||||
Copyright (c) 2006-2020, assimp team
|
Copyright (c) 2006-2020, assimp team
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
@ -47,27 +46,26 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifndef INCLUDED_IFCUTIL_H
|
#ifndef INCLUDED_IFCUTIL_H
|
||||||
#define INCLUDED_IFCUTIL_H
|
#define INCLUDED_IFCUTIL_H
|
||||||
|
|
||||||
#include "AssetLib/IFC/IFCReaderGen_2x3.h"
|
|
||||||
#include "AssetLib/IFC/IFCLoader.h"
|
#include "AssetLib/IFC/IFCLoader.h"
|
||||||
|
#include "AssetLib/IFC/IFCReaderGen_2x3.h"
|
||||||
#include "AssetLib/Step/STEPFile.h"
|
#include "AssetLib/Step/STEPFile.h"
|
||||||
|
|
||||||
#include <assimp/mesh.h>
|
|
||||||
#include <assimp/material.h>
|
#include <assimp/material.h>
|
||||||
|
#include <assimp/mesh.h>
|
||||||
|
|
||||||
struct aiNode;
|
struct aiNode;
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
namespace IFC {
|
namespace IFC {
|
||||||
|
|
||||||
typedef double IfcFloat;
|
using IfcFloat = double;
|
||||||
|
|
||||||
// IfcFloat-precision math data types
|
// IfcFloat-precision math data types
|
||||||
typedef aiVector2t<IfcFloat> IfcVector2;
|
using IfcVector2 = aiVector2t<IfcFloat>;
|
||||||
typedef aiVector3t<IfcFloat> IfcVector3;
|
using IfcVector3 = aiVector3t<IfcFloat>;
|
||||||
typedef aiMatrix4x4t<IfcFloat> IfcMatrix4;
|
using IfcMatrix4 = aiMatrix4x4t<IfcFloat>;
|
||||||
typedef aiMatrix3x3t<IfcFloat> IfcMatrix3;
|
using IfcMatrix3 = aiMatrix3x3t<IfcFloat>;
|
||||||
typedef aiColor4t<IfcFloat> IfcColor4;
|
using IfcColor4 = aiColor4t<IfcFloat>;
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Helper for std::for_each to delete all heap-allocated items in a container
|
// Helper for std::for_each to delete all heap-allocated items in a container
|
||||||
|
@ -79,8 +77,6 @@ struct delete_fun {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Helper used during mesh construction. Aids at creating aiMesh'es out of relatively few polygons.
|
// Helper used during mesh construction. Aids at creating aiMesh'es out of relatively few polygons.
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -104,17 +100,14 @@ struct TempMesh {
|
||||||
void Swap(TempMesh &other);
|
void Swap(TempMesh &other);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline
|
inline bool TempMesh::IsEmpty() const {
|
||||||
bool TempMesh::IsEmpty() const {
|
|
||||||
return mVerts.empty() && mVertcnt.empty();
|
return mVerts.empty() && mVertcnt.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Temporary representation of an opening in a wall or a floor
|
// Temporary representation of an opening in a wall or a floor
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
struct TempOpening
|
struct TempOpening {
|
||||||
{
|
|
||||||
const IFC::Schema_2x3::IfcSolidModel *solid;
|
const IFC::Schema_2x3::IfcSolidModel *solid;
|
||||||
IfcVector3 extrusionDir;
|
IfcVector3 extrusionDir;
|
||||||
|
|
||||||
|
@ -129,34 +122,33 @@ struct TempOpening
|
||||||
std::vector<IfcVector3> wallPoints;
|
std::vector<IfcVector3> wallPoints;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------
|
||||||
TempOpening()
|
TempOpening() :
|
||||||
: solid()
|
solid(),
|
||||||
, extrusionDir()
|
extrusionDir(),
|
||||||
, profileMesh()
|
profileMesh() {
|
||||||
{
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------
|
||||||
TempOpening(const IFC::Schema_2x3::IfcSolidModel *solid, IfcVector3 extrusionDir,
|
TempOpening(const IFC::Schema_2x3::IfcSolidModel *solid, IfcVector3 extrusionDir,
|
||||||
std::shared_ptr<TempMesh> profileMesh,
|
std::shared_ptr<TempMesh> profileMesh,
|
||||||
std::shared_ptr<TempMesh> profileMesh2D)
|
std::shared_ptr<TempMesh> profileMesh2D) :
|
||||||
: solid(solid)
|
solid(solid),
|
||||||
, extrusionDir(extrusionDir)
|
extrusionDir(extrusionDir),
|
||||||
, profileMesh(profileMesh)
|
profileMesh(profileMesh),
|
||||||
, profileMesh2D(profileMesh2D)
|
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
|
// Helper to sort openings by distance from a given base point
|
||||||
struct DistanceSorter {
|
struct DistanceSorter {
|
||||||
|
|
||||||
DistanceSorter(const IfcVector3& base) : base(base) {}
|
DistanceSorter(const IfcVector3 &base) :
|
||||||
|
base(base) {}
|
||||||
|
|
||||||
bool operator()(const TempOpening &a, const TempOpening &b) const {
|
bool operator()(const TempOpening &a, const TempOpening &b) const {
|
||||||
return (a.profileMesh->Center() - base).SquareLength() < (b.profileMesh->Center() - base).SquareLength();
|
return (a.profileMesh->Center() - base).SquareLength() < (b.profileMesh->Center() - base).SquareLength();
|
||||||
|
@ -166,22 +158,28 @@ struct TempOpening
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Intermediate data storage during conversion. Keeps everything and a bit more.
|
// Intermediate data storage during conversion. Keeps everything and a bit more.
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
struct ConversionData
|
struct ConversionData {
|
||||||
{
|
ConversionData(const STEP::DB &db, const IFC::Schema_2x3::IfcProject &proj, aiScene *out, const IFCImporter::Settings &settings) :
|
||||||
ConversionData(const STEP::DB& db, const IFC::Schema_2x3::IfcProject& proj, aiScene* out,const IFCImporter::Settings& settings)
|
len_scale(1.0),
|
||||||
: len_scale(1.0)
|
angle_scale(-1.0),
|
||||||
, angle_scale(-1.0)
|
plane_angle_in_radians(true),
|
||||||
, db(db)
|
db(db),
|
||||||
, proj(proj)
|
proj(proj),
|
||||||
, out(out)
|
out(out),
|
||||||
, settings(settings)
|
wcs(),
|
||||||
, apply_openings()
|
meshes(),
|
||||||
, collect_openings()
|
materials(),
|
||||||
{}
|
cached_meshes(),
|
||||||
|
cached_materials(),
|
||||||
|
settings(settings),
|
||||||
|
apply_openings(nullptr),
|
||||||
|
collect_openings(nullptr),
|
||||||
|
already_processed() {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
~ConversionData() {
|
~ConversionData() {
|
||||||
std::for_each(meshes.begin(), meshes.end(), delete_fun<aiMesh>());
|
std::for_each(meshes.begin(), meshes.end(), delete_fun<aiMesh>());
|
||||||
|
@ -200,16 +198,19 @@ struct ConversionData
|
||||||
std::vector<aiMaterial *> materials;
|
std::vector<aiMaterial *> materials;
|
||||||
|
|
||||||
struct MeshCacheIndex {
|
struct MeshCacheIndex {
|
||||||
const IFC::Schema_2x3::IfcRepresentationItem* item; unsigned int matindex;
|
const IFC::Schema_2x3::IfcRepresentationItem *item;
|
||||||
MeshCacheIndex() : item(nullptr), matindex(0) { }
|
unsigned int matindex;
|
||||||
MeshCacheIndex(const IFC::Schema_2x3::IfcRepresentationItem* i, unsigned int mi) : item(i), matindex(mi) { }
|
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 && matindex == o.matindex; }
|
||||||
bool operator<(const MeshCacheIndex &o) const { return item < o.item || (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;
|
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;
|
MaterialCache cached_materials;
|
||||||
|
|
||||||
const IFCImporter::Settings &settings;
|
const IFCImporter::Settings &settings;
|
||||||
|
@ -226,13 +227,13 @@ struct ConversionData
|
||||||
std::set<uint64_t> already_processed;
|
std::set<uint64_t> already_processed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Binary predicate to compare vectors with a given, quadratic epsilon.
|
// Binary predicate to compare vectors with a given, quadratic epsilon.
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
struct FuzzyVectorCompare {
|
struct FuzzyVectorCompare {
|
||||||
|
|
||||||
FuzzyVectorCompare(IfcFloat epsilon) : epsilon(epsilon) {}
|
FuzzyVectorCompare(IfcFloat epsilon) :
|
||||||
|
epsilon(epsilon) {}
|
||||||
bool operator()(const IfcVector3 &a, const IfcVector3 &b) {
|
bool operator()(const IfcVector3 &a, const IfcVector3 &b) {
|
||||||
return std::abs((a - b).SquareLength()) < epsilon;
|
return std::abs((a - b).SquareLength()) < epsilon;
|
||||||
}
|
}
|
||||||
|
@ -240,7 +241,6 @@ struct FuzzyVectorCompare {
|
||||||
const IfcFloat epsilon;
|
const IfcFloat epsilon;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Ordering predicate to totally order R^2 vectors first by x and then by y
|
// Ordering predicate to totally order R^2 vectors first by x and then by y
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -255,8 +255,6 @@ struct XYSorter {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// conversion routines for common IFC entities, implemented in IFCUtil.cpp
|
// 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::IfcColourRgb &in);
|
||||||
void ConvertColor(aiColor4D &out, const Schema_2x3::IfcColourOrFactor &in, ConversionData &conv, const aiColor4D *base);
|
void ConvertColor(aiColor4D &out, const Schema_2x3::IfcColourOrFactor &in, ConversionData &conv, const aiColor4D *base);
|
||||||
|
@ -272,7 +270,6 @@ void ConvertTransformOperator(IfcMatrix4& out, const Schema_2x3::IfcCartesianTra
|
||||||
bool IsTrue(const Assimp::STEP::EXPRESS::BOOLEAN &in);
|
bool IsTrue(const Assimp::STEP::EXPRESS::BOOLEAN &in);
|
||||||
IfcFloat ConvertSIPrefix(const std::string &prefix);
|
IfcFloat ConvertSIPrefix(const std::string &prefix);
|
||||||
|
|
||||||
|
|
||||||
// IFCProfile.cpp
|
// IFCProfile.cpp
|
||||||
bool ProcessProfile(const Schema_2x3::IfcProfileDef &prof, 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);
|
bool ProcessCurve(const Schema_2x3::IfcCurve &curve, TempMesh &meshout, ConversionData &conv);
|
||||||
|
@ -305,7 +302,6 @@ void ProcessBooleanExtrudedAreaSolidDifference(const Schema_2x3::IfcExtrudedArea
|
||||||
const TempMesh &first_operand,
|
const TempMesh &first_operand,
|
||||||
ConversionData &conv);
|
ConversionData &conv);
|
||||||
|
|
||||||
|
|
||||||
// IFCOpenings.cpp
|
// IFCOpenings.cpp
|
||||||
|
|
||||||
bool GenerateOpenings(std::vector<TempOpening> &openings,
|
bool GenerateOpenings(std::vector<TempOpening> &openings,
|
||||||
|
@ -315,8 +311,6 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
|
||||||
bool generate_connection_geometry,
|
bool generate_connection_geometry,
|
||||||
const IfcVector3 &wall_extrusion_axis = IfcVector3(0, 1, 0));
|
const IfcVector3 &wall_extrusion_axis = IfcVector3(0, 1, 0));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// IFCCurve.cpp
|
// IFCCurve.cpp
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -324,8 +318,8 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
class CurveError {
|
class CurveError {
|
||||||
public:
|
public:
|
||||||
CurveError(const std::string& s)
|
CurveError(const std::string &s) :
|
||||||
: mStr(s) {
|
mStr(s) {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,18 +332,17 @@ public:
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
class Curve {
|
class Curve {
|
||||||
protected:
|
protected:
|
||||||
Curve(const Schema_2x3::IfcCurve& base_entity, ConversionData& conv)
|
Curve(const Schema_2x3::IfcCurve &base_entity, ConversionData &conv) :
|
||||||
: base_entity(base_entity)
|
base_entity(base_entity),
|
||||||
, conv(conv) {
|
conv(conv) {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef std::pair<IfcFloat, IfcFloat> ParamRange;
|
using ParamRange = std::pair<IfcFloat, IfcFloat>;
|
||||||
|
|
||||||
virtual ~Curve() {}
|
virtual ~Curve() {}
|
||||||
|
|
||||||
|
|
||||||
// check if a curve is closed
|
// check if a curve is closed
|
||||||
virtual bool IsClosed() const = 0;
|
virtual bool IsClosed() const = 0;
|
||||||
|
|
||||||
|
@ -384,23 +377,19 @@ protected:
|
||||||
ConversionData &conv;
|
ConversionData &conv;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------
|
||||||
// A BoundedCurve always holds the invariant that GetParametricRange()
|
// A BoundedCurve always holds the invariant that GetParametricRange()
|
||||||
// never returns infinite values.
|
// never returns infinite values.
|
||||||
// --------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------
|
||||||
class BoundedCurve : public Curve {
|
class BoundedCurve : public Curve {
|
||||||
public:
|
public:
|
||||||
BoundedCurve(const Schema_2x3::IfcBoundedCurve& entity, ConversionData& conv)
|
BoundedCurve(const Schema_2x3::IfcBoundedCurve &entity, ConversionData &conv) :
|
||||||
: Curve(entity,conv)
|
Curve(entity, conv) {}
|
||||||
{}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
bool IsClosed() const override;
|
||||||
bool IsClosed() const;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// sample the entire curve
|
// sample the entire curve
|
||||||
void SampleDiscrete(TempMesh &out) const;
|
void SampleDiscrete(TempMesh &out) const;
|
||||||
using Curve::SampleDiscrete;
|
using Curve::SampleDiscrete;
|
||||||
|
@ -408,7 +397,8 @@ public:
|
||||||
|
|
||||||
// IfcProfile.cpp
|
// 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
|
#endif
|
||||||
|
|
|
@ -43,9 +43,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* @brief Implementation of the CPP-API class #Importer
|
* @brief Implementation of the CPP-API class #Importer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <assimp/version.h>
|
|
||||||
#include <assimp/config.h>
|
#include <assimp/config.h>
|
||||||
#include <assimp/importerdesc.h>
|
#include <assimp/importerdesc.h>
|
||||||
|
#include <assimp/version.h>
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
/* Uncomment this line to prevent Assimp from catching unknown exceptions.
|
/* Uncomment this line to prevent Assimp from catching unknown exceptions.
|
||||||
|
@ -62,29 +62,30 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Internal headers
|
// Internal headers
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
#include "Common/Importer.h"
|
|
||||||
#include "Common/BaseProcess.h"
|
#include "Common/BaseProcess.h"
|
||||||
#include "Common/DefaultProgressHandler.h"
|
#include "Common/DefaultProgressHandler.h"
|
||||||
#include "PostProcessing/ProcessHelper.h"
|
#include "Common/Importer.h"
|
||||||
#include "Common/ScenePreprocessor.h"
|
#include "Common/ScenePreprocessor.h"
|
||||||
#include "Common/ScenePrivate.h"
|
#include "Common/ScenePrivate.h"
|
||||||
|
#include "PostProcessing/ProcessHelper.h"
|
||||||
|
|
||||||
#include <assimp/BaseImporter.h>
|
#include <assimp/BaseImporter.h>
|
||||||
|
#include <assimp/Exceptional.h>
|
||||||
#include <assimp/GenericProperty.h>
|
#include <assimp/GenericProperty.h>
|
||||||
#include <assimp/MemoryIOWrapper.h>
|
#include <assimp/MemoryIOWrapper.h>
|
||||||
#include <assimp/Profiler.h>
|
#include <assimp/Profiler.h>
|
||||||
#include <assimp/TinyFormatter.h>
|
#include <assimp/TinyFormatter.h>
|
||||||
#include <assimp/Exceptional.h>
|
|
||||||
#include <assimp/Profiler.h>
|
|
||||||
#include <assimp/commonMetaData.h>
|
#include <assimp/commonMetaData.h>
|
||||||
|
|
||||||
#include <set>
|
|
||||||
#include <memory>
|
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
#include <memory>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
#include <assimp/DefaultIOStream.h>
|
#include <assimp/DefaultIOStream.h>
|
||||||
#include <assimp/DefaultIOSystem.h>
|
#include <assimp/DefaultIOSystem.h>
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
|
#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
|
||||||
# include "PostProcessing/ValidateDataStructure.h"
|
# include "PostProcessing/ValidateDataStructure.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -99,8 +100,9 @@ namespace Assimp {
|
||||||
|
|
||||||
// PostStepRegistry.cpp
|
// PostStepRegistry.cpp
|
||||||
void GetPostProcessingStepInstanceList(std::vector<BaseProcess *> &out);
|
void GetPostProcessingStepInstanceList(std::vector<BaseProcess *> &out);
|
||||||
}
|
} // namespace Assimp
|
||||||
|
|
||||||
|
// clang-format on
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
using namespace Assimp::Intern;
|
using namespace Assimp::Intern;
|
||||||
|
|
||||||
|
@ -117,8 +119,7 @@ void* AllocateFromAssimpHeap::operator new ( size_t num_bytes) {
|
||||||
void *AllocateFromAssimpHeap::operator new(size_t num_bytes, const std::nothrow_t &) throw() {
|
void *AllocateFromAssimpHeap::operator new(size_t num_bytes, const std::nothrow_t &) throw() {
|
||||||
try {
|
try {
|
||||||
return AllocateFromAssimpHeap::operator new(num_bytes);
|
return AllocateFromAssimpHeap::operator new(num_bytes);
|
||||||
}
|
} catch (...) {
|
||||||
catch( ... ) {
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,8 +146,8 @@ void AllocateFromAssimpHeap::operator delete[] ( void* data) {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Importer constructor.
|
// Importer constructor.
|
||||||
Importer::Importer()
|
Importer::Importer() :
|
||||||
: pimpl( new ImporterPimpl ) {
|
pimpl(new ImporterPimpl) {
|
||||||
pimpl->mScene = nullptr;
|
pimpl->mScene = nullptr;
|
||||||
pimpl->mErrorString = "";
|
pimpl->mErrorString = "";
|
||||||
|
|
||||||
|
@ -652,8 +653,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) {
|
||||||
// Get file size for progress handler
|
// Get file size for progress handler
|
||||||
IOStream *fileIO = pimpl->mIOHandler->Open(pFile);
|
IOStream *fileIO = pimpl->mIOHandler->Open(pFile);
|
||||||
uint32_t fileSize = 0;
|
uint32_t fileSize = 0;
|
||||||
if (fileIO)
|
if (fileIO) {
|
||||||
{
|
|
||||||
fileSize = static_cast<uint32_t>(fileIO->FileSize());
|
fileSize = static_cast<uint32_t>(fileIO->FileSize());
|
||||||
pimpl->mIOHandler->Close(fileIO);
|
pimpl->mIOHandler->Close(fileIO);
|
||||||
}
|
}
|
||||||
|
@ -738,7 +738,8 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ASSIMP_LOG_ERROR(pimpl->mErrorString);
|
ASSIMP_LOG_ERROR(pimpl->mErrorString);
|
||||||
delete pimpl->mScene; pimpl->mScene = nullptr;
|
delete pimpl->mScene;
|
||||||
|
pimpl->mScene = nullptr;
|
||||||
}
|
}
|
||||||
#endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
|
#endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
|
||||||
|
|
||||||
|
@ -748,7 +749,6 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) {
|
||||||
return pimpl->mScene;
|
return pimpl->mScene;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Apply post-processing to the currently bound scene
|
// Apply post-processing to the currently bound scene
|
||||||
const aiScene *Importer::ApplyPostProcessing(unsigned int pFlags) {
|
const aiScene *Importer::ApplyPostProcessing(unsigned int pFlags) {
|
||||||
|
@ -781,8 +781,7 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) {
|
||||||
}
|
}
|
||||||
#endif // no validation
|
#endif // no validation
|
||||||
#ifdef ASSIMP_BUILD_DEBUG
|
#ifdef ASSIMP_BUILD_DEBUG
|
||||||
if (pimpl->bExtraVerbose)
|
if (pimpl->bExtraVerbose) {
|
||||||
{
|
|
||||||
#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
|
#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
|
||||||
ASSIMP_LOG_ERROR("Verbose Import is not available due to build settings");
|
ASSIMP_LOG_ERROR("Verbose Import is not available due to build settings");
|
||||||
#endif // no validation
|
#endif // no validation
|
||||||
|
@ -870,8 +869,7 @@ const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess
|
||||||
#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
|
#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
|
||||||
// The ValidateDS process plays an exceptional role. It isn't contained in the global
|
// The ValidateDS process plays an exceptional role. It isn't contained in the global
|
||||||
// list of post-processing steps, so we need to call it manually.
|
// list of post-processing steps, so we need to call it manually.
|
||||||
if ( requestValidation )
|
if (requestValidation) {
|
||||||
{
|
|
||||||
ValidateDSProcess ds;
|
ValidateDSProcess ds;
|
||||||
ds.ExecuteOnScene(this);
|
ds.ExecuteOnScene(this);
|
||||||
if (!pimpl->mScene) {
|
if (!pimpl->mScene) {
|
||||||
|
@ -880,8 +878,7 @@ const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess
|
||||||
}
|
}
|
||||||
#endif // no validation
|
#endif // no validation
|
||||||
#ifdef ASSIMP_BUILD_DEBUG
|
#ifdef ASSIMP_BUILD_DEBUG
|
||||||
if ( pimpl->bExtraVerbose )
|
if (pimpl->bExtraVerbose) {
|
||||||
{
|
|
||||||
#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
|
#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
|
||||||
ASSIMP_LOG_ERROR("Verbose Import is not available due to build settings");
|
ASSIMP_LOG_ERROR("Verbose Import is not available due to build settings");
|
||||||
#endif // no validation
|
#endif // no validation
|
||||||
|
@ -947,7 +944,6 @@ const aiImporterDesc* Importer::GetImporterInfo(size_t index) const {
|
||||||
return pimpl->mImporter[index]->GetInfo();
|
return pimpl->mImporter[index]->GetInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
BaseImporter *Importer::GetImporter(size_t index) const {
|
BaseImporter *Importer::GetImporter(size_t index) const {
|
||||||
ai_assert(nullptr != pimpl);
|
ai_assert(nullptr != pimpl);
|
||||||
|
@ -975,7 +971,8 @@ size_t Importer::GetImporterIndex (const char* szExtension) const {
|
||||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||||
|
|
||||||
// skip over wildcard and dot characters at string head --
|
// skip over wildcard and dot characters at string head --
|
||||||
for ( ; *szExtension == '*' || *szExtension == '.'; ++szExtension );
|
for (; *szExtension == '*' || *szExtension == '.'; ++szExtension)
|
||||||
|
;
|
||||||
|
|
||||||
std::string ext(szExtension);
|
std::string ext(szExtension);
|
||||||
if (ext.empty()) {
|
if (ext.empty()) {
|
||||||
|
@ -1106,8 +1103,7 @@ aiMatrix4x4 Importer::GetPropertyMatrix(const char* szName, const aiMatrix4x4& i
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Get the memory requirements of a single node
|
// Get the memory requirements of a single node
|
||||||
inline
|
inline void AddNodeWeight(unsigned int &iScene, const aiNode *pcNode) {
|
||||||
void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode) {
|
|
||||||
if (nullptr == pcNode) {
|
if (nullptr == pcNode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,10 +44,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifndef INCLUDED_AI_IMPORTER_H
|
#ifndef INCLUDED_AI_IMPORTER_H
|
||||||
#define INCLUDED_AI_IMPORTER_H
|
#define INCLUDED_AI_IMPORTER_H
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <assimp/matrix4x4.h>
|
#include <assimp/matrix4x4.h>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
struct aiScene;
|
struct aiScene;
|
||||||
|
|
||||||
|
@ -58,7 +58,6 @@ namespace Assimp {
|
||||||
class BaseProcess;
|
class BaseProcess;
|
||||||
class SharedPostProcessInfo;
|
class SharedPostProcessInfo;
|
||||||
|
|
||||||
|
|
||||||
//! @cond never
|
//! @cond never
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** @brief Internal PIMPL implementation for Assimp::Importer
|
/** @brief Internal PIMPL implementation for Assimp::Importer
|
||||||
|
@ -70,7 +69,7 @@ namespace Assimp {
|
||||||
class ImporterPimpl {
|
class ImporterPimpl {
|
||||||
public:
|
public:
|
||||||
// Data type to store the key hash
|
// Data type to store the key hash
|
||||||
typedef unsigned int KeyType;
|
using KeyType = unsigned int;
|
||||||
|
|
||||||
// typedefs for our four configuration maps.
|
// typedefs for our four configuration maps.
|
||||||
// We don't need more, so there is no need for a generic solution
|
// We don't need more, so there is no need for a generic solution
|
||||||
|
@ -126,9 +125,7 @@ public:
|
||||||
ImporterPimpl() AI_NO_EXCEPT;
|
ImporterPimpl() AI_NO_EXCEPT;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline
|
inline ImporterPimpl::ImporterPimpl() AI_NO_EXCEPT : mIOHandler(nullptr),
|
||||||
ImporterPimpl::ImporterPimpl() AI_NO_EXCEPT :
|
|
||||||
mIOHandler( nullptr ),
|
|
||||||
mIsDefaultHandler(false),
|
mIsDefaultHandler(false),
|
||||||
mProgressHandler(nullptr),
|
mProgressHandler(nullptr),
|
||||||
mIsDefaultProgressHandler(false),
|
mIsDefaultProgressHandler(false),
|
||||||
|
@ -214,8 +211,7 @@ public:
|
||||||
unsigned int AddLoadRequest(
|
unsigned int AddLoadRequest(
|
||||||
const std::string &file,
|
const std::string &file,
|
||||||
unsigned int steps = 0,
|
unsigned int steps = 0,
|
||||||
const PropertyMap *map = nullptr
|
const PropertyMap *map = nullptr);
|
||||||
);
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Get an imported scene.
|
/** Get an imported scene.
|
||||||
|
@ -227,8 +223,7 @@ public:
|
||||||
* @return nullptr if there is no scene with this file name
|
* @return nullptr if there is no scene with this file name
|
||||||
* in the queue of the scene hasn't been loaded yet. */
|
* in the queue of the scene hasn't been loaded yet. */
|
||||||
aiScene *GetImport(
|
aiScene *GetImport(
|
||||||
unsigned int which
|
unsigned int which);
|
||||||
);
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Waits until all scenes have been loaded. This returns
|
/** Waits until all scenes have been loaded. This returns
|
||||||
|
|
|
@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
|
||||||
|
|
||||||
Copyright (c) 2006-2020, assimp team
|
Copyright (c) 2006-2020, assimp team
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
@ -45,149 +44,48 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifndef AI_POLYTOOLS_H_INCLUDED
|
#ifndef AI_POLYTOOLS_H_INCLUDED
|
||||||
#define AI_POLYTOOLS_H_INCLUDED
|
#define AI_POLYTOOLS_H_INCLUDED
|
||||||
|
|
||||||
#include <assimp/material.h>
|
|
||||||
#include <assimp/ai_assert.h>
|
#include <assimp/ai_assert.h>
|
||||||
|
#include <assimp/material.h>
|
||||||
|
#include <assimp/vector3.h>
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
template<class T>
|
||||||
/** Compute the signed area of a triangle.
|
class TBoundingBox2D {
|
||||||
* The function accepts an unconstrained template parameter for use with
|
T mMin, mMax;
|
||||||
* both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/
|
|
||||||
template <typename T>
|
TBoundingBox2D( const T &min, const T &max ) :
|
||||||
inline double GetArea2D(const T& v1, const T& v2, const T& v3)
|
mMin( min ),
|
||||||
{
|
mMax( max ) {
|
||||||
return 0.5 * (v1.x * ((double)v3.y - v2.y) + v2.x * ((double)v1.y - v3.y) + v3.x * ((double)v2.y - v1.y));
|
// empty
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using BoundingBox2D = TBoundingBox2D<aiVector2D>;
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
/** Test if a given point p2 is on the left side of the line formed by p0-p1.
|
/// Compute the normal of an arbitrary polygon in R3.
|
||||||
* The function accepts an unconstrained template parameter for use with
|
///
|
||||||
* both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/
|
/// The code is based on Newell's formula, that is a polygons normal is the ratio
|
||||||
template <typename T>
|
/// of its area when projected onto the three coordinate axes.
|
||||||
inline bool OnLeftSideOfLine2D(const T& p0, const T& p1,const T& p2)
|
///
|
||||||
{
|
/// @param out Receives the output normal
|
||||||
return GetArea2D(p0,p2,p1) > 0;
|
/// @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()
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
/** Test if a given point is inside a given triangle in R2.
|
template <size_t ofs_x, size_t ofs_y, size_t ofs_z, typename TReal>
|
||||||
* The function accepts an unconstrained template parameter for use with
|
inline void NewellNormal(aiVector3t<TReal> &out, size_t num, TReal *x, TReal *y, TReal *z, size_t bufferSize) {
|
||||||
* both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/
|
ai_assert(bufferSize > num);
|
||||||
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;
|
if (nullptr == x || nullptr == y || nullptr == z || 0 == bufferSize || 0 == num) {
|
||||||
double dot01 = v0 * v1;
|
return;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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));
|
|
||||||
|
|
||||||
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));
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
// Duplicate the first two vertices at the end
|
||||||
x[(num + 0) * ofs_x] = x[0];
|
x[(num + 0) * ofs_x] = x[0];
|
||||||
x[(num + 1) * ofs_x] = x[ofs_x];
|
x[(num + 1) * ofs_x] = x[ofs_x];
|
||||||
|
@ -204,7 +102,7 @@ inline void NewellNormal (aiVector3t<TReal>& out, int num, TReal* x, TReal* y, T
|
||||||
TReal *yptr = y + ofs_y, *ylow = y, *yhigh = y + ofs_y * 2;
|
TReal *yptr = y + ofs_y, *ylow = y, *yhigh = y + ofs_y * 2;
|
||||||
TReal *zptr = z + ofs_z, *zlow = z, *zhigh = z + ofs_z * 2;
|
TReal *zptr = z + ofs_z, *zlow = z, *zhigh = z + ofs_z * 2;
|
||||||
|
|
||||||
for (int tmp=0; tmp < num; tmp++) {
|
for (size_t tmp = 0; tmp < num; ++tmp ) {
|
||||||
sum_xy += (*xptr) * ((*yhigh) - (*ylow));
|
sum_xy += (*xptr) * ((*yhigh) - (*ylow));
|
||||||
sum_yz += (*yptr) * ((*zhigh) - (*zlow));
|
sum_yz += (*yptr) * ((*zhigh) - (*zlow));
|
||||||
sum_zx += (*zptr) * ((*xhigh) - (*xlow));
|
sum_zx += (*zptr) * ((*xhigh) - (*xlow));
|
||||||
|
@ -224,6 +122,69 @@ inline void NewellNormal (aiVector3t<TReal>& out, int num, TReal* x, TReal* y, T
|
||||||
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
|
#endif
|
||||||
|
|
|
@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
|
||||||
|
|
||||||
Copyright (c) 2006-2020, assimp team
|
Copyright (c) 2006-2020, assimp team
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
@ -45,11 +43,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* @brief Implementation of the FindDegenerates post-process step.
|
* @brief Implementation of the FindDegenerates post-process step.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// internal headers
|
// internal headers
|
||||||
#include "ProcessHelper.h"
|
|
||||||
#include "FindDegenerates.h"
|
#include "FindDegenerates.h"
|
||||||
|
#include "ProcessHelper.h"
|
||||||
#include <assimp/Exceptional.h>
|
#include <assimp/Exceptional.h>
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
@ -61,9 +57,9 @@ static void updateSceneGraph(aiNode* pNode, unsigned const index);
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Constructor to be privately used by Importer
|
// Constructor to be privately used by Importer
|
||||||
FindDegeneratesProcess::FindDegeneratesProcess()
|
FindDegeneratesProcess::FindDegeneratesProcess() :
|
||||||
: mConfigRemoveDegenerates( false )
|
mConfigRemoveDegenerates(false),
|
||||||
, mConfigCheckAreaOfTriangle( false ){
|
mConfigCheckAreaOfTriangle(false) {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,8 +87,7 @@ void FindDegeneratesProcess::SetupProperties(const Importer* pImp) {
|
||||||
// Executes the post processing step on the given imported data.
|
// 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");
|
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
|
//Do not process point cloud, ExecuteOnMesh works only with faces data
|
||||||
if ((pScene->mMeshes[i]->mPrimitiveTypes != aiPrimitiveType::aiPrimitiveType_POINT) && ExecuteOnMesh(pScene->mMeshes[i])) {
|
if ((pScene->mMeshes[i]->mPrimitiveTypes != aiPrimitiveType::aiPrimitiveType_POINT) && ExecuteOnMesh(pScene->mMeshes[i])) {
|
||||||
removeMesh(pScene, i);
|
removeMesh(pScene, i);
|
||||||
|
@ -239,8 +234,7 @@ bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to update the primitive flags array of the mesh.
|
// We need to update the primitive flags array of the mesh.
|
||||||
switch (face.mNumIndices)
|
switch (face.mNumIndices) {
|
||||||
{
|
|
||||||
case 1u:
|
case 1u:
|
||||||
mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
|
mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
|
||||||
break;
|
break;
|
||||||
|
@ -261,8 +255,7 @@ evil_jump_outside:
|
||||||
// If AI_CONFIG_PP_FD_REMOVE is true, remove degenerated faces from the import
|
// If AI_CONFIG_PP_FD_REMOVE is true, remove degenerated faces from the import
|
||||||
if (mConfigRemoveDegenerates && deg) {
|
if (mConfigRemoveDegenerates && deg) {
|
||||||
unsigned int n = 0;
|
unsigned int n = 0;
|
||||||
for (unsigned int a = 0; a < mesh->mNumFaces; ++a)
|
for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
|
||||||
{
|
|
||||||
aiFace &face_src = mesh->mFaces[a];
|
aiFace &face_src = mesh->mFaces[a];
|
||||||
if (!remove_me[a]) {
|
if (!remove_me[a]) {
|
||||||
aiFace &face_dest = mesh->mFaces[n++];
|
aiFace &face_dest = mesh->mFaces[n++];
|
||||||
|
@ -276,8 +269,7 @@ evil_jump_outside:
|
||||||
face_src.mNumIndices = 0;
|
face_src.mNumIndices = 0;
|
||||||
face_src.mIndices = nullptr;
|
face_src.mIndices = nullptr;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// Otherwise delete it if we don't need this face
|
// Otherwise delete it if we don't need this face
|
||||||
delete[] face_src.mIndices;
|
delete[] face_src.mIndices;
|
||||||
face_src.mIndices = nullptr;
|
face_src.mIndices = nullptr;
|
||||||
|
|
|
@ -47,65 +47,46 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* The triangulation algorithm will handle concave or convex polygons.
|
* The triangulation algorithm will handle concave or convex polygons.
|
||||||
* Self-intersecting or non-planar polygons are not rejected, but
|
* Self-intersecting or non-planar polygons are not rejected, but
|
||||||
* they're probably not triangulated correctly.
|
* 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
|
#ifndef ASSIMP_BUILD_NO_TRIANGULATE_PROCESS
|
||||||
|
|
||||||
#include "PostProcessing/TriangulateProcess.h"
|
#include "PostProcessing/TriangulateProcess.h"
|
||||||
#include "PostProcessing/ProcessHelper.h"
|
|
||||||
#include "Common/PolyTools.h"
|
#include "Common/PolyTools.h"
|
||||||
|
#include "PostProcessing/ProcessHelper.h"
|
||||||
|
|
||||||
|
#include "contrib/poly2tri/poly2tri/poly2tri.h"
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
//#define AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING
|
namespace Assimp {
|
||||||
//#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;
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Constructor to be privately used by Importer
|
// Constructor to be privately used by Importer
|
||||||
TriangulateProcess::TriangulateProcess()
|
TriangulateProcess::TriangulateProcess() {
|
||||||
{
|
|
||||||
// nothing to do here
|
// nothing to do here
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Destructor, private as well
|
// Destructor, private as well
|
||||||
TriangulateProcess::~TriangulateProcess()
|
TriangulateProcess::~TriangulateProcess() {
|
||||||
{
|
|
||||||
// nothing to do here
|
// nothing to do here
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Returns whether the processing step is present in the given flag field.
|
// Returns whether the processing step is present in the given flag field.
|
||||||
bool TriangulateProcess::IsActive( unsigned int pFlags) const
|
bool TriangulateProcess::IsActive(unsigned int pFlags) const {
|
||||||
{
|
|
||||||
return (pFlags & aiProcess_Triangulate) != 0;
|
return (pFlags & aiProcess_Triangulate) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Executes the post processing step on the given imported data.
|
// Executes the post processing step on the given imported data.
|
||||||
void TriangulateProcess::Execute( aiScene* pScene)
|
void TriangulateProcess::Execute(aiScene *pScene) {
|
||||||
{
|
|
||||||
ASSIMP_LOG_DEBUG("TriangulateProcess begin");
|
ASSIMP_LOG_DEBUG("TriangulateProcess begin");
|
||||||
|
|
||||||
bool bHas = false;
|
bool bHas = false;
|
||||||
for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
|
for (unsigned int a = 0; a < pScene->mNumMeshes; a++) {
|
||||||
{
|
|
||||||
if (pScene->mMeshes[a]) {
|
if (pScene->mMeshes[a]) {
|
||||||
if (TriangulateMesh(pScene->mMeshes[a])) {
|
if (TriangulateMesh(pScene->mMeshes[a])) {
|
||||||
bHas = true;
|
bHas = true;
|
||||||
|
@ -120,113 +101,40 @@ void TriangulateProcess::Execute( aiScene* pScene)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Triangulates the given mesh.
|
static bool validateNumIndices(aiMesh *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;
|
bool bNeed = false;
|
||||||
|
for (unsigned int a = 0; a < mesh->mNumFaces; a++) {
|
||||||
for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
|
const aiFace &face = mesh->mFaces[a];
|
||||||
const aiFace& face = pMesh->mFaces[a];
|
|
||||||
|
|
||||||
if (face.mNumIndices != 3) {
|
if (face.mNumIndices != 3) {
|
||||||
bNeed = true;
|
bNeed = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!bNeed)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (!(pMesh->mPrimitiveTypes & aiPrimitiveType_POLYGON)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find out how many output faces we'll get
|
return bNeed;
|
||||||
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];
|
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) {
|
if (face.mNumIndices <= 4) {
|
||||||
get_normals = false;
|
getNormals = false;
|
||||||
}
|
}
|
||||||
if (face.mNumIndices <= 3) {
|
if (face.mNumIndices <= 3) {
|
||||||
numOut++;
|
numOut++;
|
||||||
|
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
numOut += face.mNumIndices - 2;
|
numOut += face.mNumIndices - 2;
|
||||||
max_out = std::max(max_out,face.mNumIndices);
|
maxOut = std::max(maxOut, static_cast<size_t>(face.mNumIndices));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just another check whether aiMesh::mPrimitiveTypes is correct
|
// ------------------------------------------------------------------------------------------------
|
||||||
ai_assert(numOut != pMesh->mNumFaces);
|
static void quad2Triangles(const aiFace &face, const aiVector3D *verts, aiFace *curOut) {
|
||||||
|
|
||||||
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];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
// if it's a simple point,line or triangle: just copy it
|
|
||||||
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
|
// quads can have at maximum one concave vertex. Determine
|
||||||
// this vertex (if it exists) and start tri-fanning from
|
// this vertex (if it exists) and start tri-fanning from
|
||||||
// it.
|
// it.
|
||||||
|
@ -271,261 +179,162 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
|
||||||
sface.mIndices[0] = temp[start_vertex];
|
sface.mIndices[0] = temp[start_vertex];
|
||||||
sface.mIndices[1] = temp[(start_vertex + 2) % 4];
|
sface.mIndices[1] = temp[(start_vertex + 2) % 4];
|
||||||
sface.mIndices[2] = temp[(start_vertex + 3) % 4];
|
sface.mIndices[2] = temp[(start_vertex + 3) % 4];
|
||||||
|
|
||||||
// prevent double deletion of the indices field
|
|
||||||
face.mIndices = nullptr;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
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;
|
bool getContourFromePolyline(aiFace &face, aiMesh *pMesh, std::vector<p2t::Point *> &contour,
|
||||||
NewellNormal<3,3,3>(n,max,&temp_verts3d.front().x,&temp_verts3d.front().y,&temp_verts3d.front().z);
|
aiMatrix4x4 &m, aiVector3D &vmin, aiVector3D &vmax, ai_real &zcoord) {
|
||||||
if (nor_out) {
|
aiVector3D normal;
|
||||||
for (tmp = 0; tmp < max; ++tmp)
|
bool ok = true;
|
||||||
nor_out[idx[tmp]] = n;
|
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];
|
||||||
|
|
||||||
// Select largest normal coordinate to ignore for projection
|
const aiVector3D vv = m * pMesh->mVertices[index];
|
||||||
const float ax = (n.x>0 ? n.x : -n.x);
|
// keep Z offset in the plane coordinate system. Ignoring precision issues
|
||||||
const float ay = (n.y>0 ? n.y : -n.y);
|
// (which are present, of course), this should be the same value for
|
||||||
const float az = (n.z>0 ? n.z : -n.z);
|
// all polygon vertices (assuming the polygon is planar).
|
||||||
|
|
||||||
unsigned int ac = 0, bc = 1; /* no z coord. projection to xy */
|
// XXX this should be guarded, but we somehow need to pick a suitable
|
||||||
float inv = n.z;
|
// epsilon
|
||||||
if (ax > ay) {
|
// if(coord != -1.0f) {
|
||||||
if (ax > az) { /* no x coord. projection to yz */
|
// assert(std::fabs(coord - vv.z) < 1e-3f);
|
||||||
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;
|
|
||||||
// }
|
// }
|
||||||
|
zcoord += vv.z;
|
||||||
|
vmin = std::min(vv, vmin);
|
||||||
|
vmax = std::max(vv, vmax);
|
||||||
|
|
||||||
i[0] = idx[i[0]];
|
contour.push_back(new p2t::Point(vv.x, vv.y));
|
||||||
i[1] = idx[i[1]];
|
|
||||||
i[2] = idx[i[2]];
|
|
||||||
++f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete[] face.mIndices;
|
zcoord /= pMesh->mNumVertices;
|
||||||
face.mIndices = nullptr;
|
|
||||||
|
// 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
|
aiMatrix4x4 mult;
|
||||||
fclose(fout);
|
mult.a1 = static_cast<ai_real>(1.0) / vmax.x;
|
||||||
#endif
|
mult.b2 = static_cast<ai_real>(1.0) / vmax.y;
|
||||||
|
|
||||||
// kill the old faces
|
mult.a4 = -vmin.x * mult.a1;
|
||||||
delete [] pMesh->mFaces;
|
mult.b4 = -vmin.y * mult.b2;
|
||||||
|
mult.c4 = -zcoord;
|
||||||
|
m = mult * m;
|
||||||
|
|
||||||
// ... and store the new ones
|
|
||||||
pMesh->mFaces = out;
|
|
||||||
pMesh->mNumFaces = (unsigned int)(curOut-out); /* not necessarily equal to numOut */
|
|
||||||
return true;
|
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
|
||||||
|
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;
|
||||||
|
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?
|
||||||
|
|
||||||
|
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];
|
||||||
|
|
||||||
|
// if it's a simple point,line or triangle: just copy it
|
||||||
|
if (face.mNumIndices <= 3) {
|
||||||
|
aiFace &nface = *curOut++;
|
||||||
|
nface.mNumIndices = face.mNumIndices;
|
||||||
|
nface.mIndices = face.mIndices;
|
||||||
|
|
||||||
|
face.mIndices = nullptr;
|
||||||
|
} 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 */
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Assimp
|
||||||
|
|
||||||
#endif // !! ASSIMP_BUILD_NO_TRIANGULATE_PROCESS
|
#endif // !! ASSIMP_BUILD_NO_TRIANGULATE_PROCESS
|
||||||
|
|
Binary file not shown.
|
@ -1,5 +1,8 @@
|
||||||
find_package( Doxygen REQUIRED )
|
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." )
|
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
|
# Enable Microsoft CHM help style only on Windows
|
||||||
|
|
|
@ -1484,7 +1484,7 @@ MAN_LINKS = NO
|
||||||
# generate an XML file that captures the structure of
|
# generate an XML file that captures the structure of
|
||||||
# the code including all documentation.
|
# 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.
|
# 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
|
# 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
|
# pragma GCC system_header
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <cstdint>
|
||||||
#include <string.h>
|
#include <cstring>
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Hashing function taken from
|
// Hashing function taken from
|
||||||
|
|
|
@ -52,9 +52,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#pragma GCC system_header
|
#pragma GCC system_header
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <assimp/StreamReader.h>
|
|
||||||
#include <assimp/ParsingUtils.h>
|
#include <assimp/ParsingUtils.h>
|
||||||
|
#include <assimp/StreamReader.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ for(LineSplitter splitter(stream);splitter;++splitter) {
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
class LineSplitter {
|
class LineSplitter {
|
||||||
public:
|
public:
|
||||||
typedef size_t line_idx;
|
using line_idx = size_t;
|
||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
/** construct from existing stream reader
|
/** construct from existing stream reader
|
||||||
|
@ -144,21 +144,19 @@ private:
|
||||||
bool mSwallow, mSkip_empty_lines, mTrim;
|
bool mSwallow, mSkip_empty_lines, mTrim;
|
||||||
};
|
};
|
||||||
|
|
||||||
AI_FORCE_INLINE
|
AI_FORCE_INLINE LineSplitter::LineSplitter(StreamReaderLE &stream, bool skip_empty_lines, bool trim) :
|
||||||
LineSplitter::LineSplitter(StreamReaderLE& stream, bool skip_empty_lines, bool trim )
|
mIdx(0),
|
||||||
: mIdx(0)
|
mCur(),
|
||||||
, mCur()
|
mStream(stream),
|
||||||
, mStream(stream)
|
mSwallow(),
|
||||||
, mSwallow()
|
mSkip_empty_lines(skip_empty_lines),
|
||||||
, mSkip_empty_lines(skip_empty_lines)
|
mTrim(trim) {
|
||||||
, mTrim(trim) {
|
|
||||||
mCur.reserve(1024);
|
mCur.reserve(1024);
|
||||||
operator++();
|
operator++();
|
||||||
mIdx = 0;
|
mIdx = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
AI_FORCE_INLINE
|
AI_FORCE_INLINE LineSplitter::~LineSplitter() {
|
||||||
LineSplitter::~LineSplitter() {
|
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +176,8 @@ LineSplitter& LineSplitter::operator++() {
|
||||||
while (mStream.GetRemainingSize() && (s = mStream.GetI1(), 1)) {
|
while (mStream.GetRemainingSize() && (s = mStream.GetI1(), 1)) {
|
||||||
if (s == '\n' || s == '\r') {
|
if (s == '\n' || s == '\r') {
|
||||||
if (mSkip_empty_lines) {
|
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()) {
|
if (mStream.GetRemainingSize()) {
|
||||||
mStream.IncPtr(-1);
|
mStream.IncPtr(-1);
|
||||||
}
|
}
|
||||||
|
@ -188,7 +187,8 @@ LineSplitter& LineSplitter::operator++() {
|
||||||
mStream.IncPtr(-1);
|
mStream.IncPtr(-1);
|
||||||
}
|
}
|
||||||
if (mTrim) {
|
if (mTrim) {
|
||||||
while (mStream.GetRemainingSize() && ((s = mStream.GetI1()) == ' ' || s == '\t'));
|
while (mStream.GetRemainingSize() && ((s = mStream.GetI1()) == ' ' || s == '\t'))
|
||||||
|
;
|
||||||
if (mStream.GetRemainingSize()) {
|
if (mStream.GetRemainingSize()) {
|
||||||
mStream.IncPtr(-1);
|
mStream.IncPtr(-1);
|
||||||
}
|
}
|
||||||
|
@ -203,8 +203,7 @@ LineSplitter& LineSplitter::operator++() {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
AI_FORCE_INLINE
|
AI_FORCE_INLINE LineSplitter &LineSplitter::operator++(int) {
|
||||||
LineSplitter &LineSplitter::operator++(int) {
|
|
||||||
return ++(*this);
|
return ++(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,8 +225,7 @@ const char *LineSplitter::operator[] (size_t idx) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t N>
|
template <size_t N>
|
||||||
AI_FORCE_INLINE
|
AI_FORCE_INLINE void LineSplitter::get_tokens(const char *(&tokens)[N]) const {
|
||||||
void LineSplitter::get_tokens(const char* (&tokens)[N]) const {
|
|
||||||
const char *s = operator->()->c_str();
|
const char *s = operator->()->c_str();
|
||||||
|
|
||||||
SkipSpaces(&s);
|
SkipSpaces(&s);
|
||||||
|
@ -237,7 +235,8 @@ void LineSplitter::get_tokens(const char* (&tokens)[N]) const {
|
||||||
}
|
}
|
||||||
tokens[i] = s;
|
tokens[i] = s;
|
||||||
|
|
||||||
for (; *s && !IsSpace(*s); ++s);
|
for (; *s && !IsSpace(*s); ++s)
|
||||||
|
;
|
||||||
SkipSpaces(&s);
|
SkipSpaces(&s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,7 +119,7 @@ public:
|
||||||
/** @brief Normalize the vector with extra check for zero vectors */
|
/** @brief Normalize the vector with extra check for zero vectors */
|
||||||
aiVector3t& NormalizeSafe();
|
aiVector3t& NormalizeSafe();
|
||||||
|
|
||||||
/** @brief Componentwise multiplication of two vectors
|
/** @brief Component-wise multiplication of two vectors
|
||||||
*
|
*
|
||||||
* Note that vec*vec yields the dot product.
|
* Note that vec*vec yields the dot product.
|
||||||
* @param o Second factor */
|
* @param o Second factor */
|
||||||
|
@ -129,7 +129,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef aiVector3t<ai_real> aiVector3D;
|
using aiVector3D = aiVector3t<ai_real>;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
|
||||||
|
|
||||||
Copyright (c) 2006-2020, assimp team
|
Copyright (c) 2006-2020, assimp team
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
@ -306,4 +304,5 @@ aiVector3t<TReal> operator - ( const aiVector3t<TReal>& v) {
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
|
|
||||||
#endif // AI_VECTOR3D_INL_INC
|
#endif // AI_VECTOR3D_INL_INC
|
||||||
|
|
|
@ -96,6 +96,7 @@ SET( COMMON
|
||||||
unit/Common/utSpatialSort.cpp
|
unit/Common/utSpatialSort.cpp
|
||||||
unit/Common/utAssertHandler.cpp
|
unit/Common/utAssertHandler.cpp
|
||||||
unit/Common/utXmlParser.cpp
|
unit/Common/utXmlParser.cpp
|
||||||
|
unit/Common/utPolyTools.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
SET( IMPORTERS
|
SET( IMPORTERS
|
||||||
|
|
|
@ -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
|
Copyright (c) 2006-2020, assimp team
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
|
|
@ -49,8 +49,8 @@ using namespace Assimp;
|
||||||
|
|
||||||
class TriangulateProcessTest : public ::testing::Test {
|
class TriangulateProcessTest : public ::testing::Test {
|
||||||
public:
|
public:
|
||||||
virtual void SetUp();
|
void SetUp() override;
|
||||||
virtual void TearDown();
|
void TearDown() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
aiMesh *pcMesh;
|
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);
|
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
|
#ifndef AV_ANIMEVALUATOR_H_INCLUDED
|
||||||
#define AV_ANIMEVALUATOR_H_INCLUDED
|
#define AV_ANIMEVALUATOR_H_INCLUDED
|
||||||
|
|
||||||
|
#include <assimp/matrix4x4.h>
|
||||||
|
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
struct aiAnimation;
|
||||||
|
|
||||||
namespace AssimpView {
|
namespace AssimpView {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -74,7 +78,7 @@ public:
|
||||||
* the aiAnimation. */
|
* the aiAnimation. */
|
||||||
const std::vector<aiMatrix4x4> &GetTransformations() const { return mTransforms; }
|
const std::vector<aiMatrix4x4> &GetTransformations() const { return mTransforms; }
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
const aiAnimation *mAnim;
|
const aiAnimation *mAnim;
|
||||||
double mLastTime;
|
double mLastTime;
|
||||||
std::vector<std::tuple<unsigned int, unsigned int, unsigned int>> mLastPositions;
|
std::vector<std::tuple<unsigned int, unsigned int, unsigned int>> mLastPositions;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -47,7 +47,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifndef AV_SCENEANIMATOR_H_INCLUDED
|
#ifndef AV_SCENEANIMATOR_H_INCLUDED
|
||||||
#define AV_SCENEANIMATOR_H_INCLUDED
|
#define AV_SCENEANIMATOR_H_INCLUDED
|
||||||
|
|
||||||
|
#include <assimp/scene.h>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace AssimpView {
|
namespace AssimpView {
|
||||||
|
|
||||||
|
@ -72,13 +75,23 @@ struct SceneAnimNode {
|
||||||
|
|
||||||
//! Default construction
|
//! Default construction
|
||||||
SceneAnimNode() :
|
SceneAnimNode() :
|
||||||
mName(), mParent(nullptr), mChildren(), mLocalTransform(), mGlobalTransform(), mChannelIndex(-1) {
|
mName(),
|
||||||
|
mParent(nullptr),
|
||||||
|
mChildren(),
|
||||||
|
mLocalTransform(),
|
||||||
|
mGlobalTransform(),
|
||||||
|
mChannelIndex(-1) {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Construction from a given name
|
//! Construction from a given name
|
||||||
SceneAnimNode(const std::string &pName) :
|
SceneAnimNode(const std::string &pName) :
|
||||||
mName(pName), mParent(nullptr), mChildren(), mLocalTransform(), mGlobalTransform(), mChannelIndex(-1) {
|
mName(pName),
|
||||||
|
mParent(nullptr),
|
||||||
|
mChildren(),
|
||||||
|
mLocalTransform(),
|
||||||
|
mGlobalTransform(),
|
||||||
|
mChannelIndex(-1) {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +138,7 @@ public:
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
/** Calculates the node transformations for the scene. Call this to get
|
/** Calculates the node transformations for the scene. Call this to get
|
||||||
* uptodate results before calling one of the getters.
|
* up-to-date results before calling one of the getters.
|
||||||
* @param pTime Current time. Can be an arbitrary range.
|
* @param pTime Current time. Can be an arbitrary range.
|
||||||
*/
|
*/
|
||||||
void Calculate(double pTime);
|
void Calculate(double pTime);
|
||||||
|
@ -136,7 +149,7 @@ public:
|
||||||
* The returned matrix is in the node's parent's local space, just like the
|
* The returned matrix is in the node's parent's local space, just like the
|
||||||
* original node's transformation matrix. If the node is not animated, the
|
* original node's transformation matrix. If the node is not animated, the
|
||||||
* node's original transformation is returned so that you can safely use or
|
* node's original transformation is returned so that you can safely use or
|
||||||
* assign it to the node itsself. If there is no node with the given name,
|
* assign it to the node itself. If there is no node with the given name,
|
||||||
* the identity matrix is returned. All transformations are updated whenever
|
* the identity matrix is returned. All transformations are updated whenever
|
||||||
* Calculate() is called.
|
* Calculate() is called.
|
||||||
* @param pNodeName Name of the node
|
* @param pNodeName Name of the node
|
||||||
|
@ -151,7 +164,7 @@ public:
|
||||||
* The returned matrix is in world space, which is the same coordinate space
|
* The returned matrix is in world space, which is the same coordinate space
|
||||||
* as the transformation of the scene's root node. If the node is not animated,
|
* as the transformation of the scene's root node. If the node is not animated,
|
||||||
* the node's original transformation is returned so that you can safely use or
|
* the node's original transformation is returned so that you can safely use or
|
||||||
* assign it to the node itsself. If there is no node with the given name, the
|
* assign it to the node itself. If there is no node with the given name, the
|
||||||
* identity matrix is returned. All transformations are updated whenever
|
* identity matrix is returned. All transformations are updated whenever
|
||||||
* Calculate() is called.
|
* Calculate() is called.
|
||||||
* @param pNodeName Name of the node
|
* @param pNodeName Name of the node
|
||||||
|
@ -190,7 +203,7 @@ public:
|
||||||
/** @brief Get the current animation or NULL
|
/** @brief Get the current animation or NULL
|
||||||
*/
|
*/
|
||||||
aiAnimation *CurrentAnim() const {
|
aiAnimation *CurrentAnim() const {
|
||||||
return static_cast<unsigned int>(mCurrentAnimIndex) < mScene->mNumAnimations ? mScene->mAnimations[mCurrentAnimIndex] : NULL;
|
return static_cast<unsigned int>(mCurrentAnimIndex) < mScene->mNumAnimations ? mScene->mAnimations[mCurrentAnimIndex] : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
Loading…
Reference in New Issue