662 lines
14 KiB
C++
662 lines
14 KiB
C++
// Apache 2.0 License
|
|
// C ABI wrapper around engine_web-ifc for P/Invoke from ifc-dotnet.
|
|
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <exception>
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
#ifdef _WIN32
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#define NOMINMAX
|
|
#include <combaseapi.h>
|
|
#include <eh.h>
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
#include "../engine_web-ifc/src/cpp/version.h"
|
|
#include "../engine_web-ifc/src/cpp/web-ifc/modelmanager/ModelManager.h"
|
|
|
|
namespace wgeom = webifc::geometry;
|
|
namespace wmanager = webifc::manager;
|
|
namespace wparse = webifc::parsing;
|
|
namespace wschema = webifc::schema;
|
|
|
|
class Api;
|
|
struct Model;
|
|
struct NativeGeometry;
|
|
struct Mesh;
|
|
struct Vertex;
|
|
|
|
#ifdef _WIN32
|
|
#define WEBIFC_EXPORT __declspec(dllexport)
|
|
#else
|
|
#define WEBIFC_EXPORT
|
|
#endif
|
|
|
|
extern "C"
|
|
{
|
|
WEBIFC_EXPORT Api* InitializeApi();
|
|
WEBIFC_EXPORT void FinalizeApi(Api* api);
|
|
WEBIFC_EXPORT Model* LoadModel(Api* api, const wchar_t* fileName);
|
|
|
|
WEBIFC_EXPORT int GetNumGeometries(Model* model);
|
|
WEBIFC_EXPORT NativeGeometry* GetGeometryFromId(Model* model, uint32_t id);
|
|
WEBIFC_EXPORT NativeGeometry* GetGeometryFromIndex(Model* model, int32_t index);
|
|
WEBIFC_EXPORT uint32_t GetMaxId(Model* model);
|
|
WEBIFC_EXPORT const char* GetLineFromModel(Model* model, uint32_t id);
|
|
|
|
WEBIFC_EXPORT int GetNumMeshes(NativeGeometry* geom);
|
|
WEBIFC_EXPORT Mesh* GetMesh(NativeGeometry* geom, int index);
|
|
WEBIFC_EXPORT uint32_t GetGeometryId(NativeGeometry* geom);
|
|
WEBIFC_EXPORT uint32_t GetGeometryType(NativeGeometry* geom);
|
|
WEBIFC_EXPORT uint32_t GetLineId(NativeGeometry* geom);
|
|
WEBIFC_EXPORT uint32_t GetLineType(NativeGeometry* geom);
|
|
WEBIFC_EXPORT const char* GetLineArguments(NativeGeometry* geom, uint32_t lineId);
|
|
|
|
WEBIFC_EXPORT int GetNumVertices(Mesh* mesh);
|
|
WEBIFC_EXPORT Vertex* GetVertices(Mesh* mesh);
|
|
WEBIFC_EXPORT int GetNumIndices(Mesh* mesh);
|
|
WEBIFC_EXPORT uint32_t* GetIndices(Mesh* mesh);
|
|
WEBIFC_EXPORT double* GetTransform(Mesh* mesh);
|
|
WEBIFC_EXPORT double* GetColor(Mesh* mesh);
|
|
WEBIFC_EXPORT uint32_t GetMeshId(Mesh* mesh);
|
|
|
|
WEBIFC_EXPORT wchar_t* WebIfcGetVersion();
|
|
}
|
|
|
|
struct Vertex
|
|
{
|
|
double Vx, Vy, Vz;
|
|
double Nx, Ny, Nz;
|
|
};
|
|
|
|
struct Color
|
|
{
|
|
double R = 0;
|
|
double G = 0;
|
|
double B = 0;
|
|
double A = 0;
|
|
|
|
Color() = default;
|
|
Color(double r, double g, double b, double a)
|
|
: R(r), G(g), B(b), A(a)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct Mesh
|
|
{
|
|
std::vector<double> vertexData;
|
|
std::vector<uint32_t> indexData;
|
|
Color color;
|
|
uint32_t id;
|
|
std::array<double, 16> transform;
|
|
|
|
explicit Mesh(uint32_t id)
|
|
: id(id), transform({})
|
|
{
|
|
}
|
|
};
|
|
|
|
struct NativeGeometry
|
|
{
|
|
uint32_t id;
|
|
std::vector<std::unique_ptr<Mesh>> meshes;
|
|
|
|
explicit NativeGeometry(uint32_t id)
|
|
: id(id)
|
|
{
|
|
}
|
|
};
|
|
|
|
#ifdef _WIN32
|
|
class seh_exception : public std::exception
|
|
{
|
|
unsigned int _code;
|
|
|
|
public:
|
|
explicit seh_exception(unsigned int code)
|
|
: _code(code)
|
|
{
|
|
}
|
|
|
|
unsigned int code() const { return _code; }
|
|
};
|
|
|
|
static void seh_translator(unsigned int code, EXCEPTION_POINTERS*)
|
|
{
|
|
throw seh_exception(code);
|
|
}
|
|
|
|
struct SEHGuard
|
|
{
|
|
_se_translator_function _prev;
|
|
SEHGuard() : _prev(_set_se_translator(seh_translator)) {}
|
|
~SEHGuard() { _set_se_translator(_prev); }
|
|
};
|
|
#else
|
|
struct SEHGuard
|
|
{
|
|
};
|
|
#endif
|
|
|
|
struct Model
|
|
{
|
|
uint32_t id;
|
|
wparse::IfcLoader* loader;
|
|
wgeom::IfcGeometryProcessor* geometryProcessor;
|
|
std::vector<std::unique_ptr<NativeGeometry>> geometryStorage;
|
|
std::vector<NativeGeometry*> geometryList;
|
|
std::unordered_map<uint32_t, NativeGeometry*> geometries;
|
|
|
|
Model(const wschema::IfcSchemaManager& schemas, wparse::IfcLoader* loader, wgeom::IfcGeometryProcessor* processor, uint32_t id)
|
|
: id(id), loader(loader), geometryProcessor(processor)
|
|
{
|
|
SEHGuard sehGuard;
|
|
int totalElements = 0;
|
|
int skippedDupes = 0;
|
|
int skippedErrors = 0;
|
|
int totalMeshes = 0;
|
|
int meshErrors = 0;
|
|
int emptyMeshes = 0;
|
|
size_t totalVerts = 0;
|
|
|
|
for (auto type : schemas.GetIfcElementList())
|
|
{
|
|
if (type == wschema::IFCOPENINGELEMENT || type == wschema::IFCSPACE || type == wschema::IFCOPENINGSTANDARDCASE)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
for (auto eId : loader->GetExpressIDsWithType(type))
|
|
{
|
|
totalElements++;
|
|
if (geometries.count(eId) > 0)
|
|
{
|
|
skippedDupes++;
|
|
continue;
|
|
}
|
|
|
|
try
|
|
{
|
|
auto flatMesh = processor->GetFlatMesh(eId);
|
|
auto geometry = std::make_unique<NativeGeometry>(eId);
|
|
|
|
for (auto& placedGeom : flatMesh.geometries)
|
|
{
|
|
totalMeshes++;
|
|
try
|
|
{
|
|
auto mesh = std::make_unique<Mesh>(placedGeom.geometryExpressID);
|
|
mesh->color = Color(
|
|
placedGeom.color.r,
|
|
placedGeom.color.g,
|
|
placedGeom.color.b,
|
|
placedGeom.color.a);
|
|
|
|
auto& srcGeom = processor->GetGeometry(placedGeom.geometryExpressID);
|
|
srcGeom.GetVertexData();
|
|
srcGeom.GetIndexData();
|
|
|
|
mesh->vertexData = srcGeom.vertexData;
|
|
mesh->indexData = srcGeom.indexData;
|
|
mesh->transform = placedGeom.flatTransformation;
|
|
|
|
totalVerts += mesh->vertexData.size();
|
|
if (mesh->vertexData.empty())
|
|
{
|
|
emptyMeshes++;
|
|
}
|
|
|
|
geometry->meshes.push_back(std::move(mesh));
|
|
}
|
|
catch (...)
|
|
{
|
|
meshErrors++;
|
|
}
|
|
}
|
|
|
|
if (!geometry->meshes.empty())
|
|
{
|
|
auto* geometryPtr = geometry.get();
|
|
geometries[eId] = geometryPtr;
|
|
geometryList.push_back(geometryPtr);
|
|
geometryStorage.push_back(std::move(geometry));
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
skippedErrors++;
|
|
}
|
|
}
|
|
}
|
|
|
|
std::fprintf(
|
|
stderr,
|
|
"GEOM_DEBUG_078: elements=%d dupes=%d errors=%d geometries=%d meshes=%d meshErrors=%d emptyMeshes=%d totalVerts=%zu\n",
|
|
totalElements,
|
|
skippedDupes,
|
|
skippedErrors,
|
|
static_cast<int>(geometryList.size()),
|
|
totalMeshes,
|
|
meshErrors,
|
|
emptyMeshes,
|
|
totalVerts);
|
|
std::fflush(stderr);
|
|
}
|
|
|
|
NativeGeometry* GetGeometry(uint32_t id)
|
|
{
|
|
auto it = geometries.find(id);
|
|
if (it == geometries.end())
|
|
{
|
|
return nullptr;
|
|
}
|
|
return it->second;
|
|
}
|
|
};
|
|
|
|
struct Api
|
|
{
|
|
std::unique_ptr<wmanager::ModelManager> manager;
|
|
wmanager::LoaderSettings settings;
|
|
std::vector<std::unique_ptr<Model>> loadedModels;
|
|
|
|
Api()
|
|
: manager(std::make_unique<wmanager::ModelManager>(false))
|
|
{
|
|
manager->SetLogLevel(2);
|
|
settings.COORDINATE_TO_ORIGIN = false;
|
|
settings.CIRCLE_SEGMENTS = 12;
|
|
}
|
|
|
|
Model* LoadModel(const wchar_t* fileName)
|
|
{
|
|
auto modelId = manager->CreateModel(settings);
|
|
auto* loader = manager->GetIfcLoader(modelId);
|
|
std::ifstream ifs(std::filesystem::path(fileName), std::ifstream::in | std::ios::binary);
|
|
if (!ifs.is_open())
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
loader->LoadFile(ifs);
|
|
auto model = std::make_unique<Model>(
|
|
manager->GetSchemaManager(),
|
|
loader,
|
|
manager->GetGeometryProcessor(modelId),
|
|
modelId);
|
|
|
|
auto* result = model.get();
|
|
loadedModels.push_back(std::move(model));
|
|
return result;
|
|
}
|
|
};
|
|
|
|
Api* InitializeApi()
|
|
{
|
|
std::fprintf(stderr, "NATIVE_TRACE_078: InitializeApi called\n");
|
|
std::fflush(stderr);
|
|
SEHGuard g;
|
|
try
|
|
{
|
|
return new Api();
|
|
}
|
|
catch (...)
|
|
{
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
void FinalizeApi(Api* api)
|
|
{
|
|
if (!api)
|
|
{
|
|
return;
|
|
}
|
|
SEHGuard g;
|
|
try
|
|
{
|
|
delete api;
|
|
}
|
|
catch (...)
|
|
{
|
|
}
|
|
}
|
|
|
|
Model* LoadModel(Api* api, const wchar_t* fileName)
|
|
{
|
|
if (!api || !fileName)
|
|
{
|
|
return nullptr;
|
|
}
|
|
SEHGuard g;
|
|
try
|
|
{
|
|
auto* model = api->LoadModel(fileName);
|
|
if (model)
|
|
{
|
|
std::fprintf(stderr, "NATIVE_DEBUG_078: LoadModel OK, geometries=%d\n", static_cast<int>(model->geometries.size()));
|
|
}
|
|
else
|
|
{
|
|
std::fprintf(stderr, "NATIVE_DEBUG_078: LoadModel returned NULL\n");
|
|
}
|
|
std::fflush(stderr);
|
|
return model;
|
|
}
|
|
catch (...)
|
|
{
|
|
std::fprintf(stderr, "NATIVE_DEBUG_078: LoadModel CRASHED\n");
|
|
std::fflush(stderr);
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
int GetNumGeometries(Model* model)
|
|
{
|
|
if (!model)
|
|
{
|
|
return 0;
|
|
}
|
|
SEHGuard g;
|
|
try
|
|
{
|
|
return static_cast<int>(model->geometryList.size());
|
|
}
|
|
catch (...)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
NativeGeometry* GetGeometryFromId(Model* model, uint32_t id)
|
|
{
|
|
if (!model)
|
|
{
|
|
return nullptr;
|
|
}
|
|
SEHGuard g;
|
|
try
|
|
{
|
|
return model->GetGeometry(id);
|
|
}
|
|
catch (...)
|
|
{
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
NativeGeometry* GetGeometryFromIndex(Model* model, int32_t index)
|
|
{
|
|
if (!model)
|
|
{
|
|
return nullptr;
|
|
}
|
|
SEHGuard g;
|
|
try
|
|
{
|
|
if (index < 0 || index >= static_cast<int32_t>(model->geometryList.size()))
|
|
{
|
|
return nullptr;
|
|
}
|
|
return model->geometryList[index];
|
|
}
|
|
catch (...)
|
|
{
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
uint32_t GetMaxId(Model* model)
|
|
{
|
|
if (!model || model->geometryList.empty())
|
|
{
|
|
return 0;
|
|
}
|
|
SEHGuard g;
|
|
try
|
|
{
|
|
uint32_t maxId = 0;
|
|
for (auto* geometry : model->geometryList)
|
|
{
|
|
if (geometry && geometry->id > maxId)
|
|
{
|
|
maxId = geometry->id;
|
|
}
|
|
}
|
|
return maxId;
|
|
}
|
|
catch (...)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
const char* GetLineFromModel(Model*, uint32_t)
|
|
{
|
|
return "";
|
|
}
|
|
|
|
int GetNumMeshes(NativeGeometry* geom)
|
|
{
|
|
if (!geom)
|
|
{
|
|
return 0;
|
|
}
|
|
SEHGuard g;
|
|
try
|
|
{
|
|
return static_cast<int>(geom->meshes.size());
|
|
}
|
|
catch (...)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
Mesh* GetMesh(NativeGeometry* geom, int index)
|
|
{
|
|
if (!geom)
|
|
{
|
|
return nullptr;
|
|
}
|
|
SEHGuard g;
|
|
try
|
|
{
|
|
if (index < 0 || index >= static_cast<int>(geom->meshes.size()))
|
|
{
|
|
return nullptr;
|
|
}
|
|
return geom->meshes[index].get();
|
|
}
|
|
catch (...)
|
|
{
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
uint32_t GetGeometryId(NativeGeometry* geom)
|
|
{
|
|
if (!geom)
|
|
{
|
|
return 0;
|
|
}
|
|
SEHGuard g;
|
|
try
|
|
{
|
|
return geom->id;
|
|
}
|
|
catch (...)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
uint32_t GetGeometryType(NativeGeometry*)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
uint32_t GetLineId(NativeGeometry* geom)
|
|
{
|
|
return geom ? geom->id : 0;
|
|
}
|
|
|
|
uint32_t GetLineType(NativeGeometry*)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
const char* GetLineArguments(NativeGeometry*, uint32_t)
|
|
{
|
|
return "";
|
|
}
|
|
|
|
int GetNumVertices(Mesh* mesh)
|
|
{
|
|
if (!mesh)
|
|
{
|
|
return 0;
|
|
}
|
|
SEHGuard g;
|
|
try
|
|
{
|
|
return static_cast<int>(mesh->vertexData.size() / 6);
|
|
}
|
|
catch (...)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
Vertex* GetVertices(Mesh* mesh)
|
|
{
|
|
if (!mesh || mesh->vertexData.empty())
|
|
{
|
|
return nullptr;
|
|
}
|
|
SEHGuard g;
|
|
try
|
|
{
|
|
return reinterpret_cast<Vertex*>(mesh->vertexData.data());
|
|
}
|
|
catch (...)
|
|
{
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
int GetNumIndices(Mesh* mesh)
|
|
{
|
|
if (!mesh)
|
|
{
|
|
return 0;
|
|
}
|
|
SEHGuard g;
|
|
try
|
|
{
|
|
return static_cast<int>(mesh->indexData.size());
|
|
}
|
|
catch (...)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
uint32_t* GetIndices(Mesh* mesh)
|
|
{
|
|
if (!mesh || mesh->indexData.empty())
|
|
{
|
|
return nullptr;
|
|
}
|
|
SEHGuard g;
|
|
try
|
|
{
|
|
return mesh->indexData.data();
|
|
}
|
|
catch (...)
|
|
{
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
double* GetTransform(Mesh* mesh)
|
|
{
|
|
if (!mesh)
|
|
{
|
|
return nullptr;
|
|
}
|
|
SEHGuard g;
|
|
try
|
|
{
|
|
return mesh->transform.data();
|
|
}
|
|
catch (...)
|
|
{
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
double* GetColor(Mesh* mesh)
|
|
{
|
|
if (!mesh)
|
|
{
|
|
return nullptr;
|
|
}
|
|
SEHGuard g;
|
|
try
|
|
{
|
|
return &mesh->color.R;
|
|
}
|
|
catch (...)
|
|
{
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
uint32_t GetMeshId(Mesh* mesh)
|
|
{
|
|
if (!mesh)
|
|
{
|
|
return 0;
|
|
}
|
|
SEHGuard g;
|
|
try
|
|
{
|
|
return mesh->id;
|
|
}
|
|
catch (...)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
#pragma comment(linker, "/EXPORT:GetVersion=WebIfcGetVersion")
|
|
#endif
|
|
wchar_t* WebIfcGetVersion()
|
|
{
|
|
std::string version(WEB_IFC_VERSION_NUMBER);
|
|
const auto len = version.size();
|
|
wchar_t* result = static_cast<wchar_t*>(CoTaskMemAlloc((len + 1) * sizeof(wchar_t)));
|
|
if (!result)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
for (size_t i = 0; i < len; i++)
|
|
{
|
|
result[i] = static_cast<wchar_t>(version[i]);
|
|
}
|
|
result[len] = L'\0';
|
|
return result;
|
|
}
|