Files
speckle-cpp-connectors/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.cpp
T
2024-10-21 09:41:55 +02:00

263 lines
9.9 KiB
C++

#include "Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.h"
#ifdef ARCHICAD
#include "Active/Utility/Defer.h"
#include "Active/Utility/Memory.h"
#include "Active/Utility/String.h"
#include "Speckle/Database/Identity/BIMLink.h"
#include "Speckle/Environment/Addon.h"
#include "Speckle/Environment/Project.h"
#include "Speckle/Event/Type/DocStoreMergeEvent.h"
#include "Speckle/Event/Type/ProjectEvent.h"
#include "Speckle/Record/Element/Column.h"
#include "Speckle/Record/Element/ColumnSegment.h"
#include "Speckle/Record/Element/GenericElement.h"
#include "Speckle/Record/Element/Beam.h"
#include "Speckle/Record/Element/BeamSegment.h"
#include "Speckle/Record/Element/Memo.h"
#include "Speckle/Utility/Guid.h"
#include "Speckle/Utility/String.h"
#include <ACAPinc.h>
#include <ACAPI_Database.h>
#include <BM.hpp>
using namespace active::event;
using namespace active::setting;
using namespace speckle::database;
using namespace speckle::environment;
using namespace speckle::event;
using namespace speckle::record::element;
using namespace speckle::utility;
using enum ArchicadDBaseCore::Status;
namespace {
/*!
Get information about a specified Archicad table
@param tableID The ID of the target table
@return The requested table info (nullopt on failure)
*/
std::optional<API_DatabaseInfo> getTableInfo(const BIMRecordID& tableID) {
API_DatabaseInfo dbaseInfo;
dbaseInfo.databaseUnId.elemSetId = tableID;
if (auto err = ACAPI_Window_GetDatabaseInfo(&dbaseInfo); err == NoError)
return dbaseInfo;
return std::nullopt;
} //getTableInfo
/*!
Set the active Archicad table
@param tableID The target table ID
@return True on success
*/
bool setActiveTable(const BIMRecordID& tableID) {
if (!tableID)
return false; //Null guid doens't point to anything
if (auto activeTable = ArchicadElementDBaseEngine::getActiveTable(); activeTable && *activeTable == tableID)
return true;
auto dbaseInfo = getTableInfo(tableID);
if (!dbaseInfo)
return false;
return ACAPI_Database_ChangeCurrentDatabase(&*dbaseInfo) == NoError;
} //setActiveTable
/*!
Make a new element object
@param elementData The API element representation
@param tableID The ID of the parent table (defaults to the active drawing)
@return A new element object (nullptr on failure)
*/
Element::Unique makeElement(const API_Element& elementData, const BIMRecordID& tableID) {
switch (elementData.header.type.typeID) {
case API_ColumnID:
return std::make_unique<Column>(elementData, tableID);
case API_ColumnSegmentID:
return std::make_unique<ColumnSegment>(elementData, tableID);
case API_BeamID:
return std::make_unique<Beam>(elementData, tableID);
case API_BeamSegmentID:
return std::make_unique<BeamSegment>(elementData, tableID);
default:
return std::make_unique<GenericElement>(elementData, tableID);
}
}
}
/*--------------------------------------------------------------------
Get the ID of the active Archicad table
return; The active table ID (nullopt on failure)
--------------------------------------------------------------------*/
std::optional<BIMRecordID> ArchicadElementDBaseEngine::getActiveTable() {
API_WindowInfo dbaseInfo;
active::utility::Memory::erase(dbaseInfo);
if (auto err = ACAPI_Database_GetCurrentDatabase(&dbaseInfo); err == NoError)
return dbaseInfo.databaseUnId.elemSetId;
return std::nullopt;
} //ArchicadElementDBaseEngine::getActiveTable
/*--------------------------------------------------------------------
Get the current user element selection
return: A list of selected element IDs
--------------------------------------------------------------------*/
BIMLinkList ArchicadElementDBaseEngine::getSelection() const {
auto tableID = getActiveTable();
if (!tableID)
return {};
BIMLinkList result;
API_SelectionInfo selectionInfo;
active::utility::Memory::erase(selectionInfo);
GS::Array<API_Neig> selection;
if (auto err = ACAPI_Selection_Get(&selectionInfo, &selection, true); err == NoError) {
for (const auto& item : selection)
result.push_back(BIMLink{item, *tableID});
}
return result;
} //ArchicadElementDBaseEngine::getSelection
/*--------------------------------------------------------------------
Get an object by index
index: The object index
tableID: Optional table ID (defaults to the floor plan)
documentID: Optional document ID (when the object is bound to a specific document)
return: The requested object (nullptr on failure)
--------------------------------------------------------------------*/
std::unique_ptr<Element> ArchicadElementDBaseEngine::getObject(const BIMRecordID& ID, std::optional<BIMRecordID> tableID,
std::optional<BIMRecordID> documentID) const {
//Check for memo table requests
if (tableID == memoTable) {
auto memo = std::make_unique<API_ElementMemo>();
active::utility::Memory::erase(*memo);
//Use memo filtering when requested
uint64_t filter = documentID ? Guid::toInt(*documentID) : APIMemoMask_All;
if (auto err = ACAPI_Element_GetMemo(ID, memo.get(), filter); err != NoError)
ACAPI_DisposeElemMemoHdls(memo.get());
else {
auto result = std::make_unique<Memo>();
result->set(std::move(memo));
return result;
}
}
if (!tableID) {
//Use the active table if none is specified
tableID = getActiveTable();
if (!tableID)
return nullptr;
}
API_Element element;
active::utility::Memory::erase(element);
API_Guid guid{ID.operator API_Guid()};
if (ACAPI_Element_GetElementFromAnywhere(&guid, &element) != NoError)
return nullptr;
return makeElement(element, *tableID);
} //ArchicadElementDBaseEngine::getObject
/*--------------------------------------------------------------------
Get an object in a transportable form, e.g. packaged for serialisation
index: The object index
tableID: Optional table ID (defaults to the floor plan)
documentID: Optional document ID (when the object is bound to a specific document)
return: The requested wrapped cargo (nullptr on failure)
--------------------------------------------------------------------*/
active::serialise::Cargo::Unique ArchicadElementDBaseEngine::getObjectCargo(const BIMRecordID& ID, std::optional<BIMRecordID> tableID,
std::optional<BIMRecordID> documentID) const {
return nullptr; //TODO: Implement
} //ArchicadElementDBaseEngine::getObject
/*--------------------------------------------------------------------
Get all objects
tableID: Optional table ID (defaults to the floor plan)
documentID: Optional document ID (filter for this document only - nullopt = all objects)
return: The requested objects (nullptr on failure)
--------------------------------------------------------------------*/
active::container::Vector<Element> ArchicadElementDBaseEngine::getObjects(std::optional<BIMRecordID> tableID,
std::optional<BIMRecordID> documentID) const {
if (tableID)
setActiveTable(*tableID);
return {}; //TODO: Implement
} //ArchicadElementDBaseEngine::getObjects
/*--------------------------------------------------------------------
Get all objects
filter: The object filter
tableID: Optional table ID (defaults to the floor plan)
documentID: Optional document ID (filter for this document only - nullopt = all objects)
return: The requested objects (nullptr on failure)
--------------------------------------------------------------------*/
active::container::Vector<Element> ArchicadElementDBaseEngine::getObjects(const Filter& filter, std::optional<BIMRecordID> tableID,
std::optional<BIMRecordID> documentID) const {
return {};
} //ArchicadElementDBaseEngine::getObjects
/*--------------------------------------------------------------------
Write an object to the database
object: The object to write
objID: The object ID
objDocID: The object document-specific ID (unique within a specific document - nullopt if not document-bound)
tableID: Optional table ID (defaults to the floor plan)
documentID: Optional document ID (when the object is bound to a specific document)
--------------------------------------------------------------------*/
void ArchicadElementDBaseEngine::write(const Element& object, const BIMRecordID& objID, std::optional<BIMRecordID> objDocID,
std::optional<BIMRecordID> tableID, std::optional<BIMRecordID> documentID) const {
} //ArchicadElementDBaseEngine::write
/*--------------------------------------------------------------------
Erase an object by index
objID: The object ID
tableID: Optional table ID (defaults to the floor plan)
documentID: Optional document ID (when the object is bound to a specific document)
return: True if the object was successfully erased
--------------------------------------------------------------------*/
void ArchicadElementDBaseEngine::erase(const BIMRecordID& ID, std::optional<BIMRecordID> tableID,
std::optional<BIMRecordID> documentID) const {
} //ArchicadElementDBaseEngine::erase
/*--------------------------------------------------------------------
Erase all objects
tableID: Optional table ID (defaults to the floor plan)
documentID: Optional document ID (filter for this document only - nullopt = all objects)
--------------------------------------------------------------------*/
void ArchicadElementDBaseEngine::erase(std::optional<BIMRecordID> tableID, std::optional<BIMRecordID> documentID) const {
} //ArchicadElementDBaseEngine::erase
/*--------------------------------------------------------------------
Get the database outline
return: The database outline
--------------------------------------------------------------------*/
ArchicadElementDBaseEngine::Outline ArchicadElementDBaseEngine::getOutline() const {
return {};
} //ArchicadElementDBaseEngine::getOutline
#endif