From 29ece2282fa97f8537db0c8119b5dcf64b3c7403 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Mon, 23 Sep 2024 16:01:35 +0100 Subject: [PATCH 001/191] Added DocumentStoreEngine::getUniqueID Added ModelCardDatabase::getStoreID --- .../Connector/Database/ModelCardDatabase.cpp | 10 ++++++++++ .../Connector/Database/ModelCardDatabase.h | 5 +++++ .../Storage/DocumentStore/DocumentStoreEngine.h | 5 +++++ 3 files changed, 20 insertions(+) diff --git a/SpeckleConnector/Connector/Database/ModelCardDatabase.cpp b/SpeckleConnector/Connector/Database/ModelCardDatabase.cpp index 761d8fc..c10d1b6 100644 --- a/SpeckleConnector/Connector/Database/ModelCardDatabase.cpp +++ b/SpeckleConnector/Connector/Database/ModelCardDatabase.cpp @@ -101,6 +101,16 @@ void ModelCardDatabase::erase(const String& cardID) const { } //ModelCardDatabase::erase +/*-------------------------------------------------------------------- + Get the unique ID of the engine storage + + return: The databas unique ID + --------------------------------------------------------------------*/ +RecordID ModelCardDatabase::getStoreID() const { + return m_engine->getUniqueID(); +} //ModelCardDatabase::getStoreID + + /*-------------------------------------------------------------------- Get a serialisation wrapper for the database diff --git a/SpeckleConnector/Connector/Database/ModelCardDatabase.h b/SpeckleConnector/Connector/Database/ModelCardDatabase.h index d2e7db6..79a2353 100644 --- a/SpeckleConnector/Connector/Database/ModelCardDatabase.h +++ b/SpeckleConnector/Connector/Database/ModelCardDatabase.h @@ -49,6 +49,11 @@ namespace connector::database { @return A database wrapper */ std::unique_ptr wrapper() const; + /*! + Get the unique ID of the engine storage + @return The database unique ID + */ + speckle::database::RecordID getStoreID() const; // MARK: - Functions (mutating) diff --git a/SpeckleLib/Speckle/Database/Storage/DocumentStore/DocumentStoreEngine.h b/SpeckleLib/Speckle/Database/Storage/DocumentStore/DocumentStoreEngine.h index 202ea0c..1d92a70 100644 --- a/SpeckleLib/Speckle/Database/Storage/DocumentStore/DocumentStoreEngine.h +++ b/SpeckleLib/Speckle/Database/Storage/DocumentStore/DocumentStoreEngine.h @@ -122,6 +122,11 @@ namespace speckle::database { @return The database outline */ Outline getOutline() const override; + /*! + Get the engine unique ID + @return The unique ID + */ + RecordID getUniqueID() const { return getCache()->getID(); } protected: /*! From 4dd0a1b1b65ab097476598a947c7e6f81ba2d4e0 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Tue, 24 Sep 2024 21:50:28 +0100 Subject: [PATCH 002/191] Added skeleton BIM database, element, collection and Mesh classes to support sending model data --- .../Connector.xcodeproj/project.pbxproj | 20 +++ .../Interface/Browser/Bridge/Send/Send.cpp | 2 +- .../Interface/Browser/Bridge/Send/Send.h | 2 +- .../Record/Collection/RecordCollection.cpp | 75 ++++++++++ .../Record/Collection/RecordCollection.h | 91 ++++++++++++ .../Record/Collection/RootCollection.cpp | 34 +++++ .../Record/Collection/RootCollection.h | 52 +++++++ .../Speckle/Database/BIMElementDatabase.cpp | 104 +++++++++++++ .../Speckle/Database/BIMElementDatabase.h | 65 +++++++++ .../Speckle/Database/Content/BIMRecord.cpp | 24 +++ .../Speckle/Database/Content/BIMRecord.h | 62 ++++++++ .../Speckle/Database/Identity/BIMIndex.h | 30 ++++ .../Identity/{Link.cpp => BIMLink.cpp} | 9 +- .../Speckle/Database/Identity/BIMLink.h | 44 ++++++ .../Speckle/Database/Identity/BIMRecordID.h | 22 +++ SpeckleLib/Speckle/Database/Identity/Index.h | 5 +- SpeckleLib/Speckle/Database/Identity/Link.h | 8 +- .../ArchicadDBase/ArchicadDBaseCore.cpp | 95 ++++++++++++ .../Storage/ArchicadDBase/ArchicadDBaseCore.h | 86 +++++++++++ .../Element/ArchicadElementDBaseEngine.cpp | 137 ++++++++++++++++++ .../Element/ArchicadElementDBaseEngine.h | 109 ++++++++++++++ .../DocumentStore/DocumentStoreCore.cpp | 2 +- .../Event/Subscriber/SelectionSubscriber.cpp | 4 +- .../Speckle/Event/Type/SelectionEvent.h | 8 +- SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp | 63 ++++++++ SpeckleLib/Speckle/Primitive/Mesh/Mesh.h | 45 ++++++ SpeckleLib/Speckle/Record/Element/Element.cpp | 120 +++++++++++++++ SpeckleLib/Speckle/Record/Element/Element.h | 116 +++++++++++++++ .../SpeckleLib.xcodeproj/project.pbxproj | 104 ++++++++++++- 29 files changed, 1509 insertions(+), 29 deletions(-) create mode 100644 SpeckleConnector/Connector/Record/Collection/RecordCollection.cpp create mode 100644 SpeckleConnector/Connector/Record/Collection/RecordCollection.h create mode 100644 SpeckleConnector/Connector/Record/Collection/RootCollection.cpp create mode 100644 SpeckleConnector/Connector/Record/Collection/RootCollection.h create mode 100644 SpeckleLib/Speckle/Database/BIMElementDatabase.cpp create mode 100644 SpeckleLib/Speckle/Database/BIMElementDatabase.h create mode 100644 SpeckleLib/Speckle/Database/Content/BIMRecord.cpp create mode 100644 SpeckleLib/Speckle/Database/Content/BIMRecord.h create mode 100644 SpeckleLib/Speckle/Database/Identity/BIMIndex.h rename SpeckleLib/Speckle/Database/Identity/{Link.cpp => BIMLink.cpp} (63%) create mode 100644 SpeckleLib/Speckle/Database/Identity/BIMLink.h create mode 100644 SpeckleLib/Speckle/Database/Identity/BIMRecordID.h create mode 100644 SpeckleLib/Speckle/Database/Storage/ArchicadDBase/ArchicadDBaseCore.cpp create mode 100644 SpeckleLib/Speckle/Database/Storage/ArchicadDBase/ArchicadDBaseCore.h create mode 100644 SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.cpp create mode 100644 SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.h create mode 100644 SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp create mode 100644 SpeckleLib/Speckle/Primitive/Mesh/Mesh.h create mode 100644 SpeckleLib/Speckle/Record/Element/Element.cpp create mode 100644 SpeckleLib/Speckle/Record/Element/Element.h diff --git a/SpeckleConnector/Connector.xcodeproj/project.pbxproj b/SpeckleConnector/Connector.xcodeproj/project.pbxproj index 8431d0f..4f81038 100644 --- a/SpeckleConnector/Connector.xcodeproj/project.pbxproj +++ b/SpeckleConnector/Connector.xcodeproj/project.pbxproj @@ -29,6 +29,7 @@ 215F082E2C94C5C000CD343B /* FilterMover.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 215F082C2C94C5C000CD343B /* FilterMover.cpp */; }; 215F08372C95808B00CD343B /* ReceiverModelCard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 215F08362C95808B00CD343B /* ReceiverModelCard.cpp */; }; 215F08462C9633A800CD343B /* EverythingSendFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 215F08452C9633A800CD343B /* EverythingSendFilter.cpp */; }; + 2192460D2CA3469D00CF5703 /* RootCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2192460B2CA3469D00CF5703 /* RootCollection.cpp */; }; 219F30422C769283009834E9 /* ConfigTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219F30402C769282009834E9 /* ConfigTests.cpp */; }; 21B67CA32C769CB400FD64FC /* libActiveLib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 21F69EF52C64FE91008B6A06 /* libActiveLib.a */; }; 21B67CA42C769CB400FD64FC /* libArchicad27.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 21F69ECD2C64C035008B6A06 /* libArchicad27.a */; }; @@ -220,6 +221,7 @@ 21F69F8D2C70D7EE008B6A06 /* GetAccounts.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21F69F8B2C70D7EE008B6A06 /* GetAccounts.cpp */; }; 21F69FBB2C762EF0008B6A06 /* ConfigBridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21F69FB42C762EF0008B6A06 /* ConfigBridge.cpp */; }; 21F69FBC2C762EF0008B6A06 /* GetConfig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21F69FB62C762EF0008B6A06 /* GetConfig.cpp */; }; + 21FF70492CA1A7F400AAD99A /* RecordCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21FF70462CA1A7F400AAD99A /* RecordCollection.cpp */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -298,6 +300,8 @@ 215F08452C9633A800CD343B /* EverythingSendFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EverythingSendFilter.cpp; sourceTree = ""; }; 215F084A2C9782F100CD343B /* ArchicadEverythingFilter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ArchicadEverythingFilter.h; sourceTree = ""; }; 2161FD902BF2600C006D9527 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + 2192460B2CA3469D00CF5703 /* RootCollection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RootCollection.cpp; sourceTree = ""; }; + 2192460C2CA3469D00CF5703 /* RootCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RootCollection.h; sourceTree = ""; }; 219388682C4E5DE2002A0180 /* CMakeLists.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; 219F30352C768F0A009834E9 /* Connector-AC27-Test.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Connector-AC27-Test.bundle"; sourceTree = BUILT_PRODUCTS_DIR; }; 219F30402C769282009834E9 /* ConfigTests.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = ConfigTests.cpp; sourceTree = ""; }; @@ -534,6 +538,8 @@ 21F69FB72C762EF0008B6A06 /* GetConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetConfig.h; sourceTree = ""; }; 21F69FBD2C7630B3008B6A06 /* UpdateConfig.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UpdateConfig.cpp; sourceTree = ""; }; 21F69FBE2C7630B3008B6A06 /* UpdateConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UpdateConfig.h; sourceTree = ""; }; + 21FF70462CA1A7F400AAD99A /* RecordCollection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RecordCollection.cpp; sourceTree = ""; }; + 21FF70472CA1A7F400AAD99A /* RecordCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecordCollection.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1036,6 +1042,7 @@ 21D0BDD82C9387E60077E104 /* Record */ = { isa = PBXGroup; children = ( + 21FF70482CA1A7F400AAD99A /* Collection */, 21D0BDD92C9387F70077E104 /* Model */, ); path = Record; @@ -1188,6 +1195,17 @@ path = Config; sourceTree = ""; }; + 21FF70482CA1A7F400AAD99A /* Collection */ = { + isa = PBXGroup; + children = ( + 21FF70462CA1A7F400AAD99A /* RecordCollection.cpp */, + 21FF70472CA1A7F400AAD99A /* RecordCollection.h */, + 2192460B2CA3469D00CF5703 /* RootCollection.cpp */, + 2192460C2CA3469D00CF5703 /* RootCollection.h */, + ); + path = Collection; + sourceTree = ""; + }; 7EA5F91E157FA18400693CEA /* EN-GB */ = { isa = PBXGroup; children = ( @@ -1407,12 +1425,14 @@ 21D0BD602C89BFEA0077E104 /* SendBridge.cpp in Sources */, 21D0BD972C8F13F30077E104 /* GetSendFilters.cpp in Sources */, 21B67CAC2C77329800FD64FC /* BaseBridge.cpp in Sources */, + 2192460D2CA3469D00CF5703 /* RootCollection.cpp in Sources */, 21D0BD6A2C8A0DB40077E104 /* GetIsDevMode.cpp in Sources */, 210CC8832C80E6A300610F58 /* TriggerEvent.cpp in Sources */, 21B67CEB2C78D27200FD64FC /* DocumentInfo.cpp in Sources */, 21B67CB92C774BFA00FD64FC /* GetConnectorVersion.cpp in Sources */, 21B67CD92C78C83800FD64FC /* TestBridge.cpp in Sources */, 214B7A372C764BCD00D586C1 /* UpdateConfig.cpp in Sources */, + 21FF70492CA1A7F400AAD99A /* RecordCollection.cpp in Sources */, 21B67CC02C775A0D00FD64FC /* GetDocumentInfo.cpp in Sources */, 21D0BDD42C935D1A0077E104 /* UpdateModel.cpp in Sources */, 21B67CE72C78D23B00FD64FC /* ConnectorConfig.cpp in Sources */, diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp index a037058..f9efa9b 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp @@ -19,7 +19,7 @@ Send::Send() : BridgeMethod{"Send", [&](const SendArgs& args) { /*-------------------------------------------------------------------- Send a specified model - modelCardID: The ID of the madel to send + modelCardID: The ID of the model to send --------------------------------------------------------------------*/ void Send::run(const String& modelCardID) const { ///TODO: Find and send selected elements - the following is a placeholder diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.h index 60ab477..7cead55 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.h +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.h @@ -33,7 +33,7 @@ namespace connector::interfac::browser::bridge { /*! Send a specified model - @param modelCardID The ID of the madel to send + @param modelCardID The ID of the model to send */ void run(const speckle::utility::String& modelCardID) const; }; diff --git a/SpeckleConnector/Connector/Record/Collection/RecordCollection.cpp b/SpeckleConnector/Connector/Record/Collection/RecordCollection.cpp new file mode 100644 index 0000000..a6f0d5e --- /dev/null +++ b/SpeckleConnector/Connector/Record/Collection/RecordCollection.cpp @@ -0,0 +1,75 @@ +#include "Connector/Record/Collection/RecordCollection.h" + +#include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Active/Serialise/Package/Wrapper/PackageWrap.h" + +using namespace active::serialise; +using namespace connector::record; +using namespace speckle::database; +using namespace speckle::utility; + +#include + +namespace { + + ///Serialisation fields + enum FieldIndex { + nameID, + elementID, + childrenID, + }; + + ///Serialisation field IDs + static std::array fieldID = { + Identity{"name"}, + Identity{"element"}, + Identity{"child"}, + }; + +} + + +/*-------------------------------------------------------------------- + Fill an inventory with the package items + + inventory: The inventory to receive the package items + + return: True if the package has added items to the inventory + --------------------------------------------------------------------*/ +bool RecordCollection::fillInventory(Inventory& inventory) const { + using enum Entry::Type; + inventory.merge(Inventory{ + { + { fieldID[nameID], nameID, element }, + { fieldID[elementID], elementID, base::size(), std::nullopt, !base::empty() }, + { fieldID[childrenID], childrenID, m_children.size(), std::nullopt, !m_children.empty() }, + }, + }.withType(&typeid(RecordCollection))); + return true; +} //RecordCollection::fillInventory + + +/*-------------------------------------------------------------------- + Get the specified cargo + + item: The inventory item to retrieve + + return: The requested cargo (nullptr on failure) + --------------------------------------------------------------------*/ +Cargo::Unique RecordCollection::getCargo(const Inventory::Item& item) const { + if (item.ownerType != &typeid(RecordCollection)) + return nullptr; + using namespace active::serialise; + switch (item.index) { + case nameID: + return std::make_unique(m_name); + case elementID: + return nullptr; //TODO: Implement - need to interrogate BIM database for element and return as cargo + case childrenID: + if (item.available < m_children.size()) + return std::make_unique(m_children[item.available]); + return nullptr; + default: + return nullptr; //Requested an unknown index + } +} //RecordCollection::getCargo diff --git a/SpeckleConnector/Connector/Record/Collection/RecordCollection.h b/SpeckleConnector/Connector/Record/Collection/RecordCollection.h new file mode 100644 index 0000000..0d19b33 --- /dev/null +++ b/SpeckleConnector/Connector/Record/Collection/RecordCollection.h @@ -0,0 +1,91 @@ +#ifndef CONNECTOR_RECORD_RECORD_COLLECTiON +#define CONNECTOR_RECORD_RECORD_COLLECTiON + +#include "Active/Container/Vector.h" +#include "Active/Serialise/Package/Package.h" +#include "Speckle/Database/Identity/RecordID.h" +#include "Speckle/Utility/String.h" + +namespace connector::record { + + /*! + Container for a collection of elements (and potentially tables of associated attributes) for Speckle commits + + The container only stores element indices - database operations (including serialisation) will lookup records from a specified BIMDatabase on + demand. + + This container can used hierarchically, so an collection can be nested within another collection. The current structure is: + - Root + - Element containers dividing elements by level/storey + - Element containers dividing elements by classification + - [nested classification leaf nodes) + - Associated attributes, e.g. classification table (future) + + Any level in the hierarchy may contain element indices, although this is currently unlikely at the root level (all elements have a level/storey) + Each container should be named appropriately, e.g. a level/storey collection should be named to match the level/storey. + + Note that the serialisation is currently implemented for sending only. Receive can be added as required + */ + class RecordCollection : public std::vector, public active::serialise::Package { + public: + + // MARK: - Types + + using base = std::vector; + using Children = std::vector; + + // MARK: - Constructors + + using base::base; + + // MARK: - Functions (const) + + /*! + Get the container name + @return The container name + */ + const speckle::utility::String& getName() const { return m_name; } + /*! + Get the child collections + @return The child collections nested under this collection + */ + const Children& getChildren() const; + + // MARK: - Functions (mutating) + + /*! + Set the container name + @param name The container name + */ + void setName(const speckle::utility::String& name) { m_name = name; } + /*! + Add a child collection + @param child The child collection to add + */ + void addChild(RecordCollection&& child); + + // MARK: - Serialisation + + /*! + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ + bool fillInventory(active::serialise::Inventory& inventory) const override; + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + + private: + ///Child nodes of this collection + Children m_children; + ///The collection name + speckle::utility::String m_name; + }; + +} + +#endif //CONNECTOR_RECORD_RECORD_COLLECTiON diff --git a/SpeckleConnector/Connector/Record/Collection/RootCollection.cpp b/SpeckleConnector/Connector/Record/Collection/RootCollection.cpp new file mode 100644 index 0000000..90be329 --- /dev/null +++ b/SpeckleConnector/Connector/Record/Collection/RootCollection.cpp @@ -0,0 +1,34 @@ +#include "Connector/Record/Collection/RootCollection.h" + +#include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Active/Serialise/Package/Wrapper/PackageWrap.h" + +using namespace active::serialise; +using namespace connector::record; +using namespace speckle::database; +using namespace speckle::utility; + +/*-------------------------------------------------------------------- + Fill an inventory with the package items + + inventory: The inventory to receive the package items + + return: True if the package has added items to the inventory + --------------------------------------------------------------------*/ +bool RootCollection::fillInventory(Inventory& inventory) const { + //Extend with supplementary data as required + return base::fillInventory(inventory); +} //RootCollection::fillInventory + + +/*-------------------------------------------------------------------- + Get the specified cargo + + item: The inventory item to retrieve + + return: The requested cargo (nullptr on failure) + --------------------------------------------------------------------*/ +Cargo::Unique RootCollection::getCargo(const Inventory::Item& item) const { + //Extend with supplementary data as required + return base::getCargo(item); +} //RootCollection::getCargo diff --git a/SpeckleConnector/Connector/Record/Collection/RootCollection.h b/SpeckleConnector/Connector/Record/Collection/RootCollection.h new file mode 100644 index 0000000..f12a5b0 --- /dev/null +++ b/SpeckleConnector/Connector/Record/Collection/RootCollection.h @@ -0,0 +1,52 @@ +#ifndef CONNECTOR_RECORD_ROOT_COLLECTiON +#define CONNECTOR_RECORD_ROOT_COLLECTiON + +#include "Connector/Record/Collection/RecordCollection.h" + +namespace connector::record { + + /*! + Root container for sending model data to a Speckle server + + Additional information is anticipated at the root level that will not apply at any other level in the container hierarchy, e.g.: + - Classification hierarchy + - Layers + - Other attributes, e.g. materials + Add all this supplementary data to the root container as required + */ + class RootCollection : public RecordCollection { + public: + + // MARK: - Types + + using base = RecordCollection; + + // MARK: - Constructors + + using base::base; + + // MARK: - Functions (const) + + + // MARK: - Functions (mutating) + + + // MARK: - Serialisation + + /*! + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ + bool fillInventory(active::serialise::Inventory& inventory) const override; + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + }; + +} + +#endif //CONNECTOR_RECORD_ROOT_COLLECTiON diff --git a/SpeckleLib/Speckle/Database/BIMElementDatabase.cpp b/SpeckleLib/Speckle/Database/BIMElementDatabase.cpp new file mode 100644 index 0000000..f5d38ef --- /dev/null +++ b/SpeckleLib/Speckle/Database/BIMElementDatabase.cpp @@ -0,0 +1,104 @@ +#include "Speckle/Database/BIMElementDatabase.h" + +#include "Active/Database/Storage/Storage.h" +#include "Active/Serialise/UnboxedTransport.h" +#include "Speckle/Database/Identity/RecordID.h" +#include "Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.h" +#include "Speckle/Record/Element/Element.h" + +#include + +using namespace active::container; +using namespace active::database; +using namespace active::event; +using namespace active::serialise; +using namespace speckle::database; +using namespace speckle::record; +using namespace speckle::record::element; +using namespace speckle::database; +using namespace speckle::utility; + +namespace speckle::database { + + ///Define other platform engines here as required +#ifdef ARCHICAD + using ElementDatabaseEngine = ArchicadElementDBaseEngine; +#endif + + ///Element database engine declaration + class BIMElementDatabase::Engine : public ElementDatabaseEngine { + using base = ArchicadElementDBaseEngine; + using base::base; + }; + + ///Element database storage declaration + class BIMElementDatabase::Store : public Storage { + using base = Storage; + using base::base; + }; + +} + +namespace { + + ///The database storage identifier for elements + const char* elementDBaseName = "speckle::database::BIMElementDatabase"; + ///The primary model table, e.g. floor plan in Archicad + const char* modelTableName = "Model"; + +} + +/*-------------------------------------------------------------------- + Constructor + --------------------------------------------------------------------*/ +BIMElementDatabase::BIMElementDatabase() { + m_engine = std::make_shared(elementDBaseName, + //Schema + DBaseSchema{active::utility::String{elementDBaseName}, + //Tables + { + //Model element table + { + modelTableName, 0, 0, {} //The primary model. Additonal tables could be linked to other drawings/layouts in future + } + } + } + ); + m_store = std::make_shared(m_engine); +} //BIMElementDatabase::BIMElementDatabase + + +/*-------------------------------------------------------------------- + Destructor + --------------------------------------------------------------------*/ +BIMElementDatabase::~BIMElementDatabase() {} + + +/*-------------------------------------------------------------------- + Get all elements + + return: All the elements + --------------------------------------------------------------------*/ +Vector BIMElementDatabase::getElements() const { + return m_store->getObjects(); +} //BIMElementDatabase::getElements + + +/*-------------------------------------------------------------------- + Write an element to storage + + element: The element to write + --------------------------------------------------------------------*/ +void BIMElementDatabase::write(const Element& element) const { + m_store->write(element); +} //BIMElementDatabase::write + + +/*-------------------------------------------------------------------- + Erase an element + + elementID: The ID of the element to erase + --------------------------------------------------------------------*/ +void BIMElementDatabase::erase(const Guid& elementID) const { + m_store->erase(elementID); +} //BIMElementDatabase::erase diff --git a/SpeckleLib/Speckle/Database/BIMElementDatabase.h b/SpeckleLib/Speckle/Database/BIMElementDatabase.h new file mode 100644 index 0000000..5093740 --- /dev/null +++ b/SpeckleLib/Speckle/Database/BIMElementDatabase.h @@ -0,0 +1,65 @@ +#ifndef CONNECTOR_DATABASE_BIM_DATABASE +#define CONNECTOR_DATABASE_BIM_DATABASE + +#include "Speckle/Record/Element/Element.h" +#include "Speckle/Utility/Guid.h" + +namespace active::event { + class Subscriber; +} + +namespace speckle::database { + + /*! + Database of model elements relating to a specific project + */ + class BIMElementDatabase { + public: + + // MARK: - Constructors + + /*! + Constructor + */ + BIMElementDatabase(); + BIMElementDatabase(const BIMElementDatabase&) = delete; + /*! + Destructor + */ + ~BIMElementDatabase(); + + // MARK: - Functions (const) + + /*! + Get a specified element + @param elementID The ID of the target element + @return The requested element (nullptr on failure) + */ + record::element::Element::Unique getElement(const utility::Guid& elementID) const; + /*! + Get all model elements + @return All the elements + */ + active::container::Vector getElements() const; + /*! + Write an element to storage + @param element The element to write + */ + void write(const record::element::Element& element) const; + /*! + Erase an element + @param elementID The ID of the element to erase + */ + void erase(const speckle::utility::Guid& elementID) const; + + private: + class Engine; + class Store; + ///Model element database storage + std::shared_ptr m_engine; + std::shared_ptr m_store; + }; + +} + +#endif //CONNECTOR_DATABASE_BIM_DATABASE diff --git a/SpeckleLib/Speckle/Database/Content/BIMRecord.cpp b/SpeckleLib/Speckle/Database/Content/BIMRecord.cpp new file mode 100644 index 0000000..882a681 --- /dev/null +++ b/SpeckleLib/Speckle/Database/Content/BIMRecord.cpp @@ -0,0 +1,24 @@ +#include "Speckle/Database/Content/Record.h" + +#include "Speckle/Utility/Guid.h" + +using namespace active::serialise; +using namespace speckle::database; +using namespace speckle::utility; + +/*-------------------------------------------------------------------- + Fill an inventory with the package items + + inventory: The inventory to receive the package items + + return: True if the package has added items to the inventory + --------------------------------------------------------------------*/ +bool Record::fillInventory(active::serialise::Inventory& inventory) const { + using enum Entry::Type; + inventory.merge(Inventory{ + { + { Identity{"id"}, active::database::record::FieldIndex::idIndex, element }, + }, + }.withType(&typeid(base))); + return true; +} //Record::fillInventory diff --git a/SpeckleLib/Speckle/Database/Content/BIMRecord.h b/SpeckleLib/Speckle/Database/Content/BIMRecord.h new file mode 100644 index 0000000..0cd3db7 --- /dev/null +++ b/SpeckleLib/Speckle/Database/Content/BIMRecord.h @@ -0,0 +1,62 @@ +#ifndef SPECKLE_DATABASE_RECORD +#define SPECKLE_DATABASE_RECORD + +#include "Active/Database/Content/Record.h" +#include "Speckle/Database/Identity/Link.h" +#include "Speckle/Database/Identity/BIMRecordID.h" + +namespace speckle::database { + + /*! + Base class for a database record + */ + class BIMRecord : public active::database::BIMRecord { + public: + + // MARK: - Types + + using base = active::database::BIMRecord; + ///Unique pointer + using Unique = std::unique_ptr; + ///Shared pointer + using Shared = std::shared_ptr; + ///Optional + using Option = std::optional; + + // MARK: - Constructors + + /*! + Default constructor + */ + BIMRecord() : base{active::utility::Guid{true}.operator active::utility::String(), + active::utility::Guid{true}.operator active::utility::String()} {} //TODO: Implement a better default for the ID + /*! + Constructor + @param ID The record ID + */ + BIMRecord(speckle::utility::String ID, speckle::utility::String::Option globID = std::nullopt) : + base{ID, globID.value_or(active::utility::Guid{true}.operator active::utility::String())} {} + /*! + Destructor + */ + virtual ~BIMRecord() {} + + // MARK: - Functions (const) + + + // MARK: - Functions (mutating) + + + // MARK: - Serialisation + + /*! + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ + bool fillInventory(active::serialise::Inventory& inventory) const override; + }; + +} + +#endif //SPECKLE_DATABASE_RECORD diff --git a/SpeckleLib/Speckle/Database/Identity/BIMIndex.h b/SpeckleLib/Speckle/Database/Identity/BIMIndex.h new file mode 100644 index 0000000..f1ea64d --- /dev/null +++ b/SpeckleLib/Speckle/Database/Identity/BIMIndex.h @@ -0,0 +1,30 @@ +#ifndef SPECKLE_DATABASE_BIM_INDEX +#define SPECKLE_DATABASE_BIM_INDEX + +#include "Active/Database/Identity/Index.h" +#include "Speckle/Database/Identity/RecordID.h" + +namespace speckle::database { + + /*! + Record index class + + A record index is the information required to uniquely identify (and locate) a specified record in some database/app context. For Archicad, + this is typically a guid, for Revit a string and for Vectorworks a handle. Note that this index is not necessarily persistent between + sessions. + */ + class BIMIndex : public active::database::Index { + public: + + // MARK: - Types + + using base = active::database::Index; + + // MARK: - Constructors + + using base::base; + }; + +} + +#endif //SPECKLE_DATABASE_BIM_INDEX diff --git a/SpeckleLib/Speckle/Database/Identity/Link.cpp b/SpeckleLib/Speckle/Database/Identity/BIMLink.cpp similarity index 63% rename from SpeckleLib/Speckle/Database/Identity/Link.cpp rename to SpeckleLib/Speckle/Database/Identity/BIMLink.cpp index 6eb09f4..4c1ab7f 100644 --- a/SpeckleLib/Speckle/Database/Identity/Link.cpp +++ b/SpeckleLib/Speckle/Database/Identity/BIMLink.cpp @@ -1,5 +1,4 @@ -#include "Speckle/Database/Identity/Link.h" -#include "Speckle/Utility/Guid.h" +#include "Speckle/Database/Identity/BIMLink.h" using namespace speckle::database; using namespace speckle::utility; @@ -10,9 +9,9 @@ using namespace speckle::utility; selected: Information about a selected Archicad element --------------------------------------------------------------------*/ -//Link::Link(const API_Neig& selected) : base{Guid{selected.guid}} { - //More info should be extracted from API_Neig in future (as required) -//} //Link::Link +BIMLink::BIMLink(const API_Neig& selected) : base{Guid{selected.guid}} { + //More info should be extracted from API_Neig in future (as required) - extract into link settings, e.g. selection target etc +} //Link::Link #endif diff --git a/SpeckleLib/Speckle/Database/Identity/BIMLink.h b/SpeckleLib/Speckle/Database/Identity/BIMLink.h new file mode 100644 index 0000000..bd06a09 --- /dev/null +++ b/SpeckleLib/Speckle/Database/Identity/BIMLink.h @@ -0,0 +1,44 @@ +#ifndef SPECKLE_DATABASE_BIM_LINK +#define SPECKLE_DATABASE_BIM_LINK + +#include "Active/Setting/SettingList.h" +#include "Active/Database/Identity/Link.h" +#include "Speckle/Database/Identity/BIMRecordID.h" + +namespace speckle::database { + + /*! + Record link class, binding an index to additional information + + The essential part of a link is the index pointing to a target record. In some cases, e.g. where the user has selected something in a rendered + scene, the index is to a proxy object that represents another record in a specific context, e.g. a 2D representation of a 3D element rendered + in a cut plance section view. A tool working with the link might be interested in either the proxy or the original - passing a link allows + this distinction to be easily made. + + A link may optionally carry any number of settings. In the context of a user selection (for example) there might be settings describing where + the user made the selection (e.g. the hole in a floor slab), allowing a tool working on that selection to be more precise. + */ + class BIMLink : public active::database::Link { + public: + + // MARK: - Types + + using base = active::database::Link; + + // MARK: - Constructors + + using base::base; + + BIMLink() = default; +#ifdef ARCHICAD + /*! + Constructor + @param selected Information about a selected Archicad element + */ + BIMLink(const API_Neig& selected); +#endif + }; + +} + +#endif //SPECKLE_DATABASE_BIM_LINK diff --git a/SpeckleLib/Speckle/Database/Identity/BIMRecordID.h b/SpeckleLib/Speckle/Database/Identity/BIMRecordID.h new file mode 100644 index 0000000..86b6c6b --- /dev/null +++ b/SpeckleLib/Speckle/Database/Identity/BIMRecordID.h @@ -0,0 +1,22 @@ +#ifndef SPECKLE_DATABASE_BIM_ID +#define SPECKLE_DATABASE_BIM_ID + +#include "Speckle/Utility/Guid.h" + +namespace speckle::database { + +#ifdef ARCHICAD + //Common BIM record identifier type (e.g. to BIM elements) + using BIMRecordID = speckle::utility::Guid; + //Common BIM table identifier type (e.g. BIM drawing identifier) + using BIMTableID = speckle::utility::Guid; + //Common BIM database identifier type (e.g. model database, library database, attribute database) + using BIMDBaseID = speckle::utility::Guid; +#endif + + //A list of BIM record IDs + using BIMRecordIDList = std::vector; + +} + +#endif //SPECKLE_DATABASE_BIM_ID diff --git a/SpeckleLib/Speckle/Database/Identity/Index.h b/SpeckleLib/Speckle/Database/Identity/Index.h index c3b3e66..718c8c4 100644 --- a/SpeckleLib/Speckle/Database/Identity/Index.h +++ b/SpeckleLib/Speckle/Database/Identity/Index.h @@ -1,11 +1,8 @@ #ifndef SPECKLE_DATABASE_INDEX #define SPECKLE_DATABASE_INDEX -#include "Active/Database/Identity/Link.h" +#include "Active/Database/Identity/Index.h" #include "Speckle/Database/Identity/RecordID.h" -#include "Speckle/Utility/String.h" - -#include namespace speckle::database { diff --git a/SpeckleLib/Speckle/Database/Identity/Link.h b/SpeckleLib/Speckle/Database/Identity/Link.h index 2789d22..bd7d2ac 100644 --- a/SpeckleLib/Speckle/Database/Identity/Link.h +++ b/SpeckleLib/Speckle/Database/Identity/Link.h @@ -2,6 +2,7 @@ #define SPECKLE_DATABASE_LINK #include "Active/Setting/SettingList.h" +#include "Active/Database/Identity/Link.h" #include "Speckle/Database/Identity/Index.h" namespace speckle::database { @@ -29,13 +30,6 @@ namespace speckle::database { using base::base; Link() = default; -#ifdef ARCHICAD - /*! - Constructor - @param selected Information about a selected Archicad element - */ - Link(const API_Neig& selected); -#endif }; } diff --git a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/ArchicadDBaseCore.cpp b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/ArchicadDBaseCore.cpp new file mode 100644 index 0000000..5848954 --- /dev/null +++ b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/ArchicadDBaseCore.cpp @@ -0,0 +1,95 @@ +#include "Speckle/Database/Storage/ArchicadDBase/ArchicadDBaseCore.h" + +#ifdef ARCHICAD + +#include "Active/Utility/Defer.h" +#include "Active/Utility/Memory.h" +#include "Active/Utility/String.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/Utility/Guid.h" +#include "Speckle/Utility/String.h" + +#include +#include + +using namespace active::event; +using namespace active::setting; +using namespace speckle::database; +using namespace speckle::environment; +using namespace speckle::event; +using namespace speckle::utility; + +using enum ArchicadDBaseCore::Status; + +namespace { + + /*-------------------------------------------------------------------- + Convert an Archicad API error code to a ArchicadDBaseCore status + + acErrorCode: The API error code + + return: An equivalent status code + --------------------------------------------------------------------*/ + ArchicadDBaseCore::Status convertArchicadError(long acErrorCode) { + using enum ArchicadDBaseCore::Status; + switch (acErrorCode) { + case NoError: + return nominal; + case APIERR_BADPARS: + return badParameter; + case APIERR_BADID: + return badID; + default: + break; + } + return error; + } //convertArchicadError + + + ///Category for ArchicadElementDBase processing errors + class ArchicadDBaseCategory : public std::error_category { + public: + ///Category name + const char* name() const noexcept override { + return "speckle::database::archicad::category"; + } + /*! + Get a message for a specified error code + @param errorCode A ArchicadElementDBase processing code + @return The error message for the specified code + */ + std::string message(int errorCode) const override { + //TODO: These error messages are ok for developers - but can we help users more? + switch (static_cast(errorCode)) { + case nominal: + return ""; + case badParameter: + return "An internal function has been incorrectly used"; + case badID: + return "Internal data has been requested using an invalid identity"; + case error: + return "A non-specific error occurred"; + default: + return "An unknown error occurred"; + } + } + }; + + ///ArchicadElementDBase processing category error instance + static ArchicadDBaseCategory instance; + +} + +/*-------------------------------------------------------------------- + Make an error code for ArchicadElementDBase processing + + return: An STL error code + --------------------------------------------------------------------*/ +std::error_code ArchicadDBaseCore::makeError(ArchicadDBaseCore::Status code) { + return std::error_code(static_cast(code), instance); +} //ArchicadDBaseCore::makeError + +#endif diff --git a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/ArchicadDBaseCore.h b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/ArchicadDBaseCore.h new file mode 100644 index 0000000..2ac2f97 --- /dev/null +++ b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/ArchicadDBaseCore.h @@ -0,0 +1,86 @@ +#ifndef SPECKLE_DATABASE_ARCHICAD_DBASE_CORE +#define SPECKLE_DATABASE_ARCHICAD_DBASE_CORE + +#ifdef ARCHICAD + +#include "Active/File/Path.h" +#include "Active/Setting/SettingList.h" +#include "Active/Database/Storage/DBaseSchema.h" +#include "Active/Utility/NameID.h" +#include "Speckle/Event/Subscriber/DocStoreSubscriber.h" +#include "Speckle/Event/Subscriber/ProjectSubscriber.h" + +namespace speckle::database { + + using ArchicadDBaseSchema = active::database::DBaseSchema<>; + + /*! + Core functionality and definitions for a mechanism to store data in a BIM (3rd-party) document/database + + Currently implement for Archicad Add-On Objects + */ + class ArchicadDBaseCore { + public: + + // MARK: - Types + + ///Status of of the ArchicadElementDBase database + enum class Status { + nominal, /// +#include + +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; + +/*-------------------------------------------------------------------- + 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 ArchicadElementDBaseEngine::getObject(const BIMRecordID& ID, std::optional tableID, + std::optional documentID) const { + return nullptr; //TODO: Implement +} //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 tableID, + std::optional 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 ArchicadElementDBaseEngine::getObjects(std::optional tableID, + std::optional documentID) const { + return {}; +} //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 ArchicadElementDBaseEngine::getObjects(const Filter& filter, std::optional tableID, + std::optional 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 objDocID, + std::optional tableID, std::optional 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 tableID, + std::optional 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 tableID, std::optional documentID) const { + +} //ArchicadElementDBaseEngine::erase + + +/*-------------------------------------------------------------------- + Get the database outline + + return: The database outline + --------------------------------------------------------------------*/ +ArchicadElementDBaseEngine::Outline ArchicadElementDBaseEngine::getOutline() const { + return {}; +} //ArchicadElementDBaseEngine::getOutline + +#endif diff --git a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.h b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.h new file mode 100644 index 0000000..5ab6bea --- /dev/null +++ b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.h @@ -0,0 +1,109 @@ +#ifndef SPECKLE_DATABASE_ARCHICAD_ELEMENT_DBASE_ENGINE +#define SPECKLE_DATABASE_ARCHICAD_ELEMENT_DBASE_ENGINE + +#include "Active/Database/Storage/DBaseEngine.h" +#include "Active/Serialise/UnboxedTransport.h" +#include "Speckle/Database/Storage/ArchicadDBase/ArchicadDBaseCore.h" +#include "Speckle/Database/Identity/BIMRecordID.h" +#include "Speckle/Record/Element/Element.h" +#include "Speckle/Utility/Guid.h" +#include "Speckle/Utility/String.h" + +#include +#include + +namespace speckle::database { + + /*! + A database engine to read/write elements in an Archicad project database (local file or cloud-based) + */ + class ArchicadElementDBaseEngine : public ArchicadDBaseCore, + public active::database::DBaseEngine { + public: + + // MARK: - Types + + using base = active::database::DBaseEngine; + using Element = record::element::Element; + using Filter = base::Filter; + using Outline = base::Outline; + + // MARK: - Constructors + + /*! + Constructor + @param id The document storage identifier + */ + ArchicadElementDBaseEngine(const active::utility::NameID& id, ArchicadDBaseSchema&& schema) : ArchicadDBaseCore{id, std::move(schema)} {} + ArchicadElementDBaseEngine(const ArchicadElementDBaseEngine&) = delete; + + // MARK: - Functions (const) + + /*! + Get an object by index + @param objID The object ID + @param tableID Optional table ID (defaults to the floor plan) + @param documentID Optional document ID (when the object is bound to a specific document) + @return The requested object (nullptr on failure) + */ + std::unique_ptr getObject(const BIMRecordID& objID, std::optional tableID = std::nullopt, std::optional documentID = std::nullopt) const override; + /*! + Get an object in a transportable form, e.g. packaged for serialisation + @param objID The object ID + @param tableID Optional table ID (defaults to the floor plan) + @param 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 getObjectCargo(const BIMRecordID& objID, std::optional tableID = std::nullopt, std::optional documentID = std::nullopt) const override; + /*! + Get all objects + @param tableID Optional table ID (defaults to the floor plan) + @param documentID Optional document ID (filter for this document only - nullopt = all objects) + @return The requested objects (nullptr on failure) + */ + active::container::Vector getObjects(std::optional tableID = std::nullopt, std::optional documentID = std::nullopt) const override; + /*! + Get a filtered list of objects + @param filter The object filter + @param tableID Optional table ID (defaults to the floor plan) + @param documentID Optional document ID (filter for this document only - nullopt = all objects) + @return The filtered objects (nullptr on failure) + */ + active::container::Vector getObjects(const Filter& filter, std::optional tableID = std::nullopt, + std::optional documentID = std::nullopt) const override; + /*! + Write an object to the database + @param object The object to write + @param objID The object ID + @param objDocID The object document-specific ID (unique within a specific document - nullopt if not document-bound) + @param tableID Optional table ID (defaults to the floor plan) + @param documentID Optional document ID (when the object is bound to a specific document) + */ + void write(const Element& object, const BIMRecordID& objID, std::optional objDocID = std::nullopt, + std::optional tableID = std::nullopt, std::optional documentID = std::nullopt) const override; + /*! + Erase an object by index + @param ID The object ID + @param tableID Optional table ID (defaults to the floor plan) + @param documentID Optional document ID (when the object is bound to a specific document) + @throw Exception thrown on SQL error + */ + void erase(const BIMRecordID& ID, std::optional tableID = std::nullopt, + std::optional documentID = std::nullopt) const override; + /*! + Erase all objects + @param tableID Optional table ID (defaults to the floor plan) + @param documentID Optional document ID (when the object is bound to a specific document) + @throw Exception thrown on SQL error + */ + void erase(std::optional tableID = std::nullopt, std::optional documentID = std::nullopt) const override; + /*! + Get the database outline + @return The database outline + */ + Outline getOutline() const override; + }; + +} + +#endif //SPECKLE_DATABASE_ARCHICAD_ELEMENT_DBASE_ENGINE diff --git a/SpeckleLib/Speckle/Database/Storage/DocumentStore/DocumentStoreCore.cpp b/SpeckleLib/Speckle/Database/Storage/DocumentStore/DocumentStoreCore.cpp index c12d603..a7f6b90 100644 --- a/SpeckleLib/Speckle/Database/Storage/DocumentStore/DocumentStoreCore.cpp +++ b/SpeckleLib/Speckle/Database/Storage/DocumentStore/DocumentStoreCore.cpp @@ -105,7 +105,7 @@ namespace { public: ///Category name const char* name() const noexcept override { - return "active::database::sqlite::category"; + return "speckle::database::docStore::category"; } /*! Get a message for a specified error code diff --git a/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.cpp b/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.cpp index 576b4df..2d10bd6 100644 --- a/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.cpp +++ b/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.cpp @@ -1,7 +1,7 @@ #include "Speckle/Event/Subscriber/SelectionSubscriber.h" #include "Speckle/Environment/Addon.h" -#include "Speckle/Database/Identity/Link.h" +#include "Speckle/Database/Identity/BIMLink.h" #include "Speckle/Event/Type/SelectionEvent.h" #ifdef ARCHICAD @@ -23,7 +23,7 @@ namespace { */ GSErrCode __ACENV_CALL selectionCallback(const API_Neig* params) { if (addon() != nullptr) { - auto selection = (params == nullptr) ? Link{} : Link{*params}; + auto selection = (params == nullptr) ? BIMLink{} : BIMLink{*params}; addon()->publishExternal(SelectionEvent{selection}); } return NoError; diff --git a/SpeckleLib/Speckle/Event/Type/SelectionEvent.h b/SpeckleLib/Speckle/Event/Type/SelectionEvent.h index 9ebbe6c..396f698 100644 --- a/SpeckleLib/Speckle/Event/Type/SelectionEvent.h +++ b/SpeckleLib/Speckle/Event/Type/SelectionEvent.h @@ -5,7 +5,7 @@ #include "Active/Utility/Guid.h" #include "Active/Utility/String.h" -#include "Speckle/Database/Identity/Link.h" +#include "Speckle/Database/Identity/BIMLink.h" namespace speckle::event { @@ -24,7 +24,7 @@ namespace speckle::event { Constructor @param selected A link to a selected element (nullopt if the selection is empty) */ - SelectionEvent(speckle::database::Link::Option selected) : m_selectedLink{selected} {} + SelectionEvent(speckle::database::BIMLink::Option selected) : m_selectedLink{selected} {} /*! Copy constructor @param source The object to copy @@ -46,10 +46,10 @@ namespace speckle::event { Get a link to the last selected element @return A link to the last selected element (nullopt if the event selection is empty) */ - speckle::database::Link::Option getLastSelected() const { return m_selectedLink; } + speckle::database::BIMLink::Option getLastSelected() const { return m_selectedLink; } private: - speckle::database::Link::Option m_selectedLink; + speckle::database::BIMLink::Option m_selectedLink; }; } diff --git a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp new file mode 100644 index 0000000..eee7c6b --- /dev/null +++ b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp @@ -0,0 +1,63 @@ +#include "Speckle/Primitive/Mesh/Mesh.h" + +#include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Active/Serialise/Inventory/Identity.h" + +using namespace active::serialise; +using namespace speckle::primitive; + +namespace { + + ///Serialisation fields + enum FieldIndex { + vertexID, + faceID, + }; + + ///Serialisation field IDs + static std::array fieldID = { + Identity{"vertices"}, + Identity{"faces"}, + }; + +} + +/*-------------------------------------------------------------------- + Fill an inventory with the package items + + inventory: The inventory to receive the package items + + return: True if the package has added items to the inventory + --------------------------------------------------------------------*/ +bool Mesh::fillInventory(Inventory& inventory) const { + using enum Entry::Type; + inventory.merge(Inventory{ + { + //{ fieldID[vertexID], vertexID, vertices::size(), std::nullopt, !vertices::empty() }, + //{ fieldID[elementID], elementID, faces::size(), std::nullopt, !faces::empty() }, + }, + }.withType(&typeid(Mesh))); + return true; +} //Mesh::fillInventory + + +/*-------------------------------------------------------------------- + Get the specified cargo + + item: The inventory item to retrieve + + return: The requested cargo (nullptr on failure) + --------------------------------------------------------------------*/ +Cargo::Unique Mesh::getCargo(const Inventory::Item& item) const { + if (item.ownerType != &typeid(Mesh)) + return nullptr; + using namespace active::serialise; + switch (item.index) { + case vertexID: + return nullptr; //TODO: Implement vertices array + case faceID: + return nullptr; //TODO: Implement faces array + default: + return nullptr; //Requested an unknown index + } +} //Mesh::getCargo diff --git a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h new file mode 100644 index 0000000..d440fc3 --- /dev/null +++ b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h @@ -0,0 +1,45 @@ +#ifndef SPECKLE_PRIMITIVE_MESH +#define SPECKLE_PRIMITIVE_MESH + +#include "Active/Serialise/Package/Package.h" + +namespace speckle::primitive { + + /*! + Class for a 3D mesh + */ + class Mesh : public active::serialise::Package { + public: + + // MARK: - Constructors + + /*! + Default constructor + */ + Mesh() {} + + // MARK: - Functions (const) + + + // MARK: - Serialisation + + /*! + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ + bool fillInventory(active::serialise::Inventory& inventory) const override; + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + + private: + + }; + +} + +#endif //SPECKLE_PRIMITIVE_MESH diff --git a/SpeckleLib/Speckle/Record/Element/Element.cpp b/SpeckleLib/Speckle/Record/Element/Element.cpp new file mode 100644 index 0000000..7e5a1e5 --- /dev/null +++ b/SpeckleLib/Speckle/Record/Element/Element.cpp @@ -0,0 +1,120 @@ +#include "Speckle/Record/Element/Element.h" + +#include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Active/Serialise/Package/Wrapper/PackageWrap.h" +#include "Speckle/Primitive/Mesh/Mesh.h" +#include "Speckle/Utility/Guid.h" + +using namespace active::serialise; +using namespace speckle::record::element; +using namespace speckle::utility; + +#include + +namespace speckle::record::element { + + class Element::Data { + public: + Data(const API_Element& elem) : root{elem} {} + Data(const Data& source); + + private: + API_Element root; + std::unique_ptr m_cache; + }; + +} + +namespace { + + ///Serialisation fields + enum FieldIndex { + bodyID, + }; + + ///Serialisation field IDs + static std::array fieldID = { + Identity{"displayValue"}, + }; + +} + +/*-------------------------------------------------------------------- + Default constructor + --------------------------------------------------------------------*/ +Element::Element() { +} //Element::Element + + +/*-------------------------------------------------------------------- + Constructor + + elemData: Archicad element data + --------------------------------------------------------------------*/ +Element::Element(const API_Element& elemData) { + m_data = std::make_unique(elemData); +} //Element::Element + + +/*-------------------------------------------------------------------- + Copy constructor + + source: The object to copy + --------------------------------------------------------------------*/ +Element::Element(const Element& source) { + m_data = source.m_data ? std::make_unique(*m_data) : nullptr; +} //Element::Element + + +/*-------------------------------------------------------------------- + Destructor + --------------------------------------------------------------------*/ +Element::~Element() {} + + +/*-------------------------------------------------------------------- + Fill an inventory with the package items + + inventory: The inventory to receive the package items + + return: True if the package has added items to the inventory + --------------------------------------------------------------------*/ +bool Element::fillInventory(Inventory& inventory) const { + using enum Entry::Type; + auto body = getBody(); + inventory.merge(Inventory{ + { + { fieldID[bodyID], bodyID, body == nullptr ? 0 : static_cast(body->size()) }, //TODO: implement other fields + }, + }.withType(&typeid(Element))); + return base::fillInventory(inventory); +} //Element::fillInventory + + +/*-------------------------------------------------------------------- + Get the specified cargo + + item: The inventory item to retrieve + + return: The requested cargo (nullptr on failure) + --------------------------------------------------------------------*/ +Cargo::Unique Element::getCargo(const Inventory::Item& item) const { + if (item.ownerType != &typeid(Element)) + return base::getCargo(item); + using namespace active::serialise; + switch (item.index) { + case bodyID: + return nullptr; //TODO: implement + default: + return nullptr; //Requested an unknown index + } +} //Element::getCargo + + +/*-------------------------------------------------------------------- + Set to the default package content + --------------------------------------------------------------------*/ +void Element::setDefault() { + base::setDefault(); + m_data.reset(); +} //Element::setDefault diff --git a/SpeckleLib/Speckle/Record/Element/Element.h b/SpeckleLib/Speckle/Record/Element/Element.h new file mode 100644 index 0000000..ee478c9 --- /dev/null +++ b/SpeckleLib/Speckle/Record/Element/Element.h @@ -0,0 +1,116 @@ +#ifndef SPECKLE_RECORD_ELEMENT +#define SPECKLE_RECORD_ELEMENT + +#include "Speckle/Database/Content/Record.h" +#include "Speckle/Utility/String.h" + +namespace speckle::primitive { + class Mesh; +} + +namespace speckle::record::element { + + /*! + Base BIM element class + */ + class Element : public speckle::database::Record { + public: + + ///An element 3D body primitive + using Body = std::vector; + + // MARK: - Types + + using base = speckle::database::Record; + ///Unique pointer + using Unique = std::unique_ptr; + ///Shared pointer + using Shared = std::shared_ptr; + ///Optional + using Option = std::optional; + + // MARK: - Constructors + + using base::base; + + /*! + Default constructor + */ + Element(); +#ifdef ARCHICAD + /*! + Constructor + @param elemData Archicad element data + */ + Element(const API_Element& elemData); +#endif + /*! + Copy constructor + @param source The object to copy + */ + Element(const Element& source); + /*! + Destructor + */ + ~Element(); + + /*! + Object cloning + @return A clone of this object + */ + Element* clonePtr() const override { return new Element{*this}; } + + + // MARK: - Functions (const) + + /*! + Get the element body + @return An array of meshes from the element body (nullptr if no body data is available) + */ + virtual Body* getBody() const; +#ifdef ARCHICAD + /*! + Get the (immutable) API element header data + @return The element header data (only use this data for low-level operations - for normal code, call getters/setters) + */ + virtual const API_Elem_Head& getHead() const; +#endif + + // MARK: - Functions (mutating) + +#ifdef ARCHICAD + /*! + Get the (mutable) API element header data + @return The element header data (only use this data for low-level operations - for normal code, call getters/setters) + */ + virtual API_Elem_Head& getHead(); +#endif + + // MARK: - Serialisation + + /*! + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ + bool fillInventory(active::serialise::Inventory& inventory) const override; + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + /*! + Set to the default package content + */ + void setDefault() override; + + private: + class Data; + ///The element data + std::unique_ptr m_data; + }; + +} + +#endif //SPECKLE_RECORD_ELEMENT diff --git a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj index 4db2969..9c1676a 100644 --- a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj +++ b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj @@ -18,6 +18,20 @@ 215F08552C99DA8D00CD343B /* Project.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 215F08512C99DA8D00CD343B /* Project.cpp */; }; 215F08562C99DA8D00CD343B /* Project.h in Headers */ = {isa = PBXBuildFile; fileRef = 215F08542C99DA8D00CD343B /* Project.h */; }; 215F08662C9B006800CD343B /* ProjectEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 215F08652C9B006700CD343B /* ProjectEvent.cpp */; }; + 215F087D2CA18E1400CD343B /* Element.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 215F08782CA18E1400CD343B /* Element.cpp */; }; + 215F087E2CA18E1400CD343B /* Element.h in Headers */ = {isa = PBXBuildFile; fileRef = 215F08792CA18E1400CD343B /* Element.h */; }; + 215F088B2CA195EC00CD343B /* ArchicadDBaseCore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 215F08872CA195EC00CD343B /* ArchicadDBaseCore.cpp */; }; + 215F088C2CA195EC00CD343B /* ArchicadDBaseCore.h in Headers */ = {isa = PBXBuildFile; fileRef = 215F08882CA195EC00CD343B /* ArchicadDBaseCore.h */; }; + 215F088D2CA195EC00CD343B /* ArchicadElementDBaseEngine.h in Headers */ = {isa = PBXBuildFile; fileRef = 215F08892CA195EC00CD343B /* ArchicadElementDBaseEngine.h */; }; + 215F08952CA19AF800CD343B /* BIMElementDatabase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 215F08932CA19AF800CD343B /* BIMElementDatabase.cpp */; }; + 215F08962CA19AF800CD343B /* BIMElementDatabase.h in Headers */ = {isa = PBXBuildFile; fileRef = 215F08942CA19AF800CD343B /* BIMElementDatabase.h */; }; + 219245FE2CA2CC4300CF5703 /* BIMRecord.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219245FA2CA2CC4300CF5703 /* BIMRecord.cpp */; }; + 219245FF2CA2CC4300CF5703 /* BIMRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = 219245FD2CA2CC4300CF5703 /* BIMRecord.h */; }; + 219246032CA2CE2700CF5703 /* BIMLink.h in Headers */ = {isa = PBXBuildFile; fileRef = 219246012CA2CE2700CF5703 /* BIMLink.h */; }; + 219246042CA2CE2700CF5703 /* BIMLink.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219246022CA2CE2700CF5703 /* BIMLink.cpp */; }; + 219246082CA2ED2F00CF5703 /* ArchicadElementDBaseEngine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219246072CA2ED2F00CF5703 /* ArchicadElementDBaseEngine.cpp */; }; + 219246122CA34DCE00CF5703 /* Mesh.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2192460E2CA34DCE00CF5703 /* Mesh.cpp */; }; + 219246132CA34DCE00CF5703 /* Mesh.h in Headers */ = {isa = PBXBuildFile; fileRef = 2192460F2CA34DCE00CF5703 /* Mesh.h */; }; 2193517B2C624FC100E5A69C /* MenuSubscriber.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219351782C624FC100E5A69C /* MenuSubscriber.cpp */; }; 2193519B2C6278D900E5A69C /* SelectionSubscriber.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219351992C6278D900E5A69C /* SelectionSubscriber.cpp */; }; 219351B12C62CC1A00E5A69C /* Guid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219351AC2C62CC1A00E5A69C /* Guid.cpp */; }; @@ -31,7 +45,6 @@ 21D0BD2B2C86FC350077E104 /* Record.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21D0BD252C86FC350077E104 /* Record.cpp */; }; 21D0BD2C2C86FC350077E104 /* Record.h in Headers */ = {isa = PBXBuildFile; fileRef = 21D0BD262C86FC350077E104 /* Record.h */; }; 21D0BD312C86FE090077E104 /* Index.h in Headers */ = {isa = PBXBuildFile; fileRef = 21D0BD2D2C86FE090077E104 /* Index.h */; }; - 21D0BD322C86FE090077E104 /* Link.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21D0BD2E2C86FE090077E104 /* Link.cpp */; }; 21D0BD332C86FE090077E104 /* Link.h in Headers */ = {isa = PBXBuildFile; fileRef = 21D0BD2F2C86FE090077E104 /* Link.h */; }; 21D0BD4D2C8901A00077E104 /* ServerInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 21D0BD4B2C8901A00077E104 /* ServerInfo.h */; }; 21D0BD4E2C8901A00077E104 /* ServerInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21D0BD4C2C8901A00077E104 /* ServerInfo.cpp */; }; @@ -114,10 +127,26 @@ 215F085B2C9AE23200CD343B /* SpeckleResource.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SpeckleResource.h; sourceTree = ""; }; 215F08622C9AE3D200CD343B /* Speckle.grc */ = {isa = PBXFileReference; lastKnownFileType = text; path = Speckle.grc; sourceTree = ""; }; 215F08652C9B006700CD343B /* ProjectEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProjectEvent.cpp; sourceTree = ""; }; + 215F08782CA18E1400CD343B /* Element.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Element.cpp; sourceTree = ""; }; + 215F08792CA18E1400CD343B /* Element.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Element.h; sourceTree = ""; }; + 215F08872CA195EC00CD343B /* ArchicadDBaseCore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArchicadDBaseCore.cpp; sourceTree = ""; }; + 215F08882CA195EC00CD343B /* ArchicadDBaseCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArchicadDBaseCore.h; sourceTree = ""; }; + 215F08892CA195EC00CD343B /* ArchicadElementDBaseEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArchicadElementDBaseEngine.h; sourceTree = ""; }; + 215F08932CA19AF800CD343B /* BIMElementDatabase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BIMElementDatabase.cpp; sourceTree = ""; }; + 215F08942CA19AF800CD343B /* BIMElementDatabase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BIMElementDatabase.h; sourceTree = ""; }; 2167E2782C4911E2000827D3 /* CMakeLists.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; 2167E2792C4911EB000827D3 /* CMakeLists.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; 2167E27C2C49121F000827D3 /* CMakeLists.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; 218953A32C0C9CB00078F182 /* Version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Version.h; sourceTree = ""; }; + 219245FA2CA2CC4300CF5703 /* BIMRecord.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BIMRecord.cpp; sourceTree = ""; }; + 219245FD2CA2CC4300CF5703 /* BIMRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BIMRecord.h; sourceTree = ""; }; + 219246002CA2CCD700CF5703 /* BIMRecordID.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BIMRecordID.h; sourceTree = ""; }; + 219246012CA2CE2700CF5703 /* BIMLink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BIMLink.h; sourceTree = ""; }; + 219246022CA2CE2700CF5703 /* BIMLink.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BIMLink.cpp; sourceTree = ""; }; + 219246052CA2CFF000CF5703 /* BIMIndex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BIMIndex.h; sourceTree = ""; }; + 219246072CA2ED2F00CF5703 /* ArchicadElementDBaseEngine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArchicadElementDBaseEngine.cpp; sourceTree = ""; }; + 2192460E2CA34DCE00CF5703 /* Mesh.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Mesh.cpp; sourceTree = ""; }; + 2192460F2CA34DCE00CF5703 /* Mesh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Mesh.h; sourceTree = ""; }; 2193516A2C62318B00E5A69C /* ActiveLib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ActiveLib.xcodeproj; path = ../../ActiveLib/ActiveLib.xcodeproj; sourceTree = ""; }; 219351782C624FC100E5A69C /* MenuSubscriber.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MenuSubscriber.cpp; sourceTree = ""; }; 219351792C624FC100E5A69C /* MenuSubscriber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MenuSubscriber.h; sourceTree = ""; }; @@ -138,7 +167,6 @@ 21D0BD252C86FC350077E104 /* Record.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Record.cpp; sourceTree = ""; }; 21D0BD262C86FC350077E104 /* Record.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Record.h; sourceTree = ""; }; 21D0BD2D2C86FE090077E104 /* Index.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Index.h; sourceTree = ""; }; - 21D0BD2E2C86FE090077E104 /* Link.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Link.cpp; sourceTree = ""; }; 21D0BD2F2C86FE090077E104 /* Link.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Link.h; sourceTree = ""; }; 21D0BD4B2C8901A00077E104 /* ServerInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ServerInfo.h; sourceTree = ""; }; 21D0BD4C2C8901A00077E104 /* ServerInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ServerInfo.cpp; sourceTree = ""; }; @@ -213,6 +241,7 @@ 21F93AE82B2F406D009A2C5B /* Environment */, 21F93ACC2B2B67FC009A2C5B /* Event */, 21F69F1B2C6A0FE2008B6A06 /* Interface */, + 219246112CA34DCE00CF5703 /* Primitive */, 21F69F952C71087A008B6A06 /* Record */, 212A834E2AE47AD9001EAFE7 /* Serialise */, 215F085B2C9AE23200CD343B /* SpeckleResource.h */, @@ -263,6 +292,25 @@ path = RINT; sourceTree = SOURCE_ROOT; }; + 215F087A2CA18E1400CD343B /* Element */ = { + isa = PBXGroup; + children = ( + 215F08782CA18E1400CD343B /* Element.cpp */, + 215F08792CA18E1400CD343B /* Element.h */, + ); + path = Element; + sourceTree = ""; + }; + 215F088A2CA195EC00CD343B /* ArchicadDBase */ = { + isa = PBXGroup; + children = ( + 215F08872CA195EC00CD343B /* ArchicadDBaseCore.cpp */, + 215F08882CA195EC00CD343B /* ArchicadDBaseCore.h */, + 219246062CA2D22D00CF5703 /* Element */, + ); + path = ArchicadDBase; + sourceTree = ""; + }; 218953A92C0F29FB0078F182 /* EventTests */ = { isa = PBXGroup; children = ( @@ -270,6 +318,32 @@ name = EventTests; sourceTree = ""; }; + 219246062CA2D22D00CF5703 /* Element */ = { + isa = PBXGroup; + children = ( + 219246072CA2ED2F00CF5703 /* ArchicadElementDBaseEngine.cpp */, + 215F08892CA195EC00CD343B /* ArchicadElementDBaseEngine.h */, + ); + path = Element; + sourceTree = ""; + }; + 219246102CA34DCE00CF5703 /* Mesh */ = { + isa = PBXGroup; + children = ( + 2192460E2CA34DCE00CF5703 /* Mesh.cpp */, + 2192460F2CA34DCE00CF5703 /* Mesh.h */, + ); + path = Mesh; + sourceTree = ""; + }; + 219246112CA34DCE00CF5703 /* Primitive */ = { + isa = PBXGroup; + children = ( + 219246102CA34DCE00CF5703 /* Mesh */, + ); + path = Primitive; + sourceTree = ""; + }; 2193516B2C62318B00E5A69C /* Products */ = { isa = PBXGroup; children = ( @@ -334,6 +408,8 @@ children = ( 21D0BD1D2C86F0280077E104 /* AccountDatabase.cpp */, 21D0BD1E2C86F0280077E104 /* AccountDatabase.h */, + 215F08932CA19AF800CD343B /* BIMElementDatabase.cpp */, + 215F08942CA19AF800CD343B /* BIMElementDatabase.h */, 21D0BD272C86FC350077E104 /* Content */, 21D0BD302C86FE090077E104 /* Identity */, 21D0BDB02C8F8AB60077E104 /* Storage */, @@ -344,6 +420,8 @@ 21D0BD272C86FC350077E104 /* Content */ = { isa = PBXGroup; children = ( + 219245FA2CA2CC4300CF5703 /* BIMRecord.cpp */, + 219245FD2CA2CC4300CF5703 /* BIMRecord.h */, 21D0BD252C86FC350077E104 /* Record.cpp */, 21D0BD262C86FC350077E104 /* Record.h */, ); @@ -353,8 +431,11 @@ 21D0BD302C86FE090077E104 /* Identity */ = { isa = PBXGroup; children = ( + 219246052CA2CFF000CF5703 /* BIMIndex.h */, + 219246022CA2CE2700CF5703 /* BIMLink.cpp */, + 219246012CA2CE2700CF5703 /* BIMLink.h */, + 219246002CA2CCD700CF5703 /* BIMRecordID.h */, 21D0BD2D2C86FE090077E104 /* Index.h */, - 21D0BD2E2C86FE090077E104 /* Link.cpp */, 21D0BD2F2C86FE090077E104 /* Link.h */, 21D0BDE42C943D3F0077E104 /* RecordID.h */, ); @@ -374,6 +455,7 @@ 21D0BDB02C8F8AB60077E104 /* Storage */ = { isa = PBXGroup; children = ( + 215F088A2CA195EC00CD343B /* ArchicadDBase */, 21D0BDAF2C8F8AB60077E104 /* DocumentStore */, ); path = Storage; @@ -462,6 +544,7 @@ 21F69F952C71087A008B6A06 /* Record */ = { isa = PBXGroup; children = ( + 215F087A2CA18E1400CD343B /* Element */, 21F69F942C71087A008B6A06 /* Credentials */, ); path = Record; @@ -500,19 +583,26 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 215F088C2CA195EC00CD343B /* ArchicadDBaseCore.h in Headers */, 21D0BDE72C943D3F0077E104 /* RecordID.h in Headers */, 21D0BD212C86F0280077E104 /* AccountDatabase.h in Headers */, 210CC86F2C7E879700610F58 /* ArgumentBase.h in Headers */, 210CC8A02C81E34400610F58 /* Platform.h in Headers */, + 219246132CA34DCE00CF5703 /* Mesh.h in Headers */, + 219246032CA2CE2700CF5703 /* BIMLink.h in Headers */, 21B67D0D2C7E0E8D00FD64FC /* ErrorReport.h in Headers */, + 215F08962CA19AF800CD343B /* BIMElementDatabase.h in Headers */, 21D0BD332C86FE090077E104 /* Link.h in Headers */, 21D0BD5A2C8910400077E104 /* UserInfo.h in Headers */, 21D0BD562C890B1C0077E104 /* ServerMigration.h in Headers */, 210CC88F2C81A98500610F58 /* Guid64.h in Headers */, + 215F088D2CA195EC00CD343B /* ArchicadElementDBaseEngine.h in Headers */, 21B67D002C7CE15100FD64FC /* Exception.h in Headers */, 21D0BD2C2C86FC350077E104 /* Record.h in Headers */, 21D0BDB42C8F8AB60077E104 /* DocumentStoreCore.h in Headers */, + 215F087E2CA18E1400CD343B /* Element.h in Headers */, 215F08562C99DA8D00CD343B /* Project.h in Headers */, + 219245FF2CA2CC4300CF5703 /* BIMRecord.h in Headers */, 210CC8802C80CD2A00610F58 /* BridgeChild.h in Headers */, 21D0BD4D2C8901A00077E104 /* ServerInfo.h in Headers */, 21D0BDB52C8F8AB60077E104 /* DocumentStoreEngine.h in Headers */, @@ -646,21 +736,27 @@ 21F69FA62C733EDA008B6A06 /* BridgeArgument.cpp in Sources */, 21F69F682C6DFB01008B6A06 /* RunMethod.cpp in Sources */, 21F69F812C6FF3B0008B6A06 /* BridgeArgumentWrap.cpp in Sources */, + 215F088B2CA195EC00CD343B /* ArchicadDBaseCore.cpp in Sources */, 2193517B2C624FC100E5A69C /* MenuSubscriber.cpp in Sources */, 21F69F612C6D0286008B6A06 /* GetBindingsMethodNames.cpp in Sources */, 215F08662C9B006800CD343B /* ProjectEvent.cpp in Sources */, 21D0BDBD2C90F2830077E104 /* DocStoreSubscriber.cpp in Sources */, 21D0BDB32C8F8AB60077E104 /* DocumentStoreCore.cpp in Sources */, + 219246082CA2ED2F00CF5703 /* ArchicadElementDBaseEngine.cpp in Sources */, 21F93AEC2B2F406E009A2C5B /* Addon.cpp in Sources */, + 215F087D2CA18E1400CD343B /* Element.cpp in Sources */, 21D0BD4E2C8901A00077E104 /* ServerInfo.cpp in Sources */, 21B67D0E2C7E0E8D00FD64FC /* ErrorReport.cpp in Sources */, 21F69F7E2C6FD9FC008B6A06 /* GetCallResult.cpp in Sources */, + 219245FE2CA2CC4300CF5703 /* BIMRecord.cpp in Sources */, 2193519B2C6278D900E5A69C /* SelectionSubscriber.cpp in Sources */, 21D0BD2B2C86FC350077E104 /* Record.cpp in Sources */, + 219246042CA2CE2700CF5703 /* BIMLink.cpp in Sources */, + 215F08952CA19AF800CD343B /* BIMElementDatabase.cpp in Sources */, + 219246122CA34DCE00CF5703 /* Mesh.cpp in Sources */, 21D0BD592C8910400077E104 /* UserInfo.cpp in Sources */, 210CC8902C81A98500610F58 /* Guid64.cpp in Sources */, 21D0BDC42C9241940077E104 /* ProjectSubscriber.cpp in Sources */, - 21D0BD322C86FE090077E104 /* Link.cpp in Sources */, 219351B32C62CC1A00E5A69C /* String.cpp in Sources */, 219351B12C62CC1A00E5A69C /* Guid.cpp in Sources */, 21F69F512C6CCC25008B6A06 /* BrowserBridge.cpp in Sources */, From 7baedf707a7a9b28f83ac36a5ab537e068abc1c7 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Tue, 24 Sep 2024 22:29:40 +0100 Subject: [PATCH 003/191] Updated VS projects --- SpeckleConnector/Connector.vcxproj | 4 ++ SpeckleConnector/Connector.vcxproj.filters | 15 +++++ SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp | 2 + SpeckleLib/SpeckleLib17.vcxproj | 17 +++++- SpeckleLib/SpeckleLib17.vcxproj.filters | 66 +++++++++++++++++++++- 5 files changed, 100 insertions(+), 4 deletions(-) diff --git a/SpeckleConnector/Connector.vcxproj b/SpeckleConnector/Connector.vcxproj index ce15579..97d064d 100644 --- a/SpeckleConnector/Connector.vcxproj +++ b/SpeckleConnector/Connector.vcxproj @@ -122,6 +122,8 @@ + + @@ -166,6 +168,8 @@ + + diff --git a/SpeckleConnector/Connector.vcxproj.filters b/SpeckleConnector/Connector.vcxproj.filters index 8eb6949..b449f8a 100644 --- a/SpeckleConnector/Connector.vcxproj.filters +++ b/SpeckleConnector/Connector.vcxproj.filters @@ -59,6 +59,9 @@ {b6d6326c-77f4-414a-bda6-e3e587c7ded2} + + {0ac4b0a4-6a2a-4a48-9757-1172effc20e7} + @@ -198,6 +201,12 @@ Connector\Interface\Browser\Bridge\Base + + Connector\Record\Collection + + + Connector\Record\Collection + @@ -333,5 +342,11 @@ Connector\Interface\Browser\Bridge\Base + + Connector\Record\Collection + + + Connector\Record\Collection + \ No newline at end of file diff --git a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp index eee7c6b..ffe58ec 100644 --- a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp +++ b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp @@ -3,6 +3,8 @@ #include "Active/Serialise/Item/Wrapper/ValueWrap.h" #include "Active/Serialise/Inventory/Identity.h" +#include + using namespace active::serialise; using namespace speckle::primitive; diff --git a/SpeckleLib/SpeckleLib17.vcxproj b/SpeckleLib/SpeckleLib17.vcxproj index 3c8e9f8..9f10ec3 100644 --- a/SpeckleLib/SpeckleLib17.vcxproj +++ b/SpeckleLib/SpeckleLib17.vcxproj @@ -20,9 +20,16 @@ + + + + + + + @@ -54,10 +61,12 @@ + + @@ -68,8 +77,12 @@ + + - + + + @@ -86,10 +99,12 @@ + + diff --git a/SpeckleLib/SpeckleLib17.vcxproj.filters b/SpeckleLib/SpeckleLib17.vcxproj.filters index c2784c1..444eb0e 100644 --- a/SpeckleLib/SpeckleLib17.vcxproj.filters +++ b/SpeckleLib/SpeckleLib17.vcxproj.filters @@ -62,6 +62,21 @@ {c4146af8-d1a1-44cc-9810-cc8da1a705a8} + + {728f7e85-53d8-4fe0-9994-394010324eb8} + + + {896361f5-4195-4662-be29-9e8241cab17c} + + + {87719e02-08cb-466e-a01b-66fdbb278efe} + + + {c99c6ba7-cdb5-4182-9df9-debe5559b460} + + + {93db2ed5-fd21-4ed1-86ee-f549682f66a5} + @@ -202,6 +217,33 @@ Speckle + + Speckle\Record\Element + + + Speckle\Primitive\Mesh + + + Speckle\Database\Storage\ArchicadDBase + + + Speckle\Database\Storage\ArchicadDBase\Element + + + Speckle\Database + + + Speckle\Database\Content + + + Speckle\Database\Identity + + + Speckle\Database\Identity + + + Speckle\Database\Identity + @@ -252,9 +294,6 @@ Speckle\Utility - - Speckle\Database\Identity - Speckle\Database @@ -285,6 +324,27 @@ Speckle\Event\Type + + Speckle\Record\Element + + + Speckle\Primitive\Mesh + + + Speckle\Database\Storage\ArchicadDBase + + + Speckle\Database\Storage\ArchicadDBase\Element + + + Speckle\Database + + + Speckle\Database\Content + + + Speckle\Database\Identity + From b8d952c9a36fc35d37efd8d0d4d6b2ad53827b08 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Wed, 25 Sep 2024 13:29:33 +0100 Subject: [PATCH 004/191] Updated Send method to trigger a browser event rather than throwing an exception Added new resources --- .../Connector/ConnectorResource.h | 3 +- .../Interface/Browser/Bridge/Send/Send.cpp | 81 ++++++++++++++++++- SpeckleConnector/RINT/Connector.grc | 4 + 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/SpeckleConnector/Connector/ConnectorResource.h b/SpeckleConnector/Connector/ConnectorResource.h index 68b5c29..82885a1 100755 --- a/SpeckleConnector/Connector/ConnectorResource.h +++ b/SpeckleConnector/Connector/ConnectorResource.h @@ -37,7 +37,7 @@ enum PromptString { //Information strings (in UI content, logging, reports) -enum InfoString { +enum GeneralString { }; @@ -53,6 +53,7 @@ enum WarningString { //Error strings (errors displayed in alerts) enum ErrorString { + noSelectedModelItemsID = 1, }; #endif //CONNECTOR_RESOURCE diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp index f9efa9b..73c41b8 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp @@ -2,12 +2,90 @@ #include "Active/Serialise/CargoHold.h" #include "Active/Serialise/Package/Wrapper/PackageWrap.h" +#include "Connector/Connector.h" +#include "Connector/ConnectorResource.h" +#include "Speckle/Interface/Browser/Bridge/BrowserBridge.h" #include "Speckle/Utility/Exception.h" using namespace active::serialise; using namespace connector::interfac::browser::bridge; using namespace speckle::utility; +namespace { + + ///Serialisation fields + enum FieldIndex { + errorID, + cardID, + }; + + ///Serialisation field IDs + static std::array fieldID = { + Identity{"error"}, + Identity{"modelCardId"}, + }; + + /*! + A send error to return to the JS in the event of an error + */ + class SendError final : public active::serialise::Package { + public: + + // MARK: - Constructors + + /*! + Constructor + @param errMess The error message + @param card The ID of the model card associated with the wrror + */ + SendError(const String& errMess, const String& card) : message{errMess}, modelCardID{card} {} + + // MARK: - Public variables + + ///The error message + String message; + ///The ID of the model card associated with the data + String modelCardID; + + // MARK: - Serialisation + + /*! + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ + bool fillInventory(active::serialise::Inventory& inventory) const override { + using enum Entry::Type; + inventory.merge(Inventory{ + { + { fieldID[errorID], errorID, element }, + { fieldID[cardID], cardID, element }, + }, + }.withType(&typeid(SendError))); + return true; + } + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override { + if (item.ownerType != &typeid(SendError)) + return nullptr; + using namespace active::serialise; + switch (item.index) { + case errorID: + return std::make_unique>(message); + case cardID: + return std::make_unique>(modelCardID); + default: + return nullptr; //Requested an unknown index + } + } + }; + +} + /*-------------------------------------------------------------------- Default constructor --------------------------------------------------------------------*/ @@ -23,5 +101,6 @@ Send::Send() : BridgeMethod{"Send", [&](const SendArgs& args) { --------------------------------------------------------------------*/ void Send::run(const String& modelCardID) const { ///TODO: Find and send selected elements - the following is a placeholder - throw Exception{"No objects were found to convert. Please update your publish filter!"}; + getBridge()->sendEvent("setModelError", + std::make_unique(connector()->getLocalString(errorString, noSelectedModelItemsID), modelCardID)); } //Send::run diff --git a/SpeckleConnector/RINT/Connector.grc b/SpeckleConnector/RINT/Connector.grc index 20de2c7..bac807c 100644 --- a/SpeckleConnector/RINT/Connector.grc +++ b/SpeckleConnector/RINT/Connector.grc @@ -2,3 +2,7 @@ /* [ 1] */ "Speckle Connector" /* [ 2] */ "Connector to share model content with Speckle" } + +'STR#' 32604 "Error strings" { +/* [ 1] */ "No objects were found to convert. Please update your publish filter!" +} From 5abc831473730b5b6d642c10ed452fce14f2ee21 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Thu, 26 Sep 2024 13:05:22 +0100 Subject: [PATCH 005/191] Implemented Archicad element database functionality: - Retrieving the database from the Project - Gettting selected elements - Getting an element from an index/link --- SpeckleConnector/Connector/Connector.cpp | 14 +-- SpeckleConnector/Connector/Connector.h | 11 ++- .../Connector/Interface/ConnectorPalette.cpp | 18 ++++ .../Speckle/Database/BIMElementDatabase.cpp | 23 +++++ .../Speckle/Database/BIMElementDatabase.h | 17 +++- .../Speckle/Database/Identity/BIMIndex.h | 7 ++ .../Speckle/Database/Identity/BIMLink.h | 3 + .../Speckle/Database/Identity/BIMRecordID.h | 4 +- .../Element/ArchicadElementDBaseEngine.cpp | 92 ++++++++++++++++++- .../Element/ArchicadElementDBaseEngine.h | 10 +- SpeckleLib/Speckle/Environment/Project.cpp | 3 + SpeckleLib/Speckle/Environment/Project.h | 12 +++ SpeckleLib/Speckle/Record/Element/Element.cpp | 27 +++++- SpeckleLib/Speckle/Record/Element/Element.h | 2 +- 14 files changed, 221 insertions(+), 22 deletions(-) diff --git a/SpeckleConnector/Connector/Connector.cpp b/SpeckleConnector/Connector/Connector.cpp index c4369dd..23943be 100755 --- a/SpeckleConnector/Connector/Connector.cpp +++ b/SpeckleConnector/Connector/Connector.cpp @@ -2,8 +2,8 @@ #include "ConnectorResource.h" #include "Connector/Connector.h" #include "Connector/Database/ModelCardDatabase.h" -#include "Interface/ConnectorMenu.h" -#include "Interface/ConnectorPalette.h" +#include "Connector/Interface/ConnectorMenu.h" +#include "Connector/Interface/ConnectorPalette.h" #include "Speckle/Database/AccountDatabase.h" #include "Speckle/Environment/Addon.h" #include "Speckle/Utility/String.h" @@ -35,16 +35,16 @@ namespace { // MARK: Functions (const) - /*! - Get the model card database - @return The model card database - */ - const ModelCardDatabase* getModelCardDatabase() const override { return &m_modelCards; } /*! Get the account database @return The account database */ const AccountDatabase* getAccountDatabase() const override; + /*! + Get the model card database + @return The model card database + */ + const ModelCardDatabase* getModelCardDatabase() const override { return &m_modelCards; } private: mutable std::unique_ptr m_account; diff --git a/SpeckleConnector/Connector/Connector.h b/SpeckleConnector/Connector/Connector.h index 3eed043..8754584 100755 --- a/SpeckleConnector/Connector/Connector.h +++ b/SpeckleConnector/Connector/Connector.h @@ -3,6 +3,7 @@ namespace speckle::database { class AccountDatabase; + class BIMElementDatabase; } namespace connector::database { class ModelCardDatabase; @@ -16,16 +17,16 @@ namespace connector { // MARK: Functions (const) - /*! - Get the model card database - @return The model card database - */ - const virtual database::ModelCardDatabase* getModelCardDatabase() const = 0; /*! Get the account database @return The account database */ const virtual speckle::database::AccountDatabase* getAccountDatabase() const = 0; + /*! + Get the model card database + @return The model card database + */ + const virtual database::ModelCardDatabase* getModelCardDatabase() const = 0; protected: /*! diff --git a/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp b/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp index 53c0ab8..7cb332e 100644 --- a/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp +++ b/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp @@ -12,6 +12,14 @@ #include "Speckle/Event/Type/MenuEvent.h" #include "Speckle/Interface/Browser/JSPortal.h" + +#include "Speckle/Environment/Project.h" + + +#include "Connector/Connector.h" +#include "Speckle/Database/BIMElementDatabase.h" + + #include #include #include @@ -128,6 +136,16 @@ bool ConnectorPalette::start() { return: True if the event should be closed --------------------------------------------------------------------*/ bool ConnectorPalette::receive(const active::event::Event& event) { + + if (auto project = connector()->getActiveProject().lock(); project) { + auto elementDatabase = project->getElementDatabase(); + auto selected = elementDatabase->getSelection(); + for (const auto& link : selected) { + auto element = elementDatabase->getElement(link); + auto x = 1; + } + } + if (BrowserPalette::HasInstance() && BrowserPalette::GetInstance().IsVisible()) { BrowserPalette::GetInstance().Hide (); } else { diff --git a/SpeckleLib/Speckle/Database/BIMElementDatabase.cpp b/SpeckleLib/Speckle/Database/BIMElementDatabase.cpp index f5d38ef..5761233 100644 --- a/SpeckleLib/Speckle/Database/BIMElementDatabase.cpp +++ b/SpeckleLib/Speckle/Database/BIMElementDatabase.cpp @@ -74,6 +74,29 @@ BIMElementDatabase::BIMElementDatabase() { BIMElementDatabase::~BIMElementDatabase() {} +/*-------------------------------------------------------------------- + Get the current user element selection + + return: A list of selected element IDs + --------------------------------------------------------------------*/ +BIMLinkList BIMElementDatabase::getSelection() const { + return m_engine->getSelection(); +} //BIMElementDatabase::getSelection + + +/*-------------------------------------------------------------------- + Get a specified element + + elementID: The ID of the target element + + return: The requested element (nullptr on failure) + --------------------------------------------------------------------*/ +Element::Unique BIMElementDatabase::getElement(const BIMRecordID& elementID, std::optional tableID, + std::optional documentID) const { + return m_engine->getObject(elementID, tableID, documentID); +} //BIMElementDatabase::getElement + + /*-------------------------------------------------------------------- Get all elements diff --git a/SpeckleLib/Speckle/Database/BIMElementDatabase.h b/SpeckleLib/Speckle/Database/BIMElementDatabase.h index 5093740..bcb990b 100644 --- a/SpeckleLib/Speckle/Database/BIMElementDatabase.h +++ b/SpeckleLib/Speckle/Database/BIMElementDatabase.h @@ -1,6 +1,7 @@ #ifndef CONNECTOR_DATABASE_BIM_DATABASE #define CONNECTOR_DATABASE_BIM_DATABASE +#include "Speckle/Database/Identity/BIMLink.h" #include "Speckle/Record/Element/Element.h" #include "Speckle/Utility/Guid.h" @@ -30,12 +31,26 @@ namespace speckle::database { // MARK: - Functions (const) + /*! + Get the current user element selection + @return A list of selected element IDs + */ + BIMLinkList getSelection() const; /*! Get a specified element @param elementID The ID of the target element + @param tableID Optional table ID (defaults to the floor plan) + @param documentID Optional document ID (when the object is bound to a specific document) @return The requested element (nullptr on failure) */ - record::element::Element::Unique getElement(const utility::Guid& elementID) const; + record::element::Element::Unique getElement(const BIMRecordID& elementID, std::optional tableID = std::nullopt, + std::optional documentID = std::nullopt) const; + /*! + Get a specified element + @param link A link to the target element + @return The requested element (nullptr on failure) + */ + record::element::Element::Unique getElement(const BIMLink& link) const { return getElement(link, link.tableID, link.docID); } /*! Get all model elements @return All the elements diff --git a/SpeckleLib/Speckle/Database/Identity/BIMIndex.h b/SpeckleLib/Speckle/Database/Identity/BIMIndex.h index f1ea64d..ff0a09f 100644 --- a/SpeckleLib/Speckle/Database/Identity/BIMIndex.h +++ b/SpeckleLib/Speckle/Database/Identity/BIMIndex.h @@ -23,6 +23,13 @@ namespace speckle::database { // MARK: - Constructors using base::base; + + // MARK: - Public variables + + //The table identifier + BIMTableID table; + //The document identifier + BIMDocID document; }; } diff --git a/SpeckleLib/Speckle/Database/Identity/BIMLink.h b/SpeckleLib/Speckle/Database/Identity/BIMLink.h index bd06a09..a78f56e 100644 --- a/SpeckleLib/Speckle/Database/Identity/BIMLink.h +++ b/SpeckleLib/Speckle/Database/Identity/BIMLink.h @@ -39,6 +39,9 @@ namespace speckle::database { #endif }; + //A list of links to BIM records + using BIMLinkList = std::vector; + } #endif //SPECKLE_DATABASE_BIM_LINK diff --git a/SpeckleLib/Speckle/Database/Identity/BIMRecordID.h b/SpeckleLib/Speckle/Database/Identity/BIMRecordID.h index 86b6c6b..a05703a 100644 --- a/SpeckleLib/Speckle/Database/Identity/BIMRecordID.h +++ b/SpeckleLib/Speckle/Database/Identity/BIMRecordID.h @@ -8,8 +8,10 @@ namespace speckle::database { #ifdef ARCHICAD //Common BIM record identifier type (e.g. to BIM elements) using BIMRecordID = speckle::utility::Guid; - //Common BIM table identifier type (e.g. BIM drawing identifier) + //Common BIM table identifier type (e.g. primary model, views) using BIMTableID = speckle::utility::Guid; + //Common BIM document identifier type (e.g. BIM drawing identifier, e.g. section, layout etc) + using BIMDocID = speckle::utility::Guid; //Common BIM database identifier type (e.g. model database, library database, attribute database) using BIMDBaseID = speckle::utility::Guid; #endif diff --git a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.cpp b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.cpp index 7e3289a..b7cb9cd 100644 --- a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.cpp +++ b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.cpp @@ -5,6 +5,7 @@ #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" @@ -13,6 +14,7 @@ #include "Speckle/Utility/String.h" #include +#include #include using namespace active::event; @@ -25,6 +27,83 @@ 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 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 + + + /*! + Get the ID of the active Archicad table + @return The active table ID (nullopt on failure) + */ + std::optional 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; + } //getActiveTable + + + /*! + 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 = 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 + @return A new element object (nullptr on failure) + */ + Element::Unique makeElement(const API_Element& elementData) { + //Implement an object factory in future as classes for specific element types are implemented, e.g. Wall, Roof etc. using hash map + //The fallback for undefined element types will always be the base Element class + return std::make_unique(elementData); + } + +} + +/*-------------------------------------------------------------------- + Get the current user element selection + + return: A list of selected element IDs + --------------------------------------------------------------------*/ +BIMLinkList ArchicadElementDBaseEngine::getSelection() const { + BIMLinkList result; + API_SelectionInfo selectionInfo; + active::utility::Memory::erase(selectionInfo); + GS::Array selection; + if (auto err = ACAPI_Selection_Get(&selectionInfo, &selection, true); err == NoError) { + for (const auto& item : selection) + result.push_back(BIMLink{item}); + } + return result; +} //ArchicadElementDBaseEngine::getSelection + + /*-------------------------------------------------------------------- Get an object by index @@ -35,8 +114,13 @@ using enum ArchicadDBaseCore::Status; return: The requested object (nullptr on failure) --------------------------------------------------------------------*/ std::unique_ptr ArchicadElementDBaseEngine::getObject(const BIMRecordID& ID, std::optional tableID, - std::optional documentID) const { - return nullptr; //TODO: Implement + std::optional documentID) const { + 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); } //ArchicadElementDBaseEngine::getObject @@ -65,7 +149,9 @@ active::serialise::Cargo::Unique ArchicadElementDBaseEngine::getObjectCargo(cons --------------------------------------------------------------------*/ active::container::Vector ArchicadElementDBaseEngine::getObjects(std::optional tableID, std::optional documentID) const { - return {}; + if (tableID) + setActiveTable(*tableID); + return {}; //TODO: Implement } //ArchicadElementDBaseEngine::getObjects diff --git a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.h b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.h index 5ab6bea..6e23859 100644 --- a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.h +++ b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.h @@ -4,7 +4,7 @@ #include "Active/Database/Storage/DBaseEngine.h" #include "Active/Serialise/UnboxedTransport.h" #include "Speckle/Database/Storage/ArchicadDBase/ArchicadDBaseCore.h" -#include "Speckle/Database/Identity/BIMRecordID.h" +#include "Speckle/Database/Identity/BIMLink.h" #include "Speckle/Record/Element/Element.h" #include "Speckle/Utility/Guid.h" #include "Speckle/Utility/String.h" @@ -39,6 +39,11 @@ namespace speckle::database { // MARK: - Functions (const) + /*! + Get the current user element selection + @return A list of selected element IDs + */ + BIMLinkList getSelection() const; /*! Get an object by index @param objID The object ID @@ -102,6 +107,9 @@ namespace speckle::database { @return The database outline */ Outline getOutline() const override; + + private: + void setTable(std::optional tableID = std::nullopt, std::optional documentID = std::nullopt); }; } diff --git a/SpeckleLib/Speckle/Environment/Project.cpp b/SpeckleLib/Speckle/Environment/Project.cpp index 69722ed..27c401d 100644 --- a/SpeckleLib/Speckle/Environment/Project.cpp +++ b/SpeckleLib/Speckle/Environment/Project.cpp @@ -1,5 +1,6 @@ #include "Speckle/Environment/Project.h" +#include "Speckle/Database/BIMElementDatabase.h" #include "Speckle/Environment/Addon.h" #include "Speckle/SpeckleResource.h" @@ -7,6 +8,7 @@ #include #endif +using namespace speckle::database; using namespace speckle::environment; using namespace speckle::utility; @@ -20,6 +22,7 @@ namespace { identity: Optional name/ID for the subscriber --------------------------------------------------------------------*/ Project::Project() { + m_element = std::make_unique(); } //Project::Project diff --git a/SpeckleLib/Speckle/Environment/Project.h b/SpeckleLib/Speckle/Environment/Project.h index 1aac39b..284be8c 100644 --- a/SpeckleLib/Speckle/Environment/Project.h +++ b/SpeckleLib/Speckle/Environment/Project.h @@ -4,6 +4,10 @@ #include "Active/File/Path.h" #include "Speckle/Utility/String.h" +namespace speckle::database { + class BIMElementDatabase; +} + namespace speckle::environment { class Addon; @@ -50,6 +54,11 @@ namespace speckle::environment { @return Project information */ Info getInfo() const; + /*! + Get the account database + @return The account database + */ + const database::BIMElementDatabase* getElementDatabase() const { return m_element.get(); } // MARK: - Functions (mutating) @@ -62,6 +71,9 @@ namespace speckle::environment { NB: Only the Addon class can create projects. Clients can get the active project from the running add-on. */ Project(); + + private: + std::unique_ptr m_element; }; } diff --git a/SpeckleLib/Speckle/Record/Element/Element.cpp b/SpeckleLib/Speckle/Record/Element/Element.cpp index 7e5a1e5..999cfe7 100644 --- a/SpeckleLib/Speckle/Record/Element/Element.cpp +++ b/SpeckleLib/Speckle/Record/Element/Element.cpp @@ -15,11 +15,13 @@ namespace speckle::record::element { class Element::Data { public: - Data(const API_Element& elem) : root{elem} {} - Data(const Data& source); + friend class Element; + + Data(const API_Element& elem) : root{std::make_unique(elem)} {} + Data(const Data& source) : root{std::make_unique(*source.root)} {} private: - API_Element root; + std::unique_ptr root; std::unique_ptr m_cache; }; @@ -72,6 +74,25 @@ Element::Element(const Element& source) { Element::~Element() {} +/*-------------------------------------------------------------------- + Get the (immutable) API element header data + + return: The element header data (only use this data for low-level operations - for normal code, call getters/setters) + --------------------------------------------------------------------*/ +const API_Elem_Head& Element::getHead() const { + return m_data->root->header; +} //Element::getHead + +/*-------------------------------------------------------------------- + Get the (mutable) API element header data + + return: The element header data (only use this data for low-level operations - for normal code, call getters/setters) + --------------------------------------------------------------------*/ +API_Elem_Head& Element::getHead() { + return m_data->root->header; +} //Element::getHead + + /*-------------------------------------------------------------------- Fill an inventory with the package items diff --git a/SpeckleLib/Speckle/Record/Element/Element.h b/SpeckleLib/Speckle/Record/Element/Element.h index ee478c9..068d495 100644 --- a/SpeckleLib/Speckle/Record/Element/Element.h +++ b/SpeckleLib/Speckle/Record/Element/Element.h @@ -67,7 +67,7 @@ namespace speckle::record::element { Get the element body @return An array of meshes from the element body (nullptr if no body data is available) */ - virtual Body* getBody() const; + virtual Body* getBody() const { return nullptr; } #ifdef ARCHICAD /*! Get the (immutable) API element header data From 4c8a2237bf20c20ddf63d8cb78f436ae59c0c835 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Thu, 26 Sep 2024 13:28:14 +0100 Subject: [PATCH 006/191] Removed testing code --- .../Connector/Interface/ConnectorPalette.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp b/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp index 7cb332e..6b63586 100644 --- a/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp +++ b/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp @@ -136,16 +136,6 @@ bool ConnectorPalette::start() { return: True if the event should be closed --------------------------------------------------------------------*/ bool ConnectorPalette::receive(const active::event::Event& event) { - - if (auto project = connector()->getActiveProject().lock(); project) { - auto elementDatabase = project->getElementDatabase(); - auto selected = elementDatabase->getSelection(); - for (const auto& link : selected) { - auto element = elementDatabase->getElement(link); - auto x = 1; - } - } - if (BrowserPalette::HasInstance() && BrowserPalette::GetInstance().IsVisible()) { BrowserPalette::GetInstance().Hide (); } else { From deee1e80c5afd49cb65bdebb5d2a88fc5d8c255b Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Mon, 30 Sep 2024 10:50:24 +0100 Subject: [PATCH 007/191] Added classes for managing detached objects: - DetachmentManager: Manages detached objects during (de)serialisation - DetachedWrap: Wrapper for detached objects, generating references on demand from serialised data - DetachedReference: Wrapper for representation of wrapped objects with a reference - DetachedObjectStore: Interface for filing/retrieving detached objects in storage --- .../Serialise/Detached/DetachedReference.cpp | 90 ++++++++++++++++++ .../Serialise/Detached/DetachedReference.h | 77 +++++++++++++++ .../Serialise/Detached/DetachedWrap.cpp | 93 +++++++++++++++++++ .../Speckle/Serialise/Detached/DetachedWrap.h | 89 ++++++++++++++++++ .../Serialise/Detached/DetachmentManager.cpp | 89 ++++++++++++++++++ .../Serialise/Detached/DetachmentManager.h | 82 ++++++++++++++++ .../Detached/Storage/DetachedObjectStore.h | 46 +++++++++ .../SpeckleLib.xcodeproj/project.pbxproj | 38 ++++++++ 8 files changed, 604 insertions(+) create mode 100644 SpeckleLib/Speckle/Serialise/Detached/DetachedReference.cpp create mode 100644 SpeckleLib/Speckle/Serialise/Detached/DetachedReference.h create mode 100644 SpeckleLib/Speckle/Serialise/Detached/DetachedWrap.cpp create mode 100644 SpeckleLib/Speckle/Serialise/Detached/DetachedWrap.h create mode 100644 SpeckleLib/Speckle/Serialise/Detached/DetachmentManager.cpp create mode 100644 SpeckleLib/Speckle/Serialise/Detached/DetachmentManager.h create mode 100644 SpeckleLib/Speckle/Serialise/Detached/Storage/DetachedObjectStore.h diff --git a/SpeckleLib/Speckle/Serialise/Detached/DetachedReference.cpp b/SpeckleLib/Speckle/Serialise/Detached/DetachedReference.cpp new file mode 100644 index 0000000..140c476 --- /dev/null +++ b/SpeckleLib/Speckle/Serialise/Detached/DetachedReference.cpp @@ -0,0 +1,90 @@ +#include "Speckle/Serialise/Detached/DetachedReference.h" + +#include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Speckle/Serialise/Detached/DetachmentManager.h" +#include "Speckle/Utility/String.h" + +using namespace active::serialise; +using namespace speckle::serialise; +using namespace speckle::utility; + +#include + +namespace { + + ///Serialisation fields + enum FieldIndex { + refdID, + speckTypeID, + }; + + ///Serialisation field IDs + static std::array fieldID = { + Identity{"referencedId"}, + Identity{"speckle_type"}, + }; + + ///Type signature for a reference to a detached object + String referenceType{"reference"}; + +} + +/*-------------------------------------------------------------------- + Fill an inventory with the package items + + inventory: The inventory to receive the package items + + return: True if the package has added items to the inventory + --------------------------------------------------------------------*/ +bool DetachedReference::fillInventory(Inventory& inventory) const { + using enum Entry::Type; + inventory.merge(Inventory{ + { + { fieldID[refdID], refdID, element }, + { fieldID[speckTypeID], speckTypeID, element }, + }, + }.withType(&typeid(DetachedReference))); + return true; +} //DetachedReference::fillInventory + + +/*-------------------------------------------------------------------- + Get the specified cargo + + item: The inventory item to retrieve + + return: The requested cargo (nullptr on failure) + --------------------------------------------------------------------*/ +Cargo::Unique DetachedReference::getCargo(const Inventory::Item& item) const { + if (item.ownerType != &typeid(DetachedReference)) + return base::get().getCargo(item); + using namespace active::serialise; + switch (item.index) { + case refdID: { + //If we don't have an allocated string for receiving a reference (from 'setDefault') then we need to create one + if (!m_reference) { + //Ask a manager to send the detached data and provide a reference + auto detachmentManager = getManager(); + if (detachmentManager == nullptr) + return nullptr; //TODO: Discuss if this is a serious error - possibly throwing an exception is warranted + m_reference = detachmentManager->send(std::forward(base::get()), item.identity()); + if (!m_reference) + throw; //TODO: Throw a more descriptive exception + } + std::make_unique(*m_reference); + } + case speckTypeID: + return std::make_unique(m_type); + default: + return nullptr; //Requested an unknown index + } +} //DetachedReference::getCargo + + +/*-------------------------------------------------------------------- + Set to the default package content + --------------------------------------------------------------------*/ +void DetachedReference::setDefault() { + m_type.clear(); + m_reference = String{}; +} //DetachedReference::setDefault diff --git a/SpeckleLib/Speckle/Serialise/Detached/DetachedReference.h b/SpeckleLib/Speckle/Serialise/Detached/DetachedReference.h new file mode 100644 index 0000000..6993f39 --- /dev/null +++ b/SpeckleLib/Speckle/Serialise/Detached/DetachedReference.h @@ -0,0 +1,77 @@ +#ifndef SPECKLE_SERIALISE_DETACHED_REFERENCE +#define SPECKLE_SERIALISE_DETACHED_REFERENCE + +#include "Active/Serialise/Package/Package.h" +#include "Speckle/Serialise/Detached/DetachedWrap.h" +#include "Speckle/Utility/String.h" + +namespace speckle::serialise { + + /*! + Wrapper for references to a detached (serialised) object + + An object holding a child object that should be serialised as a detached object should wrap the child in this package for (de)serialisation + */ + class DetachedReference : public active::serialise::Package, std::reference_wrapper { + public: + + // MARK: - Types + + ///Item reference base + using base = std::reference_wrapper; + + // MARK: - Constructors + + /*! + Constructor + @param source The source package to wrap + */ + DetachedReference(Package& source) : base{source} {} + /*! + Constructor + @param source The source package to wrap + */ + DetachedReference(const active::serialise::Package& source) : base(const_cast(source)) {} + DetachedReference(const DetachedReference& source) = delete; + /*! + Destructor + */ + ~DetachedReference() override = default; + + // MARK: - Functions (const) + + /*! + Fill an inventory with the cargo items + @param inventory The inventory to receive the cargo items + @return True if items have been added to the inventory + */ + bool fillInventory(active::serialise::Inventory& inventory) const override; + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + + // MARK: - Functions (mutating) + + /*! + Set to the default package content + */ + void setDefault() override; + /*! + Validate the cargo data + @return True if the data has been validated + */ + bool validate() override; + + private: + ///The reference value, i.e. a hash of the object content + mutable std::optional m_reference; + ///The reference type + utility::String m_type; + }; + +} + +#endif //SPECKLE_SERIALISE_DETACHED_REFERENCE diff --git a/SpeckleLib/Speckle/Serialise/Detached/DetachedWrap.cpp b/SpeckleLib/Speckle/Serialise/Detached/DetachedWrap.cpp new file mode 100644 index 0000000..141b4b9 --- /dev/null +++ b/SpeckleLib/Speckle/Serialise/Detached/DetachedWrap.cpp @@ -0,0 +1,93 @@ +#include "Speckle/Serialise/Detached/DetachedWrap.h" + +#include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Active/Utility/BufferOut.h" +#include "Active/Utility/SHA256.h" +#include "Speckle/Serialise/Detached/DetachmentManager.h" +#include "Speckle/Utility/String.h" + +using namespace active::serialise; +using namespace speckle::database; +using namespace speckle::serialise; +using namespace speckle::utility; + +#include + +namespace { + + ///Serialisation fields + enum FieldIndex { + refdID, + }; + + ///Serialisation field IDs + static std::array fieldID = { + Identity{"id"}, + }; + +} + +/*-------------------------------------------------------------------- + Fill an inventory with the package items + + inventory: The inventory to receive the package items + + return: True if the package has added items to the inventory + --------------------------------------------------------------------*/ +bool DetachedWrap::fillInventory(Inventory& inventory) const { + using enum Entry::Type; + if (!base::get().fillInventory(inventory)) + return false; + inventory.merge(Inventory{ + { + { fieldID[refdID], refdID, element }, + }, + }.withType(&typeid(DetachedWrap))); + return true; +} //DetachedWrap::fillInventory + + +/*-------------------------------------------------------------------- + Get the specified cargo + + item: The inventory item to retrieve + + return: The requested cargo (nullptr on failure) + --------------------------------------------------------------------*/ +Cargo::Unique DetachedWrap::getCargo(const Inventory::Item& item) const { + if (item.ownerType != &typeid(DetachedWrap)) + return base::get().getCargo(item); + using namespace active::serialise; + switch (item.index) { + case refdID: { + if (!m_reference) { + if (m_bufferOut == nullptr) + return nullptr; //TODO: Consider throwing an exception here + auto serialisedData = m_bufferOut->getOutput(); + //Produce a hash from the serialised object. NB: We are currently using only the first 32 chars of the SHA256 hash + m_reference = (active::utility::SHA256() << serialisedData << String{"}"}).base64Hash().substr(0, 32); + } + return std::make_unique>(*m_reference); + } + default: + return nullptr; //Requested an unknown index + } +} //DetachedWrap::getCargo + + +/*-------------------------------------------------------------------- + Set to the default package content + --------------------------------------------------------------------*/ +void DetachedWrap::setDefault() { + m_reference = String{}; +} //DetachedWrap::setDefault + + +/*-------------------------------------------------------------------- + Validate the cargo data + + return: True if the data has been validated + --------------------------------------------------------------------*/ +bool DetachedWrap::validate() { + return m_reference && base::get().validate(); +} //DetachedWrap::validate diff --git a/SpeckleLib/Speckle/Serialise/Detached/DetachedWrap.h b/SpeckleLib/Speckle/Serialise/Detached/DetachedWrap.h new file mode 100644 index 0000000..29532b1 --- /dev/null +++ b/SpeckleLib/Speckle/Serialise/Detached/DetachedWrap.h @@ -0,0 +1,89 @@ +#ifndef SPECKLE_SERIALISE_DETACHED_WRAP +#define SPECKLE_SERIALISE_DETACHED_WRAP + +#include "Active/Serialise/Package/Package.h" + +#include "Speckle/Database/Identity/RecordID.h" + +namespace active::utility { + class BufferOut; +} + +namespace speckle::serialise { + + /*! + Lightweight interface wrapper for a detached object + + The wrapper generates a new reference ID for the object during serialisation, embedding it in the output + */ + class DetachedWrap : public active::serialise::Package, public std::reference_wrapper { + public: + + // MARK: - Types + + ///Item reference base + using base = std::reference_wrapper; + + // MARK: - Constructors + + /*! + Constructor + @param source The source package to wrap + @param bufferOut The serialisation output buffer + */ + DetachedWrap(active::serialise::Package& source, active::utility::BufferOut& bufferOut) : base(source), m_bufferOut{&bufferOut} {} + /*! + Constructor + @param source The source package to wrap + @param bufferOut The serialisation output buffer + */ + DetachedWrap(const active::serialise::Package& source, active::utility::BufferOut& bufferOut) : + DetachedWrap{const_cast(source), bufferOut} {} + /*! + Copy constructor + @param source The object to copy + */ + DetachedWrap(const DetachedWrap& source) : base(source), m_reference{source.m_reference} {} + + // MARK: - Functions (const) + + /*! + Get the detached object reference + @return The detached object reference (nullopt if the reference has not been determined yet - call after (de)serialisation) + */ + std::optional getReference() const { return m_reference; } + /*! + Fill an inventory with the cargo items + @param inventory The inventory to receive the cargo items + @return True if items have been added to the inventory + */ + bool fillInventory(active::serialise::Inventory& inventory) const override; + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + + // MARK: - Functions (mutating) + + /*! + Set to the default package content + */ + void setDefault() override; + /*! + Validate the cargo data + @return True if the data has been validated + */ + bool validate() override; + + private: + ///The detached record reference + mutable std::optional m_reference; + ///The serialisation output buffer + active::utility::BufferOut* m_bufferOut; + }; + +} + +#endif //SPECKLE_SERIALISE_DETACHED_WRAP diff --git a/SpeckleLib/Speckle/Serialise/Detached/DetachmentManager.cpp b/SpeckleLib/Speckle/Serialise/Detached/DetachmentManager.cpp new file mode 100644 index 0000000..b5e98f0 --- /dev/null +++ b/SpeckleLib/Speckle/Serialise/Detached/DetachmentManager.cpp @@ -0,0 +1,89 @@ +#include "Speckle/Serialise/Detached/DetachmentManager.h" + +#include "Active/Utility/BufferOut.h" +#include "Speckle/Serialise/Detached/DetachedWrap.h" +#include "Speckle/Serialise/Detached/Storage/DetachedObjectStore.h" + +using namespace active::serialise; +using namespace speckle::database; +using namespace speckle::serialise; +using namespace speckle::utility; + + +/*-------------------------------------------------------------------- + Default constructor + --------------------------------------------------------------------*/ +DetachmentManager::DetachmentManager() { + +} //DetachmentManager::DetachmentManager + + +/*-------------------------------------------------------------------- + Destructor + --------------------------------------------------------------------*/ +DetachmentManager::~DetachmentManager() { + +} //DetachmentManager::~DetachmentManager + + +/*-------------------------------------------------------------------- + Send cargo as a detached object + + package: The package to become a detached object + identity: The package identity (name, optional namespace) + + return: The ID of the sent detached object + --------------------------------------------------------------------*/ +std::optional DetachmentManager::send(Package&& package, const Identity& identity) const { + auto transport = m_transport.lock(); + if (!transport) + throw; //TODO: Throw meaningful exception type + //Prepare the detached object data + String serialisedData; + active::utility::BufferOut buffer{serialisedData}; + //The wrapper will manage the object serialisation and generate a unique reference based on the output + DetachedWrap wrapper{package, buffer}; + transport->send(std::forward(wrapper), identity, serialisedData); + auto detachedReference = wrapper.getReference(); + //If a reference is obtained, file/cache the object as required + if (detachedReference) { + m_store->file(*detachedReference, serialisedData); + if (m_cache) + m_cache->file(*detachedReference, serialisedData); + } + return detachedReference; +} //DetachmentManager::send + + +/*-------------------------------------------------------------------- + Receive cargo from a detached object + + id: The ID of the detached object to receive + package: The package to receive the detached object data + identity: The package identity (name, optional namespace) + + return: True if the detached object was found and received + --------------------------------------------------------------------*/ +bool DetachmentManager::receive(const database::RecordID& id, Package&& package, const Identity& identity) const { + return false; //TODO: Implement when we start receiving in Archicad +} //DetachmentManager::receive + + +/*-------------------------------------------------------------------- + Set the manager primary storage + + store: the primary storage (this is the long-term storage, e.g. a remote/cloud database) + --------------------------------------------------------------------*/ +void DetachmentManager::setStore(std::unique_ptr store) { + m_store = std::move(store); +} //DetachmentManager::setStore + + +/*-------------------------------------------------------------------- + Set the manager storage cache + + cache: the storage cache (this is intended to provide faster access than the primary storage for repeated detached objects) + --------------------------------------------------------------------*/ +void DetachmentManager::setCache(std::unique_ptr cache) { + m_cache = std::move(cache); +} //DetachmentManager::setCache diff --git a/SpeckleLib/Speckle/Serialise/Detached/DetachmentManager.h b/SpeckleLib/Speckle/Serialise/Detached/DetachmentManager.h new file mode 100644 index 0000000..094eda2 --- /dev/null +++ b/SpeckleLib/Speckle/Serialise/Detached/DetachmentManager.h @@ -0,0 +1,82 @@ +#ifndef SPECKLE_SERIALISE_DETACHMENT_MANAGER +#define SPECKLE_SERIALISE_DETACHMENT_MANAGER + +#include "Active/Serialise/Manager.h" +#include "Active/Serialise/Transport.h" +#include "Speckle/Database/Identity/RecordID.h" + +namespace active::serialise { + class Package; +} + +namespace speckle::serialise { + + class DetachedObjectStore; + + /*! + Manager for detached (serialised) objects + + Pass this manager to the target transport for (de)serialisation supporting detached objects. Note that the manager is expected to know how + to send/receive detached objects, e.g. to a JS portal, remote server or local database (or some combo) + */ + class DetachmentManager : public virtual active::serialise::Manager { + public: + + // MARK: - Types + + ///Base class + using base = active::serialise::Manager; + + /*! + Default constructor + */ + DetachmentManager(); + DetachmentManager(const DetachmentManager&) = delete; + /*! + Destructor + */ + ~DetachmentManager(); + + // MARK: - Functions (const) + + /*! + Send cargo as a detached object + @param package The package to become a detached object + @param identity The package identity (name, optional namespace) + @return The ID of the sent detached object + */ + std::optional send(active::serialise::Package&& package, const active::serialise::Identity& identity) const; + /*! + Receive cargo from a detached object + @param id The ID of the detached object to receive + @param package The package to receive the detached object data + @param identity The package identity (name, optional namespace) + @return True if the detached object was found and received + */ + bool receive(const database::RecordID& id, active::serialise::Package&& package, const active::serialise::Identity& identity) const; + + // MARK: - Functions (mutating) + + /*! + Set the manager primary storage + @param store the primary storage (this is the long-term storage, e.g. a remote/cloud database) + */ + void setStore(std::unique_ptr store); + /*! + Set the manager storage cache + @param cache the storage cache (this is intended to provide faster access than the primary storage for repeated detached objects) + */ + void setCache(std::unique_ptr cache); + + private: + ///The manager serialisation transport (NB - this is expected to be a shared resource, so the manager does not own it) + std::weak_ptr m_transport; + ///The primary store for sending/retrieving detached objects + std::unique_ptr m_store; + ///A cache for detached objects - can be used as a local store to save + std::unique_ptr m_cache; + }; + +} + +#endif //SPECKLE_SERIALISE_DETACHMENT_MANAGER diff --git a/SpeckleLib/Speckle/Serialise/Detached/Storage/DetachedObjectStore.h b/SpeckleLib/Speckle/Serialise/Detached/Storage/DetachedObjectStore.h new file mode 100644 index 0000000..546d572 --- /dev/null +++ b/SpeckleLib/Speckle/Serialise/Detached/Storage/DetachedObjectStore.h @@ -0,0 +1,46 @@ +#ifndef SPECKLE_SERIALISE_DETACHED_OBJECT_STORE +#define SPECKLE_SERIALISE_DETACHED_OBJECT_STORE + +#include "Speckle/Database/Identity/RecordID.h" +#include "Speckle/Utility/String.h" + +namespace speckle::serialise { + + /*! + Interface for objects that store/cache/send/receive detached objects + + It is currently assumed that objects will be serialised and can be held in a string. This can be revisited in future if binary data is required. + */ + class DetachedObjectStore { + public: + + // MARK: Constructors + + /*! + Destructor + */ + virtual ~DetachedObjectStore() {} + + // MARK: - Functions (const) + + /*! + Retrieve a detached object from storage + @param reference The required object reference + @return The object data (nullopt if the object cannot be found in storage) + */ + virtual utility::String::Option retrieve(const database::RecordID& reference) = 0; + + // MARK: - Functions (mutating) + + /*! + File a detached object in storage + @param reference The object reference (typically a hash generated from the object data) + @param data The object data (currently expected to be serialised as JSON) + @return True if the object was filed (typically rejected if it duplicates an object already in the store) + */ + virtual bool file(const database::RecordID& reference, const utility::String& data) const = 0; + }; + +} + +#endif //SPECKLE_SERIALISE_DETACHED_OBJECT_STORE diff --git a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj index 9c1676a..82a12ac 100644 --- a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj +++ b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj @@ -37,6 +37,10 @@ 219351B12C62CC1A00E5A69C /* Guid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219351AC2C62CC1A00E5A69C /* Guid.cpp */; }; 219351B32C62CC1A00E5A69C /* String.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219351AE2C62CC1A00E5A69C /* String.cpp */; }; 2199881E2BD833830035E5EA /* libArchicad27.a in CopyFiles */ = {isa = PBXBuildFile; fileRef = 21379E082AE47A6400A1584C /* libArchicad27.a */; }; + 21AEF9BA2CA606B5000B8681 /* DetachedReference.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9B92CA606B4000B8681 /* DetachedReference.cpp */; }; + 21AEF9BC2CA6DF84000B8681 /* DetachmentManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9BB2CA6DF84000B8681 /* DetachmentManager.cpp */; }; + 21AEF9BE2CA6FDA4000B8681 /* DetachedWrap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9BD2CA6FDA4000B8681 /* DetachedWrap.cpp */; }; + 21AEF9DD2CAAA4EA000B8681 /* DetachedObjectStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 21AEF9DB2CAAA4EA000B8681 /* DetachedObjectStore.h */; }; 21B67D002C7CE15100FD64FC /* Exception.h in Headers */ = {isa = PBXBuildFile; fileRef = 21B67CFE2C7CE15100FD64FC /* Exception.h */; }; 21B67D0D2C7E0E8D00FD64FC /* ErrorReport.h in Headers */ = {isa = PBXBuildFile; fileRef = 21B67D092C7E0E8D00FD64FC /* ErrorReport.h */; }; 21B67D0E2C7E0E8D00FD64FC /* ErrorReport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21B67D0C2C7E0E8D00FD64FC /* ErrorReport.cpp */; }; @@ -159,6 +163,13 @@ 219351AE2C62CC1A00E5A69C /* String.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = String.cpp; sourceTree = ""; }; 219351AF2C62CC1A00E5A69C /* String.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = String.h; sourceTree = ""; }; 219712682BE7E2D500D9EF7E /* Serialisation.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Serialisation.md; sourceTree = ""; }; + 21AEF9B32CA5F7CF000B8681 /* DetachedWrap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedWrap.h; sourceTree = ""; }; + 21AEF9B52CA5FA02000B8681 /* DetachedReference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedReference.h; sourceTree = ""; }; + 21AEF9B72CA5FCB6000B8681 /* DetachmentManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachmentManager.h; sourceTree = ""; }; + 21AEF9B92CA606B4000B8681 /* DetachedReference.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DetachedReference.cpp; sourceTree = ""; }; + 21AEF9BB2CA6DF84000B8681 /* DetachmentManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DetachmentManager.cpp; sourceTree = ""; }; + 21AEF9BD2CA6FDA4000B8681 /* DetachedWrap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DetachedWrap.cpp; sourceTree = ""; }; + 21AEF9DB2CAAA4EA000B8681 /* DetachedObjectStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedObjectStore.h; sourceTree = ""; }; 21B67CFE2C7CE15100FD64FC /* Exception.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Exception.h; sourceTree = ""; }; 21B67D092C7E0E8D00FD64FC /* ErrorReport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ErrorReport.h; sourceTree = ""; }; 21B67D0C2C7E0E8D00FD64FC /* ErrorReport.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ErrorReport.cpp; sourceTree = ""; }; @@ -255,6 +266,7 @@ isa = PBXGroup; children = ( 2167E27C2C49121F000827D3 /* CMakeLists.txt */, + 21AEF9C72CA818EA000B8681 /* Detached */, 21F69F3A2C6B880B008B6A06 /* JSBase */, 219712682BE7E2D500D9EF7E /* Serialisation.md */, ); @@ -403,6 +415,28 @@ path = SpeckleLibDoctest; sourceTree = ""; }; + 21AEF9C72CA818EA000B8681 /* Detached */ = { + isa = PBXGroup; + children = ( + 21AEF9B92CA606B4000B8681 /* DetachedReference.cpp */, + 21AEF9B52CA5FA02000B8681 /* DetachedReference.h */, + 21AEF9BD2CA6FDA4000B8681 /* DetachedWrap.cpp */, + 21AEF9B32CA5F7CF000B8681 /* DetachedWrap.h */, + 21AEF9BB2CA6DF84000B8681 /* DetachmentManager.cpp */, + 21AEF9B72CA5FCB6000B8681 /* DetachmentManager.h */, + 21AEF9DE2CAAA78A000B8681 /* Storage */, + ); + path = Detached; + sourceTree = ""; + }; + 21AEF9DE2CAAA78A000B8681 /* Storage */ = { + isa = PBXGroup; + children = ( + 21AEF9DB2CAAA4EA000B8681 /* DetachedObjectStore.h */, + ); + path = Storage; + sourceTree = ""; + }; 21D0BD1F2C86F0280077E104 /* Database */ = { isa = PBXGroup; children = ( @@ -596,6 +630,7 @@ 21D0BD5A2C8910400077E104 /* UserInfo.h in Headers */, 21D0BD562C890B1C0077E104 /* ServerMigration.h in Headers */, 210CC88F2C81A98500610F58 /* Guid64.h in Headers */, + 21AEF9DD2CAAA4EA000B8681 /* DetachedObjectStore.h in Headers */, 215F088D2CA195EC00CD343B /* ArchicadElementDBaseEngine.h in Headers */, 21B67D002C7CE15100FD64FC /* Exception.h in Headers */, 21D0BD2C2C86FC350077E104 /* Record.h in Headers */, @@ -749,6 +784,7 @@ 21B67D0E2C7E0E8D00FD64FC /* ErrorReport.cpp in Sources */, 21F69F7E2C6FD9FC008B6A06 /* GetCallResult.cpp in Sources */, 219245FE2CA2CC4300CF5703 /* BIMRecord.cpp in Sources */, + 21AEF9BE2CA6FDA4000B8681 /* DetachedWrap.cpp in Sources */, 2193519B2C6278D900E5A69C /* SelectionSubscriber.cpp in Sources */, 21D0BD2B2C86FC350077E104 /* Record.cpp in Sources */, 219246042CA2CE2700CF5703 /* BIMLink.cpp in Sources */, @@ -760,11 +796,13 @@ 219351B32C62CC1A00E5A69C /* String.cpp in Sources */, 219351B12C62CC1A00E5A69C /* Guid.cpp in Sources */, 21F69F512C6CCC25008B6A06 /* BrowserBridge.cpp in Sources */, + 21AEF9BC2CA6DF84000B8681 /* DetachmentManager.cpp in Sources */, 215F08552C99DA8D00CD343B /* Project.cpp in Sources */, 21F69F3B2C6B880C008B6A06 /* JSBaseTransport.cpp in Sources */, 210CC89F2C81E34400610F58 /* Platform.cpp in Sources */, 21D0BD202C86F0280077E104 /* AccountDatabase.cpp in Sources */, 21F69F962C71087A008B6A06 /* Account.cpp in Sources */, + 21AEF9BA2CA606B5000B8681 /* DetachedReference.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From e148094c81fcf3fcb28a2c24f330eabb85804e37 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Tue, 1 Oct 2024 17:24:59 +0100 Subject: [PATCH 008/191] ModelCardDatabase can retrieve a card by ID Added numerous Send argument classes: - ConversionResult (incomplete) - SendError - SendObject - SendViaBrowserArgs (incomplete) Send method looks up model card and account details, constructs send arguments AccountDatabase can find an account by ID or server URL Added DetachedMemoryStore --- .../Connector.xcodeproj/project.pbxproj | 46 ++++++ .../Connector/ConnectorResource.h | 3 + .../Connector/Database/ModelCardDatabase.cpp | 10 ++ .../Connector/Database/ModelCardDatabase.h | 5 + .../Bridge/Send/Arg/ConversionResult.cpp | 63 ++++++++ .../Bridge/Send/Arg/ConversionResult.h | 68 ++++++++ .../Browser/Bridge/Send/Arg/SendError.cpp | 63 ++++++++ .../Browser/Bridge/Send/Arg/SendError.h | 54 +++++++ .../Browser/Bridge/Send/Arg/SendObject.cpp | 146 ++++++++++++++++++ .../Browser/Bridge/Send/Arg/SendObject.h | 53 +++++++ .../Bridge/Send/Arg/SendViaBrowserArgs.cpp | 106 +++++++++++++ .../Bridge/Send/Arg/SendViaBrowserArgs.h | 78 ++++++++++ .../Interface/Browser/Bridge/Send/Send.cpp | 109 +++++-------- .../Connector/Record/Model/ModelCard.h | 2 + SpeckleConnector/RINT/Connector.grc | 3 + .../Speckle/Database/AccountDatabase.cpp | 21 +++ SpeckleLib/Speckle/Database/AccountDatabase.h | 11 ++ .../Speckle/Record/Credentials/Account.h | 11 ++ .../Speckle/Record/Credentials/ServerInfo.cpp | 2 +- .../Speckle/Record/Credentials/ServerInfo.h | 6 +- .../Serialise/Detached/DetachedWrap.cpp | 1 - .../Detached/Storage/DetachedMemoryStore.h | 52 +++++++ .../Detached/Storage/DetachedObjectStore.h | 4 +- .../SpeckleLib.xcodeproj/project.pbxproj | 2 + 24 files changed, 838 insertions(+), 81 deletions(-) create mode 100644 SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/ConversionResult.cpp create mode 100644 SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/ConversionResult.h create mode 100644 SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendError.cpp create mode 100644 SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendError.h create mode 100644 SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp create mode 100644 SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h create mode 100644 SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp create mode 100644 SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h create mode 100644 SpeckleLib/Speckle/Serialise/Detached/Storage/DetachedMemoryStore.h diff --git a/SpeckleConnector/Connector.xcodeproj/project.pbxproj b/SpeckleConnector/Connector.xcodeproj/project.pbxproj index 4f81038..37e3043 100644 --- a/SpeckleConnector/Connector.xcodeproj/project.pbxproj +++ b/SpeckleConnector/Connector.xcodeproj/project.pbxproj @@ -31,6 +31,11 @@ 215F08462C9633A800CD343B /* EverythingSendFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 215F08452C9633A800CD343B /* EverythingSendFilter.cpp */; }; 2192460D2CA3469D00CF5703 /* RootCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2192460B2CA3469D00CF5703 /* RootCollection.cpp */; }; 219F30422C769283009834E9 /* ConfigTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219F30402C769282009834E9 /* ConfigTests.cpp */; }; + 21AEF9EB2CAB56E5000B8681 /* SendError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9E32CAB56E5000B8681 /* SendError.cpp */; }; + 21AEF9EC2CAB56E5000B8681 /* SendViaBrowserArgs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9E52CAB56E5000B8681 /* SendViaBrowserArgs.cpp */; }; + 21AEF9EF2CAB5720000B8681 /* SendObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9EE2CAB5720000B8681 /* SendObject.cpp */; }; + 21AEF9F32CAC12D1000B8681 /* SendManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9F02CAC12D1000B8681 /* SendManager.cpp */; }; + 21AEF9FA2CAC3897000B8681 /* ConversionResult.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9F92CAC3897000B8681 /* ConversionResult.cpp */; }; 21B67CA32C769CB400FD64FC /* libActiveLib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 21F69EF52C64FE91008B6A06 /* libActiveLib.a */; }; 21B67CA42C769CB400FD64FC /* libArchicad27.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 21F69ECD2C64C035008B6A06 /* libArchicad27.a */; }; 21B67CAC2C77329800FD64FC /* BaseBridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21B67CA52C77329800FD64FC /* BaseBridge.cpp */; }; @@ -306,6 +311,16 @@ 219F30352C768F0A009834E9 /* Connector-AC27-Test.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Connector-AC27-Test.bundle"; sourceTree = BUILT_PRODUCTS_DIR; }; 219F30402C769282009834E9 /* ConfigTests.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = ConfigTests.cpp; sourceTree = ""; }; 219F30432C7693B6009834E9 /* Connector-AC27-Debug.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Connector-AC27-Debug.xctestplan"; sourceTree = SOURCE_ROOT; }; + 21AEF9E32CAB56E5000B8681 /* SendError.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SendError.cpp; sourceTree = ""; }; + 21AEF9E42CAB56E5000B8681 /* SendError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SendError.h; sourceTree = ""; }; + 21AEF9E52CAB56E5000B8681 /* SendViaBrowserArgs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SendViaBrowserArgs.cpp; sourceTree = ""; }; + 21AEF9E62CAB56E5000B8681 /* SendViaBrowserArgs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SendViaBrowserArgs.h; sourceTree = ""; }; + 21AEF9ED2CAB5720000B8681 /* SendObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SendObject.h; sourceTree = ""; }; + 21AEF9EE2CAB5720000B8681 /* SendObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SendObject.cpp; sourceTree = ""; }; + 21AEF9F02CAC12D1000B8681 /* SendManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SendManager.cpp; sourceTree = ""; }; + 21AEF9F12CAC12D1000B8681 /* SendManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SendManager.h; sourceTree = ""; }; + 21AEF9F82CAC3897000B8681 /* ConversionResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConversionResult.h; sourceTree = ""; }; + 21AEF9F92CAC3897000B8681 /* ConversionResult.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConversionResult.cpp; sourceTree = ""; }; 21B67CA52C77329800FD64FC /* BaseBridge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BaseBridge.cpp; sourceTree = ""; }; 21B67CA62C77329800FD64FC /* BaseBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BaseBridge.h; sourceTree = ""; }; 21B67CA72C77329800FD64FC /* GetSourceApplicationName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetSourceApplicationName.cpp; sourceTree = ""; }; @@ -945,6 +960,30 @@ path = ConnectorTests; sourceTree = ""; }; + 21AEF9E72CAB56E5000B8681 /* Arg */ = { + isa = PBXGroup; + children = ( + 21AEF9F92CAC3897000B8681 /* ConversionResult.cpp */, + 21AEF9F82CAC3897000B8681 /* ConversionResult.h */, + 21AEF9E32CAB56E5000B8681 /* SendError.cpp */, + 21AEF9E42CAB56E5000B8681 /* SendError.h */, + 21AEF9EE2CAB5720000B8681 /* SendObject.cpp */, + 21AEF9ED2CAB5720000B8681 /* SendObject.h */, + 21AEF9E52CAB56E5000B8681 /* SendViaBrowserArgs.cpp */, + 21AEF9E62CAB56E5000B8681 /* SendViaBrowserArgs.h */, + ); + path = Arg; + sourceTree = ""; + }; + 21AEF9F22CAC12D1000B8681 /* Serialise */ = { + isa = PBXGroup; + children = ( + 21AEF9F02CAC12D1000B8681 /* SendManager.cpp */, + 21AEF9F12CAC12D1000B8681 /* SendManager.h */, + ); + path = Serialise; + sourceTree = ""; + }; 21B67CAB2C77329800FD64FC /* Base */ = { isa = PBXGroup; children = ( @@ -1029,6 +1068,7 @@ 21D0BD5D2C89BFEA0077E104 /* Send */ = { isa = PBXGroup; children = ( + 21AEF9E72CAB56E5000B8681 /* Arg */, 21D0BD962C8F13F30077E104 /* GetSendFilters.cpp */, 21D0BD952C8F13F30077E104 /* GetSendFilters.h */, 21D0BD8D2C8EE4490077E104 /* Send.cpp */, @@ -1143,6 +1183,7 @@ 21F69F092C677BC0008B6A06 /* Event */, 21F69F0E2C677BC0008B6A06 /* Interface */, 21D0BDD82C9387E60077E104 /* Record */, + 21AEF9F22CAC12D1000B8681 /* Serialise */, 21B67CBA2C774C6500FD64FC /* Version.h */, ); path = Connector; @@ -1411,8 +1452,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 21AEF9FA2CAC3897000B8681 /* ConversionResult.cpp in Sources */, 21D0BDAB2C8F363E0077E104 /* CardSetting.cpp in Sources */, 21B67CE32C78D1FB00FD64FC /* SayHiArg.cpp in Sources */, + 21AEF9EB2CAB56E5000B8681 /* SendError.cpp in Sources */, 215F08462C9633A800CD343B /* EverythingSendFilter.cpp in Sources */, 21F69FBB2C762EF0008B6A06 /* ConfigBridge.cpp in Sources */, 21F69F8A2C70D2C4008B6A06 /* AccountBridge.cpp in Sources */, @@ -1427,11 +1470,13 @@ 21B67CAC2C77329800FD64FC /* BaseBridge.cpp in Sources */, 2192460D2CA3469D00CF5703 /* RootCollection.cpp in Sources */, 21D0BD6A2C8A0DB40077E104 /* GetIsDevMode.cpp in Sources */, + 21AEF9F32CAC12D1000B8681 /* SendManager.cpp in Sources */, 210CC8832C80E6A300610F58 /* TriggerEvent.cpp in Sources */, 21B67CEB2C78D27200FD64FC /* DocumentInfo.cpp in Sources */, 21B67CB92C774BFA00FD64FC /* GetConnectorVersion.cpp in Sources */, 21B67CD92C78C83800FD64FC /* TestBridge.cpp in Sources */, 214B7A372C764BCD00D586C1 /* UpdateConfig.cpp in Sources */, + 21AEF9EC2CAB56E5000B8681 /* SendViaBrowserArgs.cpp in Sources */, 21FF70492CA1A7F400AAD99A /* RecordCollection.cpp in Sources */, 21B67CC02C775A0D00FD64FC /* GetDocumentInfo.cpp in Sources */, 21D0BDD42C935D1A0077E104 /* UpdateModel.cpp in Sources */, @@ -1442,6 +1487,7 @@ 215F082A2C947F4400CD343B /* CardMover.cpp in Sources */, 215F08372C95808B00CD343B /* ReceiverModelCard.cpp in Sources */, 21D0BDD72C935DAE0077E104 /* RemoveModel.cpp in Sources */, + 21AEF9EF2CAB5720000B8681 /* SendObject.cpp in Sources */, 21B67CDC2C78C88000FD64FC /* SayHi.cpp in Sources */, 215F082E2C94C5C000CD343B /* FilterMover.cpp in Sources */, 21F69F122C677BC0008B6A06 /* ConnectorMenu.cpp in Sources */, diff --git a/SpeckleConnector/Connector/ConnectorResource.h b/SpeckleConnector/Connector/ConnectorResource.h index 82885a1..daec179 100755 --- a/SpeckleConnector/Connector/ConnectorResource.h +++ b/SpeckleConnector/Connector/ConnectorResource.h @@ -54,6 +54,9 @@ enum WarningString { //Error strings (errors displayed in alerts) enum ErrorString { noSelectedModelItemsID = 1, + modelCardNotFoundID, + noProjectOpenID, + accountNotFoundID, }; #endif //CONNECTOR_RESOURCE diff --git a/SpeckleConnector/Connector/Database/ModelCardDatabase.cpp b/SpeckleConnector/Connector/Database/ModelCardDatabase.cpp index c10d1b6..9a2f0b3 100644 --- a/SpeckleConnector/Connector/Database/ModelCardDatabase.cpp +++ b/SpeckleConnector/Connector/Database/ModelCardDatabase.cpp @@ -71,6 +71,16 @@ ModelCardDatabase::ModelCardDatabase() { ModelCardDatabase::~ModelCardDatabase() {} +/*-------------------------------------------------------------------- + Get a specified card from the database + + return: The requested card (nullptr on failure) + --------------------------------------------------------------------*/ +ModelCard::Unique ModelCardDatabase::getCard(const speckle::utility::String& cardID) const { + return m_store->getObject(cardID); +} //ModelCardDatabase::getCard + + /*-------------------------------------------------------------------- Get all model cards diff --git a/SpeckleConnector/Connector/Database/ModelCardDatabase.h b/SpeckleConnector/Connector/Database/ModelCardDatabase.h index 79a2353..2f1e080 100644 --- a/SpeckleConnector/Connector/Database/ModelCardDatabase.h +++ b/SpeckleConnector/Connector/Database/ModelCardDatabase.h @@ -29,6 +29,11 @@ namespace connector::database { // MARK: - Functions (const) + /*! + Get a specified card from the database + @return The requested card (nullptr on failure) + */ + record::ModelCard::Unique getCard(const speckle::utility::String& cardID) const; /*! Get all model cards @return All the cards diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/ConversionResult.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/ConversionResult.cpp new file mode 100644 index 0000000..c12a724 --- /dev/null +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/ConversionResult.cpp @@ -0,0 +1,63 @@ +#include "Connector/Interface/Browser/Bridge/Send/Arg/ConversionResult.h" + +#include "Active/Serialise/item/Wrapper/ValueWrap.h" + +using namespace active::serialise; +using namespace connector::interfac::browser::bridge; +using namespace speckle::utility; + +namespace { + + ///Serialisation fields + enum FieldIndex { + errorID, + cardID, + }; + + ///Serialisation field IDs + static std::array fieldID = { + Identity{"error"}, + Identity{"modelCardId"}, + }; + +} + +/*-------------------------------------------------------------------- + Fill an inventory with the package items + + inventory: The inventory to receive the package items + + return: True if the package has added items to the inventory + --------------------------------------------------------------------*/ +bool ConversionResult::fillInventory(active::serialise::Inventory& inventory) const { + using enum Entry::Type; + inventory.merge(Inventory{ + { + { fieldID[errorID], errorID, element }, + { fieldID[cardID], cardID, element }, + }, + }.withType(&typeid(ConversionResult))); + return true; +} //ConversionResult::fillInventory + + +/*-------------------------------------------------------------------- + Get the specified cargo + + item: The inventory item to retrieve + + return: The requested cargo (nullptr on failure) + --------------------------------------------------------------------*/ +Cargo::Unique ConversionResult::getCargo(const active::serialise::Inventory::Item& item) const { + if (item.ownerType != &typeid(ConversionResult)) + return nullptr; + using namespace active::serialise; + switch (item.index) { + case errorID: + return std::make_unique>(message); + case cardID: + return std::make_unique>(modelCardID); + default: + return nullptr; //Requested an unknown index + } +} //ConversionResult::getCargo diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/ConversionResult.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/ConversionResult.h new file mode 100644 index 0000000..53146fa --- /dev/null +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/ConversionResult.h @@ -0,0 +1,68 @@ +#ifndef CONNECTOR_INTERFACE_BRIDGE_SEND_CONVERSION_RESULT +#define CONNECTOR_INTERFACE_BRIDGE_SEND_CONVERSION_RESULT + +#include "Active/Serialise/Package/Wrapper/PackageWrap.h" +#include "Connector/Interface/Browser/Bridge/Send/Arg/SendError.h" +#include "Speckle/Utility/String.h" + +namespace connector::interfac::browser::bridge { + + /*! + A send error to return to the JS in the event of an error + */ + class ConversionResult final : public active::serialise::Package { + public: + enum class Status { + success = 1, + info, + warning, + error, + }; + + // MARK: - Constructors + + /*! + Constructor + @param errMess The error message + @param card The ID of the model card associated with the wrror + */ + ConversionResult(const speckle::utility::String& errMess, const speckle::utility::String& card) : message{errMess}, modelCardID{card} {} + + // MARK: - Public variables + + ///The error message + speckle::utility::String message; + ///The ID of the model card associated with the data + speckle::utility::String modelCardID; + ///The element conversion status + Status status = Status::info; + ///For receive conversion reports, this is the id of the speckle object. For send, it's the host app object id. + speckle::utility::String sourceId; + ///For receive conversion reports, this is the type of the speckle object. For send, it's the host app object type. + speckle::utility::String sourceType; + ///For receive conversion reports, this is the id of the host app object. For send, it's the speckle object id. + speckle::utility::String resultId; + ///For receive conversion reports, this is the type of the host app object. For send, it's the speckle object type. + speckle::utility::String resultType; + ///The exception (nullopt = no exception) + SendError::Option error; + + // MARK: - Serialisation + + /*! + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ + bool fillInventory(active::serialise::Inventory& inventory) const override; + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + }; + +} + +#endif //CONNECTOR_INTERFACE_BRIDGE_SEND_CONVERSION_RESULT diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendError.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendError.cpp new file mode 100644 index 0000000..a16a49b --- /dev/null +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendError.cpp @@ -0,0 +1,63 @@ +#include "Connector/Interface/Browser/Bridge/Send/Arg/SendError.h" + +#include "Active/Serialise/item/Wrapper/ValueWrap.h" + +using namespace active::serialise; +using namespace connector::interfac::browser::bridge; +using namespace speckle::utility; + +namespace { + + ///Serialisation fields + enum FieldIndex { + errorID, + cardID, + }; + + ///Serialisation field IDs + static std::array fieldID = { + Identity{"error"}, + Identity{"modelCardId"}, + }; + +} + +/*-------------------------------------------------------------------- + Fill an inventory with the package items + + inventory: The inventory to receive the package items + + return: True if the package has added items to the inventory + --------------------------------------------------------------------*/ +bool SendError::fillInventory(active::serialise::Inventory& inventory) const { + using enum Entry::Type; + inventory.merge(Inventory{ + { + { fieldID[errorID], errorID, element }, + { fieldID[cardID], cardID, element }, + }, + }.withType(&typeid(SendError))); + return true; +} //SendError::fillInventory + + +/*-------------------------------------------------------------------- + Get the specified cargo + + item: The inventory item to retrieve + + return: The requested cargo (nullptr on failure) + --------------------------------------------------------------------*/ +Cargo::Unique SendError::getCargo(const active::serialise::Inventory::Item& item) const { + if (item.ownerType != &typeid(SendError)) + return nullptr; + using namespace active::serialise; + switch (item.index) { + case errorID: + return std::make_unique>(message); + case cardID: + return std::make_unique>(modelCardID); + default: + return nullptr; //Requested an unknown index + } +} //SendError::getCargo diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendError.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendError.h new file mode 100644 index 0000000..fd9a1c4 --- /dev/null +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendError.h @@ -0,0 +1,54 @@ +#ifndef CONNECTOR_INTERFACE_BRIDGE_SEND_ERROR +#define CONNECTOR_INTERFACE_BRIDGE_SEND_ERROR + +#include "Active/Serialise/Package/Wrapper/PackageWrap.h" +#include "Speckle/Utility/String.h" + +namespace connector::interfac::browser::bridge { + + /*! + A send error to return to the JS in the event of an error + */ + class SendError final : public active::serialise::Package { + public: + + // MARK: Types + + ///Optional + using Option = std::optional; + + // MARK: - Constructors + + /*! + Constructor + @param errMess The error message + @param card The ID of the model card associated with the wrror + */ + SendError(const speckle::utility::String& errMess, const speckle::utility::String& card) : message{errMess}, modelCardID{card} {} + + // MARK: - Public variables + + ///The error message + speckle::utility::String message; + ///The ID of the model card associated with the data + speckle::utility::String modelCardID; + + // MARK: - Serialisation + + /*! + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ + bool fillInventory(active::serialise::Inventory& inventory) const override; + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + }; + +} + +#endif //CONNECTOR_INTERFACE_BRIDGE_SEND_ERROR diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp new file mode 100644 index 0000000..94666e6 --- /dev/null +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp @@ -0,0 +1,146 @@ +#include "Connector/Interface/Browser/Bridge/Send/Send.h" + +#include "Active/Serialise/CargoHold.h" +#include "Active/Serialise/Package/Wrapper/PackageWrap.h" +#include "Connector/Connector.h" +#include "Connector/ConnectorResource.h" +#include "Connector/Database/ModelCardDatabase.h" +#include "Speckle/Interface/Browser/Bridge/BrowserBridge.h" +#include "Speckle/Serialise/Detached/Storage/DetachedMemoryStore.h" +#include "Speckle/Utility/Exception.h" + +using namespace active::serialise; +using namespace connector::interfac::browser::bridge; +using namespace speckle::database; +using namespace speckle::serialise; +using namespace speckle::utility; + +namespace { + + ///Serialisation fields + enum FieldIndex { + errorID, + cardID, + }; + + ///Serialisation field IDs + static std::array fieldID = { + Identity{"error"}, + Identity{"modelCardId"}, + }; + + /*! + A send error to return to the JS in the event of an error + */ + class SendError final : public active::serialise::Package { + public: + + // MARK: - Constructors + + /*! + Constructor + @param errMess The error message + @param card The ID of the model card associated with the wrror + */ + SendError(const String& errMess, const String& card) : message{errMess}, modelCardID{card} {} + + // MARK: - Public variables + + ///The error message + String message; + ///The ID of the model card associated with the data + String modelCardID; + + // MARK: - Serialisation + + /*! + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ + bool fillInventory(active::serialise::Inventory& inventory) const override; + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + }; + + + +} + +/*-------------------------------------------------------------------- + Fill an inventory with the package items + + inventory: The inventory to receive the package items + + return: True if the package has added items to the inventory + --------------------------------------------------------------------*/ +bool SendError::fillInventory(active::serialise::Inventory& inventory) const { + using enum Entry::Type; + inventory.merge(Inventory{ + { + { fieldID[errorID], errorID, element }, + { fieldID[cardID], cardID, element }, + }, + }.withType(&typeid(SendError))); + return true; +} //SendError::fillInventory + + +/*-------------------------------------------------------------------- + Get the specified cargo + + item: The inventory item to retrieve + + return: The requested cargo (nullptr on failure) + --------------------------------------------------------------------*/ +Cargo::Unique SendError::getCargo(const active::serialise::Inventory::Item& item) const { + if (item.ownerType != &typeid(SendError)) + return nullptr; + using namespace active::serialise; + switch (item.index) { + case errorID: + return std::make_unique>(message); + case cardID: + return std::make_unique>(modelCardID); + default: + return nullptr; //Requested an unknown index + } +} //SendError::getCargo + + +/*-------------------------------------------------------------------- + Default constructor + --------------------------------------------------------------------*/ +Send::Send() : BridgeMethod{"Send", [&](const SendArgs& args) { + run(args); +}} {} + + +/*-------------------------------------------------------------------- + Send a specified model + + modelCardID: The ID of the model to send + --------------------------------------------------------------------*/ +void Send::run(const String& modelCardID) const { + //Find the specified model card + auto modelCardDatabase = connector()->getModelCardDatabase(); + auto modelCard = modelCardDatabase->getCard(modelCardID); + if (!modelCard) { + getBridge()->sendEvent("setModelError", + std::make_unique(connector()->getLocalString(errorString, modelCardNotFoundID), modelCardID)); + return; + } + //Get the active project + auto project = connector()->getActiveProject().lock(); + if (!project) { + getBridge()->sendEvent("setModelError", + std::make_unique(connector()->getLocalString(errorString, noProjectOpenID), modelCardID)); + return; + } + + DetachedMemoryStore detachedObjects; +} //Send::run diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h new file mode 100644 index 0000000..9ea777a --- /dev/null +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h @@ -0,0 +1,53 @@ +#ifndef CONNECTOR_INTERFACE_BRIDGE_SEND_OBJECT +#define CONNECTOR_INTERFACE_BRIDGE_SEND_OBJECT + +#include "Active/Serialise/CargoHold.h" +#include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Connector/Interface/Browser/Bridge/Config/Arg/ConnectorConfig.h" +#include "Speckle/Interface/Browser/Bridge/BridgeMethod.h" + +namespace connector::interfac::browser::bridge { + + /*! + Class defining the primary content of a send + */ + class SendObject final : public active::serialise::Package { + public: + + // MARK: - Constructors + + /*! + Constructor + @param errMess The error message + @param card The ID of the model card associated with the wrror + */ + SendObject() {} + + // MARK: - Public variables + + ///The root object id which should be used for creating the version + speckle::utility::String id; + ///The total number of children + int32_t totalChildrenCount; + ///JSON batches for the root object and child (detached) objects + std::vector batches; + + // MARK: - Serialisation + + /*! + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ + bool fillInventory(active::serialise::Inventory& inventory) const override; + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + }; + +} + +#endif //CONNECTOR_INTERFACE_BRIDGE_SEND_OBJECT diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp new file mode 100644 index 0000000..103d72f --- /dev/null +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp @@ -0,0 +1,106 @@ +#include "Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h" + +#include "Connector/Record/Model/ModelCard.h" +#include "Speckle/Record/Credentials/Account.h" + +using namespace active::serialise; +using namespace connector::record; +using namespace connector::interfac::browser::bridge; +using namespace speckle::database; +using namespace speckle::record::cred; +using namespace speckle::serialise; +using namespace speckle::utility; + +namespace { + + ///Serialisation fields + enum FieldIndex { + cardID, + projID, + modID, + tokenID, + serverID, + accID, + messageID, + }; + + ///Serialisation field IDs + static std::array fieldID = { + Identity{"modelCardId"}, + Identity{"projectId"}, + Identity{"modelId"}, + Identity{"token"}, + Identity{"serverUrl"}, + Identity{"accountId"}, + Identity{"message"}, + }; + +} + +/*-------------------------------------------------------------------- + Constructor + + modelCard: The model card to populate into the send info for the browser + account: The account linked to the send + --------------------------------------------------------------------*/ +SendViaBrowserArgs::SendViaBrowserArgs(const ModelCard& modelCard, const Account& account) : + modelCardID(modelCard.getID()), projectID(modelCard.getProjectID()), modelID(modelCard.getModelID()), token{account.getToken()}, + serverURL{account.getServerURL()}, accountID{account.getID()} { + +} //SendViaBrowserArgs::SendViaBrowserArgs + + +/*-------------------------------------------------------------------- + Fill an inventory with the package items + + inventory: The inventory to receive the package items + + return: True if the package has added items to the inventory + --------------------------------------------------------------------*/ +bool SendViaBrowserArgs::fillInventory(active::serialise::Inventory& inventory) const { + using enum Entry::Type; + inventory.merge(Inventory{ + { + { fieldID[cardID], cardID, element }, + { fieldID[projID], projID, element }, + { fieldID[modID], modID, element }, + { fieldID[tokenID], tokenID, element }, + { fieldID[serverID], serverID, element }, + { fieldID[accID], accID, element }, + { fieldID[messageID], messageID, element }, + }, + }.withType(&typeid(SendViaBrowserArgs))); + return true; +} //SendViaBrowserArgs::fillInventory + + +/*-------------------------------------------------------------------- + Get the specified cargo + + item: The inventory item to retrieve + + return: The requested cargo (nullptr on failure) + --------------------------------------------------------------------*/ +Cargo::Unique SendViaBrowserArgs::getCargo(const active::serialise::Inventory::Item& item) const { + if (item.ownerType != &typeid(SendViaBrowserArgs)) + return nullptr; + using namespace active::serialise; + switch (item.index) { + case cardID: + return std::make_unique(modelCardID); + case projID: + return std::make_unique(projectID); + case modID: + return std::make_unique(modelID); + case tokenID: + return std::make_unique(token); + case serverID: + return std::make_unique(serverURL); + case accID: + return std::make_unique(accountID); + case messageID: + return std::make_unique(message); + default: + return nullptr; //Requested an unknown index + } +} //SendViaBrowserArgs::getCargo diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h new file mode 100644 index 0000000..6dac55d --- /dev/null +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h @@ -0,0 +1,78 @@ +#ifndef CONNECTOR_INTERFACE_BRIDGE_SEND_VIA_BROWSER_ARGS +#define CONNECTOR_INTERFACE_BRIDGE_SEND_VIA_BROWSER_ARGS + +#include "Active/Serialise/Package/Package.h" +#include "Active/Utility/String.h" +#include "Connector/Interface/Browser/Bridge/Send/Arg/ConversionResult.h" +#include "Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h" +#include "Speckle/Database/Identity/RecordID.h" + +namespace speckle::record::cred { + class Account; +} + +namespace connector::record { + class ModelCard; +} + +namespace connector::interfac::browser::bridge { + + class ConnectorConfig; + + /*! + A commit of a project version (model) to the Speckle server + + An object of this type is prepared by the Send bridge method + */ + class SendViaBrowserArgs final : public active::serialise::Package { + public: + + // MARK: - Constructors + + /*! + Constructor + @param modelCard The model card to populate into the send info for the browser + @param account The account linked to the send + */ + SendViaBrowserArgs(const connector::record::ModelCard& modelCard, const speckle::record::cred::Account& account); + + // MARK: - Public variables + + ///ID of the model card driving the send request + speckle::database::RecordID modelCardID; + ///The source project ID (from the model card) + speckle::database::RecordID projectID; + ///The model ID (from the model card) + speckle::database::RecordID modelID; + ///The account token (from the user account info) + speckle::utility::String token; + ///The server URL (from the user account info) + speckle::utility::String serverURL; + ///The user account ID + speckle::utility::String accountID; + ///The send message + speckle::utility::String message; //TODO: Clarify what this is used for + ///The conversion report (summarising the conversion results on an element-by-element basis) + std::vector sendConversionResults; + ///The commit content + SendObject sendObject; + + // MARK: - Serialisation + + /*! + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ + bool fillInventory(active::serialise::Inventory& inventory) const override; + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + }; + +} + +#endif //CONNECTOR_INTERFACE_BRIDGE_SEND_VIA_BROWSER_ARGS diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp index 73c41b8..4fe5560 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp @@ -4,86 +4,23 @@ #include "Active/Serialise/Package/Wrapper/PackageWrap.h" #include "Connector/Connector.h" #include "Connector/ConnectorResource.h" +#include "Connector/Database/ModelCardDatabase.h" +#include "Connector/Interface/Browser/Bridge/Send/Arg/SendError.h" +#include "Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h" +#include "Speckle/Database/AccountDatabase.h" #include "Speckle/Interface/Browser/Bridge/BrowserBridge.h" +#include "Speckle/Record/Credentials/Account.h" +#include "Speckle/Serialise/Detached/Storage/DetachedMemoryStore.h" #include "Speckle/Utility/Exception.h" using namespace active::serialise; using namespace connector::interfac::browser::bridge; +using namespace speckle::database; +using namespace speckle::serialise; using namespace speckle::utility; namespace { - - ///Serialisation fields - enum FieldIndex { - errorID, - cardID, - }; - - ///Serialisation field IDs - static std::array fieldID = { - Identity{"error"}, - Identity{"modelCardId"}, - }; - - /*! - A send error to return to the JS in the event of an error - */ - class SendError final : public active::serialise::Package { - public: - - // MARK: - Constructors - /*! - Constructor - @param errMess The error message - @param card The ID of the model card associated with the wrror - */ - SendError(const String& errMess, const String& card) : message{errMess}, modelCardID{card} {} - - // MARK: - Public variables - - ///The error message - String message; - ///The ID of the model card associated with the data - String modelCardID; - - // MARK: - Serialisation - - /*! - Fill an inventory with the package items - @param inventory The inventory to receive the package items - @return True if the package has added items to the inventory - */ - bool fillInventory(active::serialise::Inventory& inventory) const override { - using enum Entry::Type; - inventory.merge(Inventory{ - { - { fieldID[errorID], errorID, element }, - { fieldID[cardID], cardID, element }, - }, - }.withType(&typeid(SendError))); - return true; - } - /*! - Get the specified cargo - @param item The inventory item to retrieve - @return The requested cargo (nullptr on failure) - */ - Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override { - if (item.ownerType != &typeid(SendError)) - return nullptr; - using namespace active::serialise; - switch (item.index) { - case errorID: - return std::make_unique>(message); - case cardID: - return std::make_unique>(modelCardID); - default: - return nullptr; //Requested an unknown index - } - } - }; - } /*-------------------------------------------------------------------- @@ -100,7 +37,31 @@ Send::Send() : BridgeMethod{"Send", [&](const SendArgs& args) { modelCardID: The ID of the model to send --------------------------------------------------------------------*/ void Send::run(const String& modelCardID) const { - ///TODO: Find and send selected elements - the following is a placeholder - getBridge()->sendEvent("setModelError", - std::make_unique(connector()->getLocalString(errorString, noSelectedModelItemsID), modelCardID)); + //Find the specified model card + auto modelCardDatabase = connector()->getModelCardDatabase(); + auto modelCard = modelCardDatabase->getCard(modelCardID); + if (!modelCard) { + getBridge()->sendEvent("setModelError", + std::make_unique(connector()->getLocalString(errorString, modelCardNotFoundID), modelCardID)); + return; + } + auto accountDatabase = connector()->getAccountDatabase(); + auto account = accountDatabase->getAccount(modelCard->getAccountID(), modelCard->getServerURL()); + if (!account) { + getBridge()->sendEvent("setModelError", + std::make_unique(connector()->getLocalString(errorString, accountNotFoundID), modelCardID)); + return; + } + //Get the active project + auto project = connector()->getActiveProject().lock(); + if (!project) { + getBridge()->sendEvent("setModelError", + std::make_unique(connector()->getLocalString(errorString, noProjectOpenID), modelCardID)); + return; + } + //We currently collect all detached object serialised data into a memory-based store - in future may be able to batch send and cache locally + DetachedMemoryStore detachedObjects; + auto result = std::make_unique(modelCard, account); + + getBridge()->sendEvent("sendByBrowser", std::move(result)); } //Send::run diff --git a/SpeckleConnector/Connector/Record/Model/ModelCard.h b/SpeckleConnector/Connector/Record/Model/ModelCard.h index a192a8b..64fd80b 100644 --- a/SpeckleConnector/Connector/Record/Model/ModelCard.h +++ b/SpeckleConnector/Connector/Record/Model/ModelCard.h @@ -19,6 +19,8 @@ namespace connector::record { // MARK: - Types using base = speckle::database::Record; + ///Unique pointer + using Unique = std::unique_ptr; //List of card settings using SettingList = active::container::Vector; diff --git a/SpeckleConnector/RINT/Connector.grc b/SpeckleConnector/RINT/Connector.grc index bac807c..c1e3741 100644 --- a/SpeckleConnector/RINT/Connector.grc +++ b/SpeckleConnector/RINT/Connector.grc @@ -5,4 +5,7 @@ 'STR#' 32604 "Error strings" { /* [ 1] */ "No objects were found to convert. Please update your publish filter!" +/* [ 2] */ "The specified model card cannot be found. Try another card or create a new one" +/* [ 3] */ "Please open a project first" +/* [ 4] */ "The specified Speckle account cannot be found. Check that you have logged into your Speckle account with the Speckle Manager" } diff --git a/SpeckleLib/Speckle/Database/AccountDatabase.cpp b/SpeckleLib/Speckle/Database/AccountDatabase.cpp index b6f2967..eb8fbe6 100644 --- a/SpeckleLib/Speckle/Database/AccountDatabase.cpp +++ b/SpeckleLib/Speckle/Database/AccountDatabase.cpp @@ -81,6 +81,27 @@ AccountDatabase::AccountDatabase(const active::file::Path& path) { AccountDatabase::~AccountDatabase() {} +/*-------------------------------------------------------------------- + Get a specified account. NB: The server URL is provided as a fallback for the search if the specified accountID is not found + + accountID: The account ID (the primary search field) + serverURL: The server URL (a fallback search field if the account ID does not exist) + + return: The requested account (nullptr on failure) + --------------------------------------------------------------------*/ +std::unique_ptr AccountDatabase::getAccount(const String& accountID, const String& serverURL) const { + //First attempt to find a matching account ID + auto matchingAccount = m_store->getObjects([&accountID](const auto& acc) { return acc.getID() == accountID; }); + if (!matchingAccount.empty()) + return matchingAccount.release(matchingAccount.begin()); + //Alternatively seek an account with a matching server URL + matchingAccount = m_store->getObjects([&serverURL](const auto& acc) { return acc.getServerURL() == serverURL; }); + if (!matchingAccount.empty()) + return matchingAccount.release(matchingAccount.begin()); + return nullptr; +} //AccountDatabase::getAccount + + /*-------------------------------------------------------------------- Get all accounts diff --git a/SpeckleLib/Speckle/Database/AccountDatabase.h b/SpeckleLib/Speckle/Database/AccountDatabase.h index 28295e9..7e4f6dd 100644 --- a/SpeckleLib/Speckle/Database/AccountDatabase.h +++ b/SpeckleLib/Speckle/Database/AccountDatabase.h @@ -4,6 +4,10 @@ #include "Active/File/Path.h" #include "Speckle/Record/Credentials/Account.h" +namespace speckle::record::cred { + class Account; +} + namespace speckle::database { /*! @@ -27,6 +31,13 @@ namespace speckle::database { // MARK: - Functions (const) + /*! + Get a specified account. NB: The server URL is provided as a fallback for the search if the specified accountID is not found + @param accountID The account ID (the primary search field) + @param serverURL The server URL (a fallback search field if the account ID does not exist) + @return The requested account (nullptr on failure) + */ + std::unique_ptr getAccount(const speckle::utility::String& accountID, const speckle::utility::String& serverURL) const; /*! Get all accounts @return All the accounts diff --git a/SpeckleLib/Speckle/Record/Credentials/Account.h b/SpeckleLib/Speckle/Record/Credentials/Account.h index 757f6a5..fc902a4 100644 --- a/SpeckleLib/Speckle/Record/Credentials/Account.h +++ b/SpeckleLib/Speckle/Record/Credentials/Account.h @@ -48,6 +48,17 @@ namespace speckle::record::cred { // MARK: - Functions (const) + /*! + Get the account server URL + @return The account server URL (nullopt if none specified) + */ + speckle::utility::String getServerURL() const { return m_serverInfo.getURL(); } + /*! + Get the account token + @return The account token + */ + speckle::utility::String getToken() const { return m_token; } + // MARK: - Functions (mutating) // MARK: - Serialisation diff --git a/SpeckleLib/Speckle/Record/Credentials/ServerInfo.cpp b/SpeckleLib/Speckle/Record/Credentials/ServerInfo.cpp index 9a237e5..377e9fd 100644 --- a/SpeckleLib/Speckle/Record/Credentials/ServerInfo.cpp +++ b/SpeckleLib/Speckle/Record/Credentials/ServerInfo.cpp @@ -89,7 +89,7 @@ Cargo::Unique ServerInfo::getCargo(const Inventory::Item& item) const { case frontEndID: return std::make_unique>(m_frontend2); case urlID: - return std::make_unique(m_url); + return std::make_unique(m_url); case migrationID: return std::make_unique(PackageUniqueWrap{m_migration}); default: diff --git a/SpeckleLib/Speckle/Record/Credentials/ServerInfo.h b/SpeckleLib/Speckle/Record/Credentials/ServerInfo.h index 7e7d1a0..409f2d0 100644 --- a/SpeckleLib/Speckle/Record/Credentials/ServerInfo.h +++ b/SpeckleLib/Speckle/Record/Credentials/ServerInfo.h @@ -32,7 +32,7 @@ namespace speckle::record::cred { */ ServerInfo(const utility::String& name, const utility::String::Option company = std::nullopt, const utility::String::Option version = std::nullopt, const utility::String::Option contact = std::nullopt, - const utility::String::Option description = std::nullopt, const utility::String::Option url = std::nullopt, + const utility::String::Option description = std::nullopt, const utility::String url = {}, bool isFrontEnd = false, std::unique_ptr migration = nullptr) : m_name{name}, m_company{company}, m_version{version}, m_adminContact{contact}, m_description{description}, m_url{url}, m_frontend2{isFrontEnd}, m_migration{std::move(migration)} {} @@ -90,7 +90,7 @@ namespace speckle::record::cred { Get the URL @return The URL */ - const utility::String::Option& getURL() const { return m_url; } + const utility::String& getURL() const { return m_url; } /*! Get the migration history @return The migration history (nullptr = no history) @@ -143,7 +143,7 @@ namespace speckle::record::cred { This field is not returned from the GQL API, it should be populated after construction. See "Speckle.Core.Credentials.AccountManager" */ - utility::String::Option m_url; + utility::String m_url; ///Server migration record std::unique_ptr m_migration; }; diff --git a/SpeckleLib/Speckle/Serialise/Detached/DetachedWrap.cpp b/SpeckleLib/Speckle/Serialise/Detached/DetachedWrap.cpp index 141b4b9..79192f8 100644 --- a/SpeckleLib/Speckle/Serialise/Detached/DetachedWrap.cpp +++ b/SpeckleLib/Speckle/Serialise/Detached/DetachedWrap.cpp @@ -3,7 +3,6 @@ #include "Active/Serialise/Item/Wrapper/ValueWrap.h" #include "Active/Utility/BufferOut.h" #include "Active/Utility/SHA256.h" -#include "Speckle/Serialise/Detached/DetachmentManager.h" #include "Speckle/Utility/String.h" using namespace active::serialise; diff --git a/SpeckleLib/Speckle/Serialise/Detached/Storage/DetachedMemoryStore.h b/SpeckleLib/Speckle/Serialise/Detached/Storage/DetachedMemoryStore.h new file mode 100644 index 0000000..5708f54 --- /dev/null +++ b/SpeckleLib/Speckle/Serialise/Detached/Storage/DetachedMemoryStore.h @@ -0,0 +1,52 @@ +#ifndef SPECKLE_SERIALISE_DETACHED_MEMORY_STORE +#define SPECKLE_SERIALISE_DETACHED_MEMORY_STORE + +#include "Speckle/Serialise/Detached/Storage/DetachedObjectStore.h" + +#include + +namespace speckle::serialise { + + /*! + Memory-based storage for detached objects + + Detached object serialised data is held in a simple unordered_map keying the data against the object reference. + This class primarily intended for collecting the JSON from detached objects and holding until they can be forwarded to the server. The data + will not persist beyond this usage. + */ + class DetachedMemoryStore : public DetachedObjectStore, public std::unordered_map { + public: + + // MARK: - Types + + using base = std::unordered_map; + + // MARK: - Functions (const) + + /*! + Retrieve a detached object from storage + @param reference The required object reference + @return The object data (nullopt if the object cannot be found in storage) + */ + utility::String::Option retrieve(const database::RecordID& reference) const override { + if (auto iter = base::find(reference); iter != base::end()) + return iter->second; + return std::nullopt; + } + + // MARK: - Functions (mutating) + + /*! + File a detached object in storage + @param reference The object reference (typically a hash generated from the object data) + @param data The object data (currently expected to be serialised as JSON) + @return True if the object was filed (typically ignored if it duplicates an object already in the store) + */ + bool file(const database::RecordID& reference, const utility::String& data) override { + return base::insert(std::make_pair(reference, data)).second; + } + }; + +} + +#endif //SPECKLE_SERIALISE_DETACHED_MEMORY_STORE diff --git a/SpeckleLib/Speckle/Serialise/Detached/Storage/DetachedObjectStore.h b/SpeckleLib/Speckle/Serialise/Detached/Storage/DetachedObjectStore.h index 546d572..441c699 100644 --- a/SpeckleLib/Speckle/Serialise/Detached/Storage/DetachedObjectStore.h +++ b/SpeckleLib/Speckle/Serialise/Detached/Storage/DetachedObjectStore.h @@ -28,7 +28,7 @@ namespace speckle::serialise { @param reference The required object reference @return The object data (nullopt if the object cannot be found in storage) */ - virtual utility::String::Option retrieve(const database::RecordID& reference) = 0; + virtual utility::String::Option retrieve(const database::RecordID& reference) const = 0; // MARK: - Functions (mutating) @@ -38,7 +38,7 @@ namespace speckle::serialise { @param data The object data (currently expected to be serialised as JSON) @return True if the object was filed (typically rejected if it duplicates an object already in the store) */ - virtual bool file(const database::RecordID& reference, const utility::String& data) const = 0; + virtual bool file(const database::RecordID& reference, const utility::String& data) = 0; }; } diff --git a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj index 82a12ac..d4d6ea1 100644 --- a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj +++ b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj @@ -170,6 +170,7 @@ 21AEF9BB2CA6DF84000B8681 /* DetachmentManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DetachmentManager.cpp; sourceTree = ""; }; 21AEF9BD2CA6FDA4000B8681 /* DetachedWrap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DetachedWrap.cpp; sourceTree = ""; }; 21AEF9DB2CAAA4EA000B8681 /* DetachedObjectStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedObjectStore.h; sourceTree = ""; }; + 21AEF9DF2CAAC2AF000B8681 /* DetachedMemoryStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedMemoryStore.h; sourceTree = ""; }; 21B67CFE2C7CE15100FD64FC /* Exception.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Exception.h; sourceTree = ""; }; 21B67D092C7E0E8D00FD64FC /* ErrorReport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ErrorReport.h; sourceTree = ""; }; 21B67D0C2C7E0E8D00FD64FC /* ErrorReport.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ErrorReport.cpp; sourceTree = ""; }; @@ -433,6 +434,7 @@ isa = PBXGroup; children = ( 21AEF9DB2CAAA4EA000B8681 /* DetachedObjectStore.h */, + 21AEF9DF2CAAC2AF000B8681 /* DetachedMemoryStore.h */, ); path = Storage; sourceTree = ""; From 8ed2abea041ce3a97e9e708e6a1bc02634de88a5 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Tue, 1 Oct 2024 18:21:30 +0100 Subject: [PATCH 009/191] Implemented skeleton of SendObject --- .../Browser/Bridge/Base/GetDocumentState.cpp | 1 - .../Browser/Bridge/Send/Arg/SendObject.cpp | 121 ++++-------------- 2 files changed, 22 insertions(+), 100 deletions(-) diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentState.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentState.cpp index ed812b5..d57c177 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentState.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentState.cpp @@ -1,7 +1,6 @@ #include "Connector/Interface/Browser/Bridge/Base/GetDocumentState.h" #include "Active/Serialise/CargoHold.h" -#include "Active/Serialise/Package/Wrapper/ContainerWrap.h" #include "Connector/Connector.h" #include "Connector/Record/Model/ModelCard.h" #include "Connector/Database/ModelCardDatabase.h" diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp index 94666e6..7b8eb71 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp @@ -1,17 +1,9 @@ -#include "Connector/Interface/Browser/Bridge/Send/Send.h" +#include "Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h" -#include "Active/Serialise/CargoHold.h" -#include "Active/Serialise/Package/Wrapper/PackageWrap.h" -#include "Connector/Connector.h" -#include "Connector/ConnectorResource.h" -#include "Connector/Database/ModelCardDatabase.h" -#include "Speckle/Interface/Browser/Bridge/BrowserBridge.h" -#include "Speckle/Serialise/Detached/Storage/DetachedMemoryStore.h" -#include "Speckle/Utility/Exception.h" +#include "Active/Serialise/Package/Wrapper/ContainerWrap.h" using namespace active::serialise; using namespace connector::interfac::browser::bridge; -using namespace speckle::database; using namespace speckle::serialise; using namespace speckle::utility; @@ -19,55 +11,17 @@ namespace { ///Serialisation fields enum FieldIndex { - errorID, - cardID, + idID, + totChildID, + batchesID, }; ///Serialisation field IDs static std::array fieldID = { Identity{"error"}, - Identity{"modelCardId"}, + Identity{"totalChildrenCount"}, + Identity{"batches"}, }; - - /*! - A send error to return to the JS in the event of an error - */ - class SendError final : public active::serialise::Package { - public: - - // MARK: - Constructors - - /*! - Constructor - @param errMess The error message - @param card The ID of the model card associated with the wrror - */ - SendError(const String& errMess, const String& card) : message{errMess}, modelCardID{card} {} - - // MARK: - Public variables - - ///The error message - String message; - ///The ID of the model card associated with the data - String modelCardID; - - // MARK: - Serialisation - - /*! - Fill an inventory with the package items - @param inventory The inventory to receive the package items - @return True if the package has added items to the inventory - */ - bool fillInventory(active::serialise::Inventory& inventory) const override; - /*! - Get the specified cargo - @param item The inventory item to retrieve - @return The requested cargo (nullptr on failure) - */ - Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; - }; - - } @@ -78,16 +32,17 @@ namespace { return: True if the package has added items to the inventory --------------------------------------------------------------------*/ -bool SendError::fillInventory(active::serialise::Inventory& inventory) const { +bool SendObject::fillInventory(active::serialise::Inventory& inventory) const { using enum Entry::Type; inventory.merge(Inventory{ { - { fieldID[errorID], errorID, element }, - { fieldID[cardID], cardID, element }, + { fieldID[idID], idID, element }, + { fieldID[totChildID], totChildID, element }, + { fieldID[batchesID], batchesID, element }, }, - }.withType(&typeid(SendError))); + }.withType(&typeid(SendObject))); return true; -} //SendError::fillInventory +} //SendObject::fillInventory /*-------------------------------------------------------------------- @@ -97,50 +52,18 @@ bool SendError::fillInventory(active::serialise::Inventory& inventory) const { return: The requested cargo (nullptr on failure) --------------------------------------------------------------------*/ -Cargo::Unique SendError::getCargo(const active::serialise::Inventory::Item& item) const { - if (item.ownerType != &typeid(SendError)) +Cargo::Unique SendObject::getCargo(const active::serialise::Inventory::Item& item) const { + if (item.ownerType != &typeid(SendObject)) return nullptr; using namespace active::serialise; switch (item.index) { - case errorID: - return std::make_unique>(message); - case cardID: - return std::make_unique>(modelCardID); + case idID: + return std::make_unique(id); + case totChildID: + return std::make_unique(totalChildrenCount); + case batchesID: + return std::make_unique>>(batches); default: return nullptr; //Requested an unknown index } -} //SendError::getCargo - - -/*-------------------------------------------------------------------- - Default constructor - --------------------------------------------------------------------*/ -Send::Send() : BridgeMethod{"Send", [&](const SendArgs& args) { - run(args); -}} {} - - -/*-------------------------------------------------------------------- - Send a specified model - - modelCardID: The ID of the model to send - --------------------------------------------------------------------*/ -void Send::run(const String& modelCardID) const { - //Find the specified model card - auto modelCardDatabase = connector()->getModelCardDatabase(); - auto modelCard = modelCardDatabase->getCard(modelCardID); - if (!modelCard) { - getBridge()->sendEvent("setModelError", - std::make_unique(connector()->getLocalString(errorString, modelCardNotFoundID), modelCardID)); - return; - } - //Get the active project - auto project = connector()->getActiveProject().lock(); - if (!project) { - getBridge()->sendEvent("setModelError", - std::make_unique(connector()->getLocalString(errorString, noProjectOpenID), modelCardID)); - return; - } - - DetachedMemoryStore detachedObjects; -} //Send::run +} //SendObject::getCargo From 8eae1e9967c37d2f75998dde9ac083c1a90c8985 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Tue, 1 Oct 2024 18:24:33 +0100 Subject: [PATCH 010/191] Updated VS projects --- SpeckleConnector/Connector.vcxproj | 8 +++++ SpeckleConnector/Connector.vcxproj.filters | 27 +++++++++++++++++ .../Browser/Bridge/Base/GetDocumentInfo.cpp | 5 ++-- .../Bridge/Send/Arg/ConversionResult.cpp | 2 ++ .../Browser/Bridge/Send/Arg/SendError.cpp | 2 ++ .../Browser/Bridge/Send/Arg/SendObject.cpp | 2 ++ .../Bridge/Send/Arg/SendViaBrowserArgs.cpp | 2 ++ .../Interface/Browser/Bridge/Send/Send.cpp | 2 +- SpeckleLib/SpeckleLib17.vcxproj | 8 +++++ SpeckleLib/SpeckleLib17.vcxproj.filters | 30 +++++++++++++++++++ 10 files changed, 85 insertions(+), 3 deletions(-) diff --git a/SpeckleConnector/Connector.vcxproj b/SpeckleConnector/Connector.vcxproj index 97d064d..d421318 100644 --- a/SpeckleConnector/Connector.vcxproj +++ b/SpeckleConnector/Connector.vcxproj @@ -111,6 +111,10 @@ + + + + @@ -157,6 +161,10 @@ + + + + diff --git a/SpeckleConnector/Connector.vcxproj.filters b/SpeckleConnector/Connector.vcxproj.filters index b449f8a..be45e91 100644 --- a/SpeckleConnector/Connector.vcxproj.filters +++ b/SpeckleConnector/Connector.vcxproj.filters @@ -62,6 +62,9 @@ {0ac4b0a4-6a2a-4a48-9757-1172effc20e7} + + {6693f9a9-5ece-4853-b008-4064d1c551ab} + @@ -207,6 +210,18 @@ Connector\Record\Collection + + Connector\Interface\Browser\Bridge\Send\Arg + + + Connector\Interface\Browser\Bridge\Send\Arg + + + Connector\Interface\Browser\Bridge\Send\Arg + + + Connector\Interface\Browser\Bridge\Send\Arg + @@ -348,5 +363,17 @@ Connector\Record\Collection + + Connector\Interface\Browser\Bridge\Send\Arg + + + Connector\Interface\Browser\Bridge\Send\Arg + + + Connector\Interface\Browser\Bridge\Send\Arg + + + Connector\Interface\Browser\Bridge\Send\Arg + \ No newline at end of file diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentInfo.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentInfo.cpp index 3d69108..ee41ff0 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentInfo.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentInfo.cpp @@ -2,6 +2,7 @@ #include "Active/Serialise/CargoHold.h" #include "Connector/Connector.h" +#include "Connector/Database/ModelCardDatabase.h" #include "Connector/Interface/Browser/Bridge/Base/Arg/DocumentInfo.h" #include "Speckle/Environment/Project.h" #include "Speckle/Utility/Guid.h" @@ -37,8 +38,8 @@ std::unique_ptr GetDocumentInfo::run() const { docInfo->name = info.name; if (info.path) docInfo->location = *info.path; - //TODO: No suitable project ID is currently available - docInfo->ID = Guid{true}.operator String(); + if (auto cardDatabase = connector()->getModelCardDatabase(); cardDatabase != nullptr) + docInfo->ID = cardDatabase->getStoreID(); } return std::make_unique(std::move(docInfo)); } //GetDocumentInfo::run diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/ConversionResult.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/ConversionResult.cpp index c12a724..d84990b 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/ConversionResult.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/ConversionResult.cpp @@ -2,6 +2,8 @@ #include "Active/Serialise/item/Wrapper/ValueWrap.h" +#include + using namespace active::serialise; using namespace connector::interfac::browser::bridge; using namespace speckle::utility; diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendError.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendError.cpp index a16a49b..9fdd5c7 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendError.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendError.cpp @@ -2,6 +2,8 @@ #include "Active/Serialise/item/Wrapper/ValueWrap.h" +#include + using namespace active::serialise; using namespace connector::interfac::browser::bridge; using namespace speckle::utility; diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp index 7b8eb71..711da6d 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp @@ -2,6 +2,8 @@ #include "Active/Serialise/Package/Wrapper/ContainerWrap.h" +#include + using namespace active::serialise; using namespace connector::interfac::browser::bridge; using namespace speckle::serialise; diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp index 103d72f..78e6234 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp @@ -3,6 +3,8 @@ #include "Connector/Record/Model/ModelCard.h" #include "Speckle/Record/Credentials/Account.h" +#include + using namespace active::serialise; using namespace connector::record; using namespace connector::interfac::browser::bridge; diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp index 4fe5560..596eba4 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp @@ -61,7 +61,7 @@ void Send::run(const String& modelCardID) const { } //We currently collect all detached object serialised data into a memory-based store - in future may be able to batch send and cache locally DetachedMemoryStore detachedObjects; - auto result = std::make_unique(modelCard, account); + auto result = std::make_unique(*modelCard, *account); getBridge()->sendEvent("sendByBrowser", std::move(result)); } //Send::run diff --git a/SpeckleLib/SpeckleLib17.vcxproj b/SpeckleLib/SpeckleLib17.vcxproj index 9f10ec3..ebc0063 100644 --- a/SpeckleLib/SpeckleLib17.vcxproj +++ b/SpeckleLib/SpeckleLib17.vcxproj @@ -67,6 +67,11 @@ + + + + + @@ -105,6 +110,9 @@ + + + diff --git a/SpeckleLib/SpeckleLib17.vcxproj.filters b/SpeckleLib/SpeckleLib17.vcxproj.filters index 444eb0e..8f90a7c 100644 --- a/SpeckleLib/SpeckleLib17.vcxproj.filters +++ b/SpeckleLib/SpeckleLib17.vcxproj.filters @@ -77,6 +77,12 @@ {93db2ed5-fd21-4ed1-86ee-f549682f66a5} + + {e9aec552-0aa8-4193-867d-69febdf93139} + + + {cb77e795-e8d8-4e31-9773-dd32beb694d3} + @@ -244,6 +250,21 @@ Speckle\Database\Identity + + Speckle\Serialise\Detached + + + Speckle\Serialise\Detached + + + Speckle\Serialise\Detached + + + Speckle\Serialise\Detached\Storage + + + Speckle\Serialise\Detached\Storage + @@ -345,6 +366,15 @@ Speckle\Database\Identity + + Speckle\Serialise\Detached + + + Speckle\Serialise\Detached + + + Speckle\Serialise\Detached + From e9f8e86f950e42cf8f069817fd3e6e4782af3cde Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Tue, 1 Oct 2024 18:58:50 +0100 Subject: [PATCH 011/191] Dummy information in SendObject --- .../Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h | 4 ++-- .../Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h index 9ea777a..6640fa0 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h @@ -26,9 +26,9 @@ namespace connector::interfac::browser::bridge { // MARK: - Public variables ///The root object id which should be used for creating the version - speckle::utility::String id; + speckle::utility::String id = "1234"; ///The total number of children - int32_t totalChildrenCount; + int32_t totalChildrenCount = 0; ///JSON batches for the root object and child (detached) objects std::vector batches; diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp index 78e6234..5218792 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp @@ -24,6 +24,7 @@ namespace { serverID, accID, messageID, + sendObjectID, }; ///Serialisation field IDs @@ -35,6 +36,7 @@ namespace { Identity{"serverUrl"}, Identity{"accountId"}, Identity{"message"}, + Identity{"sendObject"}, }; } @@ -102,6 +104,8 @@ Cargo::Unique SendViaBrowserArgs::getCargo(const active::serialise::Inventory::I return std::make_unique(accountID); case messageID: return std::make_unique(message); + case sendObjectID: + return std::make_unique(sendObject); default: return nullptr; //Requested an unknown index } From fdf371732b0420206ff90f11622676b456b2e05d Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Wed, 2 Oct 2024 09:30:53 +0100 Subject: [PATCH 012/191] Updated serialisation for send objects --- .../Connector/Interface/Browser/Bridge/Base/GetDocumentInfo.cpp | 1 + .../Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp | 2 +- .../Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentInfo.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentInfo.cpp index ee41ff0..5c8a710 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentInfo.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentInfo.cpp @@ -40,6 +40,7 @@ std::unique_ptr GetDocumentInfo::run() const { docInfo->location = *info.path; if (auto cardDatabase = connector()->getModelCardDatabase(); cardDatabase != nullptr) docInfo->ID = cardDatabase->getStoreID(); + docInfo->ID = Guid{true}.operator String(); } return std::make_unique(std::move(docInfo)); } //GetDocumentInfo::run diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp index 711da6d..fa8bca2 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp @@ -20,7 +20,7 @@ namespace { ///Serialisation field IDs static std::array fieldID = { - Identity{"error"}, + Identity{"id"}, Identity{"totalChildrenCount"}, Identity{"batches"}, }; diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp index 5218792..44eaccc 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp @@ -72,6 +72,7 @@ bool SendViaBrowserArgs::fillInventory(active::serialise::Inventory& inventory) { fieldID[serverID], serverID, element }, { fieldID[accID], accID, element }, { fieldID[messageID], messageID, element }, + { fieldID[sendObjectID], sendObjectID, element }, }, }.withType(&typeid(SendViaBrowserArgs))); return true; From a6911fad1c2beb0aa682a1884a911ed873f9d263 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Wed, 2 Oct 2024 10:09:28 +0100 Subject: [PATCH 013/191] Added GetSendSettings binding --- .../Bridge/Send/Arg/ConversionResult.cpp | 2 +- .../Browser/Bridge/Send/Arg/SendError.cpp | 2 +- .../Browser/Bridge/Send/GetSendSettings.cpp | 36 +++++++++++++++++++ .../Browser/Bridge/Send/GetSendSettings.h | 36 +++++++++++++++++++ .../Browser/Bridge/Send/SendBridge.cpp | 2 ++ 5 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 SpeckleConnector/Connector/Interface/Browser/Bridge/Send/GetSendSettings.cpp create mode 100644 SpeckleConnector/Connector/Interface/Browser/Bridge/Send/GetSendSettings.h diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/ConversionResult.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/ConversionResult.cpp index d84990b..afb3ac2 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/ConversionResult.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/ConversionResult.cpp @@ -1,6 +1,6 @@ #include "Connector/Interface/Browser/Bridge/Send/Arg/ConversionResult.h" -#include "Active/Serialise/item/Wrapper/ValueWrap.h" +#include "Active/Serialise/Item/Wrapper/ValueWrap.h" #include diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendError.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendError.cpp index 9fdd5c7..0b93763 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendError.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendError.cpp @@ -1,6 +1,6 @@ #include "Connector/Interface/Browser/Bridge/Send/Arg/SendError.h" -#include "Active/Serialise/item/Wrapper/ValueWrap.h" +#include "Active/Serialise/Item/Wrapper/ValueWrap.h" #include diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/GetSendSettings.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/GetSendSettings.cpp new file mode 100644 index 0000000..96aa118 --- /dev/null +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/GetSendSettings.cpp @@ -0,0 +1,36 @@ +#include "Connector/Interface/Browser/Bridge/Send/GetSendSettings.h" + +#include "Active/Container/Vector.h" +#include "Active/Serialise/CargoHold.h" +#include "Active/Serialise/Package/Wrapper/ContainerWrap.h" +#include "Connector/Record/Model/CardSetting.h" + +using namespace active::container; +using namespace active::serialise; +using namespace connector::record; +using namespace connector::interfac::browser::bridge; +using namespace speckle::utility; + +namespace { + + using WrappedValue = active::serialise::CargoHold, PackageWrap>, Vector>; + +} + +/*-------------------------------------------------------------------- + Default constructor + --------------------------------------------------------------------*/ +GetSendSettings::GetSendSettings() : BridgeMethod{"GetSendSettings", [&]() { + return run(); +}} {} + + +/*-------------------------------------------------------------------- + Get the send filters + + return: The send filters + --------------------------------------------------------------------*/ +std::unique_ptr GetSendSettings::run() const { + auto filters = std::make_unique>(); + return std::make_unique(std::move(filters)); +} //GetSendSettings::run diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/GetSendSettings.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/GetSendSettings.h new file mode 100644 index 0000000..4823fc8 --- /dev/null +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/GetSendSettings.h @@ -0,0 +1,36 @@ +#ifndef CONNECTOR_INTERFACE_BRIDGE_GET_SEND_SETTINGS +#define CONNECTOR_INTERFACE_BRIDGE_GET_SEND_SETTINGS + +#include "Active/Serialise/CargoHold.h" +#include "Speckle/Interface/Browser/Bridge/BridgeMethod.h" + +namespace connector::interfac::browser::bridge { + + class ConnectorConfig; + + /*! + JS Function class to retrieve the send filters + */ + class GetSendSettings : public speckle::interfac::browser::bridge::BridgeMethod { + public: + + // MARK: - Constructors + + /*! + Constructor + @param bridge The parent bridge object (provides access to bridge methods) + */ + GetSendSettings(); + + // MARK: - Functions (const) + + /*! + Get the send filters + @return The send filters + */ + std::unique_ptr run() const; + }; + +} + +#endif //CONNECTOR_INTERFACE_BRIDGE_GET_SEND_SETTINGS diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/SendBridge.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/SendBridge.cpp index d4180e6..2f34725 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/SendBridge.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/SendBridge.cpp @@ -1,6 +1,7 @@ #include "Connector/Interface/Browser/Bridge/Send/SendBridge.h" #include "Connector/Interface/Browser/Bridge/Send/GetSendFilters.h" +#include "Connector/Interface/Browser/Bridge/Send/GetSendSettings.h" #include "Connector/Interface/Browser/Bridge/Send/Send.h" using namespace connector::interfac::browser::bridge; @@ -11,5 +12,6 @@ using namespace connector::interfac::browser::bridge; SendBridge::SendBridge() : BrowserBridge{"sendBinding"} { //Add bridge methods addMethod(); + addMethod(); addMethod(); } //SendBridge::SendBridge From cc034191b43d8f6de2f6a571a1d28f5f62b7cd45 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Wed, 2 Oct 2024 12:54:48 +0100 Subject: [PATCH 014/191] Updated with GetSendSettings --- SpeckleConnector/Connector.vcxproj | 2 ++ SpeckleConnector/Connector.vcxproj.filters | 6 ++++++ SpeckleConnector/Connector/Record/Model/ModelCard.h | 7 +++++++ 3 files changed, 15 insertions(+) diff --git a/SpeckleConnector/Connector.vcxproj b/SpeckleConnector/Connector.vcxproj index d421318..f7874d4 100644 --- a/SpeckleConnector/Connector.vcxproj +++ b/SpeckleConnector/Connector.vcxproj @@ -116,6 +116,7 @@ + @@ -166,6 +167,7 @@ + diff --git a/SpeckleConnector/Connector.vcxproj.filters b/SpeckleConnector/Connector.vcxproj.filters index be45e91..b363df8 100644 --- a/SpeckleConnector/Connector.vcxproj.filters +++ b/SpeckleConnector/Connector.vcxproj.filters @@ -222,6 +222,9 @@ Connector\Interface\Browser\Bridge\Send\Arg + + Connector\Interface\Browser\Bridge\Send + @@ -375,5 +378,8 @@ Connector\Interface\Browser\Bridge\Send\Arg + + Connector\Interface\Browser\Bridge\Send + \ No newline at end of file diff --git a/SpeckleConnector/Connector/Record/Model/ModelCard.h b/SpeckleConnector/Connector/Record/Model/ModelCard.h index 64fd80b..587ea72 100644 --- a/SpeckleConnector/Connector/Record/Model/ModelCard.h +++ b/SpeckleConnector/Connector/Record/Model/ModelCard.h @@ -69,6 +69,11 @@ namespace connector::record { @return The setting type */ const speckle::utility::String& getAccountID() const { return m_accountID; } + /*! + Get the user commit message + @return The user commit message + */ + const speckle::utility::String& getMessage() const { return m_message; } /*! Get the setting type @return The setting type @@ -108,6 +113,8 @@ namespace connector::record { speckle::database::RecordID m_accountID; ///The server URL speckle::utility::String m_serverURL; + ///The commit message from the user for the card + speckle::utility::String m_message; ///Settings for the model rendering, e.g. level of detail (LoD) SettingList m_settings; ///True if the card has expired From 1a901b0a6c1dd60f7e7b13eb3154b1a661bbf5c2 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Thu, 3 Oct 2024 12:05:48 +0100 Subject: [PATCH 015/191] Send bridge is updated: - total children removed - rootObject replaces batches (sent as an object rather than a string) --- .../Connector.xcodeproj/project.pbxproj | 6 ++ .../Browser/Bridge/Send/Arg/SendObject.cpp | 16 ++---- .../Browser/Bridge/Send/Arg/SendObject.h | 18 +++--- .../Bridge/Send/Arg/SendViaBrowserArgs.cpp | 5 +- .../Bridge/Send/Arg/SendViaBrowserArgs.h | 3 +- .../Interface/Browser/Bridge/Send/Send.cpp | 7 ++- .../Speckle/Database/Content/BIMRecord.cpp | 6 +- .../Speckle/Database/Content/BIMRecord.h | 17 +++--- .../Speckle/Database/Content/Record.cpp | 55 ++++++++++++++++++- SpeckleLib/Speckle/Database/Content/Record.h | 21 ++++++- 10 files changed, 115 insertions(+), 39 deletions(-) diff --git a/SpeckleConnector/Connector.xcodeproj/project.pbxproj b/SpeckleConnector/Connector.xcodeproj/project.pbxproj index 37e3043..bd78119 100644 --- a/SpeckleConnector/Connector.xcodeproj/project.pbxproj +++ b/SpeckleConnector/Connector.xcodeproj/project.pbxproj @@ -36,6 +36,7 @@ 21AEF9EF2CAB5720000B8681 /* SendObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9EE2CAB5720000B8681 /* SendObject.cpp */; }; 21AEF9F32CAC12D1000B8681 /* SendManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9F02CAC12D1000B8681 /* SendManager.cpp */; }; 21AEF9FA2CAC3897000B8681 /* ConversionResult.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9F92CAC3897000B8681 /* ConversionResult.cpp */; }; + 21AEF9FD2CAD3FD8000B8681 /* GetSendSettings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9FB2CAD3FD8000B8681 /* GetSendSettings.cpp */; }; 21B67CA32C769CB400FD64FC /* libActiveLib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 21F69EF52C64FE91008B6A06 /* libActiveLib.a */; }; 21B67CA42C769CB400FD64FC /* libArchicad27.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 21F69ECD2C64C035008B6A06 /* libArchicad27.a */; }; 21B67CAC2C77329800FD64FC /* BaseBridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21B67CA52C77329800FD64FC /* BaseBridge.cpp */; }; @@ -321,6 +322,8 @@ 21AEF9F12CAC12D1000B8681 /* SendManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SendManager.h; sourceTree = ""; }; 21AEF9F82CAC3897000B8681 /* ConversionResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConversionResult.h; sourceTree = ""; }; 21AEF9F92CAC3897000B8681 /* ConversionResult.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConversionResult.cpp; sourceTree = ""; }; + 21AEF9FB2CAD3FD8000B8681 /* GetSendSettings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetSendSettings.cpp; sourceTree = ""; }; + 21AEF9FC2CAD3FD8000B8681 /* GetSendSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetSendSettings.h; sourceTree = ""; }; 21B67CA52C77329800FD64FC /* BaseBridge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BaseBridge.cpp; sourceTree = ""; }; 21B67CA62C77329800FD64FC /* BaseBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BaseBridge.h; sourceTree = ""; }; 21B67CA72C77329800FD64FC /* GetSourceApplicationName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetSourceApplicationName.cpp; sourceTree = ""; }; @@ -1071,6 +1074,8 @@ 21AEF9E72CAB56E5000B8681 /* Arg */, 21D0BD962C8F13F30077E104 /* GetSendFilters.cpp */, 21D0BD952C8F13F30077E104 /* GetSendFilters.h */, + 21AEF9FB2CAD3FD8000B8681 /* GetSendSettings.cpp */, + 21AEF9FC2CAD3FD8000B8681 /* GetSendSettings.h */, 21D0BD8D2C8EE4490077E104 /* Send.cpp */, 21D0BD8A2C8EE4490077E104 /* Send.h */, 21D0BD5B2C89BFEA0077E104 /* SendBridge.cpp */, @@ -1475,6 +1480,7 @@ 21B67CEB2C78D27200FD64FC /* DocumentInfo.cpp in Sources */, 21B67CB92C774BFA00FD64FC /* GetConnectorVersion.cpp in Sources */, 21B67CD92C78C83800FD64FC /* TestBridge.cpp in Sources */, + 21AEF9FD2CAD3FD8000B8681 /* GetSendSettings.cpp in Sources */, 214B7A372C764BCD00D586C1 /* UpdateConfig.cpp in Sources */, 21AEF9EC2CAB56E5000B8681 /* SendViaBrowserArgs.cpp in Sources */, 21FF70492CA1A7F400AAD99A /* RecordCollection.cpp in Sources */, diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp index fa8bca2..683d025 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp @@ -1,6 +1,7 @@ #include "Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h" #include "Active/Serialise/Package/Wrapper/ContainerWrap.h" +#include "Active/Serialise/Item/Wrapper/ValueWrap.h" #include @@ -14,15 +15,13 @@ namespace { ///Serialisation fields enum FieldIndex { idID, - totChildID, - batchesID, + rootObjID, }; ///Serialisation field IDs static std::array fieldID = { Identity{"id"}, - Identity{"totalChildrenCount"}, - Identity{"batches"}, + Identity{"rootObject"}, }; } @@ -39,8 +38,7 @@ bool SendObject::fillInventory(active::serialise::Inventory& inventory) const { inventory.merge(Inventory{ { { fieldID[idID], idID, element }, - { fieldID[totChildID], totChildID, element }, - { fieldID[batchesID], batchesID, element }, + { fieldID[rootObjID], rootObjID, element }, }, }.withType(&typeid(SendObject))); return true; @@ -61,10 +59,8 @@ Cargo::Unique SendObject::getCargo(const active::serialise::Inventory::Item& ite switch (item.index) { case idID: return std::make_unique(id); - case totChildID: - return std::make_unique(totalChildrenCount); - case batchesID: - return std::make_unique>>(batches); + case rootObjID: + return std::make_unique(base::get()); default: return nullptr; //Requested an unknown index } diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h index 6640fa0..ae31520 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h @@ -11,26 +11,24 @@ namespace connector::interfac::browser::bridge { /*! Class defining the primary content of a send */ - class SendObject final : public active::serialise::Package { + class SendObject final : public active::serialise::Package, public std::reference_wrapper { public: + + using base = std::reference_wrapper; // MARK: - Constructors /*! - Constructor - @param errMess The error message - @param card The ID of the model card associated with the wrror - */ - SendObject() {} + Default constructor + @param objID The ID of the object to send + @param object A reference to the object + */ + SendObject(const speckle::utility::String& objID, active::serialise::Package& object) : base{object} {} // MARK: - Public variables ///The root object id which should be used for creating the version speckle::utility::String id = "1234"; - ///The total number of children - int32_t totalChildrenCount = 0; - ///JSON batches for the root object and child (detached) objects - std::vector batches; // MARK: - Serialisation diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp index 44eaccc..0e502e2 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp @@ -46,10 +46,11 @@ namespace { modelCard: The model card to populate into the send info for the browser account: The account linked to the send + object: The object to be sent --------------------------------------------------------------------*/ -SendViaBrowserArgs::SendViaBrowserArgs(const ModelCard& modelCard, const Account& account) : +SendViaBrowserArgs::SendViaBrowserArgs(const ModelCard& modelCard, const Account& account, const SendObject& object) : modelCardID(modelCard.getID()), projectID(modelCard.getProjectID()), modelID(modelCard.getModelID()), token{account.getToken()}, - serverURL{account.getServerURL()}, accountID{account.getID()} { +serverURL{account.getServerURL()}, accountID{account.getID()}, sendObject{object} { } //SendViaBrowserArgs::SendViaBrowserArgs diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h index 6dac55d..0e82858 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h @@ -33,8 +33,9 @@ namespace connector::interfac::browser::bridge { Constructor @param modelCard The model card to populate into the send info for the browser @param account The account linked to the send + @param object The object to be sent */ - SendViaBrowserArgs(const connector::record::ModelCard& modelCard, const speckle::record::cred::Account& account); + SendViaBrowserArgs(const connector::record::ModelCard& modelCard, const speckle::record::cred::Account& account, const SendObject& object); // MARK: - Public variables diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp index 596eba4..4fa0250 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp @@ -8,6 +8,7 @@ #include "Connector/Interface/Browser/Bridge/Send/Arg/SendError.h" #include "Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h" #include "Speckle/Database/AccountDatabase.h" +#include "Speckle/Database/Content/BIMRecord.h" #include "Speckle/Interface/Browser/Bridge/BrowserBridge.h" #include "Speckle/Record/Credentials/Account.h" #include "Speckle/Serialise/Detached/Storage/DetachedMemoryStore.h" @@ -61,7 +62,9 @@ void Send::run(const String& modelCardID) const { } //We currently collect all detached object serialised data into a memory-based store - in future may be able to batch send and cache locally DetachedMemoryStore detachedObjects; - auto result = std::make_unique(*modelCard, *account); - + //Collect targeted elements here + Record placeholder; //Using a placeholder as a test for now + SendObject toSend{placeholder.getID(), placeholder}; + auto result = std::make_unique(*modelCard, *account, toSend); getBridge()->sendEvent("sendByBrowser", std::move(result)); } //Send::run diff --git a/SpeckleLib/Speckle/Database/Content/BIMRecord.cpp b/SpeckleLib/Speckle/Database/Content/BIMRecord.cpp index 882a681..49ebd75 100644 --- a/SpeckleLib/Speckle/Database/Content/BIMRecord.cpp +++ b/SpeckleLib/Speckle/Database/Content/BIMRecord.cpp @@ -1,4 +1,4 @@ -#include "Speckle/Database/Content/Record.h" +#include "Speckle/Database/Content/BIMRecord.h" #include "Speckle/Utility/Guid.h" @@ -13,7 +13,7 @@ using namespace speckle::utility; return: True if the package has added items to the inventory --------------------------------------------------------------------*/ -bool Record::fillInventory(active::serialise::Inventory& inventory) const { +bool BIMRecord::fillInventory(active::serialise::Inventory& inventory) const { using enum Entry::Type; inventory.merge(Inventory{ { @@ -21,4 +21,4 @@ bool Record::fillInventory(active::serialise::Inventory& inventory) const { }, }.withType(&typeid(base))); return true; -} //Record::fillInventory +} //BIMRecord::fillInventory diff --git a/SpeckleLib/Speckle/Database/Content/BIMRecord.h b/SpeckleLib/Speckle/Database/Content/BIMRecord.h index 0cd3db7..f202c40 100644 --- a/SpeckleLib/Speckle/Database/Content/BIMRecord.h +++ b/SpeckleLib/Speckle/Database/Content/BIMRecord.h @@ -1,5 +1,5 @@ -#ifndef SPECKLE_DATABASE_RECORD -#define SPECKLE_DATABASE_RECORD +#ifndef SPECKLE_DATABASE_BIM_RECORD +#define SPECKLE_DATABASE_BIM_RECORD #include "Active/Database/Content/Record.h" #include "Speckle/Database/Identity/Link.h" @@ -10,12 +10,12 @@ namespace speckle::database { /*! Base class for a database record */ - class BIMRecord : public active::database::BIMRecord { + class BIMRecord : public active::database::Record{ public: // MARK: - Types - using base = active::database::BIMRecord; + using base = active::database::Record; ///Unique pointer using Unique = std::unique_ptr; ///Shared pointer @@ -28,14 +28,13 @@ namespace speckle::database { /*! Default constructor */ - BIMRecord() : base{active::utility::Guid{true}.operator active::utility::String(), - active::utility::Guid{true}.operator active::utility::String()} {} //TODO: Implement a better default for the ID + BIMRecord() : base{active::utility::Guid{true}, active::utility::Guid{true}} {} //TODO: Implement a better default for the ID /*! Constructor @param ID The record ID */ - BIMRecord(speckle::utility::String ID, speckle::utility::String::Option globID = std::nullopt) : - base{ID, globID.value_or(active::utility::Guid{true}.operator active::utility::String())} {} + BIMRecord(speckle::utility::Guid ID, speckle::utility::Guid::Option globID = std::nullopt) : //TODO: Implement a better default for the ID + base{ID, globID.value_or(active::utility::Guid{true})} {} /*! Destructor */ @@ -59,4 +58,4 @@ namespace speckle::database { } -#endif //SPECKLE_DATABASE_RECORD +#endif //SPECKLE_DATABASE_BIM_RECORD diff --git a/SpeckleLib/Speckle/Database/Content/Record.cpp b/SpeckleLib/Speckle/Database/Content/Record.cpp index 882a681..c000641 100644 --- a/SpeckleLib/Speckle/Database/Content/Record.cpp +++ b/SpeckleLib/Speckle/Database/Content/Record.cpp @@ -6,6 +6,22 @@ using namespace active::serialise; using namespace speckle::database; using namespace speckle::utility; +namespace { + + ///Serialisation fields + enum FieldIndex { + speckleIDID, + speckleTypeID, + }; + + ///Serialisation field IDs + static std::array fieldID = { + Identity{"id"}, + Identity{"speckle_type"}, + }; + +} + /*-------------------------------------------------------------------- Fill an inventory with the package items @@ -17,8 +33,45 @@ bool Record::fillInventory(active::serialise::Inventory& inventory) const { using enum Entry::Type; inventory.merge(Inventory{ { - { Identity{"id"}, active::database::record::FieldIndex::idIndex, element }, + { Identity{fieldID[speckleIDID]}, active::database::record::FieldIndex::idIndex, element }, }, }.withType(&typeid(base))); + inventory.merge(Inventory{ + { + { Identity{fieldID[speckleTypeID]}, speckleTypeID, element }, + }, + }.withType(&typeid(Record))); return true; } //Record::fillInventory + + +/*-------------------------------------------------------------------- + Get the specified cargo + + item: The inventory item to retrieve + + return: The requested cargo (nullptr on failure) + --------------------------------------------------------------------*/ +Cargo::Unique Record::getCargo(const Inventory::Item& item) const { + if (item.ownerType != &typeid(Record)) + return base::getCargo(item); + using namespace active::serialise; + switch (item.index) { + case speckleTypeID: + //If the type is undefined, we're in a serialisation process and should populate it with whatever the object says it is + if (!m_type) + m_type = getSpeckleType(); + return std::make_unique(*m_type); + default: + return nullptr; //Requested an unknown index + } +} //Record::getCargo + + +/*-------------------------------------------------------------------- + Set to the default package content + --------------------------------------------------------------------*/ +void Record::setDefault() { + //Ensure the content starts with an empty (defined) string for deserialisation so we can discover the incoming type + m_type = String{}; +} //Record::setDefault diff --git a/SpeckleLib/Speckle/Database/Content/Record.h b/SpeckleLib/Speckle/Database/Content/Record.h index 5d70542..2cabaf9 100644 --- a/SpeckleLib/Speckle/Database/Content/Record.h +++ b/SpeckleLib/Speckle/Database/Content/Record.h @@ -42,7 +42,12 @@ namespace speckle::database { virtual ~Record() {} // MARK: - Functions (const) - + + /*! + Get the speckle type identifier + @return The speckle type (relevant objects should override as required, but "Base" is still considered a type on its own) + */ + virtual speckle::utility::String getSpeckleType() const { return "Base"; } // MARK: - Functions (mutating) @@ -55,6 +60,20 @@ namespace speckle::database { @return True if the package has added items to the inventory */ bool fillInventory(active::serialise::Inventory& inventory) const override; + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + /*! + Set to the default package content + */ + void setDefault() override; + + private: + ///Cache for the speckle type during serialisation operations + mutable speckle::utility::String::Option m_type; }; } From 8539129e7cb74e0fa3b13b0bbe3a16fe4e501f3c Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Thu, 3 Oct 2024 12:33:08 +0100 Subject: [PATCH 016/191] SendObject now the owner of the object to be sent --- .../Interface/Browser/Bridge/Send/Arg/SendObject.cpp | 4 +++- .../Interface/Browser/Bridge/Send/Arg/SendObject.h | 10 +++++++--- .../Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp | 4 ++-- .../Browser/Bridge/Send/Arg/SendViaBrowserArgs.h | 2 +- .../Connector/Interface/Browser/Bridge/Send/Send.cpp | 6 +++--- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp index 683d025..693b448 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp @@ -60,7 +60,9 @@ Cargo::Unique SendObject::getCargo(const active::serialise::Inventory::Item& ite case idID: return std::make_unique(id); case rootObjID: - return std::make_unique(base::get()); + if (m_object) + return std::make_unique(*m_object); + return std::make_unique(); default: return nullptr; //Requested an unknown index } diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h index ae31520..7183965 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h @@ -11,7 +11,7 @@ namespace connector::interfac::browser::bridge { /*! Class defining the primary content of a send */ - class SendObject final : public active::serialise::Package, public std::reference_wrapper { + class SendObject final : public active::serialise::Package { public: using base = std::reference_wrapper; @@ -21,9 +21,9 @@ namespace connector::interfac::browser::bridge { /*! Default constructor @param objID The ID of the object to send - @param object A reference to the object + @param object The object to send */ - SendObject(const speckle::utility::String& objID, active::serialise::Package& object) : base{object} {} + SendObject(const speckle::utility::String& objID, std::unique_ptr object) : m_object{std::move(object)} {} // MARK: - Public variables @@ -44,6 +44,10 @@ namespace connector::interfac::browser::bridge { @return The requested cargo (nullptr on failure) */ Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + + private: + ///The object to send + std::unique_ptr m_object; }; } diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp index 0e502e2..3644285 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp @@ -48,9 +48,9 @@ namespace { account: The account linked to the send object: The object to be sent --------------------------------------------------------------------*/ -SendViaBrowserArgs::SendViaBrowserArgs(const ModelCard& modelCard, const Account& account, const SendObject& object) : +SendViaBrowserArgs::SendViaBrowserArgs(const ModelCard& modelCard, const Account& account, SendObject&& object) : modelCardID(modelCard.getID()), projectID(modelCard.getProjectID()), modelID(modelCard.getModelID()), token{account.getToken()}, -serverURL{account.getServerURL()}, accountID{account.getID()}, sendObject{object} { + serverURL{account.getServerURL()}, accountID{account.getID()}, sendObject{std::move(object)} { } //SendViaBrowserArgs::SendViaBrowserArgs diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h index 0e82858..c611732 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h @@ -35,7 +35,7 @@ namespace connector::interfac::browser::bridge { @param account The account linked to the send @param object The object to be sent */ - SendViaBrowserArgs(const connector::record::ModelCard& modelCard, const speckle::record::cred::Account& account, const SendObject& object); + SendViaBrowserArgs(const connector::record::ModelCard& modelCard, const speckle::record::cred::Account& account, SendObject&& object); // MARK: - Public variables diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp index 4fa0250..63363cb 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp @@ -63,8 +63,8 @@ void Send::run(const String& modelCardID) const { //We currently collect all detached object serialised data into a memory-based store - in future may be able to batch send and cache locally DetachedMemoryStore detachedObjects; //Collect targeted elements here - Record placeholder; //Using a placeholder as a test for now - SendObject toSend{placeholder.getID(), placeholder}; - auto result = std::make_unique(*modelCard, *account, toSend); + auto placeholder = std::make_unique(); //Using a placeholder as a test for now + SendObject toSend{placeholder->getID(), std::move(placeholder)}; + auto result = std::make_unique(*modelCard, *account, std::move(toSend)); getBridge()->sendEvent("sendByBrowser", std::move(result)); } //Send::run From a0413d0d3a8cdae0e4cf6dfd365a369cfd16759a Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Thu, 3 Oct 2024 13:12:57 +0100 Subject: [PATCH 017/191] SendObject now holds and sends a Record --- .../Interface/Browser/Bridge/Send/Arg/SendObject.h | 9 ++++----- .../Connector/Interface/Browser/Bridge/Send/Send.cpp | 5 ++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h index 7183965..601c330 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h @@ -2,8 +2,8 @@ #define CONNECTOR_INTERFACE_BRIDGE_SEND_OBJECT #include "Active/Serialise/CargoHold.h" -#include "Active/Serialise/Item/Wrapper/ValueWrap.h" #include "Connector/Interface/Browser/Bridge/Config/Arg/ConnectorConfig.h" +#include "Speckle/Database/Content/Record.h" #include "Speckle/Interface/Browser/Bridge/BridgeMethod.h" namespace connector::interfac::browser::bridge { @@ -20,15 +20,14 @@ namespace connector::interfac::browser::bridge { /*! Default constructor - @param objID The ID of the object to send @param object The object to send */ - SendObject(const speckle::utility::String& objID, std::unique_ptr object) : m_object{std::move(object)} {} + SendObject(std::unique_ptr object) : m_object{std::move(object)} { id = m_object->getID(); } // MARK: - Public variables ///The root object id which should be used for creating the version - speckle::utility::String id = "1234"; + speckle::utility::String id; // MARK: - Serialisation @@ -47,7 +46,7 @@ namespace connector::interfac::browser::bridge { private: ///The object to send - std::unique_ptr m_object; + std::unique_ptr m_object; }; } diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp index 63363cb..e5bab6d 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp @@ -63,8 +63,7 @@ void Send::run(const String& modelCardID) const { //We currently collect all detached object serialised data into a memory-based store - in future may be able to batch send and cache locally DetachedMemoryStore detachedObjects; //Collect targeted elements here - auto placeholder = std::make_unique(); //Using a placeholder as a test for now - SendObject toSend{placeholder->getID(), std::move(placeholder)}; + SendObject toSend{std::make_unique()}; //NB: Using a placeholder object for now auto result = std::make_unique(*modelCard, *account, std::move(toSend)); - getBridge()->sendEvent("sendByBrowser", std::move(result)); + getBridge()->sendEvent("sendByBrowser", std::move(result)); } //Send::run From 6cf03010bd0b6ce5eb2d8cd7df3c7efe88bcbe0a Mon Sep 17 00:00:00 2001 From: David Kekesi Date: Thu, 3 Oct 2024 14:39:09 +0200 Subject: [PATCH 018/191] mesh export WIP --- .../Interface/Browser/Bridge/Send/Send.cpp | 2 + .../Connector/Interface/ConnectorPalette.cpp | 35 ++++++- SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp | 17 +++- SpeckleLib/Speckle/Primitive/Mesh/Mesh.h | 9 +- SpeckleLib/Speckle/Record/Element/Element.cpp | 94 ++++++++++++++++++- SpeckleLib/Speckle/Record/Element/Element.h | 2 +- 6 files changed, 150 insertions(+), 9 deletions(-) diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp index 73c41b8..c4d5c3b 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp @@ -7,6 +7,8 @@ #include "Speckle/Interface/Browser/Bridge/BrowserBridge.h" #include "Speckle/Utility/Exception.h" +#include + using namespace active::serialise; using namespace connector::interfac::browser::bridge; using namespace speckle::utility; diff --git a/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp b/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp index 6b63586..da74945 100644 --- a/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp +++ b/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp @@ -1,6 +1,9 @@ #include "Connector/Interface/ConnectorPalette.h" #include "Active/Event/Event.h" +#include "Active/Utility/String.h" +#include "Active/Serialise/JSON/JSONTransport.h" +#include "Active/Utility/BufferOut.h" #include "Connector/ConnectorResource.h" #include "Connector/Event/ConnectorEventID.h" #include "Connector/Interface/Browser/Bridge/Account/AccountBridge.h" @@ -15,10 +18,12 @@ #include "Speckle/Environment/Project.h" - #include "Connector/Connector.h" #include "Speckle/Database/BIMElementDatabase.h" +#include +#include +#include #include #include @@ -128,6 +133,31 @@ bool ConnectorPalette::start() { } //ConnectorPalette::start +static void Test() { + if (auto project = connector::connector()->getActiveProject().lock(); project) { + auto elementDatabase = project->getElementDatabase(); + auto selected = elementDatabase->getSelection(); + for (const auto& link : selected) { + auto element = elementDatabase->getElement(link); + active::utility::String output; + active::serialise::json::JSONTransport().send(std::forward(*element), active::serialise::Identity{}, output); + if (output.length() > 0) { + std::ofstream outFile("C:\\temp\\output.txt"); // Create an output file stream (opens file) + + // Check if the file opened successfully + if (outFile.is_open()) { + outFile << output.string(); + outFile.close(); + std::cout << "String written to file successfully." << std::endl; + } + else { + std::cerr << "Unable to open file." << std::endl; + } + } + } + } +} + /*-------------------------------------------------------------------- Receive a subscribed event @@ -136,6 +166,9 @@ bool ConnectorPalette::start() { return: True if the event should be closed --------------------------------------------------------------------*/ bool ConnectorPalette::receive(const active::event::Event& event) { + + Test(); + if (BrowserPalette::HasInstance() && BrowserPalette::GetInstance().IsVisible()) { BrowserPalette::GetInstance().Hide (); } else { diff --git a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp index ffe58ec..8b2d0de 100644 --- a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp +++ b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp @@ -1,6 +1,8 @@ #include "Speckle/Primitive/Mesh/Mesh.h" #include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Active/Serialise/Package/Wrapper/PackageWrap.h" +#include "Active/Serialise/Package/Wrapper/ContainerWrap.h" #include "Active/Serialise/Inventory/Identity.h" #include @@ -14,12 +16,14 @@ namespace { enum FieldIndex { vertexID, faceID, + colorID, }; ///Serialisation field IDs static std::array fieldID = { Identity{"vertices"}, Identity{"faces"}, + Identity{"colors"}, }; } @@ -35,8 +39,9 @@ bool Mesh::fillInventory(Inventory& inventory) const { using enum Entry::Type; inventory.merge(Inventory{ { - //{ fieldID[vertexID], vertexID, vertices::size(), std::nullopt, !vertices::empty() }, - //{ fieldID[elementID], elementID, faces::size(), std::nullopt, !faces::empty() }, + { fieldID[vertexID], vertexID, vertices.size(), std::nullopt, !vertices.empty() }, + { fieldID[faceID], faceID, faces.size(), std::nullopt, !faces.empty() }, + { fieldID[colorID], colorID, colors.size(), std::nullopt, !colors.empty() }, }, }.withType(&typeid(Mesh))); return true; @@ -55,10 +60,12 @@ Cargo::Unique Mesh::getCargo(const Inventory::Item& item) const { return nullptr; using namespace active::serialise; switch (item.index) { - case vertexID: - return nullptr; //TODO: Implement vertices array + case vertexID: + return std::make_unique>>(vertices); case faceID: - return nullptr; //TODO: Implement faces array + return std::make_unique>>(faces); + case colorID: + return std::make_unique>>(colors); default: return nullptr; //Requested an unknown index } diff --git a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h index d440fc3..72035e2 100644 --- a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h +++ b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h @@ -2,6 +2,7 @@ #define SPECKLE_PRIMITIVE_MESH #include "Active/Serialise/Package/Package.h" +#include "Speckle/Utility/String.h" namespace speckle::primitive { @@ -18,6 +19,9 @@ namespace speckle::primitive { */ Mesh() {} + Mesh(std::vector&& vertices, std::vector&& faces, std::vector&& colors, utility::String units = "m") + : vertices{ std::move(vertices) }, faces{ std::move(faces) }, colors{ std::move(colors) }, units{ units } {} + // MARK: - Functions (const) @@ -37,7 +41,10 @@ namespace speckle::primitive { active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; private: - + std::vector vertices; + std::vector faces; + std::vector colors; + utility::String units; }; } diff --git a/SpeckleLib/Speckle/Record/Element/Element.cpp b/SpeckleLib/Speckle/Record/Element/Element.cpp index 999cfe7..63b3cb2 100644 --- a/SpeckleLib/Speckle/Record/Element/Element.cpp +++ b/SpeckleLib/Speckle/Record/Element/Element.cpp @@ -2,6 +2,7 @@ #include "Active/Serialise/Item/Wrapper/ValueWrap.h" #include "Active/Serialise/Package/Wrapper/PackageWrap.h" +#include "Active/Serialise/Package/Wrapper/ContainerWrap.h" #include "Speckle/Primitive/Mesh/Mesh.h" #include "Speckle/Utility/Guid.h" @@ -10,6 +11,7 @@ using namespace speckle::record::element; using namespace speckle::utility; #include +#include namespace speckle::record::element { @@ -39,6 +41,14 @@ namespace { Identity{"displayValue"}, }; + void GetComponent(API_Component3D& component, API_3DTypeID typeId, Int32 index) { + component.header.typeID = typeId; + component.header.index = index; + if (ACAPI_ModelAccess_GetComponent(&component) != NoError) { + // TODO: throw + } + } + } /*-------------------------------------------------------------------- @@ -73,6 +83,81 @@ Element::Element(const Element& source) { --------------------------------------------------------------------*/ Element::~Element() {} +Element::Body* Element::getBody() const { + + if (m_data->m_cache) { + return m_data->m_cache.get(); + } + + auto elementBody = new Element::Body(); + std::map vertexIndexMap; + int currentVertexIndex = 0; + + API_ElemInfo3D info3D = {}; + + if (ACAPI_ModelAccess_Get3DInfo(getHead(), &info3D) != NoError) { + // TODO: throw + } + + for (Int32 ib = info3D.fbody; ib <= info3D.lbody; ib++) { + API_Component3D component = {}; + GetComponent(component, API_BodyID, ib); + + std::vector vertices; + std::vector faces; + std::vector colors; + + vertices.clear(); + faces.clear(); + colors.clear(); + + Int32 nPgon = component.body.nPgon; + for (Int32 ip = 1; ip <= nPgon; ip++) { + GetComponent(component, API_PgonID, ip); + + Int32 fpedg = component.pgon.fpedg; + Int32 lpedg = component.pgon.lpedg; + Int32 faceSize = lpedg - fpedg + 1; + for (Int32 ie = fpedg; ie <= lpedg; ie++) + { + GetComponent(component, API_PedgID, ie); + + // TODO is this needed? need review, not sure how ACAPI_ModelAccess works + bool wasNegative = component.pedg.pedg < 0; + Int32 edgeIndex = std::abs(component.pedg.pedg); + GetComponent(component, API_EdgeID, edgeIndex); + + // TODO is this needed? need review, not sure how ACAPI_ModelAccess works + Int32 vertexIndex = wasNegative ? component.edge.vert2 : component.edge.vert1; + /*auto materialIndex = component.pgon.iumat; + GetComponent(component, API_UmatID, materialIndex); + double R = component.umat.mater.surfaceRGB.f_red; + double G = component.umat.mater.surfaceRGB.f_green; + double B = component.umat.mater.surfaceRGB.f_blue;*/ + // TODO: other material stuff + + GetComponent(component, API_VertID, vertexIndex); + + faces.push_back(faceSize); + if (vertexIndexMap.find(vertexIndex) == vertexIndexMap.end()) { + faces.push_back(currentVertexIndex); + vertexIndexMap[vertexIndex] = currentVertexIndex++; + + vertices.push_back(component.vert.x); + vertices.push_back(component.vert.y); + vertices.push_back(component.vert.z); + } + else { + faces.push_back(vertexIndexMap[vertexIndex]); + } + } + } + elementBody->push_back(primitive::Mesh(std::move(vertices), std::move(faces), std::move(colors))); + } + m_data->m_cache.reset(elementBody); + return m_data->m_cache.get(); +} + /*-------------------------------------------------------------------- Get the (immutable) API element header data @@ -125,7 +210,14 @@ Cargo::Unique Element::getCargo(const Inventory::Item& item) const { using namespace active::serialise; switch (item.index) { case bodyID: - return nullptr; //TODO: implement + if (auto body = getBody(); body != nullptr) + { + //return std::make_unique(*body); + return Cargo::Unique{ new active::serialise::ContainerWrap{ *body } }; + } + else + return nullptr; + default: return nullptr; //Requested an unknown index } diff --git a/SpeckleLib/Speckle/Record/Element/Element.h b/SpeckleLib/Speckle/Record/Element/Element.h index 068d495..ee478c9 100644 --- a/SpeckleLib/Speckle/Record/Element/Element.h +++ b/SpeckleLib/Speckle/Record/Element/Element.h @@ -67,7 +67,7 @@ namespace speckle::record::element { Get the element body @return An array of meshes from the element body (nullptr if no body data is available) */ - virtual Body* getBody() const { return nullptr; } + virtual Body* getBody() const; #ifdef ARCHICAD /*! Get the (immutable) API element header data From 990a1ab9e1331e639b42243b7eb3edcbf963ff67 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Thu, 3 Oct 2024 13:48:22 +0100 Subject: [PATCH 019/191] Updated for VS --- .../Connector/Interface/Browser/Bridge/Send/Send.cpp | 2 -- SpeckleLib/Speckle/Database/Content/Record.cpp | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp index e5bab6d..bed68d1 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp @@ -60,8 +60,6 @@ void Send::run(const String& modelCardID) const { std::make_unique(connector()->getLocalString(errorString, noProjectOpenID), modelCardID)); return; } - //We currently collect all detached object serialised data into a memory-based store - in future may be able to batch send and cache locally - DetachedMemoryStore detachedObjects; //Collect targeted elements here SendObject toSend{std::make_unique()}; //NB: Using a placeholder object for now auto result = std::make_unique(*modelCard, *account, std::move(toSend)); diff --git a/SpeckleLib/Speckle/Database/Content/Record.cpp b/SpeckleLib/Speckle/Database/Content/Record.cpp index c000641..09c065c 100644 --- a/SpeckleLib/Speckle/Database/Content/Record.cpp +++ b/SpeckleLib/Speckle/Database/Content/Record.cpp @@ -6,6 +6,8 @@ using namespace active::serialise; using namespace speckle::database; using namespace speckle::utility; +#include + namespace { ///Serialisation fields From 844ab3544bacf4d5d4f1a6f3ae36ea68b6f33f59 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Thu, 3 Oct 2024 14:32:30 +0100 Subject: [PATCH 020/191] Commit working --- .../Connector/Interface/Browser/Bridge/Send/Send.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp index bed68d1..a035644 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp @@ -46,6 +46,7 @@ void Send::run(const String& modelCardID) const { std::make_unique(connector()->getLocalString(errorString, modelCardNotFoundID), modelCardID)); return; } + //Get the user account auto accountDatabase = connector()->getAccountDatabase(); auto account = accountDatabase->getAccount(modelCard->getAccountID(), modelCard->getServerURL()); if (!account) { @@ -61,7 +62,8 @@ void Send::run(const String& modelCardID) const { return; } //Collect targeted elements here - SendObject toSend{std::make_unique()}; //NB: Using a placeholder object for now - auto result = std::make_unique(*modelCard, *account, std::move(toSend)); + + //Send the collected information + auto result = std::make_unique(*modelCard, *account, std::make_unique()); //NB: Using a placeholder object for now getBridge()->sendEvent("sendByBrowser", std::move(result)); } //Send::run From 1a61608c42879ce619ad4e0d6c0879b32e8fb952 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Thu, 3 Oct 2024 14:33:52 +0100 Subject: [PATCH 021/191] Using preview interface for testing --- SpeckleConnector/Connector/Interface/ConnectorPalette.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp b/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp index 6b63586..68a83ca 100644 --- a/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp +++ b/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp @@ -214,7 +214,8 @@ void BrowserPalette::Hide() { void BrowserPalette::InitBrowserControl() { #ifdef TESTING_MODE - browser->LoadURL("https://boisterous-douhua-e3cefb.netlify.app/test"); + browser->LoadURL("https://deploy-preview-3180--boisterous-douhua-e3cefb.netlify.app/"); + //browser->LoadURL("https://boisterous-douhua-e3cefb.netlify.app/test"); #else browser->LoadURL("https://boisterous-douhua-e3cefb.netlify.app/"); #endif From 0592bcc947ae1e814c8f3e1674c3bf4ff3e8104f Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Thu, 3 Oct 2024 16:31:58 +0100 Subject: [PATCH 022/191] BIMRecord is a type of Record (adds applicationID) --- .../Speckle/Database/Content/BIMRecord.cpp | 44 +++++++++++++++++-- .../Speckle/Database/Content/BIMRecord.h | 31 ++++++++++--- .../Speckle/Database/Content/Record.cpp | 4 +- SpeckleLib/Speckle/Database/Content/Record.h | 11 ++--- 4 files changed, 71 insertions(+), 19 deletions(-) diff --git a/SpeckleLib/Speckle/Database/Content/BIMRecord.cpp b/SpeckleLib/Speckle/Database/Content/BIMRecord.cpp index 49ebd75..b6a7100 100644 --- a/SpeckleLib/Speckle/Database/Content/BIMRecord.cpp +++ b/SpeckleLib/Speckle/Database/Content/BIMRecord.cpp @@ -2,10 +2,26 @@ #include "Speckle/Utility/Guid.h" +#include + using namespace active::serialise; using namespace speckle::database; using namespace speckle::utility; +namespace { + + ///Serialisation fields + enum FieldIndex { + applicID, + }; + + ///Serialisation field IDs + static std::array fieldID = { + Identity{"applicationId"}, + }; + +} + /*-------------------------------------------------------------------- Fill an inventory with the package items @@ -13,12 +29,32 @@ using namespace speckle::utility; return: True if the package has added items to the inventory --------------------------------------------------------------------*/ -bool BIMRecord::fillInventory(active::serialise::Inventory& inventory) const { +bool BIMRecord::fillInventory(Inventory& inventory) const { using enum Entry::Type; inventory.merge(Inventory{ { - { Identity{"id"}, active::database::record::FieldIndex::idIndex, element }, + { Identity{fieldID[applicID]}, applicID, element }, }, - }.withType(&typeid(base))); - return true; + }.withType(&typeid(BIMRecord))); + return base::fillInventory(inventory); } //BIMRecord::fillInventory + + +/*-------------------------------------------------------------------- + Get the specified cargo + + item: The inventory item to retrieve + + return: The requested cargo (nullptr on failure) + --------------------------------------------------------------------*/ +Cargo::Unique BIMRecord::getCargo(const Inventory::Item& item) const { + if (item.ownerType != &typeid(BIMRecord)) + return base::getCargo(item); + using namespace active::serialise; + switch (item.index) { + case applicID: + return std::make_unique>(m_applicationID); + default: + return nullptr; //Requested an unknown index + } +} //BIMRecord::getCargo diff --git a/SpeckleLib/Speckle/Database/Content/BIMRecord.h b/SpeckleLib/Speckle/Database/Content/BIMRecord.h index f202c40..133912a 100644 --- a/SpeckleLib/Speckle/Database/Content/BIMRecord.h +++ b/SpeckleLib/Speckle/Database/Content/BIMRecord.h @@ -1,7 +1,7 @@ #ifndef SPECKLE_DATABASE_BIM_RECORD #define SPECKLE_DATABASE_BIM_RECORD -#include "Active/Database/Content/Record.h" +#include "Speckle/Database/Content/Record.h" #include "Speckle/Database/Identity/Link.h" #include "Speckle/Database/Identity/BIMRecordID.h" @@ -10,12 +10,12 @@ namespace speckle::database { /*! Base class for a database record */ - class BIMRecord : public active::database::Record{ + class BIMRecord : public Record { public: // MARK: - Types - using base = active::database::Record; + using base = Record; ///Unique pointer using Unique = std::unique_ptr; ///Shared pointer @@ -28,13 +28,12 @@ namespace speckle::database { /*! Default constructor */ - BIMRecord() : base{active::utility::Guid{true}, active::utility::Guid{true}} {} //TODO: Implement a better default for the ID + BIMRecord() : base{} {} /*! Constructor @param ID The record ID */ - BIMRecord(speckle::utility::Guid ID, speckle::utility::Guid::Option globID = std::nullopt) : //TODO: Implement a better default for the ID - base{ID, globID.value_or(active::utility::Guid{true})} {} + BIMRecord(speckle::utility::Guid ID) : base{}, m_applicationID{ID} {} /*! Destructor */ @@ -42,9 +41,19 @@ namespace speckle::database { // MARK: - Functions (const) + /*! + Get the BIM application ID + @return The BIM application ID + */ + BIMRecordID getBIMID() const { return m_applicationID; } // MARK: - Functions (mutating) + /*! + Set the BIM application ID + @param ID The BIM application ID + */ + void setBIMID(const BIMRecordID& ID) { m_applicationID = ID; } // MARK: - Serialisation @@ -54,6 +63,16 @@ namespace speckle::database { @return True if the package has added items to the inventory */ bool fillInventory(active::serialise::Inventory& inventory) const override; + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + + private: + ///The BIM application record ID + BIMRecordID m_applicationID; }; } diff --git a/SpeckleLib/Speckle/Database/Content/Record.cpp b/SpeckleLib/Speckle/Database/Content/Record.cpp index 09c065c..ea79570 100644 --- a/SpeckleLib/Speckle/Database/Content/Record.cpp +++ b/SpeckleLib/Speckle/Database/Content/Record.cpp @@ -2,12 +2,12 @@ #include "Speckle/Utility/Guid.h" +#include + using namespace active::serialise; using namespace speckle::database; using namespace speckle::utility; -#include - namespace { ///Serialisation fields diff --git a/SpeckleLib/Speckle/Database/Content/Record.h b/SpeckleLib/Speckle/Database/Content/Record.h index 2cabaf9..f609223 100644 --- a/SpeckleLib/Speckle/Database/Content/Record.h +++ b/SpeckleLib/Speckle/Database/Content/Record.h @@ -27,15 +27,12 @@ namespace speckle::database { /*! Default constructor - */ - Record() : base{active::utility::Guid{true}.operator active::utility::String(), - active::utility::Guid{true}.operator active::utility::String()} {} //TODO: Implement a better default for the ID - /*! - Constructor @param ID The record ID + @param globID The global ID */ - Record(speckle::utility::String ID, speckle::utility::String::Option globID = std::nullopt) : - base{ID, globID.value_or(active::utility::Guid{true}.operator active::utility::String())} {} + Record(speckle::utility::String::Option ID = std::nullopt, speckle::utility::String::Option globID = std::nullopt) : + base{ID.value_or(active::utility::Guid{true}.operator active::utility::String()), + globID.value_or(active::utility::Guid{true}.operator active::utility::String())} {} /*! Destructor */ From 8dd00005b1081dd6c64624fdbbb8b01b2ea972ac Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Thu, 3 Oct 2024 16:39:21 +0100 Subject: [PATCH 023/191] Element is a type of BIMRecord --- SpeckleLib/Speckle/Record/Element/Element.cpp | 4 ++-- SpeckleLib/Speckle/Record/Element/Element.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/SpeckleLib/Speckle/Record/Element/Element.cpp b/SpeckleLib/Speckle/Record/Element/Element.cpp index 63b3cb2..fa991b9 100644 --- a/SpeckleLib/Speckle/Record/Element/Element.cpp +++ b/SpeckleLib/Speckle/Record/Element/Element.cpp @@ -63,7 +63,7 @@ Element::Element() { elemData: Archicad element data --------------------------------------------------------------------*/ -Element::Element(const API_Element& elemData) { +Element::Element(const API_Element& elemData) : base{elemData.header.guid} { m_data = std::make_unique(elemData); } //Element::Element @@ -73,7 +73,7 @@ Element::Element(const API_Element& elemData) { source: The object to copy --------------------------------------------------------------------*/ -Element::Element(const Element& source) { +Element::Element(const Element& source) : base{source} { m_data = source.m_data ? std::make_unique(*m_data) : nullptr; } //Element::Element diff --git a/SpeckleLib/Speckle/Record/Element/Element.h b/SpeckleLib/Speckle/Record/Element/Element.h index ee478c9..59990f4 100644 --- a/SpeckleLib/Speckle/Record/Element/Element.h +++ b/SpeckleLib/Speckle/Record/Element/Element.h @@ -1,7 +1,7 @@ #ifndef SPECKLE_RECORD_ELEMENT #define SPECKLE_RECORD_ELEMENT -#include "Speckle/Database/Content/Record.h" +#include "Speckle/Database/Content/BIMRecord.h" #include "Speckle/Utility/String.h" namespace speckle::primitive { @@ -13,7 +13,7 @@ namespace speckle::record::element { /*! Base BIM element class */ - class Element : public speckle::database::Record { + class Element : public speckle::database::BIMRecord { public: ///An element 3D body primitive @@ -21,7 +21,7 @@ namespace speckle::record::element { // MARK: - Types - using base = speckle::database::Record; + using base = speckle::database::BIMRecord; ///Unique pointer using Unique = std::unique_ptr; ///Shared pointer From f066b0ee028db0ef2fcab37fcf67758cc6f1e0cf Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Thu, 3 Oct 2024 17:05:02 +0100 Subject: [PATCH 024/191] Send bridge method injects the first selected element into the sent data for testing Mesh vertices, faces and colours are all single arrays --- .../Connector/Interface/Browser/Bridge/Send/Send.cpp | 4 ++-- SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp index 3750cf3..8cd4e53 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp @@ -89,6 +89,6 @@ void Send::run(const String& modelCardID) const { //Send the collected information - auto result = std::make_unique(*modelCard, *account, std::make_unique()); //NB: Using a placeholder object for now - getBridge()->sendEvent("sendByBrowser", std::move(result)); + auto result = std::make_unique(*modelCard, *account, SendObject{std::move(element)}); //NB: Using a placeholder object for now + getBridge()->sendEvent("sendByBrowser", std::move(result)); } //Send::run diff --git a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp index 8b2d0de..a044d51 100644 --- a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp +++ b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp @@ -39,9 +39,9 @@ bool Mesh::fillInventory(Inventory& inventory) const { using enum Entry::Type; inventory.merge(Inventory{ { - { fieldID[vertexID], vertexID, vertices.size(), std::nullopt, !vertices.empty() }, - { fieldID[faceID], faceID, faces.size(), std::nullopt, !faces.empty() }, - { fieldID[colorID], colorID, colors.size(), std::nullopt, !colors.empty() }, + { fieldID[vertexID], vertexID, element }, + { fieldID[faceID], faceID, element }, + { fieldID[colorID], colorID, element }, }, }.withType(&typeid(Mesh))); return true; From f5bb3dc454d342b0de045a182fd1df2382dc395d Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Thu, 3 Oct 2024 17:50:50 +0100 Subject: [PATCH 025/191] Fix to element mesh face indices --- SpeckleLib/Speckle/Record/Element/Element.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SpeckleLib/Speckle/Record/Element/Element.cpp b/SpeckleLib/Speckle/Record/Element/Element.cpp index fa991b9..7e5f6d8 100644 --- a/SpeckleLib/Speckle/Record/Element/Element.cpp +++ b/SpeckleLib/Speckle/Record/Element/Element.cpp @@ -118,6 +118,7 @@ Element::Body* Element::getBody() const { Int32 fpedg = component.pgon.fpedg; Int32 lpedg = component.pgon.lpedg; Int32 faceSize = lpedg - fpedg + 1; + faces.push_back(faceSize); for (Int32 ie = fpedg; ie <= lpedg; ie++) { GetComponent(component, API_PedgID, ie); @@ -138,7 +139,6 @@ Element::Body* Element::getBody() const { GetComponent(component, API_VertID, vertexIndex); - faces.push_back(faceSize); if (vertexIndexMap.find(vertexIndex) == vertexIndexMap.end()) { faces.push_back(currentVertexIndex); vertexIndexMap[vertexIndex] = currentVertexIndex++; From 042a515dc407f484a6f7d38e4342567fff4a66c9 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Thu, 3 Oct 2024 17:54:01 +0100 Subject: [PATCH 026/191] Removed test code from palette --- .../Connector/Interface/ConnectorPalette.cpp | 38 ------------------- 1 file changed, 38 deletions(-) diff --git a/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp b/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp index 750dd2b..6810467 100644 --- a/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp +++ b/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp @@ -15,16 +15,6 @@ #include "Speckle/Event/Type/MenuEvent.h" #include "Speckle/Interface/Browser/JSPortal.h" - -#include "Speckle/Environment/Project.h" - -#include "Connector/Connector.h" -#include "Speckle/Database/BIMElementDatabase.h" - -#include -#include -#include - #include #include #include @@ -133,31 +123,6 @@ bool ConnectorPalette::start() { } //ConnectorPalette::start -static void Test() { - if (auto project = connector::connector()->getActiveProject().lock(); project) { - auto elementDatabase = project->getElementDatabase(); - auto selected = elementDatabase->getSelection(); - for (const auto& link : selected) { - auto element = elementDatabase->getElement(link); - active::utility::String output; - active::serialise::json::JSONTransport().send(std::forward(*element), active::serialise::Identity{}, output); - if (output.length() > 0) { - std::ofstream outFile("C:\\temp\\output.txt"); // Create an output file stream (opens file) - - // Check if the file opened successfully - if (outFile.is_open()) { - outFile << output.string(); - outFile.close(); - std::cout << "String written to file successfully." << std::endl; - } - else { - std::cerr << "Unable to open file." << std::endl; - } - } - } - } -} - /*-------------------------------------------------------------------- Receive a subscribed event @@ -166,9 +131,6 @@ static void Test() { return: True if the event should be closed --------------------------------------------------------------------*/ bool ConnectorPalette::receive(const active::event::Event& event) { - - Test(); - if (BrowserPalette::HasInstance() && BrowserPalette::GetInstance().IsVisible()) { BrowserPalette::GetInstance().Hide (); } else { From 72cd75d2e645302739cd3e3af58910a983d09d07 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Fri, 4 Oct 2024 21:03:54 +0100 Subject: [PATCH 027/191] Added speckle_type and unit properties to Record, BIMRecord, Element and Mesh classes Defined (de)serialisation for LengthType --- .../Browser/Bridge/Base/Arg/DocumentInfo.h | 20 ++-- .../Speckle/Database/Content/BIMRecord.cpp | 20 +++- .../Speckle/Database/Content/BIMRecord.h | 23 ++-- .../Speckle/Database/Content/Record.cpp | 4 +- SpeckleLib/Speckle/Database/Content/Record.h | 6 +- SpeckleLib/Speckle/Primitive/Mesh/Mesh.h | 15 ++- SpeckleLib/Speckle/Record/Element/Element.h | 49 ++++---- .../Speckle/Serialise/Units/LengthUnit.cpp | 55 +++++++++ .../Speckle/Serialise/Units/LengthUnit.h | 107 ++++++++++++++++++ .../SpeckleLib.xcodeproj/project.pbxproj | 14 +++ 10 files changed, 262 insertions(+), 51 deletions(-) create mode 100644 SpeckleLib/Speckle/Serialise/Units/LengthUnit.cpp create mode 100644 SpeckleLib/Speckle/Serialise/Units/LengthUnit.h diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/Arg/DocumentInfo.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/Arg/DocumentInfo.h index 56ac1b5..84b9848 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/Arg/DocumentInfo.h +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/Arg/DocumentInfo.h @@ -39,20 +39,20 @@ namespace connector::interfac::browser::bridge { // MARK: - Serialisation /*! - Fill an inventory with the package items - @param inventory The inventory to receive the package items - @return True if the package has added items to the inventory - */ + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ bool fillInventory(active::serialise::Inventory& inventory) const override; /*! - Get the specified cargo - @param item The inventory item to retrieve - @return The requested cargo (nullptr on failure) - */ + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; /*! - Set to the default package content - */ + Set to the default package content + */ void setDefault() override; }; diff --git a/SpeckleLib/Speckle/Database/Content/BIMRecord.cpp b/SpeckleLib/Speckle/Database/Content/BIMRecord.cpp index b6a7100..dcc55d1 100644 --- a/SpeckleLib/Speckle/Database/Content/BIMRecord.cpp +++ b/SpeckleLib/Speckle/Database/Content/BIMRecord.cpp @@ -1,5 +1,7 @@ #include "Speckle/Database/Content/BIMRecord.h" +#include "Active/Serialise/Item/Wrapper/ValueOptionWrap.h" +#include "Speckle/Serialise/Units/LengthUnit.h" #include "Speckle/Utility/Guid.h" #include @@ -8,16 +10,20 @@ using namespace active::serialise; using namespace speckle::database; using namespace speckle::utility; +using enum active::measure::LengthType; + namespace { ///Serialisation fields enum FieldIndex { applicID, + unitID, }; ///Serialisation field IDs static std::array fieldID = { Identity{"applicationId"}, + Identity{"unit"}, }; } @@ -33,7 +39,8 @@ bool BIMRecord::fillInventory(Inventory& inventory) const { using enum Entry::Type; inventory.merge(Inventory{ { - { Identity{fieldID[applicID]}, applicID, element }, + { Identity{fieldID[applicID]}, applicID, element, !m_applicationID.empty() }, + { Identity{fieldID[unitID]}, unitID, element, m_unit.operator bool() }, }, }.withType(&typeid(BIMRecord))); return base::fillInventory(inventory); @@ -54,7 +61,18 @@ Cargo::Unique BIMRecord::getCargo(const Inventory::Item& item) const { switch (item.index) { case applicID: return std::make_unique>(m_applicationID); + case unitID: + return std::make_unique>(m_unit); default: return nullptr; //Requested an unknown index } } //BIMRecord::getCargo + + +/*-------------------------------------------------------------------- + Set to the default package content + --------------------------------------------------------------------*/ +void BIMRecord::setDefault() { + m_applicationID.clear(); + m_unit.reset(); +} //BIMRecord::setDefault diff --git a/SpeckleLib/Speckle/Database/Content/BIMRecord.h b/SpeckleLib/Speckle/Database/Content/BIMRecord.h index 133912a..c9bee26 100644 --- a/SpeckleLib/Speckle/Database/Content/BIMRecord.h +++ b/SpeckleLib/Speckle/Database/Content/BIMRecord.h @@ -1,6 +1,7 @@ #ifndef SPECKLE_DATABASE_BIM_RECORD #define SPECKLE_DATABASE_BIM_RECORD +#include "Active/Setting/Values/Measurement/Units/LengthUnit.h" #include "Speckle/Database/Content/Record.h" #include "Speckle/Database/Identity/Link.h" #include "Speckle/Database/Identity/BIMRecordID.h" @@ -58,21 +59,27 @@ namespace speckle::database { // MARK: - Serialisation /*! - Fill an inventory with the package items - @param inventory The inventory to receive the package items - @return True if the package has added items to the inventory - */ + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ bool fillInventory(active::serialise::Inventory& inventory) const override; /*! - Get the specified cargo - @param item The inventory item to retrieve - @return The requested cargo (nullptr on failure) - */ + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + /*! + Set to the default package content + */ + void setDefault() override; private: ///The BIM application record ID BIMRecordID m_applicationID; + ///The BIM record unit of length measurement + std::optional m_unit = active::measure::LengthType::metre; }; } diff --git a/SpeckleLib/Speckle/Database/Content/Record.cpp b/SpeckleLib/Speckle/Database/Content/Record.cpp index ea79570..e515c45 100644 --- a/SpeckleLib/Speckle/Database/Content/Record.cpp +++ b/SpeckleLib/Speckle/Database/Content/Record.cpp @@ -35,12 +35,12 @@ bool Record::fillInventory(active::serialise::Inventory& inventory) const { using enum Entry::Type; inventory.merge(Inventory{ { - { Identity{fieldID[speckleIDID]}, active::database::record::FieldIndex::idIndex, element }, + { Identity{fieldID[speckleIDID]}, active::database::record::FieldIndex::idIndex, element, !getID().empty() }, }, }.withType(&typeid(base))); inventory.merge(Inventory{ { - { Identity{fieldID[speckleTypeID]}, speckleTypeID, element }, + { Identity{fieldID[speckleTypeID]}, speckleTypeID, element, !m_type.operator bool() }, }, }.withType(&typeid(Record))); return true; diff --git a/SpeckleLib/Speckle/Database/Content/Record.h b/SpeckleLib/Speckle/Database/Content/Record.h index f609223..fa76191 100644 --- a/SpeckleLib/Speckle/Database/Content/Record.h +++ b/SpeckleLib/Speckle/Database/Content/Record.h @@ -31,8 +31,8 @@ namespace speckle::database { @param globID The global ID */ Record(speckle::utility::String::Option ID = std::nullopt, speckle::utility::String::Option globID = std::nullopt) : - base{ID.value_or(active::utility::Guid{true}.operator active::utility::String()), - globID.value_or(active::utility::Guid{true}.operator active::utility::String())} {} + base{ID.value_or(active::utility::Guid{}.operator active::utility::String()), + globID.value_or(active::utility::Guid{}.operator active::utility::String())} {} /*! Destructor */ @@ -44,7 +44,7 @@ namespace speckle::database { Get the speckle type identifier @return The speckle type (relevant objects should override as required, but "Base" is still considered a type on its own) */ - virtual speckle::utility::String getSpeckleType() const { return "Base"; } + virtual speckle::utility::String getSpeckleType() const { return "speckle::database::Record"; } // MARK: - Functions (mutating) diff --git a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h index 72035e2..1b56f13 100644 --- a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h +++ b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h @@ -1,15 +1,15 @@ #ifndef SPECKLE_PRIMITIVE_MESH #define SPECKLE_PRIMITIVE_MESH -#include "Active/Serialise/Package/Package.h" +#include "Speckle/Database/Content/Record.h" #include "Speckle/Utility/String.h" namespace speckle::primitive { /*! Class for a 3D mesh - */ - class Mesh : public active::serialise::Package { + */ + class Mesh : public speckle::database::Record { public: // MARK: - Constructors @@ -24,6 +24,11 @@ namespace speckle::primitive { // MARK: - Functions (const) + /*! + Get the speckle type identifier + @return The speckle type (relevant objects should override as required) + */ + speckle::utility::String getSpeckleType() const override { return "speckle::primitive::Mesh"; } // MARK: - Serialisation @@ -31,13 +36,13 @@ namespace speckle::primitive { Fill an inventory with the package items @param inventory The inventory to receive the package items @return True if the package has added items to the inventory - */ + */ bool fillInventory(active::serialise::Inventory& inventory) const override; /*! Get the specified cargo @param item The inventory item to retrieve @return The requested cargo (nullptr on failure) - */ + */ active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; private: diff --git a/SpeckleLib/Speckle/Record/Element/Element.h b/SpeckleLib/Speckle/Record/Element/Element.h index 59990f4..26b26f2 100644 --- a/SpeckleLib/Speckle/Record/Element/Element.h +++ b/SpeckleLib/Speckle/Record/Element/Element.h @@ -55,24 +55,29 @@ namespace speckle::record::element { ~Element(); /*! - Object cloning - @return A clone of this object - */ + Object cloning + @return A clone of this object + */ Element* clonePtr() const override { return new Element{*this}; } // MARK: - Functions (const) /*! - Get the element body - @return An array of meshes from the element body (nullptr if no body data is available) - */ + Get the speckle type identifier + @return The speckle type (relevant objects should override as required) + */ + speckle::utility::String getSpeckleType() const override { return "speckle::record::element::Element"; } + /*! + Get the element body + @return An array of meshes from the element body (nullptr if no body data is available) + */ virtual Body* getBody() const; #ifdef ARCHICAD /*! - Get the (immutable) API element header data - @return The element header data (only use this data for low-level operations - for normal code, call getters/setters) - */ + Get the (immutable) API element header data + @return The element header data (only use this data for low-level operations - for normal code, call getters/setters) + */ virtual const API_Elem_Head& getHead() const; #endif @@ -80,29 +85,29 @@ namespace speckle::record::element { #ifdef ARCHICAD /*! - Get the (mutable) API element header data - @return The element header data (only use this data for low-level operations - for normal code, call getters/setters) - */ + Get the (mutable) API element header data + @return The element header data (only use this data for low-level operations - for normal code, call getters/setters) + */ virtual API_Elem_Head& getHead(); #endif // MARK: - Serialisation /*! - Fill an inventory with the package items - @param inventory The inventory to receive the package items - @return True if the package has added items to the inventory - */ + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ bool fillInventory(active::serialise::Inventory& inventory) const override; /*! - Get the specified cargo - @param item The inventory item to retrieve - @return The requested cargo (nullptr on failure) - */ + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; /*! - Set to the default package content - */ + Set to the default package content + */ void setDefault() override; private: diff --git a/SpeckleLib/Speckle/Serialise/Units/LengthUnit.cpp b/SpeckleLib/Speckle/Serialise/Units/LengthUnit.cpp new file mode 100644 index 0000000..bc71613 --- /dev/null +++ b/SpeckleLib/Speckle/Serialise/Units/LengthUnit.cpp @@ -0,0 +1,55 @@ +#include "Speckle/Serialise/Units/LengthUnit.h" + +#include +#include + +using namespace active::measure; +using namespace active::utility; + +using enum LengthType; + +namespace { + + //All recognised encoding types + std::map lengthNames = { + { millimetre, "mm" }, + { centimetre, "cm" }, + { metre, "m" }, + { kilometre, "km" }, + { inch, "in" }, + { foot, "ft" }, + { yard, "yd" }, + { mile, "ml" }, + }; + +} // namespace + +/*-------------------------------------------------------------------- + Convert a length unit name to a type + + name: The length unit name + + return: The length unit type (nullopt if no match found) + --------------------------------------------------------------------*/ +std::optional speckle::serialise::lengthUnitFromName(const String& name) { + if (auto match = std::find_if(lengthNames.begin(), lengthNames.end(), [&](const auto& i){ return (i.second == name); }); + match != lengthNames.end()) { + return match->first; + } + return std::nullopt; +} //encodingFromName + + +/*-------------------------------------------------------------------- + Convert a length unit type to a name + + lengthType: The length unit type + + return: The name of the length unit type (nullopt if no match found) + --------------------------------------------------------------------*/ +std::optional speckle::serialise::nameFromLengthUnit(LengthType lengthType) { + if (auto match = lengthNames.find(lengthType); match != lengthNames.end()) { + return match->second; + } + return std::nullopt; +} //nameFromEncoding diff --git a/SpeckleLib/Speckle/Serialise/Units/LengthUnit.h b/SpeckleLib/Speckle/Serialise/Units/LengthUnit.h new file mode 100644 index 0000000..417e928 --- /dev/null +++ b/SpeckleLib/Speckle/Serialise/Units/LengthUnit.h @@ -0,0 +1,107 @@ +#ifndef SPECKLE_SERIALISE_LENGTH_UNIT +#define SPECKLE_SERIALISE_LENGTH_UNIT + +#include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Active/Serialise/Item/Wrapper/ValueOptionWrap.h" +#include "Active/Setting/Values/Measurement/Units/LengthUnit.h" + +namespace speckle::serialise { + + /*! + Convert a length unit name to a type + @param name The length unit name + @return The length unit type (nullopt if no match found) + */ + std::optional lengthUnitFromName(const active::utility::String& name); + + + /*! + Convert a length unit type to a name + @param lengthType The length unit type + @return The name of the length unit type (nullopt if no match found) + */ + std::optional nameFromLengthUnit(active::measure::LengthType lengthType); + +} + + +namespace active::serialise { + + // MARK: - Specialisations for length types + + /*! + Read a length type value from the specified string + @param source The string to read + @return True if the data was successfully read + */ + inline std::pair readLengthTypeRefValue(const utility::String& source) { + using enum active::measure::LengthType; + if (auto converted = speckle::serialise::lengthUnitFromName(source); converted) + return {*converted, true}; + return {metre, false}; + } //ValueWrap::read + + + /*! + Import the object from the specified string (specialisation for length type) + @param source The string to read + @return True if the data was successfully read + */ + template<> inline + bool ValueWrap::read(const utility::String& source) { + auto result = readLengthTypeRefValue(source); + if (result.second) + base::get() = result.first; + return result.second; + } //ValueWrap::read + + + /*! + Import the object from the specified string (specialisation for length type) + @param source The string to read + @return True if the data was successfully read + */ + template<> inline + bool ValueOptionWrap::read(const utility::String& source) { + auto result = readLengthTypeRefValue(source); + if (result.second) + base::get() = result.first; + return result.second; + } //ValueWrap::read + + + /*! + Export the object to the specified string (specialisation for length type) + @param dest The string to write the data to + @return True if the data was successfully written + */ + template<> inline + bool ValueWrap::write(utility::String& dest) const { + if (auto name = speckle::serialise::nameFromLengthUnit(base::get()); name) { + dest = *name; + return true; + } + return false; + } //ValueWrap::write + + + /*! + Export the object to the specified string (specialisation for length type) + @param dest The string to write the data to + @return True if the data was successfully written + */ + template<> inline + bool ValueOptionWrap::write(utility::String& dest) const { + if (!base::get()) + return false; + if (auto name = speckle::serialise::nameFromLengthUnit(*base::get()); name) { + dest = *name; + return true; + } + return false; + } //ValueOptionWrap::write + + +} + +#endif //SPECKLE_SERIALISE_LENGTH_UNIT diff --git a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj index d4d6ea1..d67b1b9 100644 --- a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj +++ b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj @@ -36,6 +36,7 @@ 2193519B2C6278D900E5A69C /* SelectionSubscriber.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219351992C6278D900E5A69C /* SelectionSubscriber.cpp */; }; 219351B12C62CC1A00E5A69C /* Guid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219351AC2C62CC1A00E5A69C /* Guid.cpp */; }; 219351B32C62CC1A00E5A69C /* String.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219351AE2C62CC1A00E5A69C /* String.cpp */; }; + 2196F2E32CB05BAF00450DFC /* LengthUnit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2196F2E22CB05BAF00450DFC /* LengthUnit.cpp */; }; 2199881E2BD833830035E5EA /* libArchicad27.a in CopyFiles */ = {isa = PBXBuildFile; fileRef = 21379E082AE47A6400A1584C /* libArchicad27.a */; }; 21AEF9BA2CA606B5000B8681 /* DetachedReference.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9B92CA606B4000B8681 /* DetachedReference.cpp */; }; 21AEF9BC2CA6DF84000B8681 /* DetachmentManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9BB2CA6DF84000B8681 /* DetachmentManager.cpp */; }; @@ -162,6 +163,8 @@ 219351AD2C62CC1A00E5A69C /* Guid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Guid.h; sourceTree = ""; }; 219351AE2C62CC1A00E5A69C /* String.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = String.cpp; sourceTree = ""; }; 219351AF2C62CC1A00E5A69C /* String.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = String.h; sourceTree = ""; }; + 2196F2DE2CB0566500450DFC /* LengthUnit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LengthUnit.h; sourceTree = ""; }; + 2196F2E22CB05BAF00450DFC /* LengthUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LengthUnit.cpp; sourceTree = ""; }; 219712682BE7E2D500D9EF7E /* Serialisation.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Serialisation.md; sourceTree = ""; }; 21AEF9B32CA5F7CF000B8681 /* DetachedWrap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedWrap.h; sourceTree = ""; }; 21AEF9B52CA5FA02000B8681 /* DetachedReference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedReference.h; sourceTree = ""; }; @@ -269,6 +272,7 @@ 2167E27C2C49121F000827D3 /* CMakeLists.txt */, 21AEF9C72CA818EA000B8681 /* Detached */, 21F69F3A2C6B880B008B6A06 /* JSBase */, + 2196F2DF2CB0566500450DFC /* Units */, 219712682BE7E2D500D9EF7E /* Serialisation.md */, ); path = Serialise; @@ -407,6 +411,15 @@ path = Utility; sourceTree = ""; }; + 2196F2DF2CB0566500450DFC /* Units */ = { + isa = PBXGroup; + children = ( + 2196F2E22CB05BAF00450DFC /* LengthUnit.cpp */, + 2196F2DE2CB0566500450DFC /* LengthUnit.h */, + ); + path = Units; + sourceTree = ""; + }; 219987FA2BD708BC0035E5EA /* SpeckleLibDoctest */ = { isa = PBXGroup; children = ( @@ -780,6 +793,7 @@ 21D0BDBD2C90F2830077E104 /* DocStoreSubscriber.cpp in Sources */, 21D0BDB32C8F8AB60077E104 /* DocumentStoreCore.cpp in Sources */, 219246082CA2ED2F00CF5703 /* ArchicadElementDBaseEngine.cpp in Sources */, + 2196F2E32CB05BAF00450DFC /* LengthUnit.cpp in Sources */, 21F93AEC2B2F406E009A2C5B /* Addon.cpp in Sources */, 215F087D2CA18E1400CD343B /* Element.cpp in Sources */, 21D0BD4E2C8901A00077E104 /* ServerInfo.cpp in Sources */, From b51b0ecb137b07e7f83115f8860242d3f143359e Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Fri, 4 Oct 2024 22:13:32 +0100 Subject: [PATCH 028/191] Mesh serialises with speckle_type and units - now appears in 3D view --- .../Speckle/Database/Content/BIMRecord.h | 7 ++++-- .../Speckle/Database/Content/Record.cpp | 2 +- SpeckleLib/Speckle/Database/Content/Record.h | 3 +-- SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp | 4 +-- SpeckleLib/Speckle/Primitive/Mesh/Mesh.h | 25 +++++++++++++------ SpeckleLib/SpeckleLib17.vcxproj | 2 ++ SpeckleLib/SpeckleLib17.vcxproj.filters | 9 +++++++ 7 files changed, 38 insertions(+), 14 deletions(-) diff --git a/SpeckleLib/Speckle/Database/Content/BIMRecord.h b/SpeckleLib/Speckle/Database/Content/BIMRecord.h index c9bee26..dcbc4c4 100644 --- a/SpeckleLib/Speckle/Database/Content/BIMRecord.h +++ b/SpeckleLib/Speckle/Database/Content/BIMRecord.h @@ -28,13 +28,16 @@ namespace speckle::database { /*! Default constructor + @param unit The recordc unit type */ - BIMRecord() : base{} {} + BIMRecord(active::measure::LengthType unit = active::measure::LengthType::metre) : base{}, m_unit{unit} {} /*! Constructor @param ID The record ID + @param unit The recordc unit type */ - BIMRecord(speckle::utility::Guid ID) : base{}, m_applicationID{ID} {} + BIMRecord(speckle::utility::Guid ID, active::measure::LengthType unit = active::measure::LengthType::metre) : + base{}, m_applicationID{ID}, m_unit{unit} {} /*! Destructor */ diff --git a/SpeckleLib/Speckle/Database/Content/Record.cpp b/SpeckleLib/Speckle/Database/Content/Record.cpp index e515c45..3df4c86 100644 --- a/SpeckleLib/Speckle/Database/Content/Record.cpp +++ b/SpeckleLib/Speckle/Database/Content/Record.cpp @@ -40,7 +40,7 @@ bool Record::fillInventory(active::serialise::Inventory& inventory) const { }.withType(&typeid(base))); inventory.merge(Inventory{ { - { Identity{fieldID[speckleTypeID]}, speckleTypeID, element, !m_type.operator bool() }, + { Identity{fieldID[speckleTypeID]}, speckleTypeID, element }, }, }.withType(&typeid(Record))); return true; diff --git a/SpeckleLib/Speckle/Database/Content/Record.h b/SpeckleLib/Speckle/Database/Content/Record.h index fa76191..ab22bd7 100644 --- a/SpeckleLib/Speckle/Database/Content/Record.h +++ b/SpeckleLib/Speckle/Database/Content/Record.h @@ -31,8 +31,7 @@ namespace speckle::database { @param globID The global ID */ Record(speckle::utility::String::Option ID = std::nullopt, speckle::utility::String::Option globID = std::nullopt) : - base{ID.value_or(active::utility::Guid{}.operator active::utility::String()), - globID.value_or(active::utility::Guid{}.operator active::utility::String())} {} + base{ID.value_or(speckle::utility::String{}), globID.value_or(speckle::utility::String{})} {} /*! Destructor */ diff --git a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp index a044d51..dfebf16 100644 --- a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp +++ b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp @@ -44,7 +44,7 @@ bool Mesh::fillInventory(Inventory& inventory) const { { fieldID[colorID], colorID, element }, }, }.withType(&typeid(Mesh))); - return true; + return base::fillInventory(inventory); } //Mesh::fillInventory @@ -57,7 +57,7 @@ bool Mesh::fillInventory(Inventory& inventory) const { --------------------------------------------------------------------*/ Cargo::Unique Mesh::getCargo(const Inventory::Item& item) const { if (item.ownerType != &typeid(Mesh)) - return nullptr; + return base::getCargo(item); using namespace active::serialise; switch (item.index) { case vertexID: diff --git a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h index 1b56f13..93f2788 100644 --- a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h +++ b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h @@ -1,7 +1,7 @@ #ifndef SPECKLE_PRIMITIVE_MESH #define SPECKLE_PRIMITIVE_MESH -#include "Speckle/Database/Content/Record.h" +#include "Speckle/Database/Content/BIMRecord.h" #include "Speckle/Utility/String.h" namespace speckle::primitive { @@ -9,18 +9,30 @@ namespace speckle::primitive { /*! Class for a 3D mesh */ - class Mesh : public speckle::database::Record { + class Mesh : public speckle::database::BIMRecord { public: + // MARK: - Types + + using base = speckle::database::BIMRecord; + // MARK: - Constructors /*! Default constructor + @param unit The mesh unit type */ - Mesh() {} - - Mesh(std::vector&& vertices, std::vector&& faces, std::vector&& colors, utility::String units = "m") - : vertices{ std::move(vertices) }, faces{ std::move(faces) }, colors{ std::move(colors) }, units{ units } {} + Mesh(active::measure::LengthType unit = active::measure::LengthType::metre) : base{unit} {} + /*! + Constructor + @param vertices The mesh vertices + @param faces The mesh faces (the number of indices in the face followed by the vertex indices) + @param colors The mesh face colours + @param unit The mesh unit type + */ + Mesh(std::vector&& vertices, std::vector&& faces, std::vector&& colors, + active::measure::LengthType unit = active::measure::LengthType::metre) : + base{unit}, vertices {std::move(vertices)}, faces{std::move(faces)}, colors{std::move(colors)} {} // MARK: - Functions (const) @@ -49,7 +61,6 @@ namespace speckle::primitive { std::vector vertices; std::vector faces; std::vector colors; - utility::String units; }; } diff --git a/SpeckleLib/SpeckleLib17.vcxproj b/SpeckleLib/SpeckleLib17.vcxproj index ebc0063..836d23b 100644 --- a/SpeckleLib/SpeckleLib17.vcxproj +++ b/SpeckleLib/SpeckleLib17.vcxproj @@ -73,6 +73,7 @@ + @@ -114,6 +115,7 @@ + diff --git a/SpeckleLib/SpeckleLib17.vcxproj.filters b/SpeckleLib/SpeckleLib17.vcxproj.filters index 8f90a7c..65f51b4 100644 --- a/SpeckleLib/SpeckleLib17.vcxproj.filters +++ b/SpeckleLib/SpeckleLib17.vcxproj.filters @@ -83,6 +83,9 @@ {cb77e795-e8d8-4e31-9773-dd32beb694d3} + + {7d5ec9ba-bc7e-412c-9b14-16c37b183409} + @@ -265,6 +268,9 @@ Speckle\Serialise\Detached\Storage + + Speckle\Serialise\Units + @@ -375,6 +381,9 @@ Speckle\Serialise\Detached + + Speckle\Serialise\Units + From b5447b263e680b22fb2d24ceb0fbc926a34ca728 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Thu, 10 Oct 2024 08:52:18 +0100 Subject: [PATCH 029/191] NB: Interim commit - new code is untested at this point Information sent to Speckle is now presented in hiearchical collections: - Root level contains material proxies - Second level is project storeys - Third level is element type Added database and record definitions for attributes including: - Finishes (surface rendering material) - Storeys Element getters for storey and type name Aligned some speckle_type names to Revit (where possible) --- .../Connector.xcodeproj/project.pbxproj | 18 +- .../Connector/ConnectorResource.h | 1 + .../Interface/Browser/Bridge/Send/Send.cpp | 29 +- .../Record/Collection/FinishProxy.cpp | 66 ++++ .../Connector/Record/Collection/FinishProxy.h | 50 ++++ .../Record/Collection/ProjectCollection.cpp | 142 +++++++++ .../Record/Collection/ProjectCollection.h | 88 ++++++ .../Record/Collection/RecordCollection.cpp | 85 ++++-- .../Record/Collection/RecordCollection.h | 87 ++++-- .../Record/Collection/RootCollection.cpp | 34 --- .../Record/Collection/RootCollection.h | 52 ---- SpeckleConnector/RINT/Connector.grc | 1 + SpeckleLib/RINT/Speckle.grc | 1 + .../Speckle/Database/BIMAttributeDatabase.cpp | 143 +++++++++ .../Speckle/Database/BIMAttributeDatabase.h | 95 ++++++ .../Speckle/Database/BIMElementDatabase.h | 6 +- .../Speckle/Database/Content/BIMRecord.h | 27 +- SpeckleLib/Speckle/Database/Content/Record.h | 16 +- .../Speckle/Database/Identity/BIMIndex.h | 25 +- .../Speckle/Database/Identity/BIMLink.cpp | 3 +- .../Speckle/Database/Identity/BIMLink.h | 3 +- .../ArchicadAttributeDBaseEngine.cpp | 282 ++++++++++++++++++ .../Attribute/ArchicadAttributeDBaseEngine.h | 142 +++++++++ .../Element/ArchicadElementDBaseEngine.cpp | 46 +-- .../Element/ArchicadElementDBaseEngine.h | 8 + SpeckleLib/Speckle/Environment/Project.cpp | 2 + SpeckleLib/Speckle/Environment/Project.h | 9 + .../Event/Subscriber/SelectionSubscriber.cpp | 7 +- .../Speckle/Record/Attribute/Attribute.cpp | 103 +++++++ .../Speckle/Record/Attribute/Attribute.h | 120 ++++++++ .../Speckle/Record/Attribute/Finish.cpp | 164 ++++++++++ SpeckleLib/Speckle/Record/Attribute/Finish.h | 128 ++++++++ .../Speckle/Record/Attribute/Storey.cpp | 192 ++++++++++++ SpeckleLib/Speckle/Record/Attribute/Storey.h | 129 ++++++++ SpeckleLib/Speckle/Record/Element/Element.cpp | 47 ++- SpeckleLib/Speckle/Record/Element/Element.h | 16 +- SpeckleLib/Speckle/SpeckleResource.h | 1 + .../SpeckleLib.xcodeproj/project.pbxproj | 56 ++++ 38 files changed, 2214 insertions(+), 210 deletions(-) create mode 100644 SpeckleConnector/Connector/Record/Collection/FinishProxy.cpp create mode 100644 SpeckleConnector/Connector/Record/Collection/FinishProxy.h create mode 100644 SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp create mode 100644 SpeckleConnector/Connector/Record/Collection/ProjectCollection.h delete mode 100644 SpeckleConnector/Connector/Record/Collection/RootCollection.cpp delete mode 100644 SpeckleConnector/Connector/Record/Collection/RootCollection.h create mode 100644 SpeckleLib/Speckle/Database/BIMAttributeDatabase.cpp create mode 100644 SpeckleLib/Speckle/Database/BIMAttributeDatabase.h create mode 100644 SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.cpp create mode 100644 SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.h create mode 100644 SpeckleLib/Speckle/Record/Attribute/Attribute.cpp create mode 100644 SpeckleLib/Speckle/Record/Attribute/Attribute.h create mode 100644 SpeckleLib/Speckle/Record/Attribute/Finish.cpp create mode 100644 SpeckleLib/Speckle/Record/Attribute/Finish.h create mode 100644 SpeckleLib/Speckle/Record/Attribute/Storey.cpp create mode 100644 SpeckleLib/Speckle/Record/Attribute/Storey.h diff --git a/SpeckleConnector/Connector.xcodeproj/project.pbxproj b/SpeckleConnector/Connector.xcodeproj/project.pbxproj index 74a280d..fc6c93a 100644 --- a/SpeckleConnector/Connector.xcodeproj/project.pbxproj +++ b/SpeckleConnector/Connector.xcodeproj/project.pbxproj @@ -29,8 +29,9 @@ 215F082E2C94C5C000CD343B /* FilterMover.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 215F082C2C94C5C000CD343B /* FilterMover.cpp */; }; 215F08372C95808B00CD343B /* ReceiverModelCard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 215F08362C95808B00CD343B /* ReceiverModelCard.cpp */; }; 215F08462C9633A800CD343B /* EverythingSendFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 215F08452C9633A800CD343B /* EverythingSendFilter.cpp */; }; - 2192460D2CA3469D00CF5703 /* RootCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2192460B2CA3469D00CF5703 /* RootCollection.cpp */; }; + 2192460D2CA3469D00CF5703 /* ProjectCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2192460B2CA3469D00CF5703 /* ProjectCollection.cpp */; }; 219F30422C769283009834E9 /* ConfigTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219F30402C769282009834E9 /* ConfigTests.cpp */; }; + 21A0FB982CB723240023F24E /* FinishProxy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21A0FB942CB723240023F24E /* FinishProxy.cpp */; }; 21AEF9EB2CAB56E5000B8681 /* SendError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9E32CAB56E5000B8681 /* SendError.cpp */; }; 21AEF9EC2CAB56E5000B8681 /* SendViaBrowserArgs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9E52CAB56E5000B8681 /* SendViaBrowserArgs.cpp */; }; 21AEF9EF2CAB5720000B8681 /* SendObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9EE2CAB5720000B8681 /* SendObject.cpp */; }; @@ -305,12 +306,14 @@ 215F08452C9633A800CD343B /* EverythingSendFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EverythingSendFilter.cpp; sourceTree = ""; }; 215F084A2C9782F100CD343B /* ArchicadEverythingFilter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ArchicadEverythingFilter.h; sourceTree = ""; }; 2161FD902BF2600C006D9527 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; - 2192460B2CA3469D00CF5703 /* RootCollection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RootCollection.cpp; sourceTree = ""; }; - 2192460C2CA3469D00CF5703 /* RootCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RootCollection.h; sourceTree = ""; }; + 2192460B2CA3469D00CF5703 /* ProjectCollection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProjectCollection.cpp; sourceTree = ""; }; + 2192460C2CA3469D00CF5703 /* ProjectCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProjectCollection.h; sourceTree = ""; }; 219388682C4E5DE2002A0180 /* CMakeLists.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; 219F30352C768F0A009834E9 /* Connector-AC27-Test.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Connector-AC27-Test.bundle"; sourceTree = BUILT_PRODUCTS_DIR; }; 219F30402C769282009834E9 /* ConfigTests.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = ConfigTests.cpp; sourceTree = ""; }; 219F30432C7693B6009834E9 /* Connector-AC27-Debug.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Connector-AC27-Debug.xctestplan"; sourceTree = SOURCE_ROOT; }; + 21A0FB942CB723240023F24E /* FinishProxy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FinishProxy.cpp; sourceTree = ""; }; + 21A0FB972CB723240023F24E /* FinishProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FinishProxy.h; sourceTree = ""; }; 21AEF9E32CAB56E5000B8681 /* SendError.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SendError.cpp; sourceTree = ""; }; 21AEF9E42CAB56E5000B8681 /* SendError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SendError.h; sourceTree = ""; }; 21AEF9E52CAB56E5000B8681 /* SendViaBrowserArgs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SendViaBrowserArgs.cpp; sourceTree = ""; }; @@ -1231,10 +1234,12 @@ 21FF70482CA1A7F400AAD99A /* Collection */ = { isa = PBXGroup; children = ( + 21A0FB942CB723240023F24E /* FinishProxy.cpp */, + 21A0FB972CB723240023F24E /* FinishProxy.h */, 21FF70462CA1A7F400AAD99A /* RecordCollection.cpp */, 21FF70472CA1A7F400AAD99A /* RecordCollection.h */, - 2192460B2CA3469D00CF5703 /* RootCollection.cpp */, - 2192460C2CA3469D00CF5703 /* RootCollection.h */, + 2192460B2CA3469D00CF5703 /* ProjectCollection.cpp */, + 2192460C2CA3469D00CF5703 /* ProjectCollection.h */, ); path = Collection; sourceTree = ""; @@ -1456,11 +1461,12 @@ 21B67CF72C78D4DE00FD64FC /* GetComplexType.cpp in Sources */, 21D0BDDC2C93897B0077E104 /* SenderModelCard.cpp in Sources */, 21B67CAE2C77329800FD64FC /* GetSourceApplicationVersion.cpp in Sources */, + 21A0FB982CB723240023F24E /* FinishProxy.cpp in Sources */, 21B67CC32C77649F00FD64FC /* GetDocumentState.cpp in Sources */, 21D0BD602C89BFEA0077E104 /* SendBridge.cpp in Sources */, 21D0BD972C8F13F30077E104 /* GetSendFilters.cpp in Sources */, 21B67CAC2C77329800FD64FC /* BaseBridge.cpp in Sources */, - 2192460D2CA3469D00CF5703 /* RootCollection.cpp in Sources */, + 2192460D2CA3469D00CF5703 /* ProjectCollection.cpp in Sources */, 21D0BD6A2C8A0DB40077E104 /* GetIsDevMode.cpp in Sources */, 210CC8832C80E6A300610F58 /* TriggerEvent.cpp in Sources */, 21B67CEB2C78D27200FD64FC /* DocumentInfo.cpp in Sources */, diff --git a/SpeckleConnector/Connector/ConnectorResource.h b/SpeckleConnector/Connector/ConnectorResource.h index daec179..dbf6b2c 100755 --- a/SpeckleConnector/Connector/ConnectorResource.h +++ b/SpeckleConnector/Connector/ConnectorResource.h @@ -28,6 +28,7 @@ enum StringResource { enum TitleString { addonNameID = 1, addonDescriptionID, + noStoreyID, }; diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp index 8cd4e53..279fd23 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp @@ -7,6 +7,7 @@ #include "Connector/Database/ModelCardDatabase.h" #include "Connector/Interface/Browser/Bridge/Send/Arg/SendError.h" #include "Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h" +#include "Connector/Record/Collection/ProjectCollection.h" #include "Speckle/Database/AccountDatabase.h" #include "Speckle/Database/Content/BIMRecord.h" #include "Speckle/Interface/Browser/Bridge/BrowserBridge.h" @@ -23,6 +24,7 @@ using namespace speckle::record::element; using namespace active::serialise; using namespace connector::interfac::browser::bridge; +using namespace connector::record; using namespace speckle::database; using namespace speckle::serialise; using namespace speckle::utility; @@ -68,27 +70,20 @@ void Send::run(const String& modelCardID) const { std::make_unique(connector()->getLocalString(errorString, noProjectOpenID), modelCardID)); return; } - //Collect targeted elements here - - - //NB: This is a testing placeholder - - Element::Unique element; - if (auto project = connector::connector()->getActiveProject().lock(); project) { - auto elementDatabase = project->getElementDatabase(); - auto selected = elementDatabase->getSelection(); - for (const auto& link : selected) - if (element = elementDatabase->getElement(link); element) - break; - } - if (!element) { + //Build a collection from the selected elements + auto collection = std::make_unique(project); + auto elementDatabase = project->getElementDatabase(); + auto selected = elementDatabase->getSelection(); + if (selected.empty()) { getBridge()->sendEvent("setModelError", std::make_unique(connector()->getLocalString(errorString, noSelectedModelItemsID), modelCardID)); return; } - - + for (const auto& link : selected) { + if (auto element = elementDatabase->getElement(link); element) + collection->addElement(*element); + } //Send the collected information - auto result = std::make_unique(*modelCard, *account, SendObject{std::move(element)}); //NB: Using a placeholder object for now + auto result = std::make_unique(*modelCard, *account, SendObject{std::move(collection)}); getBridge()->sendEvent("sendByBrowser", std::move(result)); } //Send::run diff --git a/SpeckleConnector/Connector/Record/Collection/FinishProxy.cpp b/SpeckleConnector/Connector/Record/Collection/FinishProxy.cpp new file mode 100644 index 0000000..a4643fc --- /dev/null +++ b/SpeckleConnector/Connector/Record/Collection/FinishProxy.cpp @@ -0,0 +1,66 @@ +#include "Connector/Record/Collection/FinishProxy.h" + +#include "Active/Serialise/Package/Wrapper/ContainerWrap.h" +#include "Active/Serialise/Package/Wrapper/PackageWrap.h" + +#include + +using namespace active::serialise; +using namespace connector::record; +using namespace speckle::utility; + +namespace { + + ///Serialisation fields + enum FieldIndex { + materialID, + linkedMeshID, + }; + + ///Serialisation field IDs + static std::array fieldID = { + Identity{"value"}, + Identity{"objects"}, + }; + +} + +/*-------------------------------------------------------------------- + Fill an inventory with the package items + + inventory: The inventory to receive the package items + + return: True if the package has added items to the inventory + --------------------------------------------------------------------*/ +bool FinishProxy::fillInventory(active::serialise::Inventory& inventory) const { + using enum Entry::Type; + inventory.merge(Inventory{ + { + { fieldID[materialID], materialID, element }, + { fieldID[linkedMeshID], linkedMeshID, m_meshID.size(), std::nullopt }, + }, + }.withType(&typeid(FinishProxy))); + return true; +} //FinishProxy::fillInventory + + +/*-------------------------------------------------------------------- + Get the specified cargo + + item: The inventory item to retrieve + + return: The requested cargo (nullptr on failure) + --------------------------------------------------------------------*/ +Cargo::Unique FinishProxy::getCargo(const active::serialise::Inventory::Item& item) const { + if (item.ownerType != &typeid(FinishProxy)) + return nullptr; + using namespace active::serialise; + switch (item.index) { + case materialID: + return std::make_unique(m_finish); + case linkedMeshID: + return std::make_unique>>(m_meshID); + default: + return nullptr; //Requested an unknown index + } +} //FinishProxy::getCargo diff --git a/SpeckleConnector/Connector/Record/Collection/FinishProxy.h b/SpeckleConnector/Connector/Record/Collection/FinishProxy.h new file mode 100644 index 0000000..19fba4a --- /dev/null +++ b/SpeckleConnector/Connector/Record/Collection/FinishProxy.h @@ -0,0 +1,50 @@ +#ifndef CONNECTOR_RECORD_COLLECTION_MATERIAL_PROXY +#define CONNECTOR_RECORD_COLLECTION_MATERIAL_PROXY + +#include "Active/Serialise/Package/Package.h" +#include "Speckle/Record/Attribute/Finish.h" +#include "Speckle/Utility/String.h" + +namespace connector::record { + + /*! + A proxy record binding a surface finishes to meshes + */ + class FinishProxy : public active::serialise::Package { + public: + + // MARK: - Constructors + + /*! + Constructor + @param finish The proxy surface finish + @param meshID The list of mesh IDs the finish is applied to + */ + FinishProxy(const speckle::record::attribute::Finish& finish, const std::unordered_set& meshID) : + m_finish{finish} { std::copy(meshID.begin(), meshID.end(), std::back_inserter(m_meshID)); } + + // MARK: - Serialisation + + /*! + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ + bool fillInventory(active::serialise::Inventory& inventory) const override; + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + + private: + ///The proxy surface finish + speckle::record::attribute::Finish m_finish; + ///The list of mesh IDs the finish is applied to + std::vector m_meshID; + }; + +} + +#endif //CONNECTOR_RECORD_COLLECTION_MATERIAL_PROXY diff --git a/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp new file mode 100644 index 0000000..368c3a9 --- /dev/null +++ b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp @@ -0,0 +1,142 @@ +#include "Connector/Record/Collection/ProjectCollection.h" + +#include "Active/Serialise/CargoHold.h" +#include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Active/Serialise/Package/Wrapper/PackageWrap.h" +#include "Connector/Connector.h" +#include "Connector/ConnectorResource.h" +#include "Connector/Record/Collection/FinishProxy.h" +#include "Speckle/Database/BIMAttributeDatabase.h" +#include "Speckle/Database/BIMElementDatabase.h" +#include "Speckle/Record/Element/Element.h" + +using namespace active::serialise; +using namespace connector::record; +using namespace speckle::database; +using namespace speckle::record::attribute; +using namespace speckle::utility; + +namespace { + + ///Serialisation fields + enum FieldIndex { + finishProxyID, + }; + + ///Serialisation field IDs + static std::array fieldID = { + Identity{"renderMaterialProxies"}, + }; + + using WrappedProxy = CargoHold; + +} + +/*-------------------------------------------------------------------- + Add an element to the collection hierarchy + + index The index of the element to add + + return: True if the element was added (false typically means the element already exists) + --------------------------------------------------------------------*/ +bool ProjectCollection::addElement(const speckle::database::BIMIndex& index) { + //Lookup the element in the element database of the active project + auto elementDbase = m_project->getElementDatabase(); + if (elementDbase == nullptr) + return false; + if (auto element = elementDbase->getElement(index); element) { + addElement(*element); //Add the element to the collection hierarchy + return true; + } + return false; +} //ProjectCollection::addElement + + +/*-------------------------------------------------------------------- + Add an element to the collection hierarchy + + element: The element to add + + return: True if the element was added (false typically means the element already exists) + --------------------------------------------------------------------*/ +bool ProjectCollection::addElement(const speckle::record::element::Element& element) { + std::vector collectionNames; + //The first collection hierarchy level is the element storey/level + auto storey = element.getStorey(); + collectionNames.emplace_back(storey ? storey->getName() : connector()->getLocalString(titleString, noStoreyID)); + //The next level is the name of the element type + collectionNames.emplace_back(element.getTypeName()); + //Add any future levels here as required + RecordCollection* collection = this; + for (const auto& childName : collectionNames) + collection = collection->getChild(childName); + return collection->addIndex(BIMIndex{element.getBIMID(), element.getTableID()}); +} //ProjectCollection::addElement + + +/*-------------------------------------------------------------------- + Add a material proxy record to the collection + + materialIndex: The index of the material to add + objectID: The object the material is applied to + + return: True if the material proxy was added (false typically means the record already exists) + --------------------------------------------------------------------*/ +bool ProjectCollection::addMaterialProxy(const speckle::database::BIMIndex& materialIndex, const speckle::database::BIMRecordID& objectID) { + auto iter = m_finishProxies.find(materialIndex); + if (iter == m_finishProxies.end()) + iter = m_finishProxies.insert({materialIndex, {}}).first; + return iter->second.insert(objectID).second; +} //ProjectCollection::addMaterialProxy + + +/*-------------------------------------------------------------------- + Fill an inventory with the package items + + inventory: The inventory to receive the package items + + return: True if the package has added items to the inventory + --------------------------------------------------------------------*/ +bool ProjectCollection::fillInventory(active::serialise::Inventory& inventory) const { + using enum Entry::Type; + base::fillInventory(inventory); + inventory.merge(Inventory{ + { + { Identity{fieldID[finishProxyID]}, finishProxyID, m_finishProxies.size(), std::nullopt }, + }, + }.withType(&typeid(ProjectCollection))); + return true; +} //ProjectCollection::fillInventory + + +/*-------------------------------------------------------------------- + Get the specified cargo + + item: The inventory item to retrieve + + return: The requested cargo (nullptr on failure) + --------------------------------------------------------------------*/ +Cargo::Unique ProjectCollection::getCargo(const Inventory::Item& item) const { + if (item.ownerType != &typeid(ProjectCollection)) + return base::getCargo(item); + using namespace active::serialise; + //TODO: This is only currently coded to write collection content - reading can be added as required in future + switch (item.index) { + case finishProxyID: { + if (item.available < m_finishProxies.size()) { + auto iter = m_finishProxies.begin(); + std::advance(iter, item.available); + if (auto attribute = m_project->getAttributeDatabase()->getAttribute(iter->first, iter->first.tableID); attribute) { + if (auto finish = dynamic_cast(attribute.get()); finish != nullptr) { + auto proxy = std::make_unique(*finish, iter->second); + return std::make_unique(std::move(proxy)); + } + } + } + break; + } + default: + break; + } + return nullptr; //Requested an unknown index +} //ProjectCollection::getCargo diff --git a/SpeckleConnector/Connector/Record/Collection/ProjectCollection.h b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.h new file mode 100644 index 0000000..33b8931 --- /dev/null +++ b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.h @@ -0,0 +1,88 @@ +#ifndef CONNECTOR_RECORD_ROOT_COLLECTiON +#define CONNECTOR_RECORD_ROOT_COLLECTiON + +#include "Connector/Record/Collection/RecordCollection.h" + +#include + +namespace speckle::record::element { + class Element; +} + +namespace connector::record { + + /*! + Root collection for sending a project model to a Speckle server + + Additional information is anticipated at the root level that will not apply at any other level in the container hierarchy, e.g.: + - Classification hierarchy + - Layers + - Other attributes, e.g. materials + Add all this supplementary data to the root container as required + */ + class ProjectCollection : public RecordCollection { + public: + + // MARK: - Types + + using base = RecordCollection; + + // MARK: - Constructors + + /*! + Constructor + @param project The source project + */ + ProjectCollection(speckle::environment::Project::Shared project) : base{project->getInfo().name, project} {} + + using base::base; + + // MARK: - Functions (const) + + // MARK: - Functions (mutating) + + /*! + Add an element to the collection hierarchy + @param index The index of the element to add + @return True if the element was added (false typically means the element already exists) + */ + bool addElement(const speckle::database::BIMIndex& index); + /*! + Add an element to the collection hierarchy + @param element The element to add + @return True if the element was added (false typically means the element already exists) + */ + bool addElement(const speckle::record::element::Element& element); + /*! + Add a material proxy record to the collection + @param materialIndex The index of the material to add + @param objectID The object the material is applied to + @return True if the material proxy was added (false typically means the record already exists) + */ + bool addMaterialProxy(const speckle::database::BIMIndex& materialIndex, const speckle::database::BIMRecordID& objectID); + + // MARK: - Serialisation + + /*! + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ + bool fillInventory(active::serialise::Inventory& inventory) const override; + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + + private: + using FinishProxies = std::unordered_map>; + + ///Finish proxies accumulated from meshes generated from the collection elements + FinishProxies m_finishProxies; + }; + +} + +#endif //CONNECTOR_RECORD_ROOT_COLLECTiON diff --git a/SpeckleConnector/Connector/Record/Collection/RecordCollection.cpp b/SpeckleConnector/Connector/Record/Collection/RecordCollection.cpp index a6f0d5e..dcbbf51 100644 --- a/SpeckleConnector/Connector/Record/Collection/RecordCollection.cpp +++ b/SpeckleConnector/Connector/Record/Collection/RecordCollection.cpp @@ -1,11 +1,15 @@ #include "Connector/Record/Collection/RecordCollection.h" +#include "Active/Serialise/CargoHold.h" #include "Active/Serialise/Item/Wrapper/ValueWrap.h" #include "Active/Serialise/Package/Wrapper/PackageWrap.h" +#include "Speckle/Database/BIMElementDatabase.h" using namespace active::serialise; using namespace connector::record; using namespace speckle::database; +using namespace speckle::environment; +using namespace speckle::record::element; using namespace speckle::utility; #include @@ -14,20 +18,55 @@ namespace { ///Serialisation fields enum FieldIndex { - nameID, elementID, - childrenID, }; ///Serialisation field IDs static std::array fieldID = { - Identity{"name"}, - Identity{"element"}, - Identity{"child"}, + Identity{"elements"}, }; + using WrappedElement = CargoHold; + } +/*-------------------------------------------------------------------- + Constructor + + name: The collection name + project: The source project + --------------------------------------------------------------------*/ +RecordCollection::RecordCollection(const speckle::utility::String& name, Project::Shared project) : m_name{name}, m_project{project} { +} //RecordCollection::RecordCollection + + +/*-------------------------------------------------------------------- + Get a child collection by name (adding if missing) + + name: The child name + + return: A pointer to the requested child (nullptr on failure, caller does not take ownership) + --------------------------------------------------------------------*/ +RecordCollection* RecordCollection::getChild(const speckle::utility::String& name) { + //Return an existing child if possible + if (auto iter = m_children.find(name); iter != m_children.end()) + return &iter->second; + //Otherwise insert and return a new collection with the requested name + return &m_children.insert({name, RecordCollection{name, m_project}}).first->second; +} //RecordCollection::getChild + + +/*-------------------------------------------------------------------- + Add an index to the collection + + index: The index to add + + return: True if the index was added (false typically means the index already exists) + --------------------------------------------------------------------*/ +bool RecordCollection::addIndex(const speckle::database::BIMIndex& index) { + return m_indices.insert(index).second; +} //RecordCollection::addIndex + /*-------------------------------------------------------------------- Fill an inventory with the package items @@ -36,13 +75,12 @@ namespace { return: True if the package has added items to the inventory --------------------------------------------------------------------*/ -bool RecordCollection::fillInventory(Inventory& inventory) const { +bool RecordCollection::fillInventory(active::serialise::Inventory& inventory) const { using enum Entry::Type; + base::fillInventory(inventory); inventory.merge(Inventory{ { - { fieldID[nameID], nameID, element }, - { fieldID[elementID], elementID, base::size(), std::nullopt, !base::empty() }, - { fieldID[childrenID], childrenID, m_children.size(), std::nullopt, !m_children.empty() }, + { Identity{fieldID[elementID]}, elementID, m_children.size() + m_indices.size(), std::nullopt }, }, }.withType(&typeid(RecordCollection))); return true; @@ -58,18 +96,27 @@ bool RecordCollection::fillInventory(Inventory& inventory) const { --------------------------------------------------------------------*/ Cargo::Unique RecordCollection::getCargo(const Inventory::Item& item) const { if (item.ownerType != &typeid(RecordCollection)) - return nullptr; + return base::getCargo(item); using namespace active::serialise; + //TODO: This is only currently coded to write collection content - reading can be added as required in future switch (item.index) { - case nameID: - return std::make_unique(m_name); - case elementID: - return nullptr; //TODO: Implement - need to interrogate BIM database for element and return as cargo - case childrenID: - if (item.available < m_children.size()) - return std::make_unique(m_children[item.available]); - return nullptr; + case elementID: { + if (item.available < m_children.size()) { + auto iter = m_children.begin(); + std::advance(iter, item.available); + return std::make_unique(iter->second); + } + auto index = item.available - m_children.size(); + if (index < m_indices.size()) { + auto iter = m_indices.begin(); + std::advance(iter, index); + if (auto element = m_project->getElementDatabase()->getElement(*iter, iter->tableID); element) + return std::make_unique(std::move(element)); + } + break; + } default: - return nullptr; //Requested an unknown index + break; } + return nullptr; //Requested an unknown index } //RecordCollection::getCargo diff --git a/SpeckleConnector/Connector/Record/Collection/RecordCollection.h b/SpeckleConnector/Connector/Record/Collection/RecordCollection.h index 0d19b33..b7be102 100644 --- a/SpeckleConnector/Connector/Record/Collection/RecordCollection.h +++ b/SpeckleConnector/Connector/Record/Collection/RecordCollection.h @@ -1,13 +1,18 @@ #ifndef CONNECTOR_RECORD_RECORD_COLLECTiON #define CONNECTOR_RECORD_RECORD_COLLECTiON -#include "Active/Container/Vector.h" -#include "Active/Serialise/Package/Package.h" -#include "Speckle/Database/Identity/RecordID.h" +#include "Speckle/Database/Content/Record.h" +#include "Speckle/Database/Identity/BIMIndex.h" +#include "Speckle/Environment/Project.h" #include "Speckle/Utility/String.h" +#include +#include + namespace connector::record { + class ProjectCollection; + /*! Container for a collection of elements (and potentially tables of associated attributes) for Speckle commits @@ -26,43 +31,34 @@ namespace connector::record { Note that the serialisation is currently implemented for sending only. Receive can be added as required */ - class RecordCollection : public std::vector, public active::serialise::Package { + class RecordCollection : public speckle::database::Record { public: - // MARK: - Types - - using base = std::vector; - using Children = std::vector; - // MARK: - Constructors - using base::base; + /*! + Destructor + */ + ~RecordCollection() {} // MARK: - Functions (const) + /*! + Get the speckle type identifier + @return The speckle type (relevant objects should override as required, but "Base" is still considered a type on its own) + */ + speckle::utility::String getSpeckleType() const override { return "Speckle.Core.Models.Collections.Collection"; } /*! Get the container name @return The container name */ const speckle::utility::String& getName() const { return m_name; } /*! - Get the child collections - @return The child collections nested under this collection + Find a child by name + @param name The required child name + @return A pointer to the requested child (nullptr if not found) */ - const Children& getChildren() const; - - // MARK: - Functions (mutating) - - /*! - Set the container name - @param name The container name - */ - void setName(const speckle::utility::String& name) { m_name = name; } - /*! - Add a child collection - @param child The child collection to add - */ - void addChild(RecordCollection&& child); + RecordCollection* findChild(const speckle::utility::String& name) const; // MARK: - Serialisation @@ -70,20 +66,51 @@ namespace connector::record { Fill an inventory with the package items @param inventory The inventory to receive the package items @return True if the package has added items to the inventory - */ + */ bool fillInventory(active::serialise::Inventory& inventory) const override; /*! Get the specified cargo @param item The inventory item to retrieve @return The requested cargo (nullptr on failure) - */ + */ active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; private: - ///Child nodes of this collection - Children m_children; + friend ProjectCollection; + + // MARK: - Types + + using Indices = std::unordered_set; + using Children = std::unordered_map; + + /*! + Constructor + @param name The collection name + @param project The source project + */ + RecordCollection(const speckle::utility::String& name, speckle::environment::Project::Shared project); + + /*! + Get a child collection by name (adding if missing) + @param name The child name + @return A pointer to the requested child (nullptr on failure, caller does not take ownership) + */ + RecordCollection* getChild(const speckle::utility::String& name); + /*! + Add an index to the collection + @param index The index to add + @return True if the index was added (false typically means the index already exists) + */ + bool addIndex(const speckle::database::BIMIndex& index); + + ///The source project for the collection + speckle::environment::Project::Shared m_project; ///The collection name speckle::utility::String m_name; + ///Child nodes of this collection + Children m_children; + ///Indices of records in this collection + Indices m_indices; }; } diff --git a/SpeckleConnector/Connector/Record/Collection/RootCollection.cpp b/SpeckleConnector/Connector/Record/Collection/RootCollection.cpp deleted file mode 100644 index 90be329..0000000 --- a/SpeckleConnector/Connector/Record/Collection/RootCollection.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "Connector/Record/Collection/RootCollection.h" - -#include "Active/Serialise/Item/Wrapper/ValueWrap.h" -#include "Active/Serialise/Package/Wrapper/PackageWrap.h" - -using namespace active::serialise; -using namespace connector::record; -using namespace speckle::database; -using namespace speckle::utility; - -/*-------------------------------------------------------------------- - Fill an inventory with the package items - - inventory: The inventory to receive the package items - - return: True if the package has added items to the inventory - --------------------------------------------------------------------*/ -bool RootCollection::fillInventory(Inventory& inventory) const { - //Extend with supplementary data as required - return base::fillInventory(inventory); -} //RootCollection::fillInventory - - -/*-------------------------------------------------------------------- - Get the specified cargo - - item: The inventory item to retrieve - - return: The requested cargo (nullptr on failure) - --------------------------------------------------------------------*/ -Cargo::Unique RootCollection::getCargo(const Inventory::Item& item) const { - //Extend with supplementary data as required - return base::getCargo(item); -} //RootCollection::getCargo diff --git a/SpeckleConnector/Connector/Record/Collection/RootCollection.h b/SpeckleConnector/Connector/Record/Collection/RootCollection.h deleted file mode 100644 index f12a5b0..0000000 --- a/SpeckleConnector/Connector/Record/Collection/RootCollection.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef CONNECTOR_RECORD_ROOT_COLLECTiON -#define CONNECTOR_RECORD_ROOT_COLLECTiON - -#include "Connector/Record/Collection/RecordCollection.h" - -namespace connector::record { - - /*! - Root container for sending model data to a Speckle server - - Additional information is anticipated at the root level that will not apply at any other level in the container hierarchy, e.g.: - - Classification hierarchy - - Layers - - Other attributes, e.g. materials - Add all this supplementary data to the root container as required - */ - class RootCollection : public RecordCollection { - public: - - // MARK: - Types - - using base = RecordCollection; - - // MARK: - Constructors - - using base::base; - - // MARK: - Functions (const) - - - // MARK: - Functions (mutating) - - - // MARK: - Serialisation - - /*! - Fill an inventory with the package items - @param inventory The inventory to receive the package items - @return True if the package has added items to the inventory - */ - bool fillInventory(active::serialise::Inventory& inventory) const override; - /*! - Get the specified cargo - @param item The inventory item to retrieve - @return The requested cargo (nullptr on failure) - */ - active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; - }; - -} - -#endif //CONNECTOR_RECORD_ROOT_COLLECTiON diff --git a/SpeckleConnector/RINT/Connector.grc b/SpeckleConnector/RINT/Connector.grc index c1e3741..cfc3237 100644 --- a/SpeckleConnector/RINT/Connector.grc +++ b/SpeckleConnector/RINT/Connector.grc @@ -1,6 +1,7 @@ 'STR#' 32600 "Title strings" { /* [ 1] */ "Speckle Connector" /* [ 2] */ "Connector to share model content with Speckle" +/* [ 3] */ "No level" } 'STR#' 32604 "Error strings" { diff --git a/SpeckleLib/RINT/Speckle.grc b/SpeckleLib/RINT/Speckle.grc index 552987b..43c993f 100644 --- a/SpeckleLib/RINT/Speckle.grc +++ b/SpeckleLib/RINT/Speckle.grc @@ -1,3 +1,4 @@ 'STR#' 32700 "Speckle Title strings" { /* [ 1] */ "Untitled" +/* [ 2] */ "Unknown" } diff --git a/SpeckleLib/Speckle/Database/BIMAttributeDatabase.cpp b/SpeckleLib/Speckle/Database/BIMAttributeDatabase.cpp new file mode 100644 index 0000000..f7de91d --- /dev/null +++ b/SpeckleLib/Speckle/Database/BIMAttributeDatabase.cpp @@ -0,0 +1,143 @@ +#include "Speckle/Database/BIMAttributeDatabase.h" + +#include "Active/Database/Storage/Storage.h" +#include "Active/Serialise/UnboxedTransport.h" +#include "Speckle/Database/Identity/RecordID.h" +#include "Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.h" +#include "Speckle/Record/Attribute/Attribute.h" + +#include + +using namespace active::container; +using namespace active::database; +using namespace active::event; +using namespace active::serialise; +using namespace speckle::database; +using namespace speckle::record; +using namespace speckle::record::attribute; +using namespace speckle::database; +using namespace speckle::utility; + +namespace speckle::database { + + ///Define other platform engines here as required +#ifdef ARCHICAD + using AttributeDatabaseEngine = ArchicadAttributeDBaseEngine; +#endif + + ///Attribute database engine declaration + class BIMAttributeDatabase::Engine : public AttributeDatabaseEngine { + using base = ArchicadAttributeDBaseEngine; + using base::base; + }; + + ///Attribute database storage declaration + class BIMAttributeDatabase::Store : public Storage { + using base = Storage; + using base::base; + }; + +} + +namespace { + + ///The database storage identifier for attributes + const char* attributeDBaseName = "speckle::database::BIMAttributeDatabase"; + ///The primary model table, e.g. floor plan in Archicad + const char* modelTableName = "Model"; + +} + +/*-------------------------------------------------------------------- + Constructor + --------------------------------------------------------------------*/ +BIMAttributeDatabase::BIMAttributeDatabase() { + m_engine = std::make_shared(attributeDBaseName, + //Schema + DBaseSchema{active::utility::String{attributeDBaseName}, + //Tables + { + //Model attribute table + { + modelTableName, 0, 0, {} //The primary model. Additonal tables could be linked to other drawings/layouts in future + } + } + } + ); + m_store = std::make_shared(m_engine); +} //BIMAttributeDatabase::BIMAttributeDatabase + + +/*-------------------------------------------------------------------- + Destructor + --------------------------------------------------------------------*/ +BIMAttributeDatabase::~BIMAttributeDatabase() {} + + +/*-------------------------------------------------------------------- + Get a specified attribute + + attributeID: The ID of the target attribute + + return: The requested attribute (nullptr on failure) + --------------------------------------------------------------------*/ +Attribute::Unique BIMAttributeDatabase::getAttribute(const BIMRecordID& attributeID, std::optional tableID, + std::optional documentID) const { + return m_engine->getObject(attributeID, tableID, documentID); +} //BIMAttributeDatabase::getAttribute + + +/*-------------------------------------------------------------------- + Get all attributes + + return: All the attributes + --------------------------------------------------------------------*/ +Vector BIMAttributeDatabase::getAttributes() const { + return m_store->getObjects(); +} //BIMAttributeDatabase::getAttributes + + +/*-------------------------------------------------------------------- + Write an attribute to storage + + attribute: The attribute to write + --------------------------------------------------------------------*/ +void BIMAttributeDatabase::write(const Attribute& attribute) const { + m_store->write(attribute); +} //BIMAttributeDatabase::write + + +/*-------------------------------------------------------------------- + Erase an attribute + + attributeID: The ID of the attribute to erase + --------------------------------------------------------------------*/ +void BIMAttributeDatabase::erase(const Guid& attributeID) const { + m_store->erase(attributeID); +} //BIMAttributeDatabase::erase + + +#ifdef ARCHICAD +/*-------------------------------------------------------------------- + Get attribute data direct from the AC API. For internal use - avoid direct use + + link: A link to the required attribute + + return: The AC API attribute data + --------------------------------------------------------------------*/ +std::optional BIMAttributeDatabase::getAPIData(const BIMLink& link) const { + return m_engine->getAPIData(link); +} //BIMAttributeDatabase::getAPIData + + +/*-------------------------------------------------------------------- + Get storey data direct from the AC API. For internal use - avoid direct use + + link: A link to the required storey + + return: The AC API storey data + --------------------------------------------------------------------*/ +std::optional BIMAttributeDatabase::getAPIStorey(const BIMLink& link) const { + return m_engine->getAPIStorey(link); +} //BIMAttributeDatabase::getAPIData +#endif diff --git a/SpeckleLib/Speckle/Database/BIMAttributeDatabase.h b/SpeckleLib/Speckle/Database/BIMAttributeDatabase.h new file mode 100644 index 0000000..4ff21c8 --- /dev/null +++ b/SpeckleLib/Speckle/Database/BIMAttributeDatabase.h @@ -0,0 +1,95 @@ +#ifndef CONNECTOR_DATABASE_BIM_ATTRIBUTE_DATABASE +#define CONNECTOR_DATABASE_BIM_ATTRIBUTE_DATABASE + +#include "Speckle/Database/Identity/BIMLink.h" +#include "Speckle/Record/Attribute/Attribute.h" +#include "Speckle/Utility/Guid.h" + +namespace active::event { + class Subscriber; +} + +namespace speckle::database { + + /*! + Database of model attributes relating to a specific project + */ + class BIMAttributeDatabase { + public: + + // MARK: - Constructors + + /*! + Constructor + */ + BIMAttributeDatabase(); + BIMAttributeDatabase(const BIMAttributeDatabase&) = delete; + /*! + Destructor + */ + ~BIMAttributeDatabase(); + + // MARK: - Functions (const) + + /*! + Get the current user attribute selection + @return A list of selected attribute IDs + */ + BIMLinkList getSelection() const; + /*! + Get a specified attribute + @param attributeID The ID of the target attribute + @param tableID Optional table ID (defaults to the floor plan) + @param documentID Optional document ID (when the object is bound to a specific document) + @return The requested attribute (nullptr on failure) + */ + record::attribute::Attribute::Unique getAttribute(const BIMRecordID& attributeID, std::optional tableID = std::nullopt, + std::optional documentID = std::nullopt) const; + /*! + Get a specified attribute + @param link A link to the target attribute + @return The requested attribute (nullptr on failure) + */ + record::attribute::Attribute::Unique getAttribute(const BIMLink& link) const { return getAttribute(link, link.tableID, link.docID); } + /*! + Get all model attributes + @return All the attributes + */ + active::container::Vector getAttributes() const; + /*! + Write an attribute to storage + @param attribute The attribute to write + */ + void write(const record::attribute::Attribute& attribute) const; + /*! + Erase an attribute + @param attributeID The ID of the attribute to erase + */ + void erase(const speckle::utility::Guid& attributeID) const; + +#ifdef ARCHICAD + /*! + Get attribute data direct from the AC API. For internal use - avoid direct use + @param link A link to the required attribute + @return The AC API attribute data + */ + std::optional getAPIData(const BIMLink& link) const; + /*! + Get storey data direct from the AC API. For internal use - avoid direct use + @param link A link to the required storey + @return The AC API storey data + */ + std::optional getAPIStorey(const BIMLink& link) const; +#endif + + private: + class Engine; + class Store; + ///Model attribute database storage + std::shared_ptr m_engine; + std::shared_ptr m_store; + }; + +} + +#endif //CONNECTOR_DATABASE_BIM_ATTRIBUTE_DATABASE diff --git a/SpeckleLib/Speckle/Database/BIMElementDatabase.h b/SpeckleLib/Speckle/Database/BIMElementDatabase.h index bcb990b..27aa3db 100644 --- a/SpeckleLib/Speckle/Database/BIMElementDatabase.h +++ b/SpeckleLib/Speckle/Database/BIMElementDatabase.h @@ -1,5 +1,5 @@ -#ifndef CONNECTOR_DATABASE_BIM_DATABASE -#define CONNECTOR_DATABASE_BIM_DATABASE +#ifndef CONNECTOR_DATABASE_BIM_ELEMENT_DATABASE +#define CONNECTOR_DATABASE_BIM_ELEMENT_DATABASE #include "Speckle/Database/Identity/BIMLink.h" #include "Speckle/Record/Element/Element.h" @@ -77,4 +77,4 @@ namespace speckle::database { } -#endif //CONNECTOR_DATABASE_BIM_DATABASE +#endif //CONNECTOR_DATABASE_BIM_ELEMENT_DATABASE diff --git a/SpeckleLib/Speckle/Database/Content/BIMRecord.h b/SpeckleLib/Speckle/Database/Content/BIMRecord.h index dcbc4c4..8bf5cfc 100644 --- a/SpeckleLib/Speckle/Database/Content/BIMRecord.h +++ b/SpeckleLib/Speckle/Database/Content/BIMRecord.h @@ -3,7 +3,7 @@ #include "Active/Setting/Values/Measurement/Units/LengthUnit.h" #include "Speckle/Database/Content/Record.h" -#include "Speckle/Database/Identity/Link.h" +#include "Speckle/Database/Identity/BIMLink.h" #include "Speckle/Database/Identity/BIMRecordID.h" namespace speckle::database { @@ -34,10 +34,12 @@ namespace speckle::database { /*! Constructor @param ID The record ID - @param unit The recordc unit type + @param tableID The parent table ID + @param unit The record unit type */ - BIMRecord(speckle::utility::Guid ID, active::measure::LengthType unit = active::measure::LengthType::metre) : - base{}, m_applicationID{ID}, m_unit{unit} {} + BIMRecord(const speckle::utility::Guid& ID, const speckle::utility::Guid& tableID, + active::measure::LengthType unit = active::measure::LengthType::metre) : + base{}, m_applicationID{ID}, m_applicationTableID{tableID}, m_unit{unit} {} /*! Destructor */ @@ -50,6 +52,16 @@ namespace speckle::database { @return The BIM application ID */ BIMRecordID getBIMID() const { return m_applicationID; } + /*! + Get the BIM application parent table ID + @return The BIM table ID + */ + BIMRecordID getTableID() const { return m_applicationTableID; } + /*! + Get a link to the BIM record + @return The BIM record link + */ + BIMLink getBIMLink() const { return BIMLink{ {m_applicationID, m_applicationTableID} }; } // MARK: - Functions (mutating) @@ -58,6 +70,11 @@ namespace speckle::database { @param ID The BIM application ID */ void setBIMID(const BIMRecordID& ID) { m_applicationID = ID; } + /*! + Set the BIM application parent table ID + @param tableID The BIM table ID + */ + void setTableID(const BIMRecordID& tableID) { m_applicationTableID = tableID; } // MARK: - Serialisation @@ -81,6 +98,8 @@ namespace speckle::database { private: ///The BIM application record ID BIMRecordID m_applicationID; + ///The BIM application parent table ID + BIMRecordID m_applicationTableID; ///The BIM record unit of length measurement std::optional m_unit = active::measure::LengthType::metre; }; diff --git a/SpeckleLib/Speckle/Database/Content/Record.h b/SpeckleLib/Speckle/Database/Content/Record.h index ab22bd7..6a1adfd 100644 --- a/SpeckleLib/Speckle/Database/Content/Record.h +++ b/SpeckleLib/Speckle/Database/Content/Record.h @@ -51,16 +51,16 @@ namespace speckle::database { // MARK: - Serialisation /*! - Fill an inventory with the package items - @param inventory The inventory to receive the package items - @return True if the package has added items to the inventory - */ + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ bool fillInventory(active::serialise::Inventory& inventory) const override; /*! - Get the specified cargo - @param item The inventory item to retrieve - @return The requested cargo (nullptr on failure) - */ + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; /*! Set to the default package content diff --git a/SpeckleLib/Speckle/Database/Identity/BIMIndex.h b/SpeckleLib/Speckle/Database/Identity/BIMIndex.h index ff0a09f..89abdbc 100644 --- a/SpeckleLib/Speckle/Database/Identity/BIMIndex.h +++ b/SpeckleLib/Speckle/Database/Identity/BIMIndex.h @@ -2,7 +2,7 @@ #define SPECKLE_DATABASE_BIM_INDEX #include "Active/Database/Identity/Index.h" -#include "Speckle/Database/Identity/RecordID.h" +#include "Speckle/Database/Identity/BIMRecordID.h" namespace speckle::database { @@ -13,25 +13,30 @@ namespace speckle::database { this is typically a guid, for Revit a string and for Vectorworks a handle. Note that this index is not necessarily persistent between sessions. */ - class BIMIndex : public active::database::Index { + class BIMIndex : public active::database::Index { public: // MARK: - Types - using base = active::database::Index; + using base = active::database::Index; // MARK: - Constructors using base::base; - - // MARK: - Public variables - - //The table identifier - BIMTableID table; - //The document identifier - BIMDocID document; }; } + + ///Hashing for BIMIndex class, e.g. to use as a key in unordered_map +template<> +struct std::hash { + std::size_t operator() (const speckle::database::BIMIndex& index) const { + std::size_t h1 = std::hash{}(index); + std::size_t h2 = std::hash{}(index.tableID); + return h1 ^ (h2 << 1); + } +}; + + #endif //SPECKLE_DATABASE_BIM_INDEX diff --git a/SpeckleLib/Speckle/Database/Identity/BIMLink.cpp b/SpeckleLib/Speckle/Database/Identity/BIMLink.cpp index 4c1ab7f..af20fb4 100644 --- a/SpeckleLib/Speckle/Database/Identity/BIMLink.cpp +++ b/SpeckleLib/Speckle/Database/Identity/BIMLink.cpp @@ -8,8 +8,9 @@ using namespace speckle::utility; Constructor selected: Information about a selected Archicad element + tableID: The ID of the parent table --------------------------------------------------------------------*/ -BIMLink::BIMLink(const API_Neig& selected) : base{Guid{selected.guid}} { +BIMLink::BIMLink(const API_Neig& selected, const BIMRecordID& tableID) : base{Guid{selected.guid}, tableID} { //More info should be extracted from API_Neig in future (as required) - extract into link settings, e.g. selection target etc } //Link::Link #endif diff --git a/SpeckleLib/Speckle/Database/Identity/BIMLink.h b/SpeckleLib/Speckle/Database/Identity/BIMLink.h index a78f56e..08ec63e 100644 --- a/SpeckleLib/Speckle/Database/Identity/BIMLink.h +++ b/SpeckleLib/Speckle/Database/Identity/BIMLink.h @@ -34,8 +34,9 @@ namespace speckle::database { /*! Constructor @param selected Information about a selected Archicad element + @param tableID The ID of the parent table */ - BIMLink(const API_Neig& selected); + BIMLink(const API_Neig& selected, const BIMRecordID& tableID); #endif }; diff --git a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.cpp b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.cpp new file mode 100644 index 0000000..2da5214 --- /dev/null +++ b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.cpp @@ -0,0 +1,282 @@ +#include "Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.h" + +#ifdef ARCHICAD + +#include "Active/Utility/Defer.h" +#include "Active/Utility/Memory.h" +#include "Active/Utility/String.h" +#include "Speckle/Record/Attribute/Finish.h" +#include "Speckle/Record/Attribute/Storey.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/Utility/Guid.h" +#include "Speckle/Utility/String.h" + +#include +#include +#include + +using namespace active::event; +using namespace active::setting; +using namespace speckle::database; +using namespace speckle::environment; +using namespace speckle::event; +using namespace speckle::record::attribute; +using namespace speckle::utility; + +using enum ArchicadDBaseCore::Status; + +namespace speckle::database { + +#ifdef ARCHICAD + /*! + A class to collect and manage a list of active Archicad storeys + NB: This list has to be rebuilt every time a storey has changed because Archicad reindexes storeys each time + This class also has to release memory used by the API to hold storey data + */ + class ArchicadAttributeDBaseEngine::StoreyCache : public std::vector { + public: + /*! + Constructor (NB: This automatically gathers information about the current storeys) + */ + StoreyCache() { rebuild(); } + + /*! + Rebuild the current storey list + */ + void rebuild() { + clear(); + API_StoryInfo storeyInfo; + active::utility::Memory::erase(storeyInfo); + ACAPI_ProjectSetting_GetStorySettings(&storeyInfo); + auto storeyCount = storeyInfo.lastStory - storeyInfo.firstStory + 1; + for (auto i = 0; i < storeyCount; ++i) + push_back((*storeyInfo.data)[i]); + BMKillHandle(reinterpret_cast(&storeyInfo.data)); + } + /*! + Find a storey by unique ID + @param id The storey unique ID + @return An iterator pointing to the found storey (end() on failure) + */ + const_iterator find(const Guid& id) const { + auto floorID = static_cast(Guid::toInt(id)); + return std::find_if(begin(), end(), [&](auto storey){ return storey.floorId == floorID; }); + } + /*! + Find a storey by index + @param index The storey index + @return An iterator pointing to the found storey (end() on failure) + */ + const_iterator find(short index) const { + return std::find_if(begin(), end(), [&](auto storey){ return storey.index == index; }); + } + }; +#endif + +} + +namespace { + + ///Attribute factory + std::unordered_map> attributeFactory; + +#ifdef ARCHICAD + /*! + Make a new attribute object + @param attributeData The API attribute representation + @return A new attribute object (nullptr on failure) + */ + Attribute::Unique makeAttribute(const API_Attribute& attributeData) { + auto tableID = active::utility::Guid::fromInt(static_cast(attributeData.header.typeID)); + if (attributeFactory.empty()) { + attributeFactory[active::utility::Guid::fromInt(static_cast(attributeData.header.typeID))] = + [](API_Attribute attrData, const active::utility::Guid& tableID){ return std::make_unique(attrData, tableID); }; + } + if (auto iter = attributeFactory.find(tableID); iter != attributeFactory.end()) + return iter->second(attributeData, tableID); + return nullptr; + } + + + /*! + Get the AC API data for a specified attribute + @param ID The attribute ID + @param tableID The parent table ID + @return A new attribute object (nullptr on failure) + */ + std::optional getAPIData(const BIMRecordID& ID, std::optional tableID) { + API_Attribute attribute; + active::utility::Memory::erase(attribute); + attribute.header.index = ACAPI_CreateAttributeIndex(static_cast(Guid::toInt(ID))); + attribute.header.typeID = static_cast(Guid::toInt(*tableID)); + if (ACAPI_Attribute_Get(&attribute) != NoError) + return std::nullopt; + return attribute; + } +#endif + +} + +/*-------------------------------------------------------------------- + Constructor + + id: The document storage identifier + --------------------------------------------------------------------*/ +ArchicadAttributeDBaseEngine::ArchicadAttributeDBaseEngine(const active::utility::NameID& id, ArchicadDBaseSchema&& schema) : + ArchicadDBaseCore{id, std::move(schema)} { +} //ArchicadAttributeDBaseEngine::ArchicadAttributeDBaseEngine + + +/*-------------------------------------------------------------------- + Destructor + --------------------------------------------------------------------*/ +ArchicadAttributeDBaseEngine::~ArchicadAttributeDBaseEngine() { +} //ArchicadAttributeDBaseEngine::~ArchicadAttributeDBaseEngine + + +/*-------------------------------------------------------------------- + Get an object by ID + + objID: 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 ArchicadAttributeDBaseEngine::getObject(const BIMRecordID& objID, std::optional tableID, + std::optional documentID) const { + if (!tableID) + return nullptr; + if (auto attrData = ::getAPIData(objID, *tableID); attrData) + return makeAttribute(*attrData); + return nullptr; +} //ArchicadAttributeDBaseEngine::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 ArchicadAttributeDBaseEngine::getObjectCargo(const BIMRecordID& ID, std::optional tableID, + std::optional documentID) const { + return nullptr; //TODO: Implement +} //ArchicadAttributeDBaseEngine::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 ArchicadAttributeDBaseEngine::getObjects(std::optional tableID, + std::optional documentID) const { + return {}; //TODO: Implement +} //ArchicadAttributeDBaseEngine::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 ArchicadAttributeDBaseEngine::getObjects(const Filter& filter, std::optional tableID, + std::optional documentID) const { + return {}; //TODO: Implement +} //ArchicadAttributeDBaseEngine::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 ArchicadAttributeDBaseEngine::write(const Attribute& object, const BIMRecordID& objID, std::optional objDocID, + std::optional tableID, std::optional documentID) const { + //TODO: Implement +} //ArchicadAttributeDBaseEngine::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 ArchicadAttributeDBaseEngine::erase(const BIMRecordID& ID, std::optional tableID, + std::optional documentID) const { + //TODO: Implement +} //ArchicadAttributeDBaseEngine::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 ArchicadAttributeDBaseEngine::erase(std::optional tableID, std::optional documentID) const { + //TODO: Implement +} //ArchicadAttributeDBaseEngine::erase + + +/*-------------------------------------------------------------------- + Get the database outline + + return: The database outline + --------------------------------------------------------------------*/ +ArchicadAttributeDBaseEngine::Outline ArchicadAttributeDBaseEngine::getOutline() const { + return {}; //TODO: Implement +} //ArchicadAttributeDBaseEngine::getOutline + + +/*-------------------------------------------------------------------- + Get attribute data direct from the AC API. For internal use - avoid direct use + + link: A link to the required attribute + + return: The AC API attribute data + --------------------------------------------------------------------*/ +std::optional ArchicadAttributeDBaseEngine::getAPIData(const BIMLink& link) const { + return ::getAPIData(link, link.tableID); +} //ArchicadAttributeDBaseEngine::getAPIData + + +/*-------------------------------------------------------------------- + Get storey data direct from the AC API. For internal use - avoid direct use + + link: A link to the required storey + + return: The AC API storey data + --------------------------------------------------------------------*/ +std::optional ArchicadAttributeDBaseEngine::getAPIStorey(const BIMLink& link) const { + if (!m_storeyCache) + m_storeyCache = std::make_unique(); + if (auto iter = m_storeyCache->find(link); iter != m_storeyCache->end()) + return *iter; + return std::nullopt; +} //ArchicadAttributeDBaseEngine::getAPIStorey + +#endif diff --git a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.h b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.h new file mode 100644 index 0000000..f8a5787 --- /dev/null +++ b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.h @@ -0,0 +1,142 @@ +#ifndef SPECKLE_DATABASE_ARCHICAD_ATTRIBUTE_DBASE_ENGINE +#define SPECKLE_DATABASE_ARCHICAD_ATTRIBUTE_DBASE_ENGINE + +#include "Active/Database/Storage/DBaseEngine.h" +#include "Active/Serialise/UnboxedTransport.h" +#include "Speckle/Database/Storage/ArchicadDBase/ArchicadDBaseCore.h" +#include "Speckle/Database/Identity/BIMLink.h" +#include "Speckle/Record/Attribute/Attribute.h" +#include "Speckle/Utility/Guid.h" +#include "Speckle/Utility/String.h" + +#include +#include + +namespace speckle::database { + + /*! + A database engine to read/write elements in an Archicad project database (local file or cloud-based) + + For attribute indices: + - Each attribute type is considered to be stored in a dedicated table + - For Archicad: + - The table ID is typically the attribute type ID + - The record ID is the attribute index + - Storeys are also treated as an attribute (the API treats them separately, although application to elements is virtually the identical) + */ + class ArchicadAttributeDBaseEngine : public ArchicadDBaseCore, + public active::database::DBaseEngine { + public: + + // MARK: - Types + + using base = active::database::DBaseEngine; + using Attribute = record::attribute::Attribute; + using Filter = base::Filter; + using Outline = base::Outline; + + // MARK: - Constructors + + /*! + Constructor + @param id The document storage identifier + */ + ArchicadAttributeDBaseEngine(const active::utility::NameID& id, ArchicadDBaseSchema&& schema); + ArchicadAttributeDBaseEngine(const ArchicadAttributeDBaseEngine&) = delete; + /*! + Destructor + */ + ~ArchicadAttributeDBaseEngine(); + + // MARK: - Functions (const) + + /*! + Get an object by ID + @param objID The object ID + @param tableID Optional table ID (defaults to the floor plan) + @param documentID Optional document ID (when the object is bound to a specific document) + @return The requested object (nullptr on failure) + */ + std::unique_ptr getObject(const BIMRecordID& objID, std::optional tableID = std::nullopt, std::optional documentID = std::nullopt) const override; + /*! + Get an object in a transportable form, e.g. packaged for serialisation + @param objID The object ID + @param tableID Optional table ID (defaults to the floor plan) + @param 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 getObjectCargo(const BIMRecordID& objID, std::optional tableID = std::nullopt, std::optional documentID = std::nullopt) const override; + /*! + Get all objects + @param tableID Optional table ID (defaults to the floor plan) + @param documentID Optional document ID (filter for this document only - nullopt = all objects) + @return The requested objects (nullptr on failure) + */ + active::container::Vector getObjects(std::optional tableID = std::nullopt, std::optional documentID = std::nullopt) const override; + /*! + Get a filtered list of objects + @param filter The object filter + @param tableID Optional table ID (defaults to the floor plan) + @param documentID Optional document ID (filter for this document only - nullopt = all objects) + @return The filtered objects (nullptr on failure) + */ + active::container::Vector getObjects(const Filter& filter, std::optional tableID = std::nullopt, + std::optional documentID = std::nullopt) const override; + /*! + Write an object to the database + @param object The object to write + @param objID The object ID + @param objDocID The object document-specific ID (unique within a specific document - nullopt if not document-bound) + @param tableID Optional table ID (defaults to the floor plan) + @param documentID Optional document ID (when the object is bound to a specific document) + */ + void write(const Attribute& object, const BIMRecordID& objID, std::optional objDocID = std::nullopt, + std::optional tableID = std::nullopt, std::optional documentID = std::nullopt) const override; + /*! + Erase an object by index + @param ID The object ID + @param tableID Optional table ID (defaults to the floor plan) + @param documentID Optional document ID (when the object is bound to a specific document) + @throw Exception thrown on SQL error + */ + void erase(const BIMRecordID& ID, std::optional tableID = std::nullopt, + std::optional documentID = std::nullopt) const override; + /*! + Erase all objects + @param tableID Optional table ID (defaults to the floor plan) + @param documentID Optional document ID (when the object is bound to a specific document) + @throw Exception thrown on SQL error + */ + void erase(std::optional tableID = std::nullopt, std::optional documentID = std::nullopt) const override; + /*! + Get the database outline + @return The database outline + */ + Outline getOutline() const override; + +#ifdef ARCHICAD + /*! + Get attribute data direct from the AC API. For internal use - avoid direct use + @param link A link to the required attribute + @return The AC API attribute data + */ + std::optional getAPIData(const BIMLink& link) const; + /*! + Get storey data direct from the AC API. For internal use - avoid direct use + @param link A link to the required storey + @return The AC API storey data + */ + std::optional getAPIStorey(const BIMLink& link) const; +#endif + + private: + void setTable(std::optional tableID = std::nullopt, std::optional documentID = std::nullopt); + + class StoreyCache; + ///Cache of storeys in the database (saves repeated lookups) + mutable std::unique_ptr m_storeyCache; + }; + +} + +#endif //SPECKLE_DATABASE_ARCHICAD_ATTRIBUTE_DBASE_ENGINE diff --git a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.cpp b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.cpp index b7cb9cd..7438e6d 100644 --- a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.cpp +++ b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.cpp @@ -43,19 +43,6 @@ namespace { } //getTableInfo - /*! - Get the ID of the active Archicad table - @return The active table ID (nullopt on failure) - */ - std::optional 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; - } //getActiveTable - - /*! Set the active Archicad table @param tableID The target table ID @@ -64,7 +51,7 @@ namespace { bool setActiveTable(const BIMRecordID& tableID) { if (!tableID) return false; //Null guid doens't point to anything - if (auto activeTable = getActiveTable(); activeTable && *activeTable == tableID) + if (auto activeTable = ArchicadElementDBaseEngine::getActiveTable(); activeTable && *activeTable == tableID) return true; auto dbaseInfo = getTableInfo(tableID); if (!dbaseInfo) @@ -76,29 +63,47 @@ namespace { /*! 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) { + Element::Unique makeElement(const API_Element& elementData, const BIMRecordID& tableID) { //Implement an object factory in future as classes for specific element types are implemented, e.g. Wall, Roof etc. using hash map //The fallback for undefined element types will always be the base Element class - return std::make_unique(elementData); + return std::make_unique(elementData, tableID); } } +/*-------------------------------------------------------------------- + Get the ID of the active Archicad table + + return; The active table ID (nullopt on failure) + --------------------------------------------------------------------*/ +std::optional 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 selection; if (auto err = ACAPI_Selection_Get(&selectionInfo, &selection, true); err == NoError) { for (const auto& item : selection) - result.push_back(BIMLink{item}); + result.push_back(BIMLink{item, *tableID}); } return result; } //ArchicadElementDBaseEngine::getSelection @@ -115,12 +120,17 @@ BIMLinkList ArchicadElementDBaseEngine::getSelection() const { --------------------------------------------------------------------*/ std::unique_ptr ArchicadElementDBaseEngine::getObject(const BIMRecordID& ID, std::optional tableID, std::optional documentID) const { + if (!tableID) { + 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); + return makeElement(element, *tableID); } //ArchicadElementDBaseEngine::getObject diff --git a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.h b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.h index 6e23859..103a11a 100644 --- a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.h +++ b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.h @@ -28,6 +28,14 @@ namespace speckle::database { using Filter = base::Filter; using Outline = base::Outline; + // MARK: - Static functions + + /*! + Get the ID of the active Archicad table + @return The active table ID (nullopt on failure) + */ + static std::optional getActiveTable(); + // MARK: - Constructors /*! diff --git a/SpeckleLib/Speckle/Environment/Project.cpp b/SpeckleLib/Speckle/Environment/Project.cpp index 27c401d..a991660 100644 --- a/SpeckleLib/Speckle/Environment/Project.cpp +++ b/SpeckleLib/Speckle/Environment/Project.cpp @@ -1,5 +1,6 @@ #include "Speckle/Environment/Project.h" +#include "Speckle/Database/BIMAttributeDatabase.h" #include "Speckle/Database/BIMElementDatabase.h" #include "Speckle/Environment/Addon.h" #include "Speckle/SpeckleResource.h" @@ -23,6 +24,7 @@ namespace { --------------------------------------------------------------------*/ Project::Project() { m_element = std::make_unique(); + m_attribute = std::make_unique(); } //Project::Project diff --git a/SpeckleLib/Speckle/Environment/Project.h b/SpeckleLib/Speckle/Environment/Project.h index 284be8c..752f040 100644 --- a/SpeckleLib/Speckle/Environment/Project.h +++ b/SpeckleLib/Speckle/Environment/Project.h @@ -5,6 +5,7 @@ #include "Speckle/Utility/String.h" namespace speckle::database { + class BIMAttributeDatabase; class BIMElementDatabase; } @@ -59,6 +60,11 @@ namespace speckle::environment { @return The account database */ const database::BIMElementDatabase* getElementDatabase() const { return m_element.get(); } + /*! + Get the account database + @return The account database + */ + const database::BIMAttributeDatabase* getAttributeDatabase() const { return m_attribute.get(); } // MARK: - Functions (mutating) @@ -73,7 +79,10 @@ namespace speckle::environment { Project(); private: + ///The BIM element database std::unique_ptr m_element; + ///The BIM attribute database + std::unique_ptr m_attribute; }; } diff --git a/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.cpp b/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.cpp index 2d10bd6..48b5f04 100644 --- a/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.cpp +++ b/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.cpp @@ -2,6 +2,7 @@ #include "Speckle/Environment/Addon.h" #include "Speckle/Database/Identity/BIMLink.h" +#include "Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.h" #include "Speckle/Event/Type/SelectionEvent.h" #ifdef ARCHICAD @@ -23,8 +24,10 @@ namespace { */ GSErrCode __ACENV_CALL selectionCallback(const API_Neig* params) { if (addon() != nullptr) { - auto selection = (params == nullptr) ? BIMLink{} : BIMLink{*params}; - addon()->publishExternal(SelectionEvent{selection}); + if (auto tableID = ArchicadElementDBaseEngine::getActiveTable(); tableID) { + auto selection = (params == nullptr) ? BIMLink{} : BIMLink{*params, *tableID}; + addon()->publishExternal(SelectionEvent{selection}); + } } return NoError; } diff --git a/SpeckleLib/Speckle/Record/Attribute/Attribute.cpp b/SpeckleLib/Speckle/Record/Attribute/Attribute.cpp new file mode 100644 index 0000000..dba0b12 --- /dev/null +++ b/SpeckleLib/Speckle/Record/Attribute/Attribute.cpp @@ -0,0 +1,103 @@ +#include "Speckle/Record/Attribute/Attribute.h" + +#include "Speckle/Database/BIMAttributeDatabase.h" +#include "Speckle/Environment/Addon.h" +#include "Speckle/Environment/Project.h" + +using namespace active::serialise; +using namespace speckle::database; +using namespace speckle::environment; +using namespace speckle::record::attribute; +using namespace speckle::utility; + +#include +#include + +namespace { + + ///Serialisation fields + enum FieldIndex { + nameID, + }; + + ///Serialisation field IDs + static std::array fieldID = { + Identity{"name"}, + }; + +} + +/*-------------------------------------------------------------------- + Default constructor + --------------------------------------------------------------------*/ +Attribute::Attribute() { +} //Attribute::Attribute + + +/*-------------------------------------------------------------------- + Get the attribute name + + return: The attribute name + --------------------------------------------------------------------*/ +speckle::utility::String Attribute::getName() const { +#ifdef ARCHICAD + return getHead().name; +#endif +} //Attribute::getName + + +/*-------------------------------------------------------------------- + Fill an inventory with the package items + + inventory: The inventory to receive the package items + + return: True if the package has added items to the inventory + --------------------------------------------------------------------*/ +bool Attribute::fillInventory(Inventory& inventory) const { + using enum Entry::Type; + inventory.merge(Inventory{ + { + { fieldID[nameID], nameID, element }, + }, + }.withType(&typeid(Attribute))); + return base::fillInventory(inventory); +} //Attribute::fillInventory + + +/*-------------------------------------------------------------------- + Get the specified cargo + + item: The inventory item to retrieve + + return: The requested cargo (nullptr on failure) + --------------------------------------------------------------------*/ +Cargo::Unique Attribute::getCargo(const Inventory::Item& item) const { + if (item.ownerType != &typeid(Attribute)) + return base::getCargo(item); + using namespace active::serialise; + switch (item.index) { + case nameID: + //return std::make_unique(*body); + return std::make_unique(getHead().name); + default: + return nullptr; //Requested an unknown index + } +} //Attribute::getCargo + + +#ifdef ARCHICAD +/*-------------------------------------------------------------------- + Get the attribute data from the host BIM application + + return: The attribute data (for internal use to populate derived classes) + --------------------------------------------------------------------*/ +API_Attribute Attribute::getData() const { + if (auto project = addon()->getActiveProject().lock(); project) { + if (auto attr = project->getAttributeDatabase()->getAPIData(getBIMLink()); attr) + return *attr; + } + API_Attribute attr; + active::utility::Memory::erase(attr); + return attr; +} //Attribute::getData +#endif diff --git a/SpeckleLib/Speckle/Record/Attribute/Attribute.h b/SpeckleLib/Speckle/Record/Attribute/Attribute.h new file mode 100644 index 0000000..e1a13ed --- /dev/null +++ b/SpeckleLib/Speckle/Record/Attribute/Attribute.h @@ -0,0 +1,120 @@ +#ifndef SPECKLE_RECORD_ATTRIBUTE +#define SPECKLE_RECORD_ATTRIBUTE + +#include "Speckle/Database/Content/BIMRecord.h" +#include "Speckle/Utility/String.h" + +namespace speckle::record::attribute { + + /*! + Base BIM attribute class + */ + class Attribute : public speckle::database::BIMRecord { + public: + + // MARK: - Types + + using base = speckle::database::BIMRecord; + ///Unique pointer + using Unique = std::unique_ptr; + ///Shared pointer + using Shared = std::shared_ptr; + ///Optional + using Option = std::optional; + + // MARK: - Constants + +#ifdef ARCHICAD + ///Archicad type identifier for a storey attribute table + static constexpr int32_t storeyTableID = 0x200; + /*! + Get an attribute type ID from a table ID + @param tableID The table ID + @return The attribute type ID (NB: not strictly API_AttrTypeID - can be storeyTypeID) + */ + static API_AttrTypeID getTypeID(const active::utility::Guid& tableID) { + return static_cast(active::utility::Guid::toInt(tableID)); + } + /*! + Get an Archicad attribute index from a record ID + @param recordID The record ID + @return An attribute index + */ + static API_AttributeIndex getIndex(const active::utility::Guid& recordID) { + return ACAPI_CreateAttributeIndex(static_cast(active::utility::Guid::toInt(recordID))); + } +#endif + + // MARK: - Constructors + + using base::base; + + /*! + Default constructor + */ + Attribute(); + /*! + Constructor + @param ID The attribute ID + @param tableID The attribute table ID (attribute type) + */ + Attribute(const database::BIMRecordID& ID, const speckle::utility::Guid& tableID) : base{ID, tableID} {} + + // MARK: - Functions (const) + + /*! + Get the speckle type identifier + @return The speckle type (relevant objects should override as required) + */ + speckle::utility::String getSpeckleType() const override { return "speckle::record::attribute::Attribute"; } + /*! + Get the attribute name + @return The attribute name + */ + speckle::utility::String getName() const; +#ifdef ARCHICAD + /*! + Get the (immutable) API attribute header data + @return The attribute header data (only use this data for low-level operations - for normal code, call getters/setters) + */ + virtual const API_Attr_Head& getHead() const = 0; +#endif + + // MARK: - Functions (mutating) + +#ifdef ARCHICAD + /*! + Get the (mutable) API attribute header data + @return The attribute header data (only use this data for low-level operations - for normal code, call getters/setters) + */ + virtual API_Attr_Head& getHead() = 0; +#endif + + // MARK: - Serialisation + + /*! + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ + bool fillInventory(active::serialise::Inventory& inventory) const override; + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + + protected: +#ifdef ARCHICAD + /*! + Get the attribute data from the host BIM application + @return The attribute data (for internal use to populate derived classes) + */ + API_Attribute getData() const; +#endif + }; + +} + +#endif //SPECKLE_RECORD_ATTRIBUTE diff --git a/SpeckleLib/Speckle/Record/Attribute/Finish.cpp b/SpeckleLib/Speckle/Record/Attribute/Finish.cpp new file mode 100644 index 0000000..33aad98 --- /dev/null +++ b/SpeckleLib/Speckle/Record/Attribute/Finish.cpp @@ -0,0 +1,164 @@ +#include "Speckle/Record/Attribute/Finish.h" + +#include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Speckle/Utility/Guid.h" + +using namespace active::serialise; +using namespace speckle::database; +using namespace speckle::record::attribute; +using namespace speckle::utility; + +#include +#include + +namespace speckle::record::attribute { + + class Finish::Data { + public: +#ifdef ARCHICAD + Data(const API_Attribute& attr) : root{attr.material} {} + Data(const Data& source) : root{source.root} {} + + API_MaterialType root; +#endif + }; + +} + +namespace { + + ///Serialisation fields + enum FieldIndex { + surfaceColourID, + }; + + ///Serialisation field IDs + static std::array fieldID = { + Identity{"surfaceColour"}, + }; + +} + +/*-------------------------------------------------------------------- + Default constructor + --------------------------------------------------------------------*/ +Finish::Finish() { +} //Finish::Finish + + +/*-------------------------------------------------------------------- + Constructor + + ID: The attribute ID + --------------------------------------------------------------------*/ +Finish::Finish(const database::BIMRecordID& ID) : base{ID, Finish::table} { +} //Finish::Finish + + +#ifdef ARCHICAD +/*-------------------------------------------------------------------- + Constructor + + attrData: Archicad attribute data + tableID: The ID of the parent table + --------------------------------------------------------------------*/ +Finish::Finish(const API_Attribute& attrData, const BIMRecordID& tableID) : base{attrData.header.guid, Finish::table} { + m_data = std::make_unique(attrData); +} +#endif + + +/*-------------------------------------------------------------------- + Copy constructor + + source: The object to copy + --------------------------------------------------------------------*/ +Finish::Finish(const Finish& source) : base{source} { + m_data = source.m_data ? std::make_unique(*m_data) : nullptr; +} //Finish::Finish + + +/*-------------------------------------------------------------------- + Destructor + --------------------------------------------------------------------*/ +Finish::~Finish() {} + + +#ifdef ARCHICAD +/*-------------------------------------------------------------------- + Get the (immutable) API attribute header data + + return: The attribute header data (only use this data for low-level operations - for normal code, call getters/setters) + --------------------------------------------------------------------*/ +const API_Attr_Head& Finish::getHead() const { + confirmData(); + return m_data->root.head; +} //Finish::getHead + +/*-------------------------------------------------------------------- + Get the (mutable) API attribute header data + + return: The attribute header data (only use this data for low-level operations - for normal code, call getters/setters) + --------------------------------------------------------------------*/ +API_Attr_Head& Finish::getHead() { + confirmData(); + return m_data->root.head; +} //Finish::getHead +#endif + + +/*-------------------------------------------------------------------- + Fill an inventory with the package items + + inventory: The inventory to receive the package items + + return: True if the package has added items to the inventory + --------------------------------------------------------------------*/ +bool Finish::fillInventory(Inventory& inventory) const { + using enum Entry::Type; + inventory.merge(Inventory{ + { + { fieldID[surfaceColourID], surfaceColourID, element }, //TODO: implement other fields + }, + }.withType(&typeid(Finish))); + return base::fillInventory(inventory); +} //Finish::fillInventory + + +/*-------------------------------------------------------------------- + Get the specified cargo + + item: The inventory item to retrieve + + return: The requested cargo (nullptr on failure) + --------------------------------------------------------------------*/ +Cargo::Unique Finish::getCargo(const Inventory::Item& item) const { + if (item.ownerType != &typeid(Finish)) + return base::getCargo(item); + confirmData(); + using namespace active::serialise; + switch (item.index) { + case surfaceColourID: + return nullptr; //TODO: lookup surface colour + default: + return nullptr; //Requested an unknown index + } +} //Finish::getCargo + + +/*-------------------------------------------------------------------- + Set to the default package content + --------------------------------------------------------------------*/ +void Finish::setDefault() { + +} //Finish::setDefault + + +/*-------------------------------------------------------------------- + Confirm the internal data, either loading from the BIM application or setting a default + --------------------------------------------------------------------*/ +void Finish::confirmData() const { + if (m_data) + return; + m_data = std::make_unique(getData()); +} //Finish::confirmData diff --git a/SpeckleLib/Speckle/Record/Attribute/Finish.h b/SpeckleLib/Speckle/Record/Attribute/Finish.h new file mode 100644 index 0000000..36c274b --- /dev/null +++ b/SpeckleLib/Speckle/Record/Attribute/Finish.h @@ -0,0 +1,128 @@ +#ifndef SPECKLE_RECORD_ATTRIBUTE_FINISH +#define SPECKLE_RECORD_ATTRIBUTE_FINISH + +#include "Speckle/Record/Attribute/Attribute.h" + +namespace speckle::record::attribute { + + /*! + Class to represent the rendered finish on a 3D body, i.e. the surface colour/texture etc. + + In Archicad this attribute is represented by `API_MaterialType` + */ + class Finish : public Attribute { + public: + + // MARK: - Types + + using base = Attribute; + ///Unique pointer + using Unique = std::unique_ptr; + ///Shared pointer + using Shared = std::shared_ptr; + ///Optional + using Option = std::optional; + + // MARK: - Constants + +#ifdef ARCHICAD + ///The finishes table identifier + static constexpr active::utility::Guid table{active::utility::Guid::fromInt(API_MaterialID)}; +#endif + + // MARK: - Constructors + + using base::base; + + /*! + Default constructor + */ + Finish(); + /*! + Constructor + @param ID The attribute ID + */ + Finish(const database::BIMRecordID& ID); +#ifdef ARCHICAD + /*! + Constructor + @param attrData Archicad attribute data + @param tableID The ID of the parent table + */ + Finish(const API_Attribute& attrData, const database::BIMRecordID& tableID); +#endif + /*! + Copy constructor + @param source The object to copy + */ + Finish(const Finish& source); + /*! + Destructor + */ + ~Finish(); + + /*! + Object cloning + @return A clone of this object + */ + Finish* clonePtr() const override { return new Finish{*this}; } + + + // MARK: - Functions (const) + + /*! + Get the speckle type identifier + @return The speckle type (relevant objects should override as required) + */ + speckle::utility::String getSpeckleType() const override { return "Objects.Other.RenderMaterial"; } +#ifdef ARCHICAD + /*! + Get the (immutable) API attribute header data + @return The attribute header data (only use this data for low-level operations - for normal code, call getters/setters) + */ + const API_Attr_Head& getHead() const override; +#endif + + // MARK: - Functions (mutating) + +#ifdef ARCHICAD + /*! + Get the (mutable) API attribute header data + @return The attribute header data (only use this data for low-level operations - for normal code, call getters/setters) + */ + API_Attr_Head& getHead() override; +#endif + + // MARK: - Serialisation + + /*! + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ + bool fillInventory(active::serialise::Inventory& inventory) const override; + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + /*! + Set to the default package content + */ + void setDefault() override; + + private: + /*! + Confirm the internal data, either loading from the BIM application or setting a default + */ + void confirmData() const; + + class Data; + ///The attribute data - mutable to support lazy loading + mutable std::unique_ptr m_data; + }; + +} + +#endif //SPECKLE_RECORD_ATTRIBUTE_FINISH diff --git a/SpeckleLib/Speckle/Record/Attribute/Storey.cpp b/SpeckleLib/Speckle/Record/Attribute/Storey.cpp new file mode 100644 index 0000000..6bee954 --- /dev/null +++ b/SpeckleLib/Speckle/Record/Attribute/Storey.cpp @@ -0,0 +1,192 @@ +#include "Speckle/Record/Attribute/Storey.h" + +#include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Active/Utility/BufferOut.h" +#include "Speckle/Database/BIMAttributeDatabase.h" +#include "Speckle/Environment/Addon.h" +#include "Speckle/Environment/Project.h" +#include "Speckle/Utility/Guid.h" + +using namespace active::serialise; +using namespace speckle::database; +using namespace speckle::environment; +using namespace speckle::record::attribute; +using namespace speckle::utility; + +#include +#include + +namespace speckle::record::attribute { + + class Storey::Data { + public: +#ifdef ARCHICAD + Data(const API_StoryType& storey) : root{storey} {} + Data(const Data& source) : root{source.root} {} + + API_StoryType root; + API_Attr_Head header; +#endif + }; + +} + +namespace { + + ///Serialisation fields + enum FieldIndex { + levelID, + }; + + ///Serialisation field IDs + static std::array fieldID = { + Identity{"level"}, + }; + + +#ifdef ARCHICAD + /*! + Fill in an Archicad API attribute header based on a storey + @param header The attribute header to be populated + @param storey The storey to be copied into the header + */ + void fillHeader(API_Attr_Head& header, const API_StoryType& storey) { + active::utility::Memory::erase(header); + //NB: This is not intended to be used for API attribute calls - it only transports core properties within this framework, e.g. name + header.typeID = static_cast(Attribute::storeyTableID); + header.index = ACAPI_CreateAttributeIndex(storey.index); + header.guid = Guid{Guid::fromInt(storey.floorId)}; + String{storey.uName}.writeUTF8(active::utility::BufferOut{header.name}, true); + } +#endif + +} + +/*-------------------------------------------------------------------- + Default constructor + --------------------------------------------------------------------*/ +Storey::Storey() { +} //Storey::Storey + + +/*-------------------------------------------------------------------- + Constructor + + ID: The attribute ID + --------------------------------------------------------------------*/ +Storey::Storey(const database::BIMRecordID& ID) : base{ID, storeyTableID} { +} //Storey::Storey + + +/*-------------------------------------------------------------------- + Copy constructor + + source: The object to copy + --------------------------------------------------------------------*/ +Storey::Storey(const Storey& source) : base{source} { + m_data = source.m_data ? std::make_unique(*m_data) : nullptr; +} //Storey::Storey + + +/*-------------------------------------------------------------------- + Destructor + --------------------------------------------------------------------*/ +Storey::~Storey() {} + + +#ifdef ARCHICAD +/*-------------------------------------------------------------------- + Get the (immutable) API attribute header data + + return: The attribute header data (only use this data for low-level operations - for normal code, call getters/setters) + --------------------------------------------------------------------*/ +const API_Attr_Head& Storey::getHead() const { + confirmData(); + fillHeader(m_data->header, m_data->root); + return m_data->header; +} //Storey::getHead + +/*-------------------------------------------------------------------- + Get the (mutable) API attribute header data + + return: The attribute header data (only use this data for low-level operations - for normal code, call getters/setters) + --------------------------------------------------------------------*/ +API_Attr_Head& Storey::getHead() { + confirmData(); + fillHeader(m_data->header, m_data->root); + return m_data->header; +} //Storey::getHead +#endif + + +/*-------------------------------------------------------------------- + Fill an inventory with the package items + + inventory: The inventory to receive the package items + + return: True if the package has added items to the inventory + --------------------------------------------------------------------*/ +bool Storey::fillInventory(Inventory& inventory) const { + using enum Entry::Type; + inventory.merge(Inventory{ + { + { fieldID[levelID], levelID, element }, //TODO: implement other fields + }, + }.withType(&typeid(Storey))); + return base::fillInventory(inventory); +} //Storey::fillInventory + + +/*-------------------------------------------------------------------- + Get the specified cargo + + item: The inventory item to retrieve + + return: The requested cargo (nullptr on failure) + --------------------------------------------------------------------*/ +Cargo::Unique Storey::getCargo(const Inventory::Item& item) const { + if (item.ownerType != &typeid(Storey)) + return base::getCargo(item); + confirmData(); + using namespace active::serialise; + switch (item.index) { + case levelID: + return std::make_unique(m_data->root.level); + default: + return nullptr; //Requested an unknown index + } +} //Storey::getCargo + + +/*-------------------------------------------------------------------- + Set to the default package content + --------------------------------------------------------------------*/ +void Storey::setDefault() { + +} //Storey::setDefault + + +/*-------------------------------------------------------------------- + Confirm the internal data, either loading from the BIM application or setting a default + --------------------------------------------------------------------*/ +void Storey::confirmData() const { + if (m_data) + return; + m_data = std::make_unique(getStoreyData()); +} //Storey::confirmData + + +/*-------------------------------------------------------------------- + Get the storey data from the host BIM application + + return: The storey data (for internal use to populate derived classes) + --------------------------------------------------------------------*/ +API_StoryType Storey::getStoreyData() const { + if (auto project = addon()->getActiveProject().lock(); project) { + if (auto storey = project->getAttributeDatabase()->getAPIStorey(getBIMLink()); storey) + return *storey; + } + API_StoryType storey; + active::utility::Memory::erase(storey); + return storey; +} //Storey::getStoreyData diff --git a/SpeckleLib/Speckle/Record/Attribute/Storey.h b/SpeckleLib/Speckle/Record/Attribute/Storey.h new file mode 100644 index 0000000..67aeb35 --- /dev/null +++ b/SpeckleLib/Speckle/Record/Attribute/Storey.h @@ -0,0 +1,129 @@ +#ifndef SPECKLE_RECORD_ATTRIBUTE_STOREY +#define SPECKLE_RECORD_ATTRIBUTE_STOREY + +#include "Speckle/Record/Attribute/Attribute.h" + +namespace speckle::record::attribute { + + /*! + A storey or level in a building + + Represented in Archicad by `API_StoryType` + */ + class Storey : public Attribute { + public: + + // MARK: - Types + + using base = Attribute; + ///Unique pointer + using Unique = std::unique_ptr; + ///Shared pointer + using Shared = std::shared_ptr; + ///Optional + using Option = std::optional; + + // MARK: - Constructors + + using base::base; + + /*! + Default constructor + */ + Storey(); + /*! + Constructor + @param ID The attribute ID + */ + Storey(const database::BIMRecordID& ID); +#ifdef ARCHICAD + /*! + Constructor + @param attrData Archicad attribute data + */ + Storey(const API_StoryType& attrData); +#endif + /*! + Copy constructor + @param source The object to copy + */ + Storey(const Storey& source); + /*! + Destructor + */ + ~Storey(); + + /*! + Object cloning + @return A clone of this object + */ + Storey* clonePtr() const override { return new Storey{*this}; } + + + // MARK: - Functions (const) + + /*! + Get the speckle type identifier + @return The speckle type (relevant objects should override as required) + */ + speckle::utility::String getSpeckleType() const override { return "speckle::record::attribute::Storey"; } +#ifdef ARCHICAD + /*! + Get the (immutable) API attribute header data + @return The attribute header data (only use this data for low-level operations - for normal code, call getters/setters) + */ + const API_Attr_Head& getHead() const override; +#endif + + // MARK: - Functions (mutating) + +#ifdef ARCHICAD + /*! + Get the (mutable) API attribute header data + @return The attribute header data (only use this data for low-level operations - for normal code, call getters/setters) + */ + API_Attr_Head& getHead() override; +#endif + + // MARK: - Serialisation + + /*! + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ + bool fillInventory(active::serialise::Inventory& inventory) const override; + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + /*! + Set to the default package content + */ + void setDefault() override; + + protected: + + private: + /*! + Confirm the internal data, either loading from the BIM application or setting a default + */ + void confirmData() const; +#ifdef ARCHICAD + /*! + Get the storey data from the host BIM application + @return The storey data (for internal use to populate derived classes) + */ + API_StoryType getStoreyData() const; +#endif + + class Data; + ///The attribute data - mutable to support lazy loading + mutable std::unique_ptr m_data; + }; + +} + +#endif //SPECKLE_RECORD_ATTRIBUTE_STOREY diff --git a/SpeckleLib/Speckle/Record/Element/Element.cpp b/SpeckleLib/Speckle/Record/Element/Element.cpp index 7e5f6d8..4bfded8 100644 --- a/SpeckleLib/Speckle/Record/Element/Element.cpp +++ b/SpeckleLib/Speckle/Record/Element/Element.cpp @@ -3,10 +3,14 @@ #include "Active/Serialise/Item/Wrapper/ValueWrap.h" #include "Active/Serialise/Package/Wrapper/PackageWrap.h" #include "Active/Serialise/Package/Wrapper/ContainerWrap.h" +#include "Speckle/Environment/Addon.h" #include "Speckle/Primitive/Mesh/Mesh.h" +#include "Speckle/SpeckleResource.h" #include "Speckle/Utility/Guid.h" using namespace active::serialise; +using namespace speckle::environment; +using namespace speckle::record::attribute; using namespace speckle::record::element; using namespace speckle::utility; @@ -19,8 +23,10 @@ namespace speckle::record::element { public: friend class Element; +#ifdef ARCHICAD Data(const API_Element& elem) : root{std::make_unique(elem)} {} Data(const Data& source) : root{std::make_unique(*source.root)} {} +#endif private: std::unique_ptr root; @@ -41,6 +47,8 @@ namespace { Identity{"displayValue"}, }; + +#ifdef ARCHICAD void GetComponent(API_Component3D& component, API_3DTypeID typeId, Int32 index) { component.header.typeID = typeId; component.header.index = index; @@ -48,7 +56,8 @@ namespace { // TODO: throw } } - +#endif + } /*-------------------------------------------------------------------- @@ -62,8 +71,9 @@ Element::Element() { Constructor elemData: Archicad element data + tableID: The attribute table ID (attribute type) --------------------------------------------------------------------*/ -Element::Element(const API_Element& elemData) : base{elemData.header.guid} { +Element::Element(const API_Element& elemData, const speckle::utility::Guid& tableID) : base{elemData.header.guid, tableID} { m_data = std::make_unique(elemData); } //Element::Element @@ -83,8 +93,36 @@ Element::Element(const Element& source) : base{source} { --------------------------------------------------------------------*/ Element::~Element() {} -Element::Body* Element::getBody() const { +/*-------------------------------------------------------------------- + Get the element storey + + return: The element storey (nullopt if the element isn't linked to a storey) + --------------------------------------------------------------------*/ +Storey::Option Element::getStorey() const { +#ifdef ARCHICAD + return Storey{getHead().floorInd}; +#endif +} //Element::getStorey + + +/*-------------------------------------------------------------------- + Get the elmeent type name, e.g. "Wall", "Roof" etc + + return: The type name + --------------------------------------------------------------------*/ +String Element::getTypeName() const { +#ifdef ARCHICAD + GS::UniString typeName; + if (auto err = ACAPI_Element_GetElemTypeName(getHead().type, typeName); err != NoError) + return addon()->getLocalString(titleStringLib, unknownElementTypeID); + return typeName; +#endif +} //Element::getTypeName + + +Element::Body* Element::getBody() const { +#ifdef ARCHICAD if (m_data->m_cache) { return m_data->m_cache.get(); } @@ -156,9 +194,11 @@ Element::Body* Element::getBody() const { } m_data->m_cache.reset(elementBody); return m_data->m_cache.get(); +#endif } +#ifdef ARCHICAD /*-------------------------------------------------------------------- Get the (immutable) API element header data @@ -176,6 +216,7 @@ const API_Elem_Head& Element::getHead() const { API_Elem_Head& Element::getHead() { return m_data->root->header; } //Element::getHead +#endif /*-------------------------------------------------------------------- diff --git a/SpeckleLib/Speckle/Record/Element/Element.h b/SpeckleLib/Speckle/Record/Element/Element.h index 26b26f2..081119a 100644 --- a/SpeckleLib/Speckle/Record/Element/Element.h +++ b/SpeckleLib/Speckle/Record/Element/Element.h @@ -2,6 +2,7 @@ #define SPECKLE_RECORD_ELEMENT #include "Speckle/Database/Content/BIMRecord.h" +#include "Speckle/Record/Attribute/Storey.h" #include "Speckle/Utility/String.h" namespace speckle::primitive { @@ -41,8 +42,9 @@ namespace speckle::record::element { /*! Constructor @param elemData Archicad element data + @param tableID The element table ID (AC database, e.g. floor plan, 3D) */ - Element(const API_Element& elemData); + Element(const API_Element& elemData, const speckle::utility::Guid& tableID); #endif /*! Copy constructor @@ -67,7 +69,17 @@ namespace speckle::record::element { Get the speckle type identifier @return The speckle type (relevant objects should override as required) */ - speckle::utility::String getSpeckleType() const override { return "speckle::record::element::Element"; } + virtual speckle::utility::String getSpeckleType() const override { return "Objects.BuiltElements.Element:Objects.BuiltElements.Element"; } + /*! + Get the elmeent type name, e.g. "Wall", "Roof" etc + @return The type name + */ + virtual speckle::utility::String getTypeName() const; + /*! + Get the element storey + @return The element storey (nullopt if the element isn't linked to a storey) + */ + virtual attribute::Storey::Option getStorey() const; /*! Get the element body @return An array of meshes from the element body (nullptr if no body data is available) diff --git a/SpeckleLib/Speckle/SpeckleResource.h b/SpeckleLib/Speckle/SpeckleResource.h index 70843ea..bc56020 100755 --- a/SpeckleLib/Speckle/SpeckleResource.h +++ b/SpeckleLib/Speckle/SpeckleResource.h @@ -14,6 +14,7 @@ enum SpeckleStringResource { //Title strings (UI title/label for dialogs, controls, menu items etc) enum SpeckleTitleString { untitledProjectID = 1, + unknownElementTypeID, }; diff --git a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj index d67b1b9..fad870d 100644 --- a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj +++ b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj @@ -37,6 +37,16 @@ 219351B12C62CC1A00E5A69C /* Guid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219351AC2C62CC1A00E5A69C /* Guid.cpp */; }; 219351B32C62CC1A00E5A69C /* String.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219351AE2C62CC1A00E5A69C /* String.cpp */; }; 2196F2E32CB05BAF00450DFC /* LengthUnit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2196F2E22CB05BAF00450DFC /* LengthUnit.cpp */; }; + 2196F2EB2CB4816B00450DFC /* ArchicadAttributeDBaseEngine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2196F2E82CB4816B00450DFC /* ArchicadAttributeDBaseEngine.cpp */; }; + 2196F2EC2CB4816B00450DFC /* ArchicadAttributeDBaseEngine.h in Headers */ = {isa = PBXBuildFile; fileRef = 2196F2E92CB4816B00450DFC /* ArchicadAttributeDBaseEngine.h */; }; + 2196F2F02CB4823C00450DFC /* Attribute.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2196F2ED2CB4823C00450DFC /* Attribute.cpp */; }; + 2196F2F12CB4823C00450DFC /* Attribute.h in Headers */ = {isa = PBXBuildFile; fileRef = 2196F2EE2CB4823C00450DFC /* Attribute.h */; }; + 2196F2F42CB483D600450DFC /* Finish.h in Headers */ = {isa = PBXBuildFile; fileRef = 2196F2F22CB483D600450DFC /* Finish.h */; }; + 2196F2F52CB483D600450DFC /* Finish.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2196F2F32CB483D600450DFC /* Finish.cpp */; }; + 2196F2F82CB51ED400450DFC /* BIMAttributeDatabase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2196F2F62CB51ED400450DFC /* BIMAttributeDatabase.cpp */; }; + 2196F2F92CB51ED400450DFC /* BIMAttributeDatabase.h in Headers */ = {isa = PBXBuildFile; fileRef = 2196F2F72CB51ED400450DFC /* BIMAttributeDatabase.h */; }; + 2196F3042CB57E8000450DFC /* Storey.h in Headers */ = {isa = PBXBuildFile; fileRef = 2196F3022CB57E7F00450DFC /* Storey.h */; }; + 2196F3052CB57E8000450DFC /* Storey.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2196F3032CB57E7F00450DFC /* Storey.cpp */; }; 2199881E2BD833830035E5EA /* libArchicad27.a in CopyFiles */ = {isa = PBXBuildFile; fileRef = 21379E082AE47A6400A1584C /* libArchicad27.a */; }; 21AEF9BA2CA606B5000B8681 /* DetachedReference.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9B92CA606B4000B8681 /* DetachedReference.cpp */; }; 21AEF9BC2CA6DF84000B8681 /* DetachmentManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9BB2CA6DF84000B8681 /* DetachmentManager.cpp */; }; @@ -165,6 +175,16 @@ 219351AF2C62CC1A00E5A69C /* String.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = String.h; sourceTree = ""; }; 2196F2DE2CB0566500450DFC /* LengthUnit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LengthUnit.h; sourceTree = ""; }; 2196F2E22CB05BAF00450DFC /* LengthUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LengthUnit.cpp; sourceTree = ""; }; + 2196F2E82CB4816B00450DFC /* ArchicadAttributeDBaseEngine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArchicadAttributeDBaseEngine.cpp; sourceTree = ""; }; + 2196F2E92CB4816B00450DFC /* ArchicadAttributeDBaseEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArchicadAttributeDBaseEngine.h; sourceTree = ""; }; + 2196F2ED2CB4823C00450DFC /* Attribute.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Attribute.cpp; sourceTree = ""; }; + 2196F2EE2CB4823C00450DFC /* Attribute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Attribute.h; sourceTree = ""; }; + 2196F2F22CB483D600450DFC /* Finish.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Finish.h; sourceTree = ""; }; + 2196F2F32CB483D600450DFC /* Finish.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Finish.cpp; sourceTree = ""; }; + 2196F2F62CB51ED400450DFC /* BIMAttributeDatabase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BIMAttributeDatabase.cpp; sourceTree = ""; }; + 2196F2F72CB51ED400450DFC /* BIMAttributeDatabase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BIMAttributeDatabase.h; sourceTree = ""; }; + 2196F3022CB57E7F00450DFC /* Storey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Storey.h; sourceTree = ""; }; + 2196F3032CB57E7F00450DFC /* Storey.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Storey.cpp; sourceTree = ""; }; 219712682BE7E2D500D9EF7E /* Serialisation.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Serialisation.md; sourceTree = ""; }; 21AEF9B32CA5F7CF000B8681 /* DetachedWrap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedWrap.h; sourceTree = ""; }; 21AEF9B52CA5FA02000B8681 /* DetachedReference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedReference.h; sourceTree = ""; }; @@ -323,6 +343,7 @@ children = ( 215F08872CA195EC00CD343B /* ArchicadDBaseCore.cpp */, 215F08882CA195EC00CD343B /* ArchicadDBaseCore.h */, + 2196F2EA2CB4816B00450DFC /* Attribute */, 219246062CA2D22D00CF5703 /* Element */, ); path = ArchicadDBase; @@ -420,6 +441,28 @@ path = Units; sourceTree = ""; }; + 2196F2EA2CB4816B00450DFC /* Attribute */ = { + isa = PBXGroup; + children = ( + 2196F2E82CB4816B00450DFC /* ArchicadAttributeDBaseEngine.cpp */, + 2196F2E92CB4816B00450DFC /* ArchicadAttributeDBaseEngine.h */, + ); + path = Attribute; + sourceTree = ""; + }; + 2196F2EF2CB4823C00450DFC /* Attribute */ = { + isa = PBXGroup; + children = ( + 2196F2ED2CB4823C00450DFC /* Attribute.cpp */, + 2196F2EE2CB4823C00450DFC /* Attribute.h */, + 2196F2F32CB483D600450DFC /* Finish.cpp */, + 2196F2F22CB483D600450DFC /* Finish.h */, + 2196F3032CB57E7F00450DFC /* Storey.cpp */, + 2196F3022CB57E7F00450DFC /* Storey.h */, + ); + path = Attribute; + sourceTree = ""; + }; 219987FA2BD708BC0035E5EA /* SpeckleLibDoctest */ = { isa = PBXGroup; children = ( @@ -457,6 +500,8 @@ children = ( 21D0BD1D2C86F0280077E104 /* AccountDatabase.cpp */, 21D0BD1E2C86F0280077E104 /* AccountDatabase.h */, + 2196F2F62CB51ED400450DFC /* BIMAttributeDatabase.cpp */, + 2196F2F72CB51ED400450DFC /* BIMAttributeDatabase.h */, 215F08932CA19AF800CD343B /* BIMElementDatabase.cpp */, 215F08942CA19AF800CD343B /* BIMElementDatabase.h */, 21D0BD272C86FC350077E104 /* Content */, @@ -593,6 +638,7 @@ 21F69F952C71087A008B6A06 /* Record */ = { isa = PBXGroup; children = ( + 2196F2EF2CB4823C00450DFC /* Attribute */, 215F087A2CA18E1400CD343B /* Element */, 21F69F942C71087A008B6A06 /* Credentials */, ); @@ -641,22 +687,27 @@ 219246032CA2CE2700CF5703 /* BIMLink.h in Headers */, 21B67D0D2C7E0E8D00FD64FC /* ErrorReport.h in Headers */, 215F08962CA19AF800CD343B /* BIMElementDatabase.h in Headers */, + 2196F2F12CB4823C00450DFC /* Attribute.h in Headers */, 21D0BD332C86FE090077E104 /* Link.h in Headers */, 21D0BD5A2C8910400077E104 /* UserInfo.h in Headers */, 21D0BD562C890B1C0077E104 /* ServerMigration.h in Headers */, 210CC88F2C81A98500610F58 /* Guid64.h in Headers */, 21AEF9DD2CAAA4EA000B8681 /* DetachedObjectStore.h in Headers */, 215F088D2CA195EC00CD343B /* ArchicadElementDBaseEngine.h in Headers */, + 2196F2F42CB483D600450DFC /* Finish.h in Headers */, 21B67D002C7CE15100FD64FC /* Exception.h in Headers */, 21D0BD2C2C86FC350077E104 /* Record.h in Headers */, 21D0BDB42C8F8AB60077E104 /* DocumentStoreCore.h in Headers */, 215F087E2CA18E1400CD343B /* Element.h in Headers */, + 2196F2F92CB51ED400450DFC /* BIMAttributeDatabase.h in Headers */, 215F08562C99DA8D00CD343B /* Project.h in Headers */, 219245FF2CA2CC4300CF5703 /* BIMRecord.h in Headers */, 210CC8802C80CD2A00610F58 /* BridgeChild.h in Headers */, 21D0BD4D2C8901A00077E104 /* ServerInfo.h in Headers */, + 2196F3042CB57E8000450DFC /* Storey.h in Headers */, 21D0BDB52C8F8AB60077E104 /* DocumentStoreEngine.h in Headers */, 21D0BDC52C9241940077E104 /* ProjectSubscriber.h in Headers */, + 2196F2EC2CB4816B00450DFC /* ArchicadAttributeDBaseEngine.h in Headers */, 21D0BD312C86FE090077E104 /* Index.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -788,6 +839,7 @@ 21F69F812C6FF3B0008B6A06 /* BridgeArgumentWrap.cpp in Sources */, 215F088B2CA195EC00CD343B /* ArchicadDBaseCore.cpp in Sources */, 2193517B2C624FC100E5A69C /* MenuSubscriber.cpp in Sources */, + 2196F2F02CB4823C00450DFC /* Attribute.cpp in Sources */, 21F69F612C6D0286008B6A06 /* GetBindingsMethodNames.cpp in Sources */, 215F08662C9B006800CD343B /* ProjectEvent.cpp in Sources */, 21D0BDBD2C90F2830077E104 /* DocStoreSubscriber.cpp in Sources */, @@ -796,11 +848,14 @@ 2196F2E32CB05BAF00450DFC /* LengthUnit.cpp in Sources */, 21F93AEC2B2F406E009A2C5B /* Addon.cpp in Sources */, 215F087D2CA18E1400CD343B /* Element.cpp in Sources */, + 2196F2F82CB51ED400450DFC /* BIMAttributeDatabase.cpp in Sources */, 21D0BD4E2C8901A00077E104 /* ServerInfo.cpp in Sources */, 21B67D0E2C7E0E8D00FD64FC /* ErrorReport.cpp in Sources */, 21F69F7E2C6FD9FC008B6A06 /* GetCallResult.cpp in Sources */, + 2196F3052CB57E8000450DFC /* Storey.cpp in Sources */, 219245FE2CA2CC4300CF5703 /* BIMRecord.cpp in Sources */, 21AEF9BE2CA6FDA4000B8681 /* DetachedWrap.cpp in Sources */, + 2196F2F52CB483D600450DFC /* Finish.cpp in Sources */, 2193519B2C6278D900E5A69C /* SelectionSubscriber.cpp in Sources */, 21D0BD2B2C86FC350077E104 /* Record.cpp in Sources */, 219246042CA2CE2700CF5703 /* BIMLink.cpp in Sources */, @@ -815,6 +870,7 @@ 21AEF9BC2CA6DF84000B8681 /* DetachmentManager.cpp in Sources */, 215F08552C99DA8D00CD343B /* Project.cpp in Sources */, 21F69F3B2C6B880C008B6A06 /* JSBaseTransport.cpp in Sources */, + 2196F2EB2CB4816B00450DFC /* ArchicadAttributeDBaseEngine.cpp in Sources */, 210CC89F2C81E34400610F58 /* Platform.cpp in Sources */, 21D0BD202C86F0280077E104 /* AccountDatabase.cpp in Sources */, 21F69F962C71087A008B6A06 /* Account.cpp in Sources */, From 7ed4d8c807c43b1b11bc1894ced10604eaf5f322 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Thu, 10 Oct 2024 10:45:35 +0100 Subject: [PATCH 030/191] Updated VS projects --- SpeckleConnector/Connector.vcxproj | 6 ++-- SpeckleConnector/Connector.vcxproj.filters | 18 ++++++---- .../Speckle/Database/Content/BIMRecord.h | 2 +- SpeckleLib/SpeckleLib17.vcxproj | 10 ++++++ SpeckleLib/SpeckleLib17.vcxproj.filters | 36 +++++++++++++++++++ 5 files changed, 63 insertions(+), 9 deletions(-) diff --git a/SpeckleConnector/Connector.vcxproj b/SpeckleConnector/Connector.vcxproj index f7874d4..9ac1fc7 100644 --- a/SpeckleConnector/Connector.vcxproj +++ b/SpeckleConnector/Connector.vcxproj @@ -127,8 +127,9 @@ + + - @@ -178,8 +179,9 @@ + + - diff --git a/SpeckleConnector/Connector.vcxproj.filters b/SpeckleConnector/Connector.vcxproj.filters index b363df8..e879d95 100644 --- a/SpeckleConnector/Connector.vcxproj.filters +++ b/SpeckleConnector/Connector.vcxproj.filters @@ -207,9 +207,6 @@ Connector\Record\Collection - - Connector\Record\Collection - Connector\Interface\Browser\Bridge\Send\Arg @@ -225,6 +222,12 @@ Connector\Interface\Browser\Bridge\Send + + Connector\Record\Collection + + + Connector\Record\Collection + @@ -363,9 +366,6 @@ Connector\Record\Collection - - Connector\Record\Collection - Connector\Interface\Browser\Bridge\Send\Arg @@ -381,5 +381,11 @@ Connector\Interface\Browser\Bridge\Send + + Connector\Record\Collection + + + Connector\Record\Collection + \ No newline at end of file diff --git a/SpeckleLib/Speckle/Database/Content/BIMRecord.h b/SpeckleLib/Speckle/Database/Content/BIMRecord.h index 8bf5cfc..916cd1c 100644 --- a/SpeckleLib/Speckle/Database/Content/BIMRecord.h +++ b/SpeckleLib/Speckle/Database/Content/BIMRecord.h @@ -61,7 +61,7 @@ namespace speckle::database { Get a link to the BIM record @return The BIM record link */ - BIMLink getBIMLink() const { return BIMLink{ {m_applicationID, m_applicationTableID} }; } + BIMLink getBIMLink() const { return BIMLink{ BIMLink::base{m_applicationID, m_applicationTableID} }; } // MARK: - Functions (mutating) diff --git a/SpeckleLib/SpeckleLib17.vcxproj b/SpeckleLib/SpeckleLib17.vcxproj index 836d23b..c9fc7e8 100644 --- a/SpeckleLib/SpeckleLib17.vcxproj +++ b/SpeckleLib/SpeckleLib17.vcxproj @@ -20,6 +20,7 @@ + @@ -29,6 +30,7 @@ + @@ -62,6 +64,9 @@ + + + @@ -83,11 +88,13 @@ + + @@ -106,6 +113,9 @@ + + + diff --git a/SpeckleLib/SpeckleLib17.vcxproj.filters b/SpeckleLib/SpeckleLib17.vcxproj.filters index 65f51b4..dcbcf05 100644 --- a/SpeckleLib/SpeckleLib17.vcxproj.filters +++ b/SpeckleLib/SpeckleLib17.vcxproj.filters @@ -86,6 +86,12 @@ {7d5ec9ba-bc7e-412c-9b14-16c37b183409} + + {490a65bd-28e3-4282-bb33-67823e81e825} + + + {525b6bd6-96e4-48c8-91e9-9710e1e54389} + @@ -271,6 +277,21 @@ Speckle\Serialise\Units + + Speckle\Database + + + Speckle\Database\Storage\ArchicadDBase\Attribute + + + Speckle\Record\Attribute + + + Speckle\Record\Attribute + + + Speckle\Record\Attribute + @@ -384,6 +405,21 @@ Speckle\Serialise\Units + + Speckle\Database + + + Speckle\Database\Storage\ArchicadDBase\Attribute + + + Speckle\Record\Attribute + + + Speckle\Record\Attribute + + + Speckle\Record\Attribute + From f7112a407cf0cf06c9f3fdd714174864dfe11ab6 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Thu, 10 Oct 2024 12:12:35 +0100 Subject: [PATCH 031/191] Set correct base class for RecordCollection RecordCollection serialises name --- .../Connector/Record/Collection/RecordCollection.cpp | 5 +++++ .../Connector/Record/Collection/RecordCollection.h | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/SpeckleConnector/Connector/Record/Collection/RecordCollection.cpp b/SpeckleConnector/Connector/Record/Collection/RecordCollection.cpp index dcbbf51..55e747a 100644 --- a/SpeckleConnector/Connector/Record/Collection/RecordCollection.cpp +++ b/SpeckleConnector/Connector/Record/Collection/RecordCollection.cpp @@ -18,11 +18,13 @@ namespace { ///Serialisation fields enum FieldIndex { + nameID, elementID, }; ///Serialisation field IDs static std::array fieldID = { + Identity{"name"}, Identity{"elements"}, }; @@ -80,6 +82,7 @@ bool RecordCollection::fillInventory(active::serialise::Inventory& inventory) co base::fillInventory(inventory); inventory.merge(Inventory{ { + { Identity{fieldID[nameID]}, nameID, element }, { Identity{fieldID[elementID]}, elementID, m_children.size() + m_indices.size(), std::nullopt }, }, }.withType(&typeid(RecordCollection))); @@ -100,6 +103,8 @@ Cargo::Unique RecordCollection::getCargo(const Inventory::Item& item) const { using namespace active::serialise; //TODO: This is only currently coded to write collection content - reading can be added as required in future switch (item.index) { + case nameID: + return std::make_unique(m_name); case elementID: { if (item.available < m_children.size()) { auto iter = m_children.begin(); diff --git a/SpeckleConnector/Connector/Record/Collection/RecordCollection.h b/SpeckleConnector/Connector/Record/Collection/RecordCollection.h index b7be102..023a604 100644 --- a/SpeckleConnector/Connector/Record/Collection/RecordCollection.h +++ b/SpeckleConnector/Connector/Record/Collection/RecordCollection.h @@ -33,7 +33,11 @@ namespace connector::record { */ class RecordCollection : public speckle::database::Record { public: - + + // MARK: - Types + + using base = speckle::database::Record; + // MARK: - Constructors /*! From cc64d7df444bfaa933e8b0259185ff871f4cda9c Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Thu, 10 Oct 2024 13:02:57 +0100 Subject: [PATCH 032/191] Added lookup for AC storeys using an element floor index --- .../Speckle/Database/BIMAttributeDatabase.cpp | 12 +++++++ .../Speckle/Database/BIMAttributeDatabase.h | 6 ++++ .../Speckle/Database/Content/BIMRecord.h | 15 ++++++-- .../ArchicadAttributeDBaseEngine.cpp | 15 ++++++++ .../Attribute/ArchicadAttributeDBaseEngine.h | 6 ++++ .../Speckle/Record/Attribute/Storey.cpp | 34 ++++++++++++++++--- SpeckleLib/Speckle/Record/Attribute/Storey.h | 8 +++++ 7 files changed, 90 insertions(+), 6 deletions(-) diff --git a/SpeckleLib/Speckle/Database/BIMAttributeDatabase.cpp b/SpeckleLib/Speckle/Database/BIMAttributeDatabase.cpp index f7de91d..2fbf967 100644 --- a/SpeckleLib/Speckle/Database/BIMAttributeDatabase.cpp +++ b/SpeckleLib/Speckle/Database/BIMAttributeDatabase.cpp @@ -140,4 +140,16 @@ std::optional BIMAttributeDatabase::getAPIData(const BIMLink& lin std::optional BIMAttributeDatabase::getAPIStorey(const BIMLink& link) const { return m_engine->getAPIStorey(link); } //BIMAttributeDatabase::getAPIData + + +/*-------------------------------------------------------------------- + Get the ID of a storey from a specified index + + index: The storey index + + return: The storey ID (nullopt on failure) + --------------------------------------------------------------------*/ +std::optional BIMAttributeDatabase::getStoreyID(short index) const { + return m_engine->getStoreyID(index); +} //BIMAttributeDatabase::getStoreyID #endif diff --git a/SpeckleLib/Speckle/Database/BIMAttributeDatabase.h b/SpeckleLib/Speckle/Database/BIMAttributeDatabase.h index 4ff21c8..0a28b89 100644 --- a/SpeckleLib/Speckle/Database/BIMAttributeDatabase.h +++ b/SpeckleLib/Speckle/Database/BIMAttributeDatabase.h @@ -80,6 +80,12 @@ namespace speckle::database { @return The AC API storey data */ std::optional getAPIStorey(const BIMLink& link) const; + /*! + Get the ID of a storey from a specified index + @param index The storey index + @return The storey ID (nullopt on failure) + */ + std::optional getStoreyID(short index) const; #endif private: diff --git a/SpeckleLib/Speckle/Database/Content/BIMRecord.h b/SpeckleLib/Speckle/Database/Content/BIMRecord.h index 916cd1c..a9964f3 100644 --- a/SpeckleLib/Speckle/Database/Content/BIMRecord.h +++ b/SpeckleLib/Speckle/Database/Content/BIMRecord.h @@ -3,6 +3,7 @@ #include "Active/Setting/Values/Measurement/Units/LengthUnit.h" #include "Speckle/Database/Content/Record.h" +#include "Speckle/Database/Identity/BIMIndex.h" #include "Speckle/Database/Identity/BIMLink.h" #include "Speckle/Database/Identity/BIMRecordID.h" @@ -94,12 +95,22 @@ namespace speckle::database { Set to the default package content */ void setDefault() override; + + protected: + /*! + Reset the BIM index (used in lazy loading contexts where the index cannot otherwise be established) + @param index The BIM application index + */ + void resetIndex(const BIMIndex& index) const { + m_applicationID = index; + m_applicationTableID = index.tableID; + } private: ///The BIM application record ID - BIMRecordID m_applicationID; + mutable BIMRecordID m_applicationID; ///The BIM application parent table ID - BIMRecordID m_applicationTableID; + mutable BIMRecordID m_applicationTableID; ///The BIM record unit of length measurement std::optional m_unit = active::measure::LengthType::metre; }; diff --git a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.cpp b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.cpp index 2da5214..f16d675 100644 --- a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.cpp +++ b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.cpp @@ -279,4 +279,19 @@ std::optional ArchicadAttributeDBaseEngine::getAPIStorey(const BI return std::nullopt; } //ArchicadAttributeDBaseEngine::getAPIStorey + +/*-------------------------------------------------------------------- + Get the ID of a storey from a specified index + + index: The storey index + + return: The storey ID (nullopt on failure) + --------------------------------------------------------------------*/ +std::optional ArchicadAttributeDBaseEngine::getStoreyID(short index) const { + if (!m_storeyCache) + m_storeyCache = std::make_unique(); + if (auto iter = m_storeyCache->find(index); iter != m_storeyCache->end()) + return Guid::fromInt(iter->floorId); + return std::nullopt; +} //ArchicadAttributeDBaseEngine::getStoreyID #endif diff --git a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.h b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.h index f8a5787..0da60db 100644 --- a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.h +++ b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.h @@ -127,6 +127,12 @@ namespace speckle::database { @return The AC API storey data */ std::optional getAPIStorey(const BIMLink& link) const; + /*! + Get the ID of a storey from a specified index + @param index The storey index + @return The storey ID (nullopt on failure) + */ + std::optional getStoreyID(short index) const; #endif private: diff --git a/SpeckleLib/Speckle/Record/Attribute/Storey.cpp b/SpeckleLib/Speckle/Record/Attribute/Storey.cpp index 6bee954..eb44742 100644 --- a/SpeckleLib/Speckle/Record/Attribute/Storey.cpp +++ b/SpeckleLib/Speckle/Record/Attribute/Storey.cpp @@ -69,6 +69,18 @@ Storey::Storey() { } //Storey::Storey +#ifdef ARCHICAD +/*-------------------------------------------------------------------- + Constructor + + index: An index into the Archicad storey array + --------------------------------------------------------------------*/ +Storey::Storey(short index) { + +} //Storey::Storey +#endif + + /*-------------------------------------------------------------------- Constructor @@ -172,21 +184,35 @@ void Storey::setDefault() { void Storey::confirmData() const { if (m_data) return; +#ifdef ARCHICAD m_data = std::make_unique(getStoreyData()); +#endif } //Storey::confirmData +#ifdef ARCHICAD /*-------------------------------------------------------------------- Get the storey data from the host BIM application return: The storey data (for internal use to populate derived classes) --------------------------------------------------------------------*/ API_StoryType Storey::getStoreyData() const { - if (auto project = addon()->getActiveProject().lock(); project) { - if (auto storey = project->getAttributeDatabase()->getAPIStorey(getBIMLink()); storey) - return *storey; - } + do { + if (auto project = addon()->getActiveProject().lock(); project) { + auto attributeDatabase = project->getAttributeDatabase(); + if (m_storeyIndex) { + auto storeyID = attributeDatabase->getStoreyID(*m_storeyIndex); + m_storeyIndex.reset(); + if (!storeyID) + break; + resetIndex({Attribute::storeyTableID, Attribute::storeyTableID}); + } + if (auto storey = attributeDatabase->getAPIStorey(getBIMLink()); storey) + return *storey; + } + } while (false); API_StoryType storey; active::utility::Memory::erase(storey); return storey; } //Storey::getStoreyData +#endif diff --git a/SpeckleLib/Speckle/Record/Attribute/Storey.h b/SpeckleLib/Speckle/Record/Attribute/Storey.h index 67aeb35..803a772 100644 --- a/SpeckleLib/Speckle/Record/Attribute/Storey.h +++ b/SpeckleLib/Speckle/Record/Attribute/Storey.h @@ -37,6 +37,11 @@ namespace speckle::record::attribute { */ Storey(const database::BIMRecordID& ID); #ifdef ARCHICAD + /*! + Constructor + @param index An index into the Archicad storey array + */ + Storey(short index); /*! Constructor @param attrData Archicad attribute data @@ -117,6 +122,9 @@ namespace speckle::record::attribute { @return The storey data (for internal use to populate derived classes) */ API_StoryType getStoreyData() const; + + ///An index into the Archicad storey array - used temporarily for looking up the storey data on demand + mutable std::optional m_storeyIndex; #endif class Data; From 0c74a28982d09f99b7e01f92735479f30c4e8af2 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Thu, 10 Oct 2024 13:45:36 +0100 Subject: [PATCH 033/191] Fixes to Storey attribute class --- SpeckleLib/Speckle/Record/Attribute/Storey.cpp | 7 +++++-- SpeckleLib/Speckle/Record/Attribute/Storey.h | 2 -- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/SpeckleLib/Speckle/Record/Attribute/Storey.cpp b/SpeckleLib/Speckle/Record/Attribute/Storey.cpp index eb44742..01079b4 100644 --- a/SpeckleLib/Speckle/Record/Attribute/Storey.cpp +++ b/SpeckleLib/Speckle/Record/Attribute/Storey.cpp @@ -76,7 +76,7 @@ Storey::Storey() { index: An index into the Archicad storey array --------------------------------------------------------------------*/ Storey::Storey(short index) { - + m_storeyIndex = index; } //Storey::Storey #endif @@ -97,6 +97,9 @@ Storey::Storey(const database::BIMRecordID& ID) : base{ID, storeyTableID} { --------------------------------------------------------------------*/ Storey::Storey(const Storey& source) : base{source} { m_data = source.m_data ? std::make_unique(*m_data) : nullptr; +#ifdef ARCHICAD + m_storeyIndex = source.m_storeyIndex; +#endif } //Storey::Storey @@ -205,7 +208,7 @@ API_StoryType Storey::getStoreyData() const { m_storeyIndex.reset(); if (!storeyID) break; - resetIndex({Attribute::storeyTableID, Attribute::storeyTableID}); + resetIndex({*storeyID, Attribute::storeyTableID}); } if (auto storey = attributeDatabase->getAPIStorey(getBIMLink()); storey) return *storey; diff --git a/SpeckleLib/Speckle/Record/Attribute/Storey.h b/SpeckleLib/Speckle/Record/Attribute/Storey.h index 803a772..cbcf505 100644 --- a/SpeckleLib/Speckle/Record/Attribute/Storey.h +++ b/SpeckleLib/Speckle/Record/Attribute/Storey.h @@ -109,8 +109,6 @@ namespace speckle::record::attribute { */ void setDefault() override; - protected: - private: /*! Confirm the internal data, either loading from the BIM application or setting a default From 21fc2cff25a93b457c5866abc0a8151f020271d6 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Fri, 11 Oct 2024 09:58:26 +0100 Subject: [PATCH 034/191] Added FinishCollector interface as a serialisation manager to collect finishes from meshes as they are serialised ProjectCollection is now a FinishCollector (accumulates the finishes to write the material proxies at the end) --- .../Record/Collection/ProjectCollection.cpp | 59 +++++++++++++++++-- .../Record/Collection/ProjectCollection.h | 26 +++++++- .../Speckle/Record/Attribute/Finish.cpp | 41 +++++++++++++ SpeckleLib/Speckle/Record/Attribute/Finish.h | 11 ++++ .../Serialise/Collection/FinishCollector.h | 48 +++++++++++++++ .../Serialise/Detached/DetachedReference.cpp | 2 +- .../Serialise/Detached/DetachmentManager.h | 2 +- .../SpeckleLib.xcodeproj/project.pbxproj | 12 ++++ 8 files changed, 191 insertions(+), 10 deletions(-) create mode 100644 SpeckleLib/Speckle/Serialise/Collection/FinishCollector.h diff --git a/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp index 368c3a9..5ecbc69 100644 --- a/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp +++ b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp @@ -10,12 +10,22 @@ #include "Speckle/Database/BIMElementDatabase.h" #include "Speckle/Record/Element/Element.h" +#ifdef ARCHICAD +#include +#endif + using namespace active::serialise; using namespace connector::record; using namespace speckle::database; using namespace speckle::record::attribute; using namespace speckle::utility; +#ifdef ARCHICAD +namespace connector::record { + class ProjectCollection::FinishCache : public std::unordered_map {}; +} +#endif + namespace { ///Serialisation fields @@ -32,6 +42,23 @@ namespace { } +/*-------------------------------------------------------------------- + Constructor + + project: The source project + --------------------------------------------------------------------*/ +ProjectCollection::ProjectCollection(speckle::environment::Project::Shared project) : base{project->getInfo().name, project} { + m_finishes = std::make_unique(); +} //ProjectCollection::ProjectCollection + + +/*-------------------------------------------------------------------- + Destructor + --------------------------------------------------------------------*/ +ProjectCollection::~ProjectCollection() { +} //ProjectCollection::~ProjectCollection + + /*-------------------------------------------------------------------- Add an element to the collection hierarchy @@ -90,6 +117,25 @@ bool ProjectCollection::addMaterialProxy(const speckle::database::BIMIndex& mate } //ProjectCollection::addMaterialProxy +#ifdef ARCHICAD +/*-------------------------------------------------------------------- + Add a ModelerAPI material to the collection (NB: These are not persistent so need to be captured by this method) + + material: A material + objectID: The object the material is applied to + + return: True if the material proxy was added (false typically means the record already exists) + --------------------------------------------------------------------*/ +bool ProjectCollection::addMaterialProxy(const ModelerAPI::Material& material, const speckle::database::BIMRecordID& objectID) { + auto finishID = Guid::fromInt(material.GenerateHashValue()); + if (m_finishes->find(finishID) != m_finishes->end()) + return false; + auto finish = std::make_unique(material); + return m_finishes->insert({finishID, std::move(finish)}).second; +} //ProjectCollection::addMaterialProxy +#endif + + /*-------------------------------------------------------------------- Fill an inventory with the package items @@ -126,11 +172,14 @@ Cargo::Unique ProjectCollection::getCargo(const Inventory::Item& item) const { if (item.available < m_finishProxies.size()) { auto iter = m_finishProxies.begin(); std::advance(iter, item.available); - if (auto attribute = m_project->getAttributeDatabase()->getAttribute(iter->first, iter->first.tableID); attribute) { - if (auto finish = dynamic_cast(attribute.get()); finish != nullptr) { - auto proxy = std::make_unique(*finish, iter->second); - return std::make_unique(std::move(proxy)); - } + const Finish* finish = nullptr; + if (auto fin = m_finishes->find(iter->first); fin != m_finishes->end()) + finish = fin->second.get(); + else if (auto attribute = m_project->getAttributeDatabase()->getAttribute(iter->first, iter->first.tableID); attribute) + finish = dynamic_cast(attribute.get()); + if (finish != nullptr) { + auto proxy = std::make_unique(*finish, iter->second); + return std::make_unique(std::move(proxy)); } } break; diff --git a/SpeckleConnector/Connector/Record/Collection/ProjectCollection.h b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.h index 33b8931..ddf287a 100644 --- a/SpeckleConnector/Connector/Record/Collection/ProjectCollection.h +++ b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.h @@ -2,6 +2,7 @@ #define CONNECTOR_RECORD_ROOT_COLLECTiON #include "Connector/Record/Collection/RecordCollection.h" +#include "Speckle/Serialise/Collection/FinishCollector.h" #include @@ -20,7 +21,7 @@ namespace connector::record { - Other attributes, e.g. materials Add all this supplementary data to the root container as required */ - class ProjectCollection : public RecordCollection { + class ProjectCollection : public RecordCollection, public speckle::serialise::FinishCollector { public: // MARK: - Types @@ -33,7 +34,12 @@ namespace connector::record { Constructor @param project The source project */ - ProjectCollection(speckle::environment::Project::Shared project) : base{project->getInfo().name, project} {} + ProjectCollection(speckle::environment::Project::Shared project); + ProjectCollection(const ProjectCollection&) = delete; + /*! + Destructor + */ + ~ProjectCollection(); using base::base; @@ -59,7 +65,16 @@ namespace connector::record { @param objectID The object the material is applied to @return True if the material proxy was added (false typically means the record already exists) */ - bool addMaterialProxy(const speckle::database::BIMIndex& materialIndex, const speckle::database::BIMRecordID& objectID); + bool addMaterialProxy(const speckle::database::BIMIndex& materialIndex, const speckle::database::BIMRecordID& objectID) override; +#ifdef ARCHICAD + /*! + Add a ModelerAPI material to the collection (NB: These are not persistent so need to be captured by this method) + @param material A material + @param objectID The object the material is applied to + @return True if the material proxy was added (false typically means the record already exists) + */ + bool addMaterialProxy(const ModelerAPI::Material& material, const speckle::database::BIMRecordID& objectID) override; +#endif // MARK: - Serialisation @@ -81,6 +96,11 @@ namespace connector::record { ///Finish proxies accumulated from meshes generated from the collection elements FinishProxies m_finishProxies; +#ifdef ARCHICAD + class FinishCache; + ///Finishes cached from ModelerAPI materials + std::unique_ptr m_finishes; +#endif }; } diff --git a/SpeckleLib/Speckle/Record/Attribute/Finish.cpp b/SpeckleLib/Speckle/Record/Attribute/Finish.cpp index 33aad98..3f346fd 100644 --- a/SpeckleLib/Speckle/Record/Attribute/Finish.cpp +++ b/SpeckleLib/Speckle/Record/Attribute/Finish.cpp @@ -1,8 +1,13 @@ #include "Speckle/Record/Attribute/Finish.h" #include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Active/Utility/BufferOut.h" #include "Speckle/Utility/Guid.h" +#ifdef ARCHICAD +#include +#endif + using namespace active::serialise; using namespace speckle::database; using namespace speckle::record::attribute; @@ -37,6 +42,16 @@ namespace { Identity{"surfaceColour"}, }; +#ifdef ARCHICAD + /*! + Copy a ModelerAPI colour to an AC RGB colour + */ + void copyModelerColor(const ModelerAPI::Color& modelColour, API_RGBColor& colour) { + colour.f_red = modelColour.red; + colour.f_green = modelColour.green; + colour.f_blue = modelColour.blue; + } //copyModelerColor +#endif } /*-------------------------------------------------------------------- @@ -65,6 +80,31 @@ Finish::Finish(const database::BIMRecordID& ID) : base{ID, Finish::table} { Finish::Finish(const API_Attribute& attrData, const BIMRecordID& tableID) : base{attrData.header.guid, Finish::table} { m_data = std::make_unique(attrData); } + + +/*-------------------------------------------------------------------- + Constructor + + material: A ModelerAPI material definition + --------------------------------------------------------------------*/ +Finish::Finish(const ModelerAPI::Material& material) { + API_Attribute attr; + active::utility::Memory::erase(attr); + String{material.GetName()}.writeUTF8(active::utility::BufferOut{attr.header.name}); + attr.header.guid = Guid{Guid::fromInt(material.GenerateHashValue())}; + attr.material.mtype = static_cast(material.GetType()); + attr.material.ambientPc = material.GetAmbientReflection(); + attr.material.diffusePc = material.GetDiffuseReflection(); + attr.material.specularPc = material.GetSpecularReflection(); + attr.material.transpPc = material.GetTransparency(); + attr.material.shine = material.GetShining(); + attr.material.transpAtt = material.GetTransparencyAttenuation(); + attr.material.emissionAtt = material.GetEmissionAttenuation(); + copyModelerColor(material.GetSurfaceColor(), attr.material.surfaceRGB); + copyModelerColor(material.GetSpecularColor(), attr.material.specularRGB); + copyModelerColor(material.GetEmissionColor(), attr.material.emissionRGB); + m_data = std::make_unique(attr); +} //Finish::Finish #endif @@ -95,6 +135,7 @@ const API_Attr_Head& Finish::getHead() const { return m_data->root.head; } //Finish::getHead + /*-------------------------------------------------------------------- Get the (mutable) API attribute header data diff --git a/SpeckleLib/Speckle/Record/Attribute/Finish.h b/SpeckleLib/Speckle/Record/Attribute/Finish.h index 36c274b..1c597f7 100644 --- a/SpeckleLib/Speckle/Record/Attribute/Finish.h +++ b/SpeckleLib/Speckle/Record/Attribute/Finish.h @@ -3,6 +3,12 @@ #include "Speckle/Record/Attribute/Attribute.h" +#ifdef ARCHICAD +namespace ModelerAPI { + class Material; +} +#endif + namespace speckle::record::attribute { /*! @@ -50,6 +56,11 @@ namespace speckle::record::attribute { @param tableID The ID of the parent table */ Finish(const API_Attribute& attrData, const database::BIMRecordID& tableID); + /*! + Constructor + @param material A ModelerAPI material definition + */ + Finish(const ModelerAPI::Material& material); #endif /*! Copy constructor diff --git a/SpeckleLib/Speckle/Serialise/Collection/FinishCollector.h b/SpeckleLib/Speckle/Serialise/Collection/FinishCollector.h new file mode 100644 index 0000000..44d5f87 --- /dev/null +++ b/SpeckleLib/Speckle/Serialise/Collection/FinishCollector.h @@ -0,0 +1,48 @@ +#ifndef SPECKLE_SERIALISE_FINISH_COLLECTOR +#define SPECKLE_SERIALISE_FINISH_COLLECTOR + +#include "Active/Serialise/Management/Manager.h" + +#ifdef ARCHICAD +namespace ModelerAPI { + class Material; +} +#endif + +namespace speckle::serialise { + + /*! + Collector for object finishes + + Used as a serialisation manager to collect finishes from serialised objects + */ + class FinishCollector : public active::serialise::Manager { + public: + /*! + Destructor + */ + virtual ~FinishCollector() {} + + // MARK: - Functions (mutating) + + /*! + Add a material proxy record to the collection + @param materialIndex The index of the material to add + @param objectID The object the material is applied to + @return True if the material proxy was added (false typically means the record already exists) + */ + virtual bool addMaterialProxy(const speckle::database::BIMIndex& materialIndex, const speckle::database::BIMRecordID& objectID) = 0; +#ifdef ARCHICAD + /*! + Add a ModelerAPI material to the collection (NB: These are not persistent so need to be captured by this method) + @param material A material + @param objectID The object the material is applied to + @return True if the material proxy was added (false typically means the record already exists) + */ + virtual bool addMaterialProxy(const ModelerAPI::Material& material, const speckle::database::BIMRecordID& objectID) = 0; +#endif + }; + +} + +#endif //SPECKLE_SERIALISE_FINISH_COLLECTOR diff --git a/SpeckleLib/Speckle/Serialise/Detached/DetachedReference.cpp b/SpeckleLib/Speckle/Serialise/Detached/DetachedReference.cpp index 140c476..ac692a0 100644 --- a/SpeckleLib/Speckle/Serialise/Detached/DetachedReference.cpp +++ b/SpeckleLib/Speckle/Serialise/Detached/DetachedReference.cpp @@ -64,7 +64,7 @@ Cargo::Unique DetachedReference::getCargo(const Inventory::Item& item) const { //If we don't have an allocated string for receiving a reference (from 'setDefault') then we need to create one if (!m_reference) { //Ask a manager to send the detached data and provide a reference - auto detachmentManager = getManager(); + auto detachmentManager = (management() == nullptr) ? nullptr : management()->get(); if (detachmentManager == nullptr) return nullptr; //TODO: Discuss if this is a serious error - possibly throwing an exception is warranted m_reference = detachmentManager->send(std::forward(base::get()), item.identity()); diff --git a/SpeckleLib/Speckle/Serialise/Detached/DetachmentManager.h b/SpeckleLib/Speckle/Serialise/Detached/DetachmentManager.h index 094eda2..99f4119 100644 --- a/SpeckleLib/Speckle/Serialise/Detached/DetachmentManager.h +++ b/SpeckleLib/Speckle/Serialise/Detached/DetachmentManager.h @@ -1,7 +1,7 @@ #ifndef SPECKLE_SERIALISE_DETACHMENT_MANAGER #define SPECKLE_SERIALISE_DETACHMENT_MANAGER -#include "Active/Serialise/Manager.h" +#include "Active/Serialise/Management/Manager.h" #include "Active/Serialise/Transport.h" #include "Speckle/Database/Identity/RecordID.h" diff --git a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj index fad870d..6c8998f 100644 --- a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj +++ b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj @@ -48,6 +48,7 @@ 2196F3042CB57E8000450DFC /* Storey.h in Headers */ = {isa = PBXBuildFile; fileRef = 2196F3022CB57E7F00450DFC /* Storey.h */; }; 2196F3052CB57E8000450DFC /* Storey.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2196F3032CB57E7F00450DFC /* Storey.cpp */; }; 2199881E2BD833830035E5EA /* libArchicad27.a in CopyFiles */ = {isa = PBXBuildFile; fileRef = 21379E082AE47A6400A1584C /* libArchicad27.a */; }; + 21A0FBA42CB880690023F24E /* FinishCollector.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A0FB9F2CB880690023F24E /* FinishCollector.h */; }; 21AEF9BA2CA606B5000B8681 /* DetachedReference.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9B92CA606B4000B8681 /* DetachedReference.cpp */; }; 21AEF9BC2CA6DF84000B8681 /* DetachmentManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9BB2CA6DF84000B8681 /* DetachmentManager.cpp */; }; 21AEF9BE2CA6FDA4000B8681 /* DetachedWrap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9BD2CA6FDA4000B8681 /* DetachedWrap.cpp */; }; @@ -186,6 +187,7 @@ 2196F3022CB57E7F00450DFC /* Storey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Storey.h; sourceTree = ""; }; 2196F3032CB57E7F00450DFC /* Storey.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Storey.cpp; sourceTree = ""; }; 219712682BE7E2D500D9EF7E /* Serialisation.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Serialisation.md; sourceTree = ""; }; + 21A0FB9F2CB880690023F24E /* FinishCollector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FinishCollector.h; sourceTree = ""; }; 21AEF9B32CA5F7CF000B8681 /* DetachedWrap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedWrap.h; sourceTree = ""; }; 21AEF9B52CA5FA02000B8681 /* DetachedReference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedReference.h; sourceTree = ""; }; 21AEF9B72CA5FCB6000B8681 /* DetachmentManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachmentManager.h; sourceTree = ""; }; @@ -290,6 +292,7 @@ isa = PBXGroup; children = ( 2167E27C2C49121F000827D3 /* CMakeLists.txt */, + 21A0FBA02CB880690023F24E /* Collection */, 21AEF9C72CA818EA000B8681 /* Detached */, 21F69F3A2C6B880B008B6A06 /* JSBase */, 2196F2DF2CB0566500450DFC /* Units */, @@ -472,6 +475,14 @@ path = SpeckleLibDoctest; sourceTree = ""; }; + 21A0FBA02CB880690023F24E /* Collection */ = { + isa = PBXGroup; + children = ( + 21A0FB9F2CB880690023F24E /* FinishCollector.h */, + ); + path = Collection; + sourceTree = ""; + }; 21AEF9C72CA818EA000B8681 /* Detached */ = { isa = PBXGroup; children = ( @@ -693,6 +704,7 @@ 21D0BD562C890B1C0077E104 /* ServerMigration.h in Headers */, 210CC88F2C81A98500610F58 /* Guid64.h in Headers */, 21AEF9DD2CAAA4EA000B8681 /* DetachedObjectStore.h in Headers */, + 21A0FBA42CB880690023F24E /* FinishCollector.h in Headers */, 215F088D2CA195EC00CD343B /* ArchicadElementDBaseEngine.h in Headers */, 2196F2F42CB483D600450DFC /* Finish.h in Headers */, 21B67D002C7CE15100FD64FC /* Exception.h in Headers */, From 30163bfd9d95710cca09a68bd6e28112daabcef5 Mon Sep 17 00:00:00 2001 From: David Kekesi Date: Fri, 11 Oct 2024 12:44:55 +0200 Subject: [PATCH 035/191] export mesh, vertices, faces, colors --- SpeckleLib/Speckle/Record/Element/Element.cpp | 212 ++++++++++-------- 1 file changed, 117 insertions(+), 95 deletions(-) diff --git a/SpeckleLib/Speckle/Record/Element/Element.cpp b/SpeckleLib/Speckle/Record/Element/Element.cpp index 4bfded8..d9ebf92 100644 --- a/SpeckleLib/Speckle/Record/Element/Element.cpp +++ b/SpeckleLib/Speckle/Record/Element/Element.cpp @@ -8,6 +8,14 @@ #include "Speckle/SpeckleResource.h" #include "Speckle/Utility/Guid.h" +#include "Sight.hpp" +#include "Model.hpp" +#include "ModelMaterial.hpp" +#include "ModelElement.hpp" +#include "exp.h" +#include "ModelMeshBody.hpp" +#include "ConvexPolygon.hpp" + using namespace active::serialise; using namespace speckle::environment; using namespace speckle::record::attribute; @@ -18,46 +26,45 @@ using namespace speckle::utility; #include namespace speckle::record::element { - + class Element::Data { public: friend class Element; - + #ifdef ARCHICAD - Data(const API_Element& elem) : root{std::make_unique(elem)} {} - Data(const Data& source) : root{std::make_unique(*source.root)} {} + Data(const API_Element& elem) : root{ std::make_unique(elem) } {} + Data(const Data& source) : root{ std::make_unique(*source.root) } {} #endif - + private: std::unique_ptr root; std::unique_ptr m_cache; }; - + } namespace { - - ///Serialisation fields + + ///Serialisation fields enum FieldIndex { bodyID, }; - ///Serialisation field IDs + ///Serialisation field IDs static std::array fieldID = { Identity{"displayValue"}, }; - -#ifdef ARCHICAD - void GetComponent(API_Component3D& component, API_3DTypeID typeId, Int32 index) { - component.header.typeID = typeId; - component.header.index = index; - if (ACAPI_ModelAccess_GetComponent(&component) != NoError) { - // TODO: throw - } + int32_t ARGBToInt(double alpha, double red, double green, double blue) { + // Convert double (0.0 - 1.0) to uint8_t (0 - 255) + uint8_t a = static_cast(std::round(alpha * 255.0)); + uint8_t r = static_cast(std::round(red * 255.0)); + uint8_t g = static_cast(std::round(green * 255.0)); + uint8_t b = static_cast(std::round(blue * 255.0)); + + // Pack ARGB into a single 32-bit integer + return (a << 24) | (r << 16) | (g << 8) | b; } -#endif - } /*-------------------------------------------------------------------- @@ -69,21 +76,21 @@ Element::Element() { /*-------------------------------------------------------------------- Constructor - + elemData: Archicad element data tableID: The attribute table ID (attribute type) --------------------------------------------------------------------*/ -Element::Element(const API_Element& elemData, const speckle::utility::Guid& tableID) : base{elemData.header.guid, tableID} { +Element::Element(const API_Element& elemData, const speckle::utility::Guid& tableID) : base{ elemData.header.guid, tableID } { m_data = std::make_unique(elemData); } //Element::Element /*-------------------------------------------------------------------- Copy constructor - - source: The object to copy + + source: The object to copy --------------------------------------------------------------------*/ -Element::Element(const Element& source) : base{source} { +Element::Element(const Element& source) : base{ source } { m_data = source.m_data ? std::make_unique(*m_data) : nullptr; } //Element::Element @@ -96,19 +103,19 @@ Element::~Element() {} /*-------------------------------------------------------------------- Get the element storey - + return: The element storey (nullopt if the element isn't linked to a storey) --------------------------------------------------------------------*/ Storey::Option Element::getStorey() const { #ifdef ARCHICAD - return Storey{getHead().floorInd}; + return Storey{ getHead().floorInd }; #endif } //Element::getStorey /*-------------------------------------------------------------------- - Get the elmeent type name, e.g. "Wall", "Roof" etc - + Get the element type name, e.g. "Wall", "Roof" etc + return: The type name --------------------------------------------------------------------*/ String Element::getTypeName() const { @@ -121,76 +128,92 @@ String Element::getTypeName() const { } //Element::getTypeName +/*-------------------------------------------------------------------- + Get the element body as a list of faces or Meshes + + return: A pointer to the element body + --------------------------------------------------------------------*/ Element::Body* Element::getBody() const { #ifdef ARCHICAD if (m_data->m_cache) { return m_data->m_cache.get(); } - auto elementBody = new Element::Body(); - std::map vertexIndexMap; - int currentVertexIndex = 0; - API_ElemInfo3D info3D = {}; - - if (ACAPI_ModelAccess_Get3DInfo(getHead(), &info3D) != NoError) { - // TODO: throw + void* dummy = nullptr; + GSErrCode err = ACAPI_Sight_GetCurrentWindowSight(&dummy); + if (err != NoError) + { + // TODO: should this throw? } - for (Int32 ib = info3D.fbody; ib <= info3D.lbody; ib++) { - API_Component3D component = {}; - GetComponent(component, API_BodyID, ib); + Modeler::SightPtr currentSightPtr((Modeler::Sight*)dummy); // init the shared ptr with the raw pointer + ModelerAPI::Model acModel; + Modeler::IAttributeReader* attrReader = ACAPI_Attribute_GetCurrentAttributeSetReader(); - std::vector vertices; - std::vector faces; - std::vector colors; + err = EXPGetModel(currentSightPtr, &acModel, attrReader); + if (err != NoError) + { + // TODO: should this throw? + } - vertices.clear(); - faces.clear(); - colors.clear(); + auto elementBody = new Element::Body(); - Int32 nPgon = component.body.nPgon; - for (Int32 ip = 1; ip <= nPgon; ip++) { - GetComponent(component, API_PgonID, ip); + Int32 nElements = acModel.GetElementCount(); + for (Int32 iElement = 1; iElement <= nElements; iElement++) + { + ModelerAPI::Element elem{}; + acModel.GetElement(iElement, &elem); + if (elem.GetElemGuid() != getHead().guid) + continue; - Int32 fpedg = component.pgon.fpedg; - Int32 lpedg = component.pgon.lpedg; - Int32 faceSize = lpedg - fpedg + 1; - faces.push_back(faceSize); - for (Int32 ie = fpedg; ie <= lpedg; ie++) + Int32 nBodies = elem.GetTessellatedBodyCount(); + for (Int32 bodyIndex = 1; bodyIndex <= nBodies; ++bodyIndex) + { + ModelerAPI::MeshBody body{}; + elem.GetTessellatedBody(bodyIndex, &body); + + Int32 polyCount = body.GetPolygonCount(); + for (Int32 polyIndex = 1; polyIndex <= polyCount; ++polyIndex) { - GetComponent(component, API_PedgID, ie); + ModelerAPI::Polygon polygon{}; + body.GetPolygon(polyIndex, &polygon); - // TODO is this needed? need review, not sure how ACAPI_ModelAccess works - bool wasNegative = component.pedg.pedg < 0; - Int32 edgeIndex = std::abs(component.pedg.pedg); - GetComponent(component, API_EdgeID, edgeIndex); + ModelerAPI::Material material{}; + polygon.GetMaterial(&material); + Int32 convexPolyCount = polygon.GetConvexPolygonCount(); - // TODO is this needed? need review, not sure how ACAPI_ModelAccess works - Int32 vertexIndex = wasNegative ? component.edge.vert2 : component.edge.vert1; - /*auto materialIndex = component.pgon.iumat; - GetComponent(component, API_UmatID, materialIndex); - double R = component.umat.mater.surfaceRGB.f_red; - double G = component.umat.mater.surfaceRGB.f_green; - double B = component.umat.mater.surfaceRGB.f_blue;*/ - // TODO: other material stuff + for (Int32 convPolyIndex = 1; convPolyIndex <= convexPolyCount; ++convPolyIndex) + { + std::vector vertices; + std::vector faces; + std::vector colors; - GetComponent(component, API_VertID, vertexIndex); + ModelerAPI::ConvexPolygon convexPolygon{}; + polygon.GetConvexPolygon(convPolyIndex, &convexPolygon); + Int32 vertexCount = convexPolygon.GetVertexCount(); - if (vertexIndexMap.find(vertexIndex) == vertexIndexMap.end()) { - faces.push_back(currentVertexIndex); - vertexIndexMap[vertexIndex] = currentVertexIndex++; + faces.push_back(vertexCount); + for (Int32 vertexIndex = 1; vertexIndex <= vertexCount; ++vertexIndex) + { + ModelerAPI::Vertex vertex{}; + body.GetVertex(convexPolygon.GetVertexIndex(vertexIndex), &vertex); - vertices.push_back(component.vert.x); - vertices.push_back(component.vert.y); - vertices.push_back(component.vert.z); - } - else { - faces.push_back(vertexIndexMap[vertexIndex]); + // TODO: change vertices array to hold Vertex instead of double values + vertices.push_back(vertex.x); + vertices.push_back(vertex.y); + vertices.push_back(vertex.z); + + double alpha = material.GetTransparency(); + ModelerAPI::Color color = material.GetSurfaceColor(); + colors.push_back(ARGBToInt(alpha, color.red, color.green, color.blue)); + + faces.push_back(vertexIndex - 1); + } + elementBody->push_back(primitive::Mesh(std::move(vertices), std::move(faces), std::move(colors))); } } } - elementBody->push_back(primitive::Mesh(std::move(vertices), std::move(faces), std::move(colors))); } m_data->m_cache.reset(elementBody); return m_data->m_cache.get(); @@ -201,7 +224,7 @@ Element::Body* Element::getBody() const { #ifdef ARCHICAD /*-------------------------------------------------------------------- Get the (immutable) API element header data - + return: The element header data (only use this data for low-level operations - for normal code, call getters/setters) --------------------------------------------------------------------*/ const API_Elem_Head& Element::getHead() const { @@ -210,7 +233,7 @@ const API_Elem_Head& Element::getHead() const { /*-------------------------------------------------------------------- Get the (mutable) API element header data - + return: The element header data (only use this data for low-level operations - for normal code, call getters/setters) --------------------------------------------------------------------*/ API_Elem_Head& Element::getHead() { @@ -221,9 +244,9 @@ API_Elem_Head& Element::getHead() { /*-------------------------------------------------------------------- Fill an inventory with the package items - + inventory: The inventory to receive the package items - + return: True if the package has added items to the inventory --------------------------------------------------------------------*/ bool Element::fillInventory(Inventory& inventory) const { @@ -231,18 +254,18 @@ bool Element::fillInventory(Inventory& inventory) const { auto body = getBody(); inventory.merge(Inventory{ { - { fieldID[bodyID], bodyID, body == nullptr ? 0 : static_cast(body->size()) }, //TODO: implement other fields + { fieldID[bodyID], bodyID, element }, //TODO: implement other fields }, - }.withType(&typeid(Element))); + }.withType(&typeid(Element))); return base::fillInventory(inventory); } //Element::fillInventory /*-------------------------------------------------------------------- Get the specified cargo - + item: The inventory item to retrieve - + return: The requested cargo (nullptr on failure) --------------------------------------------------------------------*/ Cargo::Unique Element::getCargo(const Inventory::Item& item) const { @@ -250,17 +273,16 @@ Cargo::Unique Element::getCargo(const Inventory::Item& item) const { return base::getCargo(item); using namespace active::serialise; switch (item.index) { - case bodyID: - if (auto body = getBody(); body != nullptr) - { - //return std::make_unique(*body); - return Cargo::Unique{ new active::serialise::ContainerWrap{ *body } }; - } - else - return nullptr; - - default: - return nullptr; //Requested an unknown index + case bodyID: + if (auto body = getBody(); body != nullptr) + { + return Cargo::Unique{ new active::serialise::ContainerWrap{ *body } }; + } + else + return nullptr; + + default: + return nullptr; //Requested an unknown index } } //Element::getCargo From de46d899b07fae5a068e02abbb2d42715bbf45bb Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Fri, 11 Oct 2024 11:45:10 +0100 Subject: [PATCH 036/191] Added FinishProxy to collect mesh finishes (to build 'material proxy collection) --- SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp | 7 +++ .../Speckle/Record/Attribute/Finish.cpp | 3 ++ .../Serialise/Collection/FinishProxy.h | 54 +++++++++++++++++++ .../SpeckleLib.xcodeproj/project.pbxproj | 2 + 4 files changed, 66 insertions(+) create mode 100644 SpeckleLib/Speckle/Serialise/Collection/FinishProxy.h diff --git a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp index dfebf16..5251c28 100644 --- a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp +++ b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp @@ -4,6 +4,7 @@ #include "Active/Serialise/Package/Wrapper/PackageWrap.h" #include "Active/Serialise/Package/Wrapper/ContainerWrap.h" #include "Active/Serialise/Inventory/Identity.h" +#include "Speckle/Serialise/Collection/FinishProxy.h" #include @@ -17,6 +18,7 @@ namespace { vertexID, faceID, colorID, + proxyID, }; ///Serialisation field IDs @@ -24,6 +26,7 @@ namespace { Identity{"vertices"}, Identity{"faces"}, Identity{"colors"}, + Identity{"proxy"}, }; } @@ -42,6 +45,7 @@ bool Mesh::fillInventory(Inventory& inventory) const { { fieldID[vertexID], vertexID, element }, { fieldID[faceID], faceID, element }, { fieldID[colorID], colorID, element }, + { fieldID[proxyID], proxyID, element }, }, }.withType(&typeid(Mesh))); return base::fillInventory(inventory); @@ -66,6 +70,9 @@ Cargo::Unique Mesh::getCargo(const Inventory::Item& item) const { return std::make_unique>>(faces); case colorID: return std::make_unique>>(colors); + case proxyID: + return nullptr; //Activate the following line when the mesh material is available to add to the collector + //return std::make_unique(getBIMID(), material); default: return nullptr; //Requested an unknown index } diff --git a/SpeckleLib/Speckle/Record/Attribute/Finish.cpp b/SpeckleLib/Speckle/Record/Attribute/Finish.cpp index 3f346fd..448b9d4 100644 --- a/SpeckleLib/Speckle/Record/Attribute/Finish.cpp +++ b/SpeckleLib/Speckle/Record/Attribute/Finish.cpp @@ -1,7 +1,9 @@ #include "Speckle/Record/Attribute/Finish.h" #include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Active/Serialise/Management/Management.h" #include "Active/Utility/BufferOut.h" +#include "Speckle/Serialise/Collection/FinishCollector.h" #include "Speckle/Utility/Guid.h" #ifdef ARCHICAD @@ -11,6 +13,7 @@ using namespace active::serialise; using namespace speckle::database; using namespace speckle::record::attribute; +using namespace speckle::serialise; using namespace speckle::utility; #include diff --git a/SpeckleLib/Speckle/Serialise/Collection/FinishProxy.h b/SpeckleLib/Speckle/Serialise/Collection/FinishProxy.h new file mode 100644 index 0000000..97e29a0 --- /dev/null +++ b/SpeckleLib/Speckle/Serialise/Collection/FinishProxy.h @@ -0,0 +1,54 @@ +#ifndef SPECKLE_SERIALISE_FINISH_PROXY +#define SPECKLE_SERIALISE_FINISH_PROXY + +#include "Active/Serialise/Management/Management.h" + +#include "Speckle/Serialise/Collection/FinishCollector.h" + +#ifdef ARCHICAD +namespace ModelerAPI { + class Material; +} +#endif + +namespace speckle::serialise { + + /*! + Proxy cargo for tranporting a mesh finish + + Mesh finishes are currently not serialised with the mesh - instead, they are gathered into a 'material proxy' container that points back to + the target meshes. This proxy allows the mesh to inform the finishes collector (acting as a serialisation manager) to link the mesh with + its finish so the manager can build the 'material proxies' at the end of the project collection. + */ + class FinishProxy : public active::serialise::Package { + public: + FinishProxy(const database::BIMRecordID& meshID, const ModelerAPI::Material& material) : m_objectID{meshID}, m_material{material} {} + + /*! + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return: True if the package has added items to the inventory + */ + bool fillInventory(active::serialise::Inventory& inventory) const { + //NB: This object only exists to populate the finish collection - it doesn't carry any serialisable content + if (management() != nullptr) { + if (auto collector = management()->get(); collector != nullptr) + collector->addMaterialProxy(m_material, m_objectID); + } + return true; + } //DocumentInfo::fillInventory + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const { return nullptr; } //Empty placeholder + + private: + const database::BIMRecordID& m_objectID; + const ModelerAPI::Material& m_material; + }; + +} + +#endif //SPECKLE_SERIALISE_FINISH_PROXY diff --git a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj index 6c8998f..2a4d670 100644 --- a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj +++ b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj @@ -188,6 +188,7 @@ 2196F3032CB57E7F00450DFC /* Storey.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Storey.cpp; sourceTree = ""; }; 219712682BE7E2D500D9EF7E /* Serialisation.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Serialisation.md; sourceTree = ""; }; 21A0FB9F2CB880690023F24E /* FinishCollector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FinishCollector.h; sourceTree = ""; }; + 21A0FBA92CB9324A0023F24E /* FinishProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FinishProxy.h; sourceTree = ""; }; 21AEF9B32CA5F7CF000B8681 /* DetachedWrap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedWrap.h; sourceTree = ""; }; 21AEF9B52CA5FA02000B8681 /* DetachedReference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedReference.h; sourceTree = ""; }; 21AEF9B72CA5FCB6000B8681 /* DetachmentManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachmentManager.h; sourceTree = ""; }; @@ -479,6 +480,7 @@ isa = PBXGroup; children = ( 21A0FB9F2CB880690023F24E /* FinishCollector.h */, + 21A0FBA92CB9324A0023F24E /* FinishProxy.h */, ); path = Collection; sourceTree = ""; From a117e327c736437a1f8162cd58b4787dc275182f Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Fri, 11 Oct 2024 11:47:35 +0100 Subject: [PATCH 037/191] Updated VS project --- SpeckleLib/SpeckleLib17.vcxproj | 2 ++ SpeckleLib/SpeckleLib17.vcxproj.filters | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/SpeckleLib/SpeckleLib17.vcxproj b/SpeckleLib/SpeckleLib17.vcxproj index c9fc7e8..73d3154 100644 --- a/SpeckleLib/SpeckleLib17.vcxproj +++ b/SpeckleLib/SpeckleLib17.vcxproj @@ -72,6 +72,8 @@ + + diff --git a/SpeckleLib/SpeckleLib17.vcxproj.filters b/SpeckleLib/SpeckleLib17.vcxproj.filters index dcbcf05..458d545 100644 --- a/SpeckleLib/SpeckleLib17.vcxproj.filters +++ b/SpeckleLib/SpeckleLib17.vcxproj.filters @@ -92,6 +92,9 @@ {525b6bd6-96e4-48c8-91e9-9710e1e54389} + + {b5733e9f-b72a-4162-9fc7-8feeec594e5b} + @@ -292,6 +295,12 @@ Speckle\Record\Attribute + + Speckle\Serialise\Collection + + + Speckle\Serialise\Collection + From 791e9f072ffef984e4e23a4f25866b5a68ce6cf3 Mon Sep 17 00:00:00 2001 From: David Kekesi Date: Fri, 11 Oct 2024 17:10:05 +0200 Subject: [PATCH 038/191] finish proxies wip --- .../Record/Collection/ProjectCollection.cpp | 10 +-- SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp | 10 +-- SpeckleLib/Speckle/Primitive/Mesh/Mesh.h | 19 +++-- .../Speckle/Record/Attribute/Finish.cpp | 69 +++++++++++++++---- SpeckleLib/Speckle/Record/Element/Element.cpp | 6 +- 5 files changed, 85 insertions(+), 29 deletions(-) diff --git a/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp index 5ecbc69..f491fe3 100644 --- a/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp +++ b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp @@ -128,10 +128,12 @@ bool ProjectCollection::addMaterialProxy(const speckle::database::BIMIndex& mate --------------------------------------------------------------------*/ bool ProjectCollection::addMaterialProxy(const ModelerAPI::Material& material, const speckle::database::BIMRecordID& objectID) { auto finishID = Guid::fromInt(material.GenerateHashValue()); - if (m_finishes->find(finishID) != m_finishes->end()) - return false; - auto finish = std::make_unique(material); - return m_finishes->insert({finishID, std::move(finish)}).second; + auto iter = m_finishes->find(finishID); + if (iter == m_finishes->end()) { + auto finish = std::make_unique(material); + iter = m_finishes->insert({ finishID, std::move(finish) }).first; + } + return addMaterialProxy(finishID, objectID); } //ProjectCollection::addMaterialProxy #endif diff --git a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp index 5251c28..b07ea0f 100644 --- a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp +++ b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp @@ -10,6 +10,7 @@ using namespace active::serialise; using namespace speckle::primitive; +using namespace speckle::serialise; namespace { @@ -65,14 +66,13 @@ Cargo::Unique Mesh::getCargo(const Inventory::Item& item) const { using namespace active::serialise; switch (item.index) { case vertexID: - return std::make_unique>>(vertices); + return std::make_unique>>(m_vertices); case faceID: - return std::make_unique>>(faces); + return std::make_unique>>(m_faces); case colorID: - return std::make_unique>>(colors); + return std::make_unique>>(m_colors); case proxyID: - return nullptr; //Activate the following line when the mesh material is available to add to the collector - //return std::make_unique(getBIMID(), material); + return std::make_unique(getBIMID(), m_material); default: return nullptr; //Requested an unknown index } diff --git a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h index 93f2788..993f653 100644 --- a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h +++ b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h @@ -4,6 +4,10 @@ #include "Speckle/Database/Content/BIMRecord.h" #include "Speckle/Utility/String.h" +#ifdef ARCHICAD +#include "ModelMaterial.hpp" +#endif + namespace speckle::primitive { /*! @@ -22,7 +26,7 @@ namespace speckle::primitive { Default constructor @param unit The mesh unit type */ - Mesh(active::measure::LengthType unit = active::measure::LengthType::metre) : base{unit} {} + Mesh(active::measure::LengthType unit = active::measure::LengthType::metre) : base{ utility::Guid{true}, utility::Guid{}, unit } {} /*! Constructor @param vertices The mesh vertices @@ -30,9 +34,9 @@ namespace speckle::primitive { @param colors The mesh face colours @param unit The mesh unit type */ - Mesh(std::vector&& vertices, std::vector&& faces, std::vector&& colors, + Mesh(std::vector&& vertices, std::vector&& faces, std::vector&& colors, const ModelerAPI::Material& material, active::measure::LengthType unit = active::measure::LengthType::metre) : - base{unit}, vertices {std::move(vertices)}, faces{std::move(faces)}, colors{std::move(colors)} {} + base{ unit }, m_vertices{ std::move(vertices) }, m_faces{ std::move(faces) }, m_colors{ std::move(colors) }, m_material{ material } {} // MARK: - Functions (const) @@ -58,9 +62,12 @@ namespace speckle::primitive { active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; private: - std::vector vertices; - std::vector faces; - std::vector colors; + std::vector m_vertices; + std::vector m_faces; + std::vector m_colors; +#ifdef ARCHICAD + ModelerAPI::Material m_material; +#endif }; } diff --git a/SpeckleLib/Speckle/Record/Attribute/Finish.cpp b/SpeckleLib/Speckle/Record/Attribute/Finish.cpp index 448b9d4..49976db 100644 --- a/SpeckleLib/Speckle/Record/Attribute/Finish.cpp +++ b/SpeckleLib/Speckle/Record/Attribute/Finish.cpp @@ -2,6 +2,7 @@ #include "Active/Serialise/Item/Wrapper/ValueWrap.h" #include "Active/Serialise/Management/Management.h" +#include "Active/Serialise/CargoHold.h" #include "Active/Utility/BufferOut.h" #include "Speckle/Serialise/Collection/FinishCollector.h" #include "Speckle/Utility/Guid.h" @@ -37,12 +38,20 @@ namespace { ///Serialisation fields enum FieldIndex { - surfaceColourID, + diffuseID, + opacityID, + emissiveID, + metalnessID, + roughnessID, }; ///Serialisation field IDs static std::array fieldID = { - Identity{"surfaceColour"}, + Identity{"diffuse"}, + Identity{"opacity"}, + Identity{"emissive"}, + Identity{"metalness"}, + Identity{"roughness"}, }; #ifdef ARCHICAD @@ -55,6 +64,28 @@ namespace { colour.f_blue = modelColour.blue; } //copyModelerColor #endif + + int32_t ARGBToInt(double alpha, double red, double green, double blue) { + // Convert double (0.0 - 1.0) to uint8_t (0 - 255) + uint8_t a = static_cast(std::round(alpha * 255.0)); + uint8_t r = static_cast(std::round(red * 255.0)); + uint8_t g = static_cast(std::round(green * 255.0)); + uint8_t b = static_cast(std::round(blue * 255.0)); + + // Pack ARGB into a single 32-bit integer + return (a << 24) | (r << 16) | (g << 8) | b; + } + + int32_t ARGBToInt(double alpha, const API_RGBColor& color) { + // Convert double (0.0 - 1.0) to uint8_t (0 - 255) + uint8_t a = static_cast(std::round(alpha * 255.0)); + uint8_t r = static_cast(std::round(color.f_red * 255.0)); + uint8_t g = static_cast(std::round(color.f_green * 255.0)); + uint8_t b = static_cast(std::round(color.f_blue * 255.0)); + + // Pack ARGB into a single 32-bit integer + return (a << 24) | (r << 16) | (g << 8) | b; + } } /*-------------------------------------------------------------------- @@ -96,13 +127,13 @@ Finish::Finish(const ModelerAPI::Material& material) { String{material.GetName()}.writeUTF8(active::utility::BufferOut{attr.header.name}); attr.header.guid = Guid{Guid::fromInt(material.GenerateHashValue())}; attr.material.mtype = static_cast(material.GetType()); - attr.material.ambientPc = material.GetAmbientReflection(); - attr.material.diffusePc = material.GetDiffuseReflection(); - attr.material.specularPc = material.GetSpecularReflection(); - attr.material.transpPc = material.GetTransparency(); - attr.material.shine = material.GetShining(); - attr.material.transpAtt = material.GetTransparencyAttenuation(); - attr.material.emissionAtt = material.GetEmissionAttenuation(); + attr.material.ambientPc = static_cast(material.GetAmbientReflection() * 100); + attr.material.diffusePc = static_cast(material.GetDiffuseReflection() * 100); + attr.material.specularPc = static_cast(material.GetSpecularReflection() * 100); + attr.material.transpPc = static_cast(material.GetTransparency() * 100); + attr.material.shine = static_cast(material.GetShining() * 10000); + attr.material.transpAtt = static_cast(material.GetTransparencyAttenuation() * 400); + attr.material.emissionAtt = static_cast(material.GetEmissionAttenuation() * 65535); copyModelerColor(material.GetSurfaceColor(), attr.material.surfaceRGB); copyModelerColor(material.GetSpecularColor(), attr.material.specularRGB); copyModelerColor(material.GetEmissionColor(), attr.material.emissionRGB); @@ -162,7 +193,11 @@ bool Finish::fillInventory(Inventory& inventory) const { using enum Entry::Type; inventory.merge(Inventory{ { - { fieldID[surfaceColourID], surfaceColourID, element }, //TODO: implement other fields + { fieldID[diffuseID], diffuseID, element }, + { fieldID[opacityID], opacityID, element }, + { fieldID[emissiveID], emissiveID, element }, + { fieldID[metalnessID], metalnessID, element }, + { fieldID[roughnessID], roughnessID, element }, }, }.withType(&typeid(Finish))); return base::fillInventory(inventory); @@ -182,8 +217,18 @@ Cargo::Unique Finish::getCargo(const Inventory::Item& item) const { confirmData(); using namespace active::serialise; switch (item.index) { - case surfaceColourID: - return nullptr; //TODO: lookup surface colour + case diffuseID: { + auto opacity = 1.0 - m_data->root.transpPc; + return std::make_unique>(ARGBToInt(opacity, m_data->root.surfaceRGB)); + } + case opacityID: + return std::make_unique>(1.0); + case emissiveID: + return std::make_unique>(ARGBToInt(0.0, 0.0, 0.0, 0.0)); + case metalnessID: + return std::make_unique>(1.0); + case roughnessID: + return std::make_unique>(1.0); default: return nullptr; //Requested an unknown index } diff --git a/SpeckleLib/Speckle/Record/Element/Element.cpp b/SpeckleLib/Speckle/Record/Element/Element.cpp index d9ebf92..ae55843 100644 --- a/SpeckleLib/Speckle/Record/Element/Element.cpp +++ b/SpeckleLib/Speckle/Record/Element/Element.cpp @@ -8,6 +8,7 @@ #include "Speckle/SpeckleResource.h" #include "Speckle/Utility/Guid.h" +#ifdef ARCHICAD #include "Sight.hpp" #include "Model.hpp" #include "ModelMaterial.hpp" @@ -15,6 +16,7 @@ #include "exp.h" #include "ModelMeshBody.hpp" #include "ConvexPolygon.hpp" +#endif using namespace active::serialise; using namespace speckle::environment; @@ -206,11 +208,11 @@ Element::Body* Element::getBody() const { double alpha = material.GetTransparency(); ModelerAPI::Color color = material.GetSurfaceColor(); - colors.push_back(ARGBToInt(alpha, color.red, color.green, color.blue)); + //colors.push_back(ARGBToInt(alpha, color.red, color.green, color.blue)); faces.push_back(vertexIndex - 1); } - elementBody->push_back(primitive::Mesh(std::move(vertices), std::move(faces), std::move(colors))); + elementBody->push_back(primitive::Mesh(std::move(vertices), std::move(faces), std::move(colors), material)); } } } From 65b636accb5cf3b0e2f0e0a03fe6d829fadaf9d5 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Fri, 11 Oct 2024 16:53:42 +0100 Subject: [PATCH 039/191] Mesh serialisation now directly engages with management to populate material proxies rather than using a "dummy" field --- SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp | 19 ++++++++++++++----- SpeckleLib/Speckle/Primitive/Mesh/Mesh.h | 5 +++++ SpeckleLib/Speckle/Record/Element/Element.cpp | 9 ++++----- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp index b07ea0f..23b0f83 100644 --- a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp +++ b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.cpp @@ -19,7 +19,6 @@ namespace { vertexID, faceID, colorID, - proxyID, }; ///Serialisation field IDs @@ -27,7 +26,6 @@ namespace { Identity{"vertices"}, Identity{"faces"}, Identity{"colors"}, - Identity{"proxy"}, }; } @@ -46,7 +44,6 @@ bool Mesh::fillInventory(Inventory& inventory) const { { fieldID[vertexID], vertexID, element }, { fieldID[faceID], faceID, element }, { fieldID[colorID], colorID, element }, - { fieldID[proxyID], proxyID, element }, }, }.withType(&typeid(Mesh))); return base::fillInventory(inventory); @@ -71,9 +68,21 @@ Cargo::Unique Mesh::getCargo(const Inventory::Item& item) const { return std::make_unique>>(m_faces); case colorID: return std::make_unique>>(m_colors); - case proxyID: - return std::make_unique(getBIMID(), m_material); default: return nullptr; //Requested an unknown index } } //Mesh::getCargo + + +/*-------------------------------------------------------------------- + Use a manager in (de)serialisation processes + + management: The management to use + --------------------------------------------------------------------*/ +void Mesh::useManagement(Management* management) const { + //NB: This object only exists to populate the finish collection - it doesn't carry any serialisable content + if (management != nullptr) { + if (auto collector = management->get(); collector != nullptr) + collector->addMaterialProxy(m_material, getBIMID()); + } +} //Mesh::useManagement diff --git a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h index 993f653..2fe5dbb 100644 --- a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h +++ b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h @@ -60,6 +60,11 @@ namespace speckle::primitive { @return The requested cargo (nullptr on failure) */ active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + /*! + Use a manager in (de)serialisation processes + @param management The management to use + */ + void useManagement(active::serialise::Management* management) const override; private: std::vector m_vertices; diff --git a/SpeckleLib/Speckle/Record/Element/Element.cpp b/SpeckleLib/Speckle/Record/Element/Element.cpp index ae55843..d5605fd 100644 --- a/SpeckleLib/Speckle/Record/Element/Element.cpp +++ b/SpeckleLib/Speckle/Record/Element/Element.cpp @@ -206,8 +206,8 @@ Element::Body* Element::getBody() const { vertices.push_back(vertex.y); vertices.push_back(vertex.z); - double alpha = material.GetTransparency(); - ModelerAPI::Color color = material.GetSurfaceColor(); + //double alpha = material.GetTransparency(); + //ModelerAPI::Color color = material.GetSurfaceColor(); //colors.push_back(ARGBToInt(alpha, color.red, color.green, color.blue)); faces.push_back(vertexIndex - 1); @@ -253,12 +253,11 @@ API_Elem_Head& Element::getHead() { --------------------------------------------------------------------*/ bool Element::fillInventory(Inventory& inventory) const { using enum Entry::Type; - auto body = getBody(); inventory.merge(Inventory{ { { fieldID[bodyID], bodyID, element }, //TODO: implement other fields }, - }.withType(&typeid(Element))); + }.withType(&typeid(Element))); return base::fillInventory(inventory); } //Element::fillInventory @@ -278,7 +277,7 @@ Cargo::Unique Element::getCargo(const Inventory::Item& item) const { case bodyID: if (auto body = getBody(); body != nullptr) { - return Cargo::Unique{ new active::serialise::ContainerWrap{ *body } }; + return Cargo::Unique{ new active::serialise::ContainerWrap{*body} }; } else return nullptr; From d3492512cd978baa2c24038531986d4c222c4aa7 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Fri, 11 Oct 2024 17:19:04 +0100 Subject: [PATCH 040/191] Update SendObject and SendViaBrowserArgs to use serialisation management (to support collection of material proxies) --- .../Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h | 5 +++++ .../Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h index 601c330..86d6ea8 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h @@ -43,6 +43,11 @@ namespace connector::interfac::browser::bridge { @return The requested cargo (nullptr on failure) */ Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + /*! + Use a manager in (de)serialisation processes + @param management The management to use + */ + void useManagement(active::serialise::Management* management) const override { m_object->useManagement(management); } private: ///The object to send diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h index c611732..b2b2347 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h @@ -72,6 +72,11 @@ namespace connector::interfac::browser::bridge { @return The requested cargo (nullptr on failure) */ Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + /*! + Use a manager in (de)serialisation processes + @param management The management to use + */ + void useManagement(active::serialise::Management* management) const override { sendObject.useManagement(management); } }; } From 36e50bb63e7570a2ad83c1a7bd2d01a08904c8a1 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Fri, 11 Oct 2024 17:44:41 +0100 Subject: [PATCH 041/191] SendObject and SendViaBrowserArgs forward the wrapped object management to the serialiser ProjectCollection defines itself as a serialisation manager (to collect material proxies) --- .../Interface/Browser/Bridge/Send/Arg/SendObject.h | 5 +++++ .../Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h | 5 +++++ .../Connector/Record/Collection/ProjectCollection.cpp | 6 +++++- .../Connector/Record/Collection/ProjectCollection.h | 5 +++++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h index 86d6ea8..662b2e3 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h @@ -48,6 +48,11 @@ namespace connector::interfac::browser::bridge { @param management The management to use */ void useManagement(active::serialise::Management* management) const override { m_object->useManagement(management); } + /*! + Get the cargo management + @return The active management + */ + active::serialise::Management* management() const override { return m_object->management(); } private: ///The object to send diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h index b2b2347..71cef33 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h @@ -77,6 +77,11 @@ namespace connector::interfac::browser::bridge { @param management The management to use */ void useManagement(active::serialise::Management* management) const override { sendObject.useManagement(management); } + /*! + Get the cargo management + @return The active management + */ + active::serialise::Management* management() const override { return sendObject.management(); } }; } diff --git a/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp index f491fe3..44ded4a 100644 --- a/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp +++ b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp @@ -2,6 +2,7 @@ #include "Active/Serialise/CargoHold.h" #include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Active/Serialise/Management/Management.h" #include "Active/Serialise/Package/Wrapper/PackageWrap.h" #include "Connector/Connector.h" #include "Connector/ConnectorResource.h" @@ -47,8 +48,11 @@ namespace { project: The source project --------------------------------------------------------------------*/ -ProjectCollection::ProjectCollection(speckle::environment::Project::Shared project) : base{project->getInfo().name, project} { +ProjectCollection::ProjectCollection(speckle::environment::Project::Shared project) : base{project->getInfo().name, project}, + m_management{std::make_unique()} { + m_management->push_back(this); m_finishes = std::make_unique(); + base::useManagement(m_management.get()); } //ProjectCollection::ProjectCollection diff --git a/SpeckleConnector/Connector/Record/Collection/ProjectCollection.h b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.h index ddf287a..7d2f2c6 100644 --- a/SpeckleConnector/Connector/Record/Collection/ProjectCollection.h +++ b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.h @@ -6,6 +6,10 @@ #include +namespace active::serialise { + class Management; +} + namespace speckle::record::element { class Element; } @@ -94,6 +98,7 @@ namespace connector::record { private: using FinishProxies = std::unordered_map>; + std::unique_ptr m_management; ///Finish proxies accumulated from meshes generated from the collection elements FinishProxies m_finishProxies; #ifdef ARCHICAD From dbc2c79f2acb9efc25e89370f0d3e6a0e3f85d3c Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Sat, 12 Oct 2024 09:06:32 +0100 Subject: [PATCH 042/191] Added serilaisation wrapper for 256-byte char array (used for some AC string types) --- .../Speckle/Database/Content/BIMRecord.cpp | 2 +- SpeckleLib/Speckle/Serialise/Types/Str256.h | 55 +++++++++++++++++++ .../{ => Types}/Units/LengthUnit.cpp | 2 +- .../Serialise/{ => Types}/Units/LengthUnit.h | 0 .../SpeckleLib.xcodeproj/project.pbxproj | 14 ++++- 5 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 SpeckleLib/Speckle/Serialise/Types/Str256.h rename SpeckleLib/Speckle/Serialise/{ => Types}/Units/LengthUnit.cpp (93%) rename SpeckleLib/Speckle/Serialise/{ => Types}/Units/LengthUnit.h (100%) diff --git a/SpeckleLib/Speckle/Database/Content/BIMRecord.cpp b/SpeckleLib/Speckle/Database/Content/BIMRecord.cpp index dcc55d1..52782a9 100644 --- a/SpeckleLib/Speckle/Database/Content/BIMRecord.cpp +++ b/SpeckleLib/Speckle/Database/Content/BIMRecord.cpp @@ -1,7 +1,7 @@ #include "Speckle/Database/Content/BIMRecord.h" #include "Active/Serialise/Item/Wrapper/ValueOptionWrap.h" -#include "Speckle/Serialise/Units/LengthUnit.h" +#include "Speckle/Serialise/Types/Units/LengthUnit.h" #include "Speckle/Utility/Guid.h" #include diff --git a/SpeckleLib/Speckle/Serialise/Types/Str256.h b/SpeckleLib/Speckle/Serialise/Types/Str256.h new file mode 100644 index 0000000..13f16b7 --- /dev/null +++ b/SpeckleLib/Speckle/Serialise/Types/Str256.h @@ -0,0 +1,55 @@ +#ifndef SPECKLE_SERIALISE_LENGTH_UNIT +#define SPECKLE_SERIALISE_LENGTH_UNIT + +#include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Active/Serialise/Item/Wrapper/ValueOptionWrap.h" +#include "Active/Utility/BufferOut.h" + +namespace active::serialise { + + constexpr size_t str256Size = 256; + + ///NB: This is primarily for Archicad that still uses fixed 256-bytes char array strings in some contexts + using Str256 = std::array; + + // MARK: - Specialisations for bool + + /*! + Import the object from the specified string (specialisation for bool) + @param source The string to read + @return True if the data was successfully read + */ + template<> inline + bool ValueWrap::read(const utility::String& source) { + source.writeUTF8(active::utility::BufferOut{get()}); + return true; + } //ValueWrap::read + + + /*! + Import the object from the specified string (specialisation for bool) + @param source The string to read + @return True if the data was successfully read + */ + template<> inline + bool ValueWrap>::read(const utility::String& source) { + base::get() = Str256{}; + source.writeUTF8(active::utility::BufferOut{*base::get()}); + return true; + } //ValueWrap::read + + + /*! + Export the object to the specified string (specialisation for bool) + @param dest The string to write the data to + @return True if the data was successfully written + */ + template<> inline + bool ValueWrap::write(utility::String& dest) const { + dest.assign(reinterpret_cast(&get()), str256Size); + return true; + } //ValueWrap::write + +} + +#endif //SPECKLE_SERIALISE_LENGTH_UNIT diff --git a/SpeckleLib/Speckle/Serialise/Units/LengthUnit.cpp b/SpeckleLib/Speckle/Serialise/Types/Units/LengthUnit.cpp similarity index 93% rename from SpeckleLib/Speckle/Serialise/Units/LengthUnit.cpp rename to SpeckleLib/Speckle/Serialise/Types/Units/LengthUnit.cpp index bc71613..cd8fb9f 100644 --- a/SpeckleLib/Speckle/Serialise/Units/LengthUnit.cpp +++ b/SpeckleLib/Speckle/Serialise/Types/Units/LengthUnit.cpp @@ -1,4 +1,4 @@ -#include "Speckle/Serialise/Units/LengthUnit.h" +#include "Speckle/Serialise/Types/Units/LengthUnit.h" #include #include diff --git a/SpeckleLib/Speckle/Serialise/Units/LengthUnit.h b/SpeckleLib/Speckle/Serialise/Types/Units/LengthUnit.h similarity index 100% rename from SpeckleLib/Speckle/Serialise/Units/LengthUnit.h rename to SpeckleLib/Speckle/Serialise/Types/Units/LengthUnit.h diff --git a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj index 2a4d670..18f49e9 100644 --- a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj +++ b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj @@ -49,6 +49,7 @@ 2196F3052CB57E8000450DFC /* Storey.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2196F3032CB57E7F00450DFC /* Storey.cpp */; }; 2199881E2BD833830035E5EA /* libArchicad27.a in CopyFiles */ = {isa = PBXBuildFile; fileRef = 21379E082AE47A6400A1584C /* libArchicad27.a */; }; 21A0FBA42CB880690023F24E /* FinishCollector.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A0FB9F2CB880690023F24E /* FinishCollector.h */; }; + 21A0FBB52CBA5E380023F24E /* Str256.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A0FBB42CBA5E380023F24E /* Str256.h */; }; 21AEF9BA2CA606B5000B8681 /* DetachedReference.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9B92CA606B4000B8681 /* DetachedReference.cpp */; }; 21AEF9BC2CA6DF84000B8681 /* DetachmentManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9BB2CA6DF84000B8681 /* DetachmentManager.cpp */; }; 21AEF9BE2CA6FDA4000B8681 /* DetachedWrap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9BD2CA6FDA4000B8681 /* DetachedWrap.cpp */; }; @@ -189,6 +190,7 @@ 219712682BE7E2D500D9EF7E /* Serialisation.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Serialisation.md; sourceTree = ""; }; 21A0FB9F2CB880690023F24E /* FinishCollector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FinishCollector.h; sourceTree = ""; }; 21A0FBA92CB9324A0023F24E /* FinishProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FinishProxy.h; sourceTree = ""; }; + 21A0FBB42CBA5E380023F24E /* Str256.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Str256.h; sourceTree = ""; }; 21AEF9B32CA5F7CF000B8681 /* DetachedWrap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedWrap.h; sourceTree = ""; }; 21AEF9B52CA5FA02000B8681 /* DetachedReference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedReference.h; sourceTree = ""; }; 21AEF9B72CA5FCB6000B8681 /* DetachmentManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachmentManager.h; sourceTree = ""; }; @@ -296,8 +298,8 @@ 21A0FBA02CB880690023F24E /* Collection */, 21AEF9C72CA818EA000B8681 /* Detached */, 21F69F3A2C6B880B008B6A06 /* JSBase */, - 2196F2DF2CB0566500450DFC /* Units */, 219712682BE7E2D500D9EF7E /* Serialisation.md */, + 21A0FBB12CBA5E0E0023F24E /* Types */, ); path = Serialise; sourceTree = ""; @@ -485,6 +487,15 @@ path = Collection; sourceTree = ""; }; + 21A0FBB12CBA5E0E0023F24E /* Types */ = { + isa = PBXGroup; + children = ( + 21A0FBB42CBA5E380023F24E /* Str256.h */, + 2196F2DF2CB0566500450DFC /* Units */, + ); + path = Types; + sourceTree = ""; + }; 21AEF9C72CA818EA000B8681 /* Detached */ = { isa = PBXGroup; children = ( @@ -694,6 +705,7 @@ 215F088C2CA195EC00CD343B /* ArchicadDBaseCore.h in Headers */, 21D0BDE72C943D3F0077E104 /* RecordID.h in Headers */, 21D0BD212C86F0280077E104 /* AccountDatabase.h in Headers */, + 21A0FBB52CBA5E380023F24E /* Str256.h in Headers */, 210CC86F2C7E879700610F58 /* ArgumentBase.h in Headers */, 210CC8A02C81E34400610F58 /* Platform.h in Headers */, 219246132CA34DCE00CF5703 /* Mesh.h in Headers */, From 05c2cdc47a690cf20dfa113f2df4a43bdd6b76a9 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Sat, 12 Oct 2024 09:19:09 +0100 Subject: [PATCH 043/191] Updated VS projects Using Str256 for AC attribute name WIP - using fixed size for material proxy serialisation count (actual count not known at this point - may need to use something like max size_t) --- .../Record/Collection/ProjectCollection.cpp | 2 +- .../Speckle/Record/Attribute/Attribute.cpp | 6 +++-- .../Speckle/Record/Attribute/Finish.cpp | 2 +- SpeckleLib/SpeckleLib17.vcxproj | 5 ++-- SpeckleLib/SpeckleLib17.vcxproj.filters | 24 ++++++++++++------- 5 files changed, 24 insertions(+), 15 deletions(-) diff --git a/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp index 44ded4a..ca4239c 100644 --- a/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp +++ b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp @@ -154,7 +154,7 @@ bool ProjectCollection::fillInventory(active::serialise::Inventory& inventory) c base::fillInventory(inventory); inventory.merge(Inventory{ { - { Identity{fieldID[finishProxyID]}, finishProxyID, m_finishProxies.size(), std::nullopt }, + { Identity{fieldID[finishProxyID]}, finishProxyID, 100, std::nullopt }, }, }.withType(&typeid(ProjectCollection))); return true; diff --git a/SpeckleLib/Speckle/Record/Attribute/Attribute.cpp b/SpeckleLib/Speckle/Record/Attribute/Attribute.cpp index dba0b12..eece72d 100644 --- a/SpeckleLib/Speckle/Record/Attribute/Attribute.cpp +++ b/SpeckleLib/Speckle/Record/Attribute/Attribute.cpp @@ -3,6 +3,7 @@ #include "Speckle/Database/BIMAttributeDatabase.h" #include "Speckle/Environment/Addon.h" #include "Speckle/Environment/Project.h" +#include "Speckle/Serialise/Types/Str256.h" using namespace active::serialise; using namespace speckle::database; @@ -77,8 +78,9 @@ Cargo::Unique Attribute::getCargo(const Inventory::Item& item) const { using namespace active::serialise; switch (item.index) { case nameID: - //return std::make_unique(*body); - return std::make_unique(getHead().name); +#ifdef ARCHICAD + return std::make_unique>(reinterpret_cast(getHead().name)); +#endif default: return nullptr; //Requested an unknown index } diff --git a/SpeckleLib/Speckle/Record/Attribute/Finish.cpp b/SpeckleLib/Speckle/Record/Attribute/Finish.cpp index 49976db..7f2221b 100644 --- a/SpeckleLib/Speckle/Record/Attribute/Finish.cpp +++ b/SpeckleLib/Speckle/Record/Attribute/Finish.cpp @@ -148,7 +148,7 @@ Finish::Finish(const ModelerAPI::Material& material) { source: The object to copy --------------------------------------------------------------------*/ Finish::Finish(const Finish& source) : base{source} { - m_data = source.m_data ? std::make_unique(*m_data) : nullptr; + m_data = source.m_data ? std::make_unique(*source.m_data) : nullptr; } //Finish::Finish diff --git a/SpeckleLib/SpeckleLib17.vcxproj b/SpeckleLib/SpeckleLib17.vcxproj index 73d3154..b7c224e 100644 --- a/SpeckleLib/SpeckleLib17.vcxproj +++ b/SpeckleLib/SpeckleLib17.vcxproj @@ -80,7 +80,8 @@ - + + @@ -127,7 +128,7 @@ - + diff --git a/SpeckleLib/SpeckleLib17.vcxproj.filters b/SpeckleLib/SpeckleLib17.vcxproj.filters index 458d545..3331655 100644 --- a/SpeckleLib/SpeckleLib17.vcxproj.filters +++ b/SpeckleLib/SpeckleLib17.vcxproj.filters @@ -83,9 +83,6 @@ {cb77e795-e8d8-4e31-9773-dd32beb694d3} - - {7d5ec9ba-bc7e-412c-9b14-16c37b183409} - {490a65bd-28e3-4282-bb33-67823e81e825} @@ -95,6 +92,12 @@ {b5733e9f-b72a-4162-9fc7-8feeec594e5b} + + {b992941c-66d5-4f16-89b2-82e27a22e229} + + + {7f43d4ea-b876-4587-a646-90eab81f7976} + @@ -277,9 +280,6 @@ Speckle\Serialise\Detached\Storage - - Speckle\Serialise\Units - Speckle\Database @@ -301,6 +301,12 @@ Speckle\Serialise\Collection + + Speckle\Serialise\Types + + + Speckle\Serialise\Types\Units + @@ -411,9 +417,6 @@ Speckle\Serialise\Detached - - Speckle\Serialise\Units - Speckle\Database @@ -429,6 +432,9 @@ Speckle\Record\Attribute + + Speckle\Serialise\Types\Units + From 7f4b7112ae9b1bdbfbb72bfe721cb060c31a4a7c Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Sun, 13 Oct 2024 17:49:17 +0100 Subject: [PATCH 044/191] Finishes incorporates all Archicad material properties Serialisation wrapper for Archicad colour rgb colour --- .../Speckle/Record/Attribute/Finish.cpp | 81 +++++++++++-------- SpeckleLib/Speckle/Record/Attribute/Finish.h | 5 ++ SpeckleLib/Speckle/Record/Element/Element.cpp | 10 --- .../Speckle/Serialise/Types/ArchicadRGB.h | 79 ++++++++++++++++++ SpeckleLib/Speckle/Serialise/Types/Str256.h | 20 ++--- .../SpeckleLib.xcodeproj/project.pbxproj | 4 + 6 files changed, 145 insertions(+), 54 deletions(-) create mode 100644 SpeckleLib/Speckle/Serialise/Types/ArchicadRGB.h diff --git a/SpeckleLib/Speckle/Record/Attribute/Finish.cpp b/SpeckleLib/Speckle/Record/Attribute/Finish.cpp index 7f2221b..0946417 100644 --- a/SpeckleLib/Speckle/Record/Attribute/Finish.cpp +++ b/SpeckleLib/Speckle/Record/Attribute/Finish.cpp @@ -5,6 +5,7 @@ #include "Active/Serialise/CargoHold.h" #include "Active/Utility/BufferOut.h" #include "Speckle/Serialise/Collection/FinishCollector.h" +#include "Speckle/Serialise/Types/ArchicadRGB.h" #include "Speckle/Utility/Guid.h" #ifdef ARCHICAD @@ -22,14 +23,28 @@ using namespace speckle::utility; namespace speckle::record::attribute { + ///Internal representation of a rendered finish on a 3D body, i.e. the surface colour/texture etc. class Finish::Data { public: #ifdef ARCHICAD - Data(const API_Attribute& attr) : root{attr.material} {} - Data(const Data& source) : root{source.root} {} + /*! + Constructor from Archicad surface material + @param attr An Archicad attribute + */ + Data(const API_Attribute& attr) : root{attr.material} { + opacity = 1.0 - (static_cast(attr.material.transpPc) / 100.0); + roughness = 1.0 - (static_cast(attr.material.shine) / 10000.0); + } + ///Archicad representation of a surface material API_MaterialType root; #endif + //Opacity (0.0 -> 1.0) + double opacity = 1.0; + //Roughness (0.0 -> 1.0) + double roughness = 0.0; + //Metalness (0.0 -> 1.0) + double metalness = 0.0; }; } @@ -57,35 +72,15 @@ namespace { #ifdef ARCHICAD /*! Copy a ModelerAPI colour to an AC RGB colour + @param modelColour The modeler API colour + @param colour The attribute API colour */ void copyModelerColor(const ModelerAPI::Color& modelColour, API_RGBColor& colour) { colour.f_red = modelColour.red; colour.f_green = modelColour.green; colour.f_blue = modelColour.blue; - } //copyModelerColor + } #endif - - int32_t ARGBToInt(double alpha, double red, double green, double blue) { - // Convert double (0.0 - 1.0) to uint8_t (0 - 255) - uint8_t a = static_cast(std::round(alpha * 255.0)); - uint8_t r = static_cast(std::round(red * 255.0)); - uint8_t g = static_cast(std::round(green * 255.0)); - uint8_t b = static_cast(std::round(blue * 255.0)); - - // Pack ARGB into a single 32-bit integer - return (a << 24) | (r << 16) | (g << 8) | b; - } - - int32_t ARGBToInt(double alpha, const API_RGBColor& color) { - // Convert double (0.0 - 1.0) to uint8_t (0 - 255) - uint8_t a = static_cast(std::round(alpha * 255.0)); - uint8_t r = static_cast(std::round(color.f_red * 255.0)); - uint8_t g = static_cast(std::round(color.f_green * 255.0)); - uint8_t b = static_cast(std::round(color.f_blue * 255.0)); - - // Pack ARGB into a single 32-bit integer - return (a << 24) | (r << 16) | (g << 8) | b; - } } /*-------------------------------------------------------------------- @@ -217,18 +212,20 @@ Cargo::Unique Finish::getCargo(const Inventory::Item& item) const { confirmData(); using namespace active::serialise; switch (item.index) { - case diffuseID: { - auto opacity = 1.0 - m_data->root.transpPc; - return std::make_unique>(ARGBToInt(opacity, m_data->root.surfaceRGB)); - } + case diffuseID: +#ifdef ARCHICAD + return std::make_unique>(m_data->root.surfaceRGB); +#endif case opacityID: - return std::make_unique>(1.0); + return std::make_unique(m_data->opacity); case emissiveID: - return std::make_unique>(ARGBToInt(0.0, 0.0, 0.0, 0.0)); +#ifdef ARCHICAD + return std::make_unique>(m_data->root.emissionRGB); +#endif case metalnessID: - return std::make_unique>(1.0); + return std::make_unique(m_data->metalness); case roughnessID: - return std::make_unique>(1.0); + return std::make_unique(m_data->roughness); default: return nullptr; //Requested an unknown index } @@ -239,10 +236,26 @@ Cargo::Unique Finish::getCargo(const Inventory::Item& item) const { Set to the default package content --------------------------------------------------------------------*/ void Finish::setDefault() { - + m_data->root = {}; + m_data->opacity = 0.0; + m_data->roughness = 1.0; + m_data->metalness = 0.0; } //Finish::setDefault +/*-------------------------------------------------------------------- + Validate the cargo data + + return: True if the data has been validated + --------------------------------------------------------------------*/ +bool Finish::validate() { + m_data->root.transpPc = static_cast(100 * (1.0 - m_data->opacity)); + m_data->root.shine = static_cast(10000 * (1.0 - m_data->roughness)); + //NB: Archicad has no metalness value - currently discarded + return true; +} //Finish::validate + + /*-------------------------------------------------------------------- Confirm the internal data, either loading from the BIM application or setting a default --------------------------------------------------------------------*/ diff --git a/SpeckleLib/Speckle/Record/Attribute/Finish.h b/SpeckleLib/Speckle/Record/Attribute/Finish.h index 1c597f7..72fb19d 100644 --- a/SpeckleLib/Speckle/Record/Attribute/Finish.h +++ b/SpeckleLib/Speckle/Record/Attribute/Finish.h @@ -122,6 +122,11 @@ namespace speckle::record::attribute { Set to the default package content */ void setDefault() override; + /*! + Validate the cargo data + @return True if the data has been validated + */ + bool validate() override; private: /*! diff --git a/SpeckleLib/Speckle/Record/Element/Element.cpp b/SpeckleLib/Speckle/Record/Element/Element.cpp index d5605fd..02fda04 100644 --- a/SpeckleLib/Speckle/Record/Element/Element.cpp +++ b/SpeckleLib/Speckle/Record/Element/Element.cpp @@ -57,16 +57,6 @@ namespace { Identity{"displayValue"}, }; - int32_t ARGBToInt(double alpha, double red, double green, double blue) { - // Convert double (0.0 - 1.0) to uint8_t (0 - 255) - uint8_t a = static_cast(std::round(alpha * 255.0)); - uint8_t r = static_cast(std::round(red * 255.0)); - uint8_t g = static_cast(std::round(green * 255.0)); - uint8_t b = static_cast(std::round(blue * 255.0)); - - // Pack ARGB into a single 32-bit integer - return (a << 24) | (r << 16) | (g << 8) | b; - } } /*-------------------------------------------------------------------- diff --git a/SpeckleLib/Speckle/Serialise/Types/ArchicadRGB.h b/SpeckleLib/Speckle/Serialise/Types/ArchicadRGB.h new file mode 100644 index 0000000..ad076d0 --- /dev/null +++ b/SpeckleLib/Speckle/Serialise/Types/ArchicadRGB.h @@ -0,0 +1,79 @@ +#ifndef SPECKLE_SERIALISE_ARCHICAD_RGB +#define SPECKLE_SERIALISE_ARCHICAD_RGB + +#ifdef ARCHICAD + +#include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Active/Serialise/Item/Wrapper/ValueOptionWrap.h" +#include "Active/Utility/BufferOut.h" + +#include + +namespace active::serialise { + + // MARK: - Specialisations for API_RGBColor + + /*! + Convert a string (encoding a 32-bit unsigned integer) to an Archicad RGB colour structure + @param source The source string to convert + @return The equivalent colour (nullopt on failure) + */ + std::optional convertToAPI_RGBColor(const utility::String& source) { + auto intValue = source.toUInt32(); + if (!intValue) + return std::nullopt; + API_RGBColor result{}; + *intValue >>= 8; + result.f_red = static_cast(*intValue & 0xFF) / 255.0; + *intValue >>= 8; + result.f_green = static_cast(*intValue & 0xFF) / 255.0; + *intValue >>= 8; + result.f_blue = static_cast(*intValue & 0xFF) / 255.0; + return result; + } + + /*! + Import the object from the specified string (specialisation for API_RGBColor) + @param source The string to read + @return True if the data was successfully read + */ + template<> inline + bool ValueWrap::read(const utility::String& source) { + if (auto colour = convertToAPI_RGBColor(source); colour) { + get() = *colour; + return true; + } + return false; + } //ValueWrap::read + + + /*! + Import the object from the specified string (specialisation for API_RGBColor) + @param source The string to read + @return True if the data was successfully read + */ + template<> inline + bool ValueWrap>::read(const utility::String& source) { + if (auto colour = convertToAPI_RGBColor(source); colour) + get() = colour; + return true; + } //ValueWrap::read + + + /*! + Export the object to the specified string (specialisation for API_RGBColor) + @param dest The string to write the data to + @return True if the data was successfully written + */ + template<> inline + bool ValueWrap::write(utility::String& dest) const { + dest = speckle::utility::String{(static_cast(get().f_red * 255.0) << 24) | + ((static_cast(get().f_green * 255.0)) << 16) | + ((static_cast(get().f_blue * 255.0)) << 8)}; + return true; + } //ValueWrap::write + +} + +#endif //ARCHICAD +#endif //SPECKLE_SERIALISE_ARCHICAD_RGB diff --git a/SpeckleLib/Speckle/Serialise/Types/Str256.h b/SpeckleLib/Speckle/Serialise/Types/Str256.h index 13f16b7..76a85c1 100644 --- a/SpeckleLib/Speckle/Serialise/Types/Str256.h +++ b/SpeckleLib/Speckle/Serialise/Types/Str256.h @@ -1,5 +1,5 @@ -#ifndef SPECKLE_SERIALISE_LENGTH_UNIT -#define SPECKLE_SERIALISE_LENGTH_UNIT +#ifndef SPECKLE_SERIALISE_STR256 +#define SPECKLE_SERIALISE_STR256 #include "Active/Serialise/Item/Wrapper/ValueWrap.h" #include "Active/Serialise/Item/Wrapper/ValueOptionWrap.h" @@ -12,10 +12,10 @@ namespace active::serialise { ///NB: This is primarily for Archicad that still uses fixed 256-bytes char array strings in some contexts using Str256 = std::array; - // MARK: - Specialisations for bool + // MARK: - Specialisations for Str256 /*! - Import the object from the specified string (specialisation for bool) + Import the object from the specified string (specialisation for Str256) @param source The string to read @return True if the data was successfully read */ @@ -23,11 +23,11 @@ namespace active::serialise { bool ValueWrap::read(const utility::String& source) { source.writeUTF8(active::utility::BufferOut{get()}); return true; - } //ValueWrap::read + } //ValueWrap::read /*! - Import the object from the specified string (specialisation for bool) + Import the object from the specified string (specialisation for Str256) @param source The string to read @return True if the data was successfully read */ @@ -36,11 +36,11 @@ namespace active::serialise { base::get() = Str256{}; source.writeUTF8(active::utility::BufferOut{*base::get()}); return true; - } //ValueWrap::read + } //ValueWrap::read /*! - Export the object to the specified string (specialisation for bool) + Export the object to the specified string (specialisation for Str256) @param dest The string to write the data to @return True if the data was successfully written */ @@ -48,8 +48,8 @@ namespace active::serialise { bool ValueWrap::write(utility::String& dest) const { dest.assign(reinterpret_cast(&get()), str256Size); return true; - } //ValueWrap::write + } //ValueWrap::write } -#endif //SPECKLE_SERIALISE_LENGTH_UNIT +#endif //SPECKLE_SERIALISE_STR256 diff --git a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj index 18f49e9..0781bc6 100644 --- a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj +++ b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj @@ -50,6 +50,7 @@ 2199881E2BD833830035E5EA /* libArchicad27.a in CopyFiles */ = {isa = PBXBuildFile; fileRef = 21379E082AE47A6400A1584C /* libArchicad27.a */; }; 21A0FBA42CB880690023F24E /* FinishCollector.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A0FB9F2CB880690023F24E /* FinishCollector.h */; }; 21A0FBB52CBA5E380023F24E /* Str256.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A0FBB42CBA5E380023F24E /* Str256.h */; }; + 21A0FBBC2CBBC04C0023F24E /* ArchicadRGB.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A0FBB92CBBC04C0023F24E /* ArchicadRGB.h */; }; 21AEF9BA2CA606B5000B8681 /* DetachedReference.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9B92CA606B4000B8681 /* DetachedReference.cpp */; }; 21AEF9BC2CA6DF84000B8681 /* DetachmentManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9BB2CA6DF84000B8681 /* DetachmentManager.cpp */; }; 21AEF9BE2CA6FDA4000B8681 /* DetachedWrap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9BD2CA6FDA4000B8681 /* DetachedWrap.cpp */; }; @@ -191,6 +192,7 @@ 21A0FB9F2CB880690023F24E /* FinishCollector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FinishCollector.h; sourceTree = ""; }; 21A0FBA92CB9324A0023F24E /* FinishProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FinishProxy.h; sourceTree = ""; }; 21A0FBB42CBA5E380023F24E /* Str256.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Str256.h; sourceTree = ""; }; + 21A0FBB92CBBC04C0023F24E /* ArchicadRGB.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArchicadRGB.h; sourceTree = ""; }; 21AEF9B32CA5F7CF000B8681 /* DetachedWrap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedWrap.h; sourceTree = ""; }; 21AEF9B52CA5FA02000B8681 /* DetachedReference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedReference.h; sourceTree = ""; }; 21AEF9B72CA5FCB6000B8681 /* DetachmentManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachmentManager.h; sourceTree = ""; }; @@ -490,6 +492,7 @@ 21A0FBB12CBA5E0E0023F24E /* Types */ = { isa = PBXGroup; children = ( + 21A0FBB92CBBC04C0023F24E /* ArchicadRGB.h */, 21A0FBB42CBA5E380023F24E /* Str256.h */, 2196F2DF2CB0566500450DFC /* Units */, ); @@ -731,6 +734,7 @@ 210CC8802C80CD2A00610F58 /* BridgeChild.h in Headers */, 21D0BD4D2C8901A00077E104 /* ServerInfo.h in Headers */, 2196F3042CB57E8000450DFC /* Storey.h in Headers */, + 21A0FBBC2CBBC04C0023F24E /* ArchicadRGB.h in Headers */, 21D0BDB52C8F8AB60077E104 /* DocumentStoreEngine.h in Headers */, 21D0BDC52C9241940077E104 /* ProjectSubscriber.h in Headers */, 2196F2EC2CB4816B00450DFC /* ArchicadAttributeDBaseEngine.h in Headers */, From 45c0705a60d997ab0f37b0af3e1970220f8d22e7 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Sun, 13 Oct 2024 19:57:01 +0100 Subject: [PATCH 045/191] #include prior to other includes --- .../Connector/Record/Collection/ProjectCollection.cpp | 1 + SpeckleLib/Speckle/Record/Attribute/Finish.cpp | 1 + SpeckleLib/Speckle/Serialise/Types/ArchicadRGB.h | 5 ++++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp index ca4239c..3b46167 100644 --- a/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp +++ b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp @@ -12,6 +12,7 @@ #include "Speckle/Record/Element/Element.h" #ifdef ARCHICAD +#include #include #endif diff --git a/SpeckleLib/Speckle/Record/Attribute/Finish.cpp b/SpeckleLib/Speckle/Record/Attribute/Finish.cpp index 0946417..a408874 100644 --- a/SpeckleLib/Speckle/Record/Attribute/Finish.cpp +++ b/SpeckleLib/Speckle/Record/Attribute/Finish.cpp @@ -9,6 +9,7 @@ #include "Speckle/Utility/Guid.h" #ifdef ARCHICAD +#include #include #endif diff --git a/SpeckleLib/Speckle/Serialise/Types/ArchicadRGB.h b/SpeckleLib/Speckle/Serialise/Types/ArchicadRGB.h index ad076d0..e4f6263 100644 --- a/SpeckleLib/Speckle/Serialise/Types/ArchicadRGB.h +++ b/SpeckleLib/Speckle/Serialise/Types/ArchicadRGB.h @@ -7,7 +7,10 @@ #include "Active/Serialise/Item/Wrapper/ValueOptionWrap.h" #include "Active/Utility/BufferOut.h" -#include +#ifdef ARCHICAD +#include +#include +#endif namespace active::serialise { From 11bfb9333f2389217cc2c95cc44a57ed7feaabdc Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Sun, 13 Oct 2024 21:35:10 +0100 Subject: [PATCH 046/191] Updated VS projects --- SpeckleLib/SpeckleLib17.vcxproj | 2 ++ SpeckleLib/SpeckleLib17.vcxproj.filters | 3 +++ 2 files changed, 5 insertions(+) diff --git a/SpeckleLib/SpeckleLib17.vcxproj b/SpeckleLib/SpeckleLib17.vcxproj index b7c224e..6dc6cba 100644 --- a/SpeckleLib/SpeckleLib17.vcxproj +++ b/SpeckleLib/SpeckleLib17.vcxproj @@ -80,6 +80,7 @@ + @@ -284,6 +285,7 @@ true true TurnOffAllWarnings + false diff --git a/SpeckleLib/SpeckleLib17.vcxproj.filters b/SpeckleLib/SpeckleLib17.vcxproj.filters index 3331655..42974d7 100644 --- a/SpeckleLib/SpeckleLib17.vcxproj.filters +++ b/SpeckleLib/SpeckleLib17.vcxproj.filters @@ -307,6 +307,9 @@ Speckle\Serialise\Types\Units + + Speckle\Serialise\Types + From 373179fa657bf8fa4a053a0820a378f7756e5201 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Sun, 13 Oct 2024 22:16:52 +0100 Subject: [PATCH 047/191] Assigned serialisation type for Str256 Linked mesh IDs in finish proxies is a single array --- .../Connector/Record/Collection/FinishProxy.cpp | 8 +++++--- SpeckleLib/Speckle/Serialise/Types/Str256.h | 12 +++++++++++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/SpeckleConnector/Connector/Record/Collection/FinishProxy.cpp b/SpeckleConnector/Connector/Record/Collection/FinishProxy.cpp index a4643fc..75eb1f1 100644 --- a/SpeckleConnector/Connector/Record/Collection/FinishProxy.cpp +++ b/SpeckleConnector/Connector/Record/Collection/FinishProxy.cpp @@ -37,7 +37,7 @@ bool FinishProxy::fillInventory(active::serialise::Inventory& inventory) const { inventory.merge(Inventory{ { { fieldID[materialID], materialID, element }, - { fieldID[linkedMeshID], linkedMeshID, m_meshID.size(), std::nullopt }, + { fieldID[linkedMeshID], linkedMeshID, element }, }, }.withType(&typeid(FinishProxy))); return true; @@ -58,8 +58,10 @@ Cargo::Unique FinishProxy::getCargo(const active::serialise::Inventory::Item& it switch (item.index) { case materialID: return std::make_unique(m_finish); - case linkedMeshID: - return std::make_unique>>(m_meshID); + case linkedMeshID: { + auto result = new ContainerWrap(m_meshID); + return Cargo::Unique{result}; + } default: return nullptr; //Requested an unknown index } diff --git a/SpeckleLib/Speckle/Serialise/Types/Str256.h b/SpeckleLib/Speckle/Serialise/Types/Str256.h index 76a85c1..d6cfcae 100644 --- a/SpeckleLib/Speckle/Serialise/Types/Str256.h +++ b/SpeckleLib/Speckle/Serialise/Types/Str256.h @@ -49,7 +49,17 @@ namespace active::serialise { dest.assign(reinterpret_cast(&get()), str256Size); return true; } //ValueWrap::write - + + + /*! + Get the serialisation type for the item value + @return The item value serialisation type (nullopt = unspecified, i.e. a default is acceptable) + */ + template<> inline + std::optional ValueWrap::type() const { + return Item::Type::text; + } //ValueWrap::type + } #endif //SPECKLE_SERIALISE_STR256 From 7e742796f5fc71d142a89b03ccf378c6bb7ce3ba Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Sun, 13 Oct 2024 22:27:59 +0100 Subject: [PATCH 048/191] Corrected Mesh speckle_type Mesh constructor failed to set BIM ID --- SpeckleLib/Speckle/Primitive/Mesh/Mesh.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h index 2fe5dbb..7c4853a 100644 --- a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h +++ b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h @@ -26,7 +26,7 @@ namespace speckle::primitive { Default constructor @param unit The mesh unit type */ - Mesh(active::measure::LengthType unit = active::measure::LengthType::metre) : base{ utility::Guid{true}, utility::Guid{}, unit } {} + Mesh(active::measure::LengthType unit = active::measure::LengthType::metre) : base{utility::Guid{true}, utility::Guid{}, unit} {} /*! Constructor @param vertices The mesh vertices @@ -36,7 +36,7 @@ namespace speckle::primitive { */ Mesh(std::vector&& vertices, std::vector&& faces, std::vector&& colors, const ModelerAPI::Material& material, active::measure::LengthType unit = active::measure::LengthType::metre) : - base{ unit }, m_vertices{ std::move(vertices) }, m_faces{ std::move(faces) }, m_colors{ std::move(colors) }, m_material{ material } {} + base{utility::Guid{true}, utility::Guid{}, unit}, m_vertices{std::move(vertices)}, m_faces{std::move(faces)}, m_colors{std::move(colors)}, m_material{material} {} // MARK: - Functions (const) @@ -44,7 +44,7 @@ namespace speckle::primitive { Get the speckle type identifier @return The speckle type (relevant objects should override as required) */ - speckle::utility::String getSpeckleType() const override { return "speckle::primitive::Mesh"; } + speckle::utility::String getSpeckleType() const override { return "Objects.Geometry.Mesh"; } // MARK: - Serialisation @@ -61,9 +61,9 @@ namespace speckle::primitive { */ active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; /*! - Use a manager in (de)serialisation processes - @param management The management to use - */ + Use a manager in (de)serialisation processes + @param management The management to use + */ void useManagement(active::serialise::Management* management) const override; private: From bd54ae399513f486c8a8fddb29b03e84d9493971 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Mon, 14 Oct 2024 09:50:07 +0100 Subject: [PATCH 049/191] Change JSON tag from "unit" to "units" --- SpeckleLib/Speckle/Database/Content/BIMRecord.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SpeckleLib/Speckle/Database/Content/BIMRecord.cpp b/SpeckleLib/Speckle/Database/Content/BIMRecord.cpp index 52782a9..9f230d3 100644 --- a/SpeckleLib/Speckle/Database/Content/BIMRecord.cpp +++ b/SpeckleLib/Speckle/Database/Content/BIMRecord.cpp @@ -23,7 +23,7 @@ namespace { ///Serialisation field IDs static std::array fieldID = { Identity{"applicationId"}, - Identity{"unit"}, + Identity{"units"}, }; } From 24f6a6349a17f6fa9ddc926dbfb20e127c5b2cc4 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Mon, 14 Oct 2024 10:00:23 +0100 Subject: [PATCH 050/191] Capture ID of Modeler::Material in Finish --- SpeckleLib/Speckle/Record/Attribute/Finish.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SpeckleLib/Speckle/Record/Attribute/Finish.cpp b/SpeckleLib/Speckle/Record/Attribute/Finish.cpp index a408874..974ab11 100644 --- a/SpeckleLib/Speckle/Record/Attribute/Finish.cpp +++ b/SpeckleLib/Speckle/Record/Attribute/Finish.cpp @@ -117,11 +117,11 @@ Finish::Finish(const API_Attribute& attrData, const BIMRecordID& tableID) : base material: A ModelerAPI material definition --------------------------------------------------------------------*/ -Finish::Finish(const ModelerAPI::Material& material) { +Finish::Finish(const ModelerAPI::Material& material) : base{Guid{Guid::fromInt(material.GenerateHashValue())}, Finish::table} { API_Attribute attr; active::utility::Memory::erase(attr); String{material.GetName()}.writeUTF8(active::utility::BufferOut{attr.header.name}); - attr.header.guid = Guid{Guid::fromInt(material.GenerateHashValue())}; + attr.header.guid = getBIMID(); attr.material.mtype = static_cast(material.GetType()); attr.material.ambientPc = static_cast(material.GetAmbientReflection() * 100); attr.material.diffusePc = static_cast(material.GetDiffuseReflection() * 100); From 36b95436ae3bd79389e845bf2d3792075c843039 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Mon, 14 Oct 2024 10:13:23 +0100 Subject: [PATCH 051/191] Finishes have no unit of measurement --- SpeckleLib/Speckle/Database/Content/BIMRecord.h | 10 ++++++++++ SpeckleLib/Speckle/Record/Attribute/Finish.cpp | 2 ++ 2 files changed, 12 insertions(+) diff --git a/SpeckleLib/Speckle/Database/Content/BIMRecord.h b/SpeckleLib/Speckle/Database/Content/BIMRecord.h index a9964f3..7a392fe 100644 --- a/SpeckleLib/Speckle/Database/Content/BIMRecord.h +++ b/SpeckleLib/Speckle/Database/Content/BIMRecord.h @@ -63,6 +63,11 @@ namespace speckle::database { @return The BIM record link */ BIMLink getBIMLink() const { return BIMLink{ BIMLink::base{m_applicationID, m_applicationTableID} }; } + /*! + Get the record unit type + @return The record unit type (nullopt if the record has no applicable unit type) + */ + std::optional getUnit() const { return m_unit; } // MARK: - Functions (mutating) @@ -76,6 +81,11 @@ namespace speckle::database { @param tableID The BIM table ID */ void setTableID(const BIMRecordID& tableID) { m_applicationTableID = tableID; } + /*! + Set the record unit type + @param unit The record unit type (nullopt if the record has no applicable unit type) + */ + void setUnit(std::optional unit) { m_unit = unit; } // MARK: - Serialisation diff --git a/SpeckleLib/Speckle/Record/Attribute/Finish.cpp b/SpeckleLib/Speckle/Record/Attribute/Finish.cpp index 974ab11..b95652f 100644 --- a/SpeckleLib/Speckle/Record/Attribute/Finish.cpp +++ b/SpeckleLib/Speckle/Record/Attribute/Finish.cpp @@ -109,6 +109,7 @@ Finish::Finish(const database::BIMRecordID& ID) : base{ID, Finish::table} { --------------------------------------------------------------------*/ Finish::Finish(const API_Attribute& attrData, const BIMRecordID& tableID) : base{attrData.header.guid, Finish::table} { m_data = std::make_unique(attrData); + setUnit(std::nullopt); //Finishes have no unit } @@ -134,6 +135,7 @@ Finish::Finish(const ModelerAPI::Material& material) : base{Guid{Guid::fromInt(m copyModelerColor(material.GetSpecularColor(), attr.material.specularRGB); copyModelerColor(material.GetEmissionColor(), attr.material.emissionRGB); m_data = std::make_unique(attr); + setUnit(std::nullopt); //Finishes have no unit } //Finish::Finish #endif From 2fab7da57d300e3e6d7cf1607d3aa620bff16850 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Mon, 14 Oct 2024 11:17:17 +0100 Subject: [PATCH 052/191] Update FinishProxy to be a BIMRecord, i.e. export speckle_type and applicaiton ID BIMRecord constructor should allow units to be initialised to nullopt --- .../Connector/Record/Collection/FinishProxy.h | 16 +++++++++++++--- SpeckleLib/Speckle/Database/Content/BIMRecord.h | 2 +- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/SpeckleConnector/Connector/Record/Collection/FinishProxy.h b/SpeckleConnector/Connector/Record/Collection/FinishProxy.h index 19fba4a..3ad7b3e 100644 --- a/SpeckleConnector/Connector/Record/Collection/FinishProxy.h +++ b/SpeckleConnector/Connector/Record/Collection/FinishProxy.h @@ -1,7 +1,7 @@ #ifndef CONNECTOR_RECORD_COLLECTION_MATERIAL_PROXY #define CONNECTOR_RECORD_COLLECTION_MATERIAL_PROXY -#include "Active/Serialise/Package/Package.h" +#include "Speckle/Database/Content/BIMRecord.h" #include "Speckle/Record/Attribute/Finish.h" #include "Speckle/Utility/String.h" @@ -10,9 +10,11 @@ namespace connector::record { /*! A proxy record binding a surface finishes to meshes */ - class FinishProxy : public active::serialise::Package { + class FinishProxy : public speckle::database::BIMRecord { public: + using base = speckle::database::BIMRecord; + // MARK: - Constructors /*! @@ -21,8 +23,16 @@ namespace connector::record { @param meshID The list of mesh IDs the finish is applied to */ FinishProxy(const speckle::record::attribute::Finish& finish, const std::unordered_set& meshID) : - m_finish{finish} { std::copy(meshID.begin(), meshID.end(), std::back_inserter(m_meshID)); } + base{speckle::utility::Guid{true}, speckle::utility::Guid{}, std::nullopt}, m_finish{finish} { + std::copy(meshID.begin(), meshID.end(), std::back_inserter(m_meshID)); + } + /*! + Get the speckle type identifier + @return The speckle type (relevant objects should override as required, but "Base" is still considered a type on its own) + */ + speckle::utility::String getSpeckleType() const override { return "Objects.Other.RenderMaterialProxy"; } + // MARK: - Serialisation /*! diff --git a/SpeckleLib/Speckle/Database/Content/BIMRecord.h b/SpeckleLib/Speckle/Database/Content/BIMRecord.h index 7a392fe..aebd2be 100644 --- a/SpeckleLib/Speckle/Database/Content/BIMRecord.h +++ b/SpeckleLib/Speckle/Database/Content/BIMRecord.h @@ -39,7 +39,7 @@ namespace speckle::database { @param unit The record unit type */ BIMRecord(const speckle::utility::Guid& ID, const speckle::utility::Guid& tableID, - active::measure::LengthType unit = active::measure::LengthType::metre) : + std::optional unit = active::measure::LengthType::metre) : base{}, m_applicationID{ID}, m_applicationTableID{tableID}, m_unit{unit} {} /*! Destructor From e82698ac3ad77aef988b010455bc312d84e509f2 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Mon, 14 Oct 2024 11:18:48 +0100 Subject: [PATCH 053/191] Shininess in Modeler::Material is 1-100 scale (NB: looks logarithmic but will resolve on advice from GS) --- SpeckleLib/Speckle/Record/Attribute/Finish.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/SpeckleLib/Speckle/Record/Attribute/Finish.cpp b/SpeckleLib/Speckle/Record/Attribute/Finish.cpp index b95652f..86d45dd 100644 --- a/SpeckleLib/Speckle/Record/Attribute/Finish.cpp +++ b/SpeckleLib/Speckle/Record/Attribute/Finish.cpp @@ -128,7 +128,8 @@ Finish::Finish(const ModelerAPI::Material& material) : base{Guid{Guid::fromInt(m attr.material.diffusePc = static_cast(material.GetDiffuseReflection() * 100); attr.material.specularPc = static_cast(material.GetSpecularReflection() * 100); attr.material.transpPc = static_cast(material.GetTransparency() * 100); - attr.material.shine = static_cast(material.GetShining() * 10000); + auto temp = material.GetShining(); + attr.material.shine = static_cast(material.GetShining() * 100); attr.material.transpAtt = static_cast(material.GetTransparencyAttenuation() * 400); attr.material.emissionAtt = static_cast(material.GetEmissionAttenuation() * 65535); copyModelerColor(material.GetSurfaceColor(), attr.material.surfaceRGB); From a67361c9038ad758ff6adf2324ab3dfdb1501505 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Mon, 14 Oct 2024 11:25:09 +0100 Subject: [PATCH 054/191] FinishProxy should call base object when (de)serialising --- SpeckleConnector/Connector/Record/Collection/FinishProxy.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SpeckleConnector/Connector/Record/Collection/FinishProxy.cpp b/SpeckleConnector/Connector/Record/Collection/FinishProxy.cpp index 75eb1f1..3979204 100644 --- a/SpeckleConnector/Connector/Record/Collection/FinishProxy.cpp +++ b/SpeckleConnector/Connector/Record/Collection/FinishProxy.cpp @@ -40,7 +40,7 @@ bool FinishProxy::fillInventory(active::serialise::Inventory& inventory) const { { fieldID[linkedMeshID], linkedMeshID, element }, }, }.withType(&typeid(FinishProxy))); - return true; + return base::fillInventory(inventory); } //FinishProxy::fillInventory @@ -53,7 +53,7 @@ bool FinishProxy::fillInventory(active::serialise::Inventory& inventory) const { --------------------------------------------------------------------*/ Cargo::Unique FinishProxy::getCargo(const active::serialise::Inventory::Item& item) const { if (item.ownerType != &typeid(FinishProxy)) - return nullptr; + return base::getCargo(item); using namespace active::serialise; switch (item.index) { case materialID: From 902fb0f62692a1adf99c127639aa51fdba547bb4 Mon Sep 17 00:00:00 2001 From: David Kekesi Date: Mon, 14 Oct 2024 15:46:12 +0200 Subject: [PATCH 055/191] changed ArchicadRGB::write to export ARGB colors instead of RGB --- SpeckleLib/Speckle/Serialise/Types/ArchicadRGB.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SpeckleLib/Speckle/Serialise/Types/ArchicadRGB.h b/SpeckleLib/Speckle/Serialise/Types/ArchicadRGB.h index e4f6263..83517a0 100644 --- a/SpeckleLib/Speckle/Serialise/Types/ArchicadRGB.h +++ b/SpeckleLib/Speckle/Serialise/Types/ArchicadRGB.h @@ -70,9 +70,9 @@ namespace active::serialise { */ template<> inline bool ValueWrap::write(utility::String& dest) const { - dest = speckle::utility::String{(static_cast(get().f_red * 255.0) << 24) | - ((static_cast(get().f_green * 255.0)) << 16) | - ((static_cast(get().f_blue * 255.0)) << 8)}; + dest = speckle::utility::String{(static_cast(get().f_red * 255.0) << 16) | + ((static_cast(get().f_green * 255.0)) << 8) | + ((static_cast(get().f_blue * 255.0)))}; return true; } //ValueWrap::write From def9162e4ce81e7b899da7b27051acf08daaadee Mon Sep 17 00:00:00 2001 From: David Kekesi Date: Tue, 15 Oct 2024 17:10:48 +0200 Subject: [PATCH 056/191] added SelectionBridge, SelectionInfo, GetSelection --- SpeckleConnector/Connector.vcxproj | 6 ++ SpeckleConnector/Connector.vcxproj.filters | 24 +++++++ .../Bridge/Selection/Arg/SelectionInfo.cpp | 60 ++++++++++++++++ .../Bridge/Selection/Arg/SelectionInfo.h | 47 +++++++++++++ .../Browser/Bridge/Selection/GetSelection.cpp | 68 +++++++++++++++++++ .../Browser/Bridge/Selection/GetSelection.h | 30 ++++++++ .../Bridge/Selection/SelectionBridge.cpp | 13 ++++ .../Bridge/Selection/SelectionBridge.h | 29 ++++++++ .../Connector/Interface/ConnectorPalette.cpp | 2 + 9 files changed, 279 insertions(+) create mode 100644 SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.cpp create mode 100644 SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h create mode 100644 SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.cpp create mode 100644 SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.h create mode 100644 SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.cpp create mode 100644 SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h diff --git a/SpeckleConnector/Connector.vcxproj b/SpeckleConnector/Connector.vcxproj index 9ac1fc7..acf33d4 100644 --- a/SpeckleConnector/Connector.vcxproj +++ b/SpeckleConnector/Connector.vcxproj @@ -111,6 +111,9 @@ + + + @@ -163,6 +166,9 @@ + + + diff --git a/SpeckleConnector/Connector.vcxproj.filters b/SpeckleConnector/Connector.vcxproj.filters index e879d95..374c759 100644 --- a/SpeckleConnector/Connector.vcxproj.filters +++ b/SpeckleConnector/Connector.vcxproj.filters @@ -65,6 +65,12 @@ {6693f9a9-5ece-4853-b008-4064d1c551ab} + + {806f4af5-fa02-49b8-ac01-297991fe90ea} + + + {8bb3df60-affe-4b66-8d78-f1b98e6ba8df} + @@ -228,6 +234,15 @@ Connector\Record\Collection + + Connector\Interface\Browser\Bridge\Selection + + + Connector\Interface\Browser\Bridge\Selection + + + Connector\Interface\Browser\Bridge\Selection\Arg + @@ -387,5 +402,14 @@ Connector\Record\Collection + + Connector\Interface\Browser\Bridge\Selection + + + Connector\Interface\Browser\Bridge\Selection + + + Connector\Interface\Browser\Bridge\Selection\Arg + \ No newline at end of file diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.cpp new file mode 100644 index 0000000..42611d6 --- /dev/null +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.cpp @@ -0,0 +1,60 @@ +#include "Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h" + +#include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Active/Serialise/Package/Wrapper/PackageWrap.h" + +#include + +using namespace active::serialise; +using namespace connector::interfac::browser::bridge; + +namespace { + + ///Serialisation fields + enum FieldIndex { + summaryID, + }; + + ///Serialisation field IDs + static std::array fieldID = { + Identity{"summary"}, + }; + +} + +/*-------------------------------------------------------------------- + Fill an inventory with the package items + + inventory: The inventory to receive the package items + + return: True if the package has added items to the inventory + --------------------------------------------------------------------*/ +bool SelectionInfo::fillInventory(Inventory& inventory) const { + using enum Entry::Type; + inventory.merge(Inventory{ + { + { fieldID[summaryID], summaryID, element }, + }, + }.withType(&typeid(SelectionInfo))); + return true; +} //ConnectorConfig::fillInventory + + +/*-------------------------------------------------------------------- + Get the specified cargo + + item: The inventory item to retrieve + + return: The requested cargo (nullptr on failure) + --------------------------------------------------------------------*/ +Cargo::Unique SelectionInfo::getCargo(const Inventory::Item& item) const { + if (item.ownerType != &typeid(SelectionInfo)) + return nullptr; + using namespace active::serialise; + switch (item.index) { + case summaryID: + return std::make_unique>(summary); + default: + return nullptr; //Requested an unknown index + } +} //ConnectorConfig::getCargo diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h new file mode 100644 index 0000000..2e81bea --- /dev/null +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h @@ -0,0 +1,47 @@ +#ifndef CONNECTOR_INTERFACE_BRIDGE_SELECTION_INFO +#define CONNECTOR_INTERFACE_BRIDGE_SELECTION_INFO + +#include "Active/Serialise/Package/Package.h" +#include "Speckle/Interface/Browser/Bridge/ArgumentBase.h" + +namespace connector::interfac::browser::bridge { + + /*! + Configuration settings class + */ + class SelectionInfo : public active::serialise::Package { + public: + + // MARK: - Types + + using base = active::serialise::Package; + + // MARK: - Constructors + + /*! + Default constructor + */ + SelectionInfo() = default; + + active::utility::String summary = "Nothing is selected"; + std::vector selectedElementIds; + + // MARK: - Serialisation + + /*! + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ + bool fillInventory(active::serialise::Inventory& inventory) const override; + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + }; + +} + +#endif //CONNECTOR_INTERFACE_BRIDGE_SELECTION_INFO diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.cpp new file mode 100644 index 0000000..fc239a7 --- /dev/null +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.cpp @@ -0,0 +1,68 @@ +#include "Connector/Interface/Browser/Bridge/Selection/GetSelection.h" + +#include "Active/Serialise/CargoHold.h" +#include "Active/Serialise/Package/Wrapper/PackageWrap.h" +#include "Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h" + +#include "Connector/Connector.h" +#include "Connector/Record/Collection/ProjectCollection.h" + +#include "Speckle/Database/BIMElementDatabase.h" +#include "Speckle/Environment/Project.h" +#include "Speckle/Record/Element/Element.h" +using namespace speckle::record::element; + +#include + +using namespace active::serialise; +using namespace connector::interfac::browser::bridge; +using namespace speckle::utility; +using namespace connector::record; + +namespace { + + ///Return type for retrieving the current configuration + using WrappedValue = CargoHold; + +} +/*-------------------------------------------------------------------- + Default constructor + --------------------------------------------------------------------*/ +GetSelection::GetSelection() : BridgeMethod{"GetSelection", [&]() { + return run(); +}} {} + + +/*-------------------------------------------------------------------- + Send a specified model + + modelCardID: The ID of the model to send + --------------------------------------------------------------------*/ +std::unique_ptr GetSelection::run() const { + + auto selectionInfo = std::make_unique(); + + auto project = connector()->getActiveProject().lock(); + if (!project) { + // TODO + } + + //Build a collection from the selected elements + auto collection = std::make_unique(project); + auto elementDatabase = project->getElementDatabase(); + auto selected = elementDatabase->getSelection(); + + active::utility::String summary(selected.size()); + summary += " objects selected."; + + selectionInfo->summary = summary; + + for (const auto& link : selected) { + if (auto element = elementDatabase->getElement(link); element) { + collection->addElement(*element); + selectionInfo->selectedElementIds.push_back(element->getBIMID()); + } + } + + return std::make_unique(std::move(selectionInfo)); +} //GetSelection::run diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.h new file mode 100644 index 0000000..8f9b73d --- /dev/null +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.h @@ -0,0 +1,30 @@ +#ifndef CONNECTOR_INTERFACE_BRIDGE_GETSELECTION +#define CONNECTOR_INTERFACE_BRIDGE_GETSELECTION + +#include "Speckle/Interface/Browser/Bridge/BridgeMethod.h" + +namespace connector::interfac::browser::bridge { + + class GetSelection : public speckle::interfac::browser::bridge::BridgeMethod { + public: + + // MARK: - Constructors + + /*! + Constructor + @param bridge The parent bridge object (provides access to bridge methods) + */ + GetSelection(); + + // MARK: - Functions (const) + + /*! + Send a specified model + @param modelCardID The ID of the model to send + */ + std::unique_ptr run() const; + }; + +} + +#endif //CONNECTOR_INTERFACE_BRIDGE_GETSELECTION diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.cpp new file mode 100644 index 0000000..5fa969f --- /dev/null +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.cpp @@ -0,0 +1,13 @@ +#include "Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h" + +#include "Connector/Interface/Browser/Bridge/Selection/GetSelection.h" + +using namespace connector::interfac::browser::bridge; + +/*-------------------------------------------------------------------- + Default constructor + --------------------------------------------------------------------*/ +SelectionBridge::SelectionBridge() : BrowserBridge{"selectionBinding"} { + //Add bridge methods + addMethod(); +} //SelectionBridge::SelectionBridge diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h new file mode 100644 index 0000000..053fba2 --- /dev/null +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h @@ -0,0 +1,29 @@ +#ifndef CONNECTOR_INTERFACE_BRIDGE_SELECTION_BRIDGE +#define CONNECTOR_INTERFACE_BRIDGE_SELECTION_BRIDGE + +#include "Speckle/Interface/Browser/Bridge/BrowserBridge.h" + +namespace connector::interfac::browser::bridge { + + /*! + A browser bridge to support sending model data to a Speckle server + */ + class SelectionBridge : public speckle::interfac::browser::bridge::BrowserBridge { + public: + + // MARK: - Types + + using base = speckle::interfac::browser::bridge::BrowserBridge; + + // MARK: - Constructors + + using base::base; + /*! + Default constructor + */ + SelectionBridge(); + }; + +} + +#endif //CONNECTOR_INTERFACE_BRIDGE_SELECTION_BRIDGE diff --git a/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp b/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp index 6810467..0800691 100644 --- a/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp +++ b/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp @@ -10,6 +10,7 @@ #include "Connector/Interface/Browser/Bridge/Base/BaseBridge.h" #include "Connector/Interface/Browser/Bridge/Config/ConfigBridge.h" #include "Connector/Interface/Browser/Bridge/Send/SendBridge.h" +#include "Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h" #include "Connector/Interface/Browser/Bridge/Test/TestBridge.h" #include "Speckle/Environment/Addon.h" #include "Speckle/Event/Type/MenuEvent.h" @@ -170,6 +171,7 @@ BrowserPalette::BrowserPalette() : install(); install(); install(); + install(); install(); InitBrowserControl(); } From e54962e76fdf6e9d73e1f83c2b82eda959c09c70 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Tue, 15 Oct 2024 21:05:57 +0100 Subject: [PATCH 057/191] Added Column support: - Column element - ColumnSegment element - SegmentedColumn for managing segment retrieval - Segment/Path interfaces - Element Part interface GenericElement now represents all element types with no specific class Element becomes abstract base for all elements Added Memo to handle supplementary element data Added BIMMemory for common BIM memory utilities BIMElementDatabase adds Memo table support ArchicadElementDBaseEngine creates GenericElement, Column or ColumnSegment elements --- .../Speckle/Database/BIMElementDatabase.cpp | 20 ++ .../Speckle/Database/BIMElementDatabase.h | 16 +- .../Element/ArchicadElementDBaseEngine.cpp | 27 ++- .../Element/ArchicadElementDBaseEngine.h | 9 +- .../Event/Subscriber/SelectionSubscriber.h | 4 +- .../Speckle/Record/Attribute/Finish.cpp | 1 - SpeckleLib/Speckle/Record/Element/Column.cpp | 174 ++++++++++++++++++ SpeckleLib/Speckle/Record/Element/Column.h | 142 ++++++++++++++ .../Speckle/Record/Element/ColumnSegment.cpp | 149 +++++++++++++++ .../Speckle/Record/Element/ColumnSegment.h | 130 +++++++++++++ SpeckleLib/Speckle/Record/Element/Element.cpp | 75 ++++---- SpeckleLib/Speckle/Record/Element/Element.h | 33 ++-- .../Speckle/Record/Element/GenericElement.cpp | 157 ++++++++++++++++ .../Speckle/Record/Element/GenericElement.h | 112 +++++++++++ .../Element/Interface/Assembly/Path.cpp | 23 +++ .../Record/Element/Interface/Assembly/Path.h | 48 +++++ .../Element/Interface/Assembly/Segment.cpp | 67 +++++++ .../Element/Interface/Assembly/Segment.h | 91 +++++++++ .../Speckle/Record/Element/Interface/Part.cpp | 23 +++ .../Speckle/Record/Element/Interface/Part.h | 92 +++++++++ .../Element/Interface/SegmentedColumn.cpp | 158 ++++++++++++++++ .../Element/Interface/SegmentedColumn.h | 103 +++++++++++ SpeckleLib/Speckle/Record/Element/Memo.cpp | 54 ++++++ SpeckleLib/Speckle/Record/Element/Memo.h | 81 ++++++++ SpeckleLib/Speckle/Utility/BIMMemory.cpp | 39 ++++ SpeckleLib/Speckle/Utility/BIMMemory.h | 23 +++ .../SpeckleLib.xcodeproj/project.pbxproj | 88 +++++++++ 27 files changed, 1874 insertions(+), 65 deletions(-) create mode 100644 SpeckleLib/Speckle/Record/Element/Column.cpp create mode 100644 SpeckleLib/Speckle/Record/Element/Column.h create mode 100644 SpeckleLib/Speckle/Record/Element/ColumnSegment.cpp create mode 100644 SpeckleLib/Speckle/Record/Element/ColumnSegment.h create mode 100644 SpeckleLib/Speckle/Record/Element/GenericElement.cpp create mode 100644 SpeckleLib/Speckle/Record/Element/GenericElement.h create mode 100644 SpeckleLib/Speckle/Record/Element/Interface/Assembly/Path.cpp create mode 100644 SpeckleLib/Speckle/Record/Element/Interface/Assembly/Path.h create mode 100644 SpeckleLib/Speckle/Record/Element/Interface/Assembly/Segment.cpp create mode 100644 SpeckleLib/Speckle/Record/Element/Interface/Assembly/Segment.h create mode 100644 SpeckleLib/Speckle/Record/Element/Interface/Part.cpp create mode 100644 SpeckleLib/Speckle/Record/Element/Interface/Part.h create mode 100644 SpeckleLib/Speckle/Record/Element/Interface/SegmentedColumn.cpp create mode 100644 SpeckleLib/Speckle/Record/Element/Interface/SegmentedColumn.h create mode 100644 SpeckleLib/Speckle/Record/Element/Memo.cpp create mode 100644 SpeckleLib/Speckle/Record/Element/Memo.h create mode 100644 SpeckleLib/Speckle/Utility/BIMMemory.cpp create mode 100644 SpeckleLib/Speckle/Utility/BIMMemory.h diff --git a/SpeckleLib/Speckle/Database/BIMElementDatabase.cpp b/SpeckleLib/Speckle/Database/BIMElementDatabase.cpp index 5761233..d98a57f 100644 --- a/SpeckleLib/Speckle/Database/BIMElementDatabase.cpp +++ b/SpeckleLib/Speckle/Database/BIMElementDatabase.cpp @@ -5,6 +5,7 @@ #include "Speckle/Database/Identity/RecordID.h" #include "Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.h" #include "Speckle/Record/Element/Element.h" +#include "Speckle/Record/Element/Memo.h" #include @@ -107,6 +108,25 @@ Vector BIMElementDatabase::getElements() const { } //BIMElementDatabase::getElements +/*-------------------------------------------------------------------- + Get memo memo (supplementary) data for a specified element + + elementID: The of the source element + filter: Filter for the required supplementary data + + return: The requested element memo data (nullptr on failure) + --------------------------------------------------------------------*/ +Memo::Unique BIMElementDatabase::getMemo(const BIMRecordID& elementID, Part::filter_bits filter) const { + //NB: The filter bits are passed as the source document ID + auto result = m_engine->getObject(elementID, ArchicadElementDBaseEngine::memoTable, Guid::fromInt(filter)); + if (auto memo = dynamic_cast(result.get()); memo != nullptr) { + result.release(); + return Memo::Unique{memo}; + } + return nullptr; +} //BIMElementDatabase::getMemo + + /*-------------------------------------------------------------------- Write an element to storage diff --git a/SpeckleLib/Speckle/Database/BIMElementDatabase.h b/SpeckleLib/Speckle/Database/BIMElementDatabase.h index 27aa3db..efd1d18 100644 --- a/SpeckleLib/Speckle/Database/BIMElementDatabase.h +++ b/SpeckleLib/Speckle/Database/BIMElementDatabase.h @@ -3,12 +3,17 @@ #include "Speckle/Database/Identity/BIMLink.h" #include "Speckle/Record/Element/Element.h" +#include "Speckle/Record/Element/Interface/Part.h" #include "Speckle/Utility/Guid.h" namespace active::event { class Subscriber; } +namespace speckle::record::element { + class Memo; +} + namespace speckle::database { /*! @@ -43,19 +48,26 @@ namespace speckle::database { @param documentID Optional document ID (when the object is bound to a specific document) @return The requested element (nullptr on failure) */ - record::element::Element::Unique getElement(const BIMRecordID& elementID, std::optional tableID = std::nullopt, + std::unique_ptr getElement(const BIMRecordID& elementID, std::optional tableID = std::nullopt, std::optional documentID = std::nullopt) const; /*! Get a specified element @param link A link to the target element @return The requested element (nullptr on failure) */ - record::element::Element::Unique getElement(const BIMLink& link) const { return getElement(link, link.tableID, link.docID); } + std::unique_ptr getElement(const BIMLink& link) const { return getElement(link, link.tableID, link.docID); } /*! Get all model elements @return All the elements */ active::container::Vector getElements() const; + /*! + Get memo memo (supplementary) data for a specified element + @param elementID The of the source element + @param filter Filter for the required supplementary data + @return The requested element memo data (nullptr on failure) + */ + std::unique_ptr getMemo(const BIMRecordID& elementID, record::element::Part::filter_bits filter) const; /*! Write an element to storage @param element The element to write diff --git a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.cpp b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.cpp index 7438e6d..b6ed332 100644 --- a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.cpp +++ b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.cpp @@ -10,6 +10,10 @@ #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/Memo.h" #include "Speckle/Utility/Guid.h" #include "Speckle/Utility/String.h" @@ -67,9 +71,14 @@ namespace { @return A new element object (nullptr on failure) */ Element::Unique makeElement(const API_Element& elementData, const BIMRecordID& tableID) { - //Implement an object factory in future as classes for specific element types are implemented, e.g. Wall, Roof etc. using hash map - //The fallback for undefined element types will always be the base Element class - return std::make_unique(elementData, tableID); + switch (elementData.header.type.typeID) { + case API_ColumnID: + return std::make_unique(elementData, tableID); + case API_ColumnSegmentID: + return std::make_unique(elementData, tableID); + default: + return std::make_unique(elementData, tableID); + } } } @@ -120,7 +129,19 @@ BIMLinkList ArchicadElementDBaseEngine::getSelection() const { --------------------------------------------------------------------*/ std::unique_ptr ArchicadElementDBaseEngine::getObject(const BIMRecordID& ID, std::optional tableID, std::optional documentID) const { + //Check for memo table requests + if (tableID == memoTable) { + auto memo = std::make_unique(); + 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 + return std::make_unique(std::move(memo)); + } if (!tableID) { + //Use the active table if none is specified tableID = getActiveTable(); if (!tableID) return nullptr; diff --git a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.h b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.h index 103a11a..864ba6b 100644 --- a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.h +++ b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.h @@ -18,16 +18,21 @@ namespace speckle::database { A database engine to read/write elements in an Archicad project database (local file or cloud-based) */ class ArchicadElementDBaseEngine : public ArchicadDBaseCore, - public active::database::DBaseEngine { + public active::database::DBaseEngine { public: // MARK: - Types - using base = active::database::DBaseEngine; + using base = active::database::DBaseEngine; using Element = record::element::Element; using Filter = base::Filter; using Outline = base::Outline; + // MARK: - Constants + + ///The memo table ID (supplementary element data) + static const inline utility::Guid memoTable{utility::String{"fdff96d2-8c34-4f8b-8a76-a96a2b242758"}}; + // MARK: - Static functions /*! diff --git a/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.h b/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.h index 975eb0c..6ed904b 100644 --- a/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.h +++ b/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.h @@ -53,8 +53,8 @@ namespace speckle::event { */ virtual bool start() override; /*! - Handle the menu selection - @param event The menu event + Handle a selection change + @param event The selection event @return True if the event should be closed */ virtual bool handle(const SelectionEvent& event) = 0; diff --git a/SpeckleLib/Speckle/Record/Attribute/Finish.cpp b/SpeckleLib/Speckle/Record/Attribute/Finish.cpp index 86d45dd..1861b6a 100644 --- a/SpeckleLib/Speckle/Record/Attribute/Finish.cpp +++ b/SpeckleLib/Speckle/Record/Attribute/Finish.cpp @@ -128,7 +128,6 @@ Finish::Finish(const ModelerAPI::Material& material) : base{Guid{Guid::fromInt(m attr.material.diffusePc = static_cast(material.GetDiffuseReflection() * 100); attr.material.specularPc = static_cast(material.GetSpecularReflection() * 100); attr.material.transpPc = static_cast(material.GetTransparency() * 100); - auto temp = material.GetShining(); attr.material.shine = static_cast(material.GetShining() * 100); attr.material.transpAtt = static_cast(material.GetTransparencyAttenuation() * 400); attr.material.emissionAtt = static_cast(material.GetEmissionAttenuation() * 65535); diff --git a/SpeckleLib/Speckle/Record/Element/Column.cpp b/SpeckleLib/Speckle/Record/Element/Column.cpp new file mode 100644 index 0000000..36aada6 --- /dev/null +++ b/SpeckleLib/Speckle/Record/Element/Column.cpp @@ -0,0 +1,174 @@ +#include "Speckle/Record/Element/Column.h" + +#include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Active/Serialise/Package/Wrapper/PackageWrap.h" +#include "Active/Serialise/Package/Wrapper/ContainerWrap.h" +#include "Speckle/Environment/Addon.h" +#include "Speckle/Primitive/Mesh/Mesh.h" +#include "Speckle/SpeckleResource.h" +#include "Speckle/Utility/Guid.h" + +using namespace active::serialise; +using namespace speckle::environment; +using namespace speckle::record::attribute; +using namespace speckle::record::element; +using namespace speckle::utility; + +#include +#include + +namespace speckle::record::element { + + class Column::Data { + public: + friend class Column; + +#ifdef ARCHICAD + Data(const API_Element& elem) : root{ std::make_unique(elem.column) } {} + Data(const Data& source) : root{ std::make_unique(*source.root) } {} +#endif + + private: + std::unique_ptr root; + }; + +} + +namespace { + + ///Serialisation fields + enum FieldIndex { + segmentID, + }; + + ///Serialisation field IDs + static std::array fieldID = { + Identity{"segments"}, + }; + +} + +/*-------------------------------------------------------------------- + Default constructor + --------------------------------------------------------------------*/ +Column::Column() { +} //Column::Column + + +#ifdef ARCHICAD +/*-------------------------------------------------------------------- + Constructor + + elemData: Archicad element data + tableID: The element table ID (AC database, e.g. floor plan, 3D) + --------------------------------------------------------------------*/ +Column::Column(const API_Element& elemData, const speckle::utility::Guid& tableID) : base{ elemData.header.guid, tableID } { + m_data = std::make_unique(elemData); +} //Column::Column +#endif + + +/*-------------------------------------------------------------------- + Copy constructor + + source: The object to copy + --------------------------------------------------------------------*/ +Column::Column(const Column& source) : base{ source } { + m_data = source.m_data ? std::make_unique(*m_data) : nullptr; +} //Column::Column + + +/*-------------------------------------------------------------------- + Destructor + --------------------------------------------------------------------*/ +Column::~Column() {} + + +#ifdef ARCHICAD +/*-------------------------------------------------------------------- + Get the (immutable) API element header data + + return: The element header data (only use this data for low-level operations - for normal code, call getters/setters) + --------------------------------------------------------------------*/ +const API_Elem_Head& Column::getHead() const { + return m_data->root->head; +} //Column::getHead + +/*-------------------------------------------------------------------- + Get the (mutable) API element header data + + return: The element header data (only use this data for low-level operations - for normal code, call getters/setters) + --------------------------------------------------------------------*/ +API_Elem_Head& Column::getHead() { + return m_data->root->head; +} //Column::getHead + + +/*-------------------------------------------------------------------- + Load the element memo structure (elements must override according to requirements) + + filter: Filter bits specifying memo requirements + --------------------------------------------------------------------*/ +void Column::loadMemo(filter_bits filter, std::unique_ptr& memo) const { + //Establish the memo filter for this element + if (!SegmentedColumn::isMemoLoaded()) + filter |= SegmentedColumn::getPartFilter(); + Element::loadMemo(filter, memo); + //Receive the memo data into the element (when available) + if (memo) { + if (filter & SegmentedColumn::getPartFilter()) + SegmentedColumn::receive(*memo); + } + SegmentedColumn::setMemoLoaded(true); //Always mark the data as loaded to prevent repeated attempts on error +} //Column::loadMemo +#endif + + +/*-------------------------------------------------------------------- + Fill an inventory with the package items + + inventory: The inventory to receive the package items + + return: True if the package has added items to the inventory + --------------------------------------------------------------------*/ +bool Column::fillInventory(Inventory& inventory) const { + using enum Entry::Type; + inventory.merge(Inventory{ + { + { fieldID[segmentID], segmentID, getSegmentCount(), std::nullopt }, //TODO: implement other fields + }, + }.withType(&typeid(Column))); + return base::fillInventory(inventory); +} //Column::fillInventory + + +/*-------------------------------------------------------------------- + Get the specified cargo + + item: The inventory item to retrieve + + return: The requested cargo (nullptr on failure) + --------------------------------------------------------------------*/ +Cargo::Unique Column::getCargo(const Inventory::Item& item) const { + if (item.ownerType != &typeid(Column)) + return base::getCargo(item); + using namespace active::serialise; + switch (item.index) { + case segmentID: + if (auto segment = getSegment(item.available); segment != nullptr) { + return Cargo::Unique{new PackageWrap{*segment}}; + } else + return nullptr; + default: + return nullptr; //Requested an unknown index + } +} //Column::getCargo + + +/*-------------------------------------------------------------------- + Set to the default package content + --------------------------------------------------------------------*/ +void Column::setDefault() { + base::setDefault(); + m_data.reset(); +} //Column::setDefault diff --git a/SpeckleLib/Speckle/Record/Element/Column.h b/SpeckleLib/Speckle/Record/Element/Column.h new file mode 100644 index 0000000..a70185f --- /dev/null +++ b/SpeckleLib/Speckle/Record/Element/Column.h @@ -0,0 +1,142 @@ +#ifndef SPECKLE_RECORD_ELEMENT_COLUMN +#define SPECKLE_RECORD_ELEMENT_COLUMN + +#include "Speckle/Record/Element/ColumnSegment.h" +#include "Speckle/Record/Element/Element.h" +#include "Speckle/Record/Element/Interface/Assembly/Path.h" +#include "Speckle/Record/Element/Interface/SegmentedColumn.h" + +namespace speckle::record::element { + + class ColumnSegment; + + /*! + BIM column class + */ + class Column : public Element, public SegmentedColumn, public assembly::Path { + public: + + // MARK: - Types + + using base = Element; + ///Unique pointer + using Unique = std::unique_ptr; + ///Shared pointer + using Shared = std::shared_ptr; + ///Optional + using Option = std::optional; + + // MARK: - Constructors + + using base::base; + + /*! + Default constructor + */ + Column(); +#ifdef ARCHICAD + /*! + Constructor + @param elemData Archicad element data + @param tableID The column element ID (AC database, e.g. floor plan, 3D) + */ + Column(const API_Element& elemData, const speckle::utility::Guid& tableID); +#endif + /*! + Copy constructor + @param source The object to copy + */ + Column(const Column& source); + /*! + Destructor + */ + ~Column(); + + /*! + Object cloning + @return A clone of this object + */ + Column* clonePtr() const override { return new Column{*this}; } + + + // MARK: - Functions (const) + + /*! + Get the speckle type identifier + @return The speckle type (relevant objects should override as required) + */ + speckle::utility::String getSpeckleType() const override { return "Objects.BuiltElements.Element:Objects.BuiltElements.Column"; } + /*! + Get the BIM application parent table ID + @return The BIM table ID + */ + virtual database::BIMRecordID getTableID() const override { return Element::getTableID(); } + /*! + Get the element body + @return nullptr (Columns don't explicitly have a 3D body - this comes from its child segments) + */ + virtual Body* getBody() const override { return nullptr; } + /*! + Get the number of segments in the path (elements must override according to requirements) + @return The segment count + */ + virtual size_t getSegmentCount() const override { return SegmentedColumn::getSegmentCount(); } + /*! + Get a segment from the path (elements must override according to requirements) + @param index The index of the required segment + @return The requested segment (nullptr on failure) + */ + virtual ColumnSegment* getSegment(size_t index) const override { return SegmentedColumn::getSegment(index); } +#ifdef ARCHICAD + /*! + Get the (immutable) API element header data + @return The element header data (only use this data for low-level operations - for normal code, call getters/setters) + */ + const API_Elem_Head& getHead() const override; +#endif + + // MARK: - Functions (mutating) + +#ifdef ARCHICAD + /*! + Get the (mutable) API element header data + @return The element header data (only use this data for low-level operations - for normal code, call getters/setters) + */ + API_Elem_Head& getHead() override; +#endif + + // MARK: - Serialisation + + /*! + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ + bool fillInventory(active::serialise::Inventory& inventory) const override; + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + /*! + Set to the default package content + */ + void setDefault() override; + + protected: + /*! + Load the element memo structure (elements must override according to requirements) + @param filter Filter bits specifying memo requirements + */ + virtual void loadMemo(filter_bits filter, std::unique_ptr& memo) const override; + + private: + class Data; + ///The column data + std::unique_ptr m_data; + }; + +} + +#endif //SPECKLE_RECORD_ELEMENT_COLUMN diff --git a/SpeckleLib/Speckle/Record/Element/ColumnSegment.cpp b/SpeckleLib/Speckle/Record/Element/ColumnSegment.cpp new file mode 100644 index 0000000..f18b949 --- /dev/null +++ b/SpeckleLib/Speckle/Record/Element/ColumnSegment.cpp @@ -0,0 +1,149 @@ +#include "Speckle/Record/Element/ColumnSegment.h" + +#include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Active/Serialise/Package/Wrapper/PackageWrap.h" +#include "Active/Serialise/Package/Wrapper/ContainerWrap.h" +#include "Speckle/Environment/Addon.h" +#include "Speckle/Primitive/Mesh/Mesh.h" +#include "Speckle/SpeckleResource.h" +#include "Speckle/Utility/Guid.h" + +#ifdef ARCHICAD +#include +#endif + +using namespace active::serialise; +using namespace speckle::environment; +using namespace speckle::record::attribute; +using namespace speckle::record::element; +using namespace speckle::utility; + +#include +#include + +namespace speckle::record::element { + + class ColumnSegment::Data { + public: + friend class ColumnSegment; + +#ifdef ARCHICAD + Data(const API_ColumnSegmentType& seg) : root{ std::make_unique(seg) } {} + Data(const Data& source) : root{ std::make_unique(*source.root) } {} + + private: + std::unique_ptr root; +#endif + }; + +} + +/*-------------------------------------------------------------------- + Default constructor + --------------------------------------------------------------------*/ +ColumnSegment::ColumnSegment() { +} //ColumnSegment::ColumnSegment + + +#ifdef ARCHICAD +/*-------------------------------------------------------------------- + Constructor + + elemData: Archicad element data + tableID: The element table ID (AC database, e.g. floor plan, 3D) + --------------------------------------------------------------------*/ +ColumnSegment::ColumnSegment(const API_Element& elemData, const speckle::utility::Guid& tableID) : base{ elemData.header.guid, tableID } { + m_data = std::make_unique(elemData.columnSegment); +} //ColumnSegment::ColumnSegment + + +/*-------------------------------------------------------------------- + Constructor + + segment: The segment element data + tableID: The parent table ID + cutOrigin: Cut at the segment origin + cutEnd: Cut at the segment end + scheme: The segment scheme + profile: The segment profile (nullptr = none) + --------------------------------------------------------------------*/ +ColumnSegment::ColumnSegment(const API_ColumnSegmentType& segment, const speckle::utility::Guid& tableID, const API_AssemblySegmentCutData& cutOrigin, + const API_AssemblySegmentCutData& cutEnd, const API_AssemblySegmentSchemeData& scheme, + const API_AssemblySegmentProfileData* profile) : + base{segment.head.guid, tableID}, assembly::Segment{cutOrigin, cutEnd, scheme, profile} { + m_data = std::make_unique(segment); +} //ColumnSegment::ColumnSegment +#endif + + +/*-------------------------------------------------------------------- + Copy constructor + + source: The object to copy + --------------------------------------------------------------------*/ +ColumnSegment::ColumnSegment(const ColumnSegment& source) : base{ source } { + m_data = source.m_data ? std::make_unique(*m_data) : nullptr; +} //ColumnSegment::ColumnSegment + + +/*-------------------------------------------------------------------- + Destructor + --------------------------------------------------------------------*/ +ColumnSegment::~ColumnSegment() {} + + +#ifdef ARCHICAD +/*-------------------------------------------------------------------- + Get the (immutable) API element header data + + return: The element header data (only use this data for low-level operations - for normal code, call getters/setters) + --------------------------------------------------------------------*/ +const API_Elem_Head& ColumnSegment::getHead() const { + return m_data->root->head; +} //ColumnSegment::getHead + + +/*-------------------------------------------------------------------- + Get the (mutable) API element header data + + return: The element header data (only use this data for low-level operations - for normal code, call getters/setters) + --------------------------------------------------------------------*/ +API_Elem_Head& ColumnSegment::getHead() { + return m_data->root->head; +} //ColumnSegment::getHead +#endif + + +/*-------------------------------------------------------------------- + Fill an inventory with the package items + + inventory: The inventory to receive the package items + + return: True if the package has added items to the inventory + --------------------------------------------------------------------*/ +bool ColumnSegment::fillInventory(Inventory& inventory) const { + using enum Entry::Type; + //TODO: Implement other fields as required + return base::fillInventory(inventory); +} //ColumnSegment::fillInventory + + +/*-------------------------------------------------------------------- + Get the specified cargo + + item: The inventory item to retrieve + + return: The requested cargo (nullptr on failure) + --------------------------------------------------------------------*/ +Cargo::Unique ColumnSegment::getCargo(const Inventory::Item& item) const { + //TODO: Implement other fields as required + return base::getCargo(item); +} //ColumnSegment::getCargo + + +/*-------------------------------------------------------------------- + Set to the default package content + --------------------------------------------------------------------*/ +void ColumnSegment::setDefault() { + m_data.reset(); +} //ColumnSegment::setDefault diff --git a/SpeckleLib/Speckle/Record/Element/ColumnSegment.h b/SpeckleLib/Speckle/Record/Element/ColumnSegment.h new file mode 100644 index 0000000..d16b414 --- /dev/null +++ b/SpeckleLib/Speckle/Record/Element/ColumnSegment.h @@ -0,0 +1,130 @@ +#ifndef SPECKLE_RECORD_ELEMENT_COLUMN_SEGMENT +#define SPECKLE_RECORD_ELEMENT_COLUMN_SEGMENT + +#include "Speckle/Record/Element/Element.h" +#include "Speckle/Record/Element/Interface/Assembly/Segment.h" + +namespace speckle::record::element { + + class SegmentedColumn; + + /*! + BIM column class + */ + class ColumnSegment : public Element, public assembly::Segment { + public: + + // MARK: - Types + + using base = Element; + ///Unique pointer + using Unique = std::unique_ptr; + ///Shared pointer + using Shared = std::shared_ptr; + ///Optional + using Option = std::optional; + + // MARK: - Constructors + + using base::base; + + /*! + Default constructor + */ + ColumnSegment(); +#ifdef ARCHICAD + /*! + Constructor + @param elemData Archicad element data + @param tableID The element table ID (AC database, e.g. floor plan, 3D) + */ + ColumnSegment(const API_Element& elemData, const speckle::utility::Guid& tableID); +#endif + /*! + Copy constructor + @param source The object to copy + */ + ColumnSegment(const ColumnSegment& source); + /*! + Destructor + */ + ~ColumnSegment(); + + /*! + Object cloning + @return A clone of this object + */ + ColumnSegment* clonePtr() const override { return new ColumnSegment{*this}; } + + + // MARK: - Functions (const) + + /*! + Get the speckle type identifier + @return The speckle type (relevant objects should override as required) + */ + speckle::utility::String getSpeckleType() const override { return "Objects.BuiltElements.Element:Objects.BuiltElements.ColumnSegment"; } +#ifdef ARCHICAD + /*! + Get the (immutable) API element header data + @return The element header data (only use this data for low-level operations - for normal code, call getters/setters) + */ + const API_Elem_Head& getHead() const override; +#endif + + // MARK: - Functions (mutating) + +#ifdef ARCHICAD + /*! + Get the (mutable) API element header data + @return The element header data (only use this data for low-level operations - for normal code, call getters/setters) + */ + API_Elem_Head& getHead() override; +#endif + + // MARK: - Serialisation + + /*! + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ + bool fillInventory(active::serialise::Inventory& inventory) const override; + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + /*! + Set to the default package content + */ + void setDefault() override; + + protected: + friend class SegmentedColumn; + +#ifdef ARCHICAD + /*! + Constructor + @param segment The segment element data + @param tableID The parent table ID + @param cutOrigin Cut at the segment origin + @param cutEnd Cut at the segment end + @param scheme The segment scheme + @param profile The segment profile (nullptr = none) + */ + ColumnSegment(const API_ColumnSegmentType& segment, const speckle::utility::Guid& tableID, const API_AssemblySegmentCutData& cutOrigin, + const API_AssemblySegmentCutData& cutEnd, const API_AssemblySegmentSchemeData& scheme, + const API_AssemblySegmentProfileData* profile = nullptr); +#endif + + private: + class Data; + ///The column data + std::unique_ptr m_data; + }; + +} + +#endif //SPECKLE_RECORD_ELEMENT_COLUMN_SEGMENT diff --git a/SpeckleLib/Speckle/Record/Element/Element.cpp b/SpeckleLib/Speckle/Record/Element/Element.cpp index 02fda04..d2a80ff 100644 --- a/SpeckleLib/Speckle/Record/Element/Element.cpp +++ b/SpeckleLib/Speckle/Record/Element/Element.cpp @@ -3,19 +3,22 @@ #include "Active/Serialise/Item/Wrapper/ValueWrap.h" #include "Active/Serialise/Package/Wrapper/PackageWrap.h" #include "Active/Serialise/Package/Wrapper/ContainerWrap.h" +#include "Speckle/Database/BIMElementDatabase.h" #include "Speckle/Environment/Addon.h" +#include "Speckle/Environment/Project.h" #include "Speckle/Primitive/Mesh/Mesh.h" +#include "Speckle/Record/Element/Memo.h" #include "Speckle/SpeckleResource.h" #include "Speckle/Utility/Guid.h" #ifdef ARCHICAD -#include "Sight.hpp" -#include "Model.hpp" -#include "ModelMaterial.hpp" -#include "ModelElement.hpp" -#include "exp.h" -#include "ModelMeshBody.hpp" -#include "ConvexPolygon.hpp" +#include +#include +#include +#include +#include +#include +#include #endif using namespace active::serialise; @@ -32,14 +35,10 @@ namespace speckle::record::element { class Element::Data { public: friend class Element; - -#ifdef ARCHICAD - Data(const API_Element& elem) : root{ std::make_unique(elem) } {} - Data(const Data& source) : root{ std::make_unique(*source.root) } {} -#endif + Data() {} + Data(const Data& source) {} private: - std::unique_ptr root; std::unique_ptr m_cache; }; @@ -68,12 +67,13 @@ Element::Element() { /*-------------------------------------------------------------------- Constructor - - elemData: Archicad element data - tableID: The attribute table ID (attribute type) + + ID: The record ID + tableID: The parent table ID + unit: The record unit type --------------------------------------------------------------------*/ -Element::Element(const API_Element& elemData, const speckle::utility::Guid& tableID) : base{ elemData.header.guid, tableID } { - m_data = std::make_unique(elemData); +Element::Element(const Guid& ID, const Guid& tableID, std::optional unit) : base{ID, tableID, unit} { + m_data = std::make_unique(); } //Element::Element @@ -213,27 +213,6 @@ Element::Body* Element::getBody() const { } -#ifdef ARCHICAD -/*-------------------------------------------------------------------- - Get the (immutable) API element header data - - return: The element header data (only use this data for low-level operations - for normal code, call getters/setters) - --------------------------------------------------------------------*/ -const API_Elem_Head& Element::getHead() const { - return m_data->root->header; -} //Element::getHead - -/*-------------------------------------------------------------------- - Get the (mutable) API element header data - - return: The element header data (only use this data for low-level operations - for normal code, call getters/setters) - --------------------------------------------------------------------*/ -API_Elem_Head& Element::getHead() { - return m_data->root->header; -} //Element::getHead -#endif - - /*-------------------------------------------------------------------- Fill an inventory with the package items @@ -285,3 +264,21 @@ void Element::setDefault() { base::setDefault(); m_data.reset(); } //Element::setDefault + + +/*-------------------------------------------------------------------- + Load the element memo structure (elements must override according to requirements) + + filter: Filter bits specifying memo requirements + --------------------------------------------------------------------*/ +void Element::loadMemo(Part::filter_bits filter, std::unique_ptr& memo) const { + //If the memo data isn't loaded, fetch it now + if (!memo) { + auto project = addon()->getActiveProject().lock(); + if (!project) + return; + auto elementDatabase = project->getElementDatabase(); + if (auto loaded = elementDatabase->getMemo(getBIMID(), filter); loaded) + memo.reset(loaded.release()); + } +} //Element::loadMemo diff --git a/SpeckleLib/Speckle/Record/Element/Element.h b/SpeckleLib/Speckle/Record/Element/Element.h index 081119a..80e479d 100644 --- a/SpeckleLib/Speckle/Record/Element/Element.h +++ b/SpeckleLib/Speckle/Record/Element/Element.h @@ -2,6 +2,7 @@ #define SPECKLE_RECORD_ELEMENT #include "Speckle/Database/Content/BIMRecord.h" +#include "Speckle/Record/Element/Interface/Part.h" #include "Speckle/Record/Attribute/Storey.h" #include "Speckle/Utility/String.h" @@ -11,6 +12,8 @@ namespace speckle::primitive { namespace speckle::record::element { + class Memo; + /*! Base BIM element class */ @@ -32,20 +35,18 @@ namespace speckle::record::element { // MARK: - Constructors - using base::base; - /*! Default constructor */ Element(); -#ifdef ARCHICAD /*! Constructor - @param elemData Archicad element data - @param tableID The element table ID (AC database, e.g. floor plan, 3D) + @param ID The record ID + @param tableID The parent table ID + @param unit The record unit type */ - Element(const API_Element& elemData, const speckle::utility::Guid& tableID); -#endif + Element(const speckle::utility::Guid& ID, const speckle::utility::Guid& tableID, + std::optional unit = active::measure::LengthType::metre); /*! Copy constructor @param source The object to copy @@ -56,13 +57,6 @@ namespace speckle::record::element { */ ~Element(); - /*! - Object cloning - @return A clone of this object - */ - Element* clonePtr() const override { return new Element{*this}; } - - // MARK: - Functions (const) /*! @@ -90,7 +84,7 @@ namespace speckle::record::element { Get the (immutable) API element header data @return The element header data (only use this data for low-level operations - for normal code, call getters/setters) */ - virtual const API_Elem_Head& getHead() const; + virtual const API_Elem_Head& getHead() const = 0; #endif // MARK: - Functions (mutating) @@ -100,7 +94,7 @@ namespace speckle::record::element { Get the (mutable) API element header data @return The element header data (only use this data for low-level operations - for normal code, call getters/setters) */ - virtual API_Elem_Head& getHead(); + virtual API_Elem_Head& getHead() = 0; #endif // MARK: - Serialisation @@ -122,6 +116,13 @@ namespace speckle::record::element { */ void setDefault() override; + protected: + /*! + Load the element memo structure (elements must override according to requirements) + @param filter Filter bits specifying memo requirements + */ + virtual void loadMemo(Part::filter_bits filter, std::unique_ptr& memo) const; + private: class Data; ///The element data diff --git a/SpeckleLib/Speckle/Record/Element/GenericElement.cpp b/SpeckleLib/Speckle/Record/Element/GenericElement.cpp new file mode 100644 index 0000000..9267061 --- /dev/null +++ b/SpeckleLib/Speckle/Record/Element/GenericElement.cpp @@ -0,0 +1,157 @@ +#include "Speckle/Record/Element/GenericElement.h" + +#include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Active/Serialise/Package/Wrapper/PackageWrap.h" +#include "Active/Serialise/Package/Wrapper/ContainerWrap.h" +#include "Speckle/Environment/Addon.h" +#include "Speckle/Primitive/Mesh/Mesh.h" +#include "Speckle/SpeckleResource.h" +#include "Speckle/Utility/Guid.h" + +using namespace active::serialise; +using namespace speckle::environment; +using namespace speckle::record::attribute; +using namespace speckle::record::element; +using namespace speckle::utility; + +#include +#include + +namespace speckle::record::element { + + class GenericElement::Data { + public: + friend class GenericElement; + +#ifdef ARCHICAD + Data(const API_Element& elem) : root{ std::make_unique(elem) } {} + Data(const Data& source) : root{ std::make_unique(*source.root) } {} +#endif + + private: + std::unique_ptr root; + std::unique_ptr m_cache; + }; + +} + +namespace { + + ///Serialisation fields + enum FieldIndex { + bodyID, + }; + + ///Serialisation field IDs + static std::array fieldID = { + Identity{"displayValue"}, + }; + +} + +/*-------------------------------------------------------------------- + Default constructor + --------------------------------------------------------------------*/ +GenericElement::GenericElement() { +} //GenericElement::GenericElement + + +/*-------------------------------------------------------------------- + Constructor + + elemData: Archicad element data + tableID: The attribute table ID (attribute type) + --------------------------------------------------------------------*/ +GenericElement::GenericElement(const API_Element& elemData, const speckle::utility::Guid& tableID) : base{ elemData.header.guid, tableID } { + m_data = std::make_unique(elemData); +} //GenericElement::GenericElement + + +/*-------------------------------------------------------------------- + Copy constructor + + source: The object to copy + --------------------------------------------------------------------*/ +GenericElement::GenericElement(const GenericElement& source) : base{ source } { + m_data = source.m_data ? std::make_unique(*m_data) : nullptr; +} //GenericElement::GenericElement + + +/*-------------------------------------------------------------------- + Destructor + --------------------------------------------------------------------*/ +GenericElement::~GenericElement() {} + + +#ifdef ARCHICAD +/*-------------------------------------------------------------------- + Get the (immutable) API element header data + + return: The element header data (only use this data for low-level operations - for normal code, call getters/setters) + --------------------------------------------------------------------*/ +const API_Elem_Head& GenericElement::getHead() const { + return m_data->root->header; +} //GenericElement::getHead + +/*-------------------------------------------------------------------- + Get the (mutable) API element header data + + return: The element header data (only use this data for low-level operations - for normal code, call getters/setters) + --------------------------------------------------------------------*/ +API_Elem_Head& GenericElement::getHead() { + return m_data->root->header; +} //GenericElement::getHead +#endif + + +/*-------------------------------------------------------------------- + Fill an inventory with the package items + + inventory: The inventory to receive the package items + + return: True if the package has added items to the inventory + --------------------------------------------------------------------*/ +bool GenericElement::fillInventory(Inventory& inventory) const { + using enum Entry::Type; + inventory.merge(Inventory{ + { + { fieldID[bodyID], bodyID, element }, //TODO: implement other fields + }, + }.withType(&typeid(GenericElement))); + return base::fillInventory(inventory); +} //GenericElement::fillInventory + + +/*-------------------------------------------------------------------- + Get the specified cargo + + item: The inventory item to retrieve + + return: The requested cargo (nullptr on failure) + --------------------------------------------------------------------*/ +Cargo::Unique GenericElement::getCargo(const Inventory::Item& item) const { + if (item.ownerType != &typeid(GenericElement)) + return base::getCargo(item); + using namespace active::serialise; + switch (item.index) { + case bodyID: + if (auto body = getBody(); body != nullptr) + { + return Cargo::Unique{ new active::serialise::ContainerWrap{*body} }; + } + else + return nullptr; + + default: + return nullptr; //Requested an unknown index + } +} //GenericElement::getCargo + + +/*-------------------------------------------------------------------- + Set to the default package content + --------------------------------------------------------------------*/ +void GenericElement::setDefault() { + base::setDefault(); + m_data.reset(); +} //GenericElement::setDefault diff --git a/SpeckleLib/Speckle/Record/Element/GenericElement.h b/SpeckleLib/Speckle/Record/Element/GenericElement.h new file mode 100644 index 0000000..a1d052e --- /dev/null +++ b/SpeckleLib/Speckle/Record/Element/GenericElement.h @@ -0,0 +1,112 @@ +#ifndef SPECKLE_RECORD_GENERIC_ELEMENT +#define SPECKLE_RECORD_GENERIC_ELEMENT + +#include "Speckle/Record/Element/Element.h" + +namespace speckle::record::element { + + /*! + Catch-all class for elements that are not represented by a specific class + */ + class GenericElement : public Element { + public: + + ///An element 3D body primitive + using Body = std::vector; + + // MARK: - Types + + using base = Element; + ///Unique pointer + using Unique = std::unique_ptr; + ///Shared pointer + using Shared = std::shared_ptr; + ///Optional + using Option = std::optional; + + // MARK: - Constructors + + using base::base; + + /*! + Default constructor + */ + GenericElement(); +#ifdef ARCHICAD + /*! + Constructor + @param elemData Archicad element data + @param tableID The element table ID (AC database, e.g. floor plan, 3D) + */ + GenericElement(const API_Element& elemData, const speckle::utility::Guid& tableID); +#endif + /*! + Copy constructor + @param source The object to copy + */ + GenericElement(const GenericElement& source); + /*! + Destructor + */ + ~GenericElement(); + + /*! + Object cloning + @return A clone of this object + */ + GenericElement* clonePtr() const override { return new GenericElement{*this}; } + + + // MARK: - Functions (const) + + /*! + Get the speckle type identifier + @return The speckle type (relevant objects should override as required) + */ + virtual speckle::utility::String getSpeckleType() const override { return "Objects.BuiltElements.GenericElement:Objects.BuiltElements.GenericElement"; } +#ifdef ARCHICAD + /*! + Get the (immutable) API element header data + @return The element header data (only use this data for low-level operations - for normal code, call getters/setters) + */ + virtual const API_Elem_Head& getHead() const override; +#endif + + // MARK: - Functions (mutating) + +#ifdef ARCHICAD + /*! + Get the (mutable) API element header data + @return The element header data (only use this data for low-level operations - for normal code, call getters/setters) + */ + virtual API_Elem_Head& getHead() override; +#endif + + // MARK: - Serialisation + + /*! + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ + bool fillInventory(active::serialise::Inventory& inventory) const override; + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + /*! + Set to the default package content + */ + void setDefault() override; + + private: + class Data; + ///The element data + std::unique_ptr m_data; + }; + +} + +#endif //SPECKLE_RECORD_GENERIC_ELEMENT diff --git a/SpeckleLib/Speckle/Record/Element/Interface/Assembly/Path.cpp b/SpeckleLib/Speckle/Record/Element/Interface/Assembly/Path.cpp new file mode 100644 index 0000000..37534b0 --- /dev/null +++ b/SpeckleLib/Speckle/Record/Element/Interface/Assembly/Path.cpp @@ -0,0 +1,23 @@ +#include "Speckle/Record/Element/Interface/Assembly/Path.h" + +#include "Active/Geometry/PolyEdge.h" + +#ifdef ARCHICAD +#include +#endif + +using namespace active::geometry; +using namespace speckle::database; +using namespace speckle::record::element::assembly; + +/*-------------------------------------------------------------------- + Get a specified edge from the segmented path + + index: The index of the required edge + + return: The requested edge (nullptr on failure) + --------------------------------------------------------------------*/ +std::unique_ptr Path::getSegmentEdge(const database::BIMIndex& index) const { + //TODO: Complete when required + return nullptr; +} diff --git a/SpeckleLib/Speckle/Record/Element/Interface/Assembly/Path.h b/SpeckleLib/Speckle/Record/Element/Interface/Assembly/Path.h new file mode 100644 index 0000000..62a286e --- /dev/null +++ b/SpeckleLib/Speckle/Record/Element/Interface/Assembly/Path.h @@ -0,0 +1,48 @@ +#ifndef SPECKLE_RECORD_ELEMENT_ASSEMBLY_PATH +#define SPECKLE_RECORD_ELEMENT_ASSEMBLY_PATH + +#include "Speckle/Database/Identity/BIMIndex.h" + +#include +#include + +namespace active::geometry { + class PolyEdge; +} + +namespace speckle::record::element::assembly { + + class Segment; + + /*! + Interface for assemblies forming a path made up of a consecutive series of segments, e.g. a portal frame made from a series of beams + */ + class Path { + public: + + // MARK: - Functions (const) + + /*! + Get a specified edge from the segmented path + @param index The index of the required edge + @return The requested edge (nullptr on failure) + */ + std::unique_ptr getSegmentEdge(const database::BIMIndex& index) const; + + protected: + /*! + Get the number of segments in the path (elements must override according to requirements) + @return The segment count + */ + virtual size_t getSegmentCount() const = 0; + /*! + Get a segment from the path (elements must override according to requirements) + @param index The index of the required segment + @return The requested segment (nullptr on failure) + */ + virtual Segment* getSegment(size_t index) const = 0; + }; + +} + +#endif //SPECKLE_RECORD_ELEMENT_ASSEMBLY_PATH diff --git a/SpeckleLib/Speckle/Record/Element/Interface/Assembly/Segment.cpp b/SpeckleLib/Speckle/Record/Element/Interface/Assembly/Segment.cpp new file mode 100644 index 0000000..72b6973 --- /dev/null +++ b/SpeckleLib/Speckle/Record/Element/Interface/Assembly/Segment.cpp @@ -0,0 +1,67 @@ +#include "Speckle/Record/Element/Interface/Assembly/Segment.h" + +#include "Active/Geometry/PolyEdge.h" +#include "Active/Utility/Memory.h" + +#ifdef ARCHICAD +#include +#include +#include +#endif + +using namespace active::geometry; +using namespace speckle::record::element::assembly; + +/*-------------------------------------------------------------------- + Default constructor + --------------------------------------------------------------------*/ +Segment::Segment() : + m_cutOrigin{std::make_unique()}, + m_cutEnd{std::make_unique()}, + m_scheme{std::make_unique()} { + +} //Segment::Segment + +/*-------------------------------------------------------------------- + Constructor + + cutOrigin: Cut at the segment origin + cutEnd: Cut at the segment end + scheme: The segment scheme + profile: The segment profile (nullptr = none) + --------------------------------------------------------------------*/ +Segment::Segment(const API_AssemblySegmentCutData& cutOrigin, const API_AssemblySegmentCutData& cutEnd, const API_AssemblySegmentSchemeData& scheme, + const API_AssemblySegmentProfileData* profile) : + m_cutOrigin{std::make_unique(cutOrigin)}, + m_cutEnd{std::make_unique(cutEnd)}, + m_scheme{std::make_unique(scheme)} { + if (profile != nullptr) { + if (profile->customOrigProfile != nullptr) + m_customProfile = std::make_unique(*profile->customOrigProfile); + if (profile->stretchedProfile != nullptr) + m_stretchedProfile = std::make_unique(*profile->stretchedProfile); + } +} //Segment::Segment + +/*-------------------------------------------------------------------- + Copy constructor + + source: The object to copy + --------------------------------------------------------------------*/ +Segment::Segment(const Segment& source) : + m_cutOrigin{std::make_unique(*source.m_cutOrigin)}, + m_cutEnd{std::make_unique(*source.m_cutEnd)}, + m_scheme{std::make_unique(*source.m_scheme)}, + m_edge{source.m_edge ? std::make_unique(*source.m_edge) : nullptr}, + m_customProfile{source.m_customProfile ? std::make_unique(*source.m_customProfile) : nullptr}, + m_stretchedProfile{source.m_stretchedProfile ? std::make_unique(*source.m_stretchedProfile) : nullptr} { + m_path = source.m_path; +} //Segment::Segment + + +/*-------------------------------------------------------------------- + Destructor + --------------------------------------------------------------------*/ +Segment::~Segment() {} + + diff --git a/SpeckleLib/Speckle/Record/Element/Interface/Assembly/Segment.h b/SpeckleLib/Speckle/Record/Element/Interface/Assembly/Segment.h new file mode 100644 index 0000000..bc6d248 --- /dev/null +++ b/SpeckleLib/Speckle/Record/Element/Interface/Assembly/Segment.h @@ -0,0 +1,91 @@ +#ifndef SPECKLE_RECORD_ELEMENT_ASSEMBLY_SEGMENT +#define SPECKLE_RECORD_ELEMENT_ASSEMBLY_SEGMENT + +#include "Speckle/Database/Identity/BIMIndex.h" + +#include +#include + +#ifdef ARCHICAD +struct API_AssemblySegmentCutData; +struct API_AssemblySegmentSchemeData; +class ProfileVectorImage; +#endif + +namespace active::geometry { + class PolyEdge; +} + +namespace speckle::record::element::assembly { + + class Path; + + /*! + Interface for elements forming a path made up of a consecutive series of segments, e.g. a portal frame made from a series of beams + */ + class Segment { + public: + /*! + Default constructor + */ + Segment(); + /*! + Copy constructor + @param source The object to copy + */ + Segment(const Segment& source); + /*! + Destructor + */ + ~Segment(); + + // MARK: - Functions (const) + + /*! + Get the segment path + @return The segment path (nullptr = undefined) + */ + const assembly::Path* getPath() const { return m_path; } + + // MARK: - Functions (mutating) + + /*! + Set the segment path + @param path The segment path + */ + void setPath(const assembly::Path* path) { m_path = path; } + + protected: + /*! + Constructor + @param cutOrigin Cut at the segment origin + @param cutEnd Cut at the segment end + @param scheme The segment scheme + @param profile The segment profile (nullptr = none) + */ + Segment(const API_AssemblySegmentCutData& cutOrigin, const API_AssemblySegmentCutData& cutEnd, const API_AssemblySegmentSchemeData& scheme, + const API_AssemblySegmentProfileData* profile = nullptr); + + private: +#ifdef ARCHICAD + //NB: The following properties are mutable to support lazy loading + ///Cut at the segment origin + mutable std::unique_ptr m_cutOrigin; + ///Cut at the segment end + mutable std::unique_ptr m_cutEnd; + ///The segment scheme + mutable std::unique_ptr m_scheme; + ///An optional custom profile (nullptr = none) + mutable std::unique_ptr m_customProfile; + ///An optional stretched profile (nullptr = none) + mutable std::unique_ptr m_stretchedProfile; +#endif + //The segment edge + mutable std::unique_ptr m_edge; + //The segment path + mutable const assembly::Path* m_path = nullptr; + }; + +} + +#endif //SPECKLE_RECORD_ELEMENT_ASSEMBLY_SEGMENT diff --git a/SpeckleLib/Speckle/Record/Element/Interface/Part.cpp b/SpeckleLib/Speckle/Record/Element/Interface/Part.cpp new file mode 100644 index 0000000..8c1fe9e --- /dev/null +++ b/SpeckleLib/Speckle/Record/Element/Interface/Part.cpp @@ -0,0 +1,23 @@ +#include "Speckle/Record/Element/Interface/Part.h" + +#include "Speckle/Record/Element/Memo.h" + +using namespace active::serialise; +using namespace speckle::record::attribute; +using namespace speckle::record::element; +using namespace speckle::utility; + +/*-------------------------------------------------------------------- + Confirm that the element part data is loaded and valid (elements must override according to requirements) + + filter: Filter bits specifying memo requirements + + return: True if the part data is ready to use + --------------------------------------------------------------------*/ +bool Part::confirmPart(filter_bits filter) const { + if (!isMemoLoaded()) { + std::unique_ptr memo; + loadMemo(filter, memo); + } + return isMemoLoaded(); +} //Part::confirmPart diff --git a/SpeckleLib/Speckle/Record/Element/Interface/Part.h b/SpeckleLib/Speckle/Record/Element/Interface/Part.h new file mode 100644 index 0000000..faa383e --- /dev/null +++ b/SpeckleLib/Speckle/Record/Element/Interface/Part.h @@ -0,0 +1,92 @@ +#ifndef SPECKLE_RECORD_ELEMENT_PART +#define SPECKLE_RECORD_ELEMENT_PART + +#include +#include + +namespace speckle::record::element { + + class Memo; + + /*! + Interface for an element part, i.e. some component in an assembly element + + Although this concept is slanted toward Archicad's memo structure, the fundamentals are applicable to any data structures that separate out + the constituent parts of an assembly to support lazy loading + Note that this class is intended to be an interface - management and/or storage of the data should be provided by subclassing + */ + class Part { + public: + ///Filter bits for memo loading + using filter_bits = uint64_t; + + // MARK: - Types + + ///Unique pointer + using Unique = std::unique_ptr; + ///Shared pointer + using Shared = std::shared_ptr; + ///Optional + using Option = std::optional; + + // MARK: - Constructors + + /*! + Destructor + */ + virtual ~Part() {} + + // MARK: - Functions (const) + + + // MARK: - Functions (mutating) + + protected: + /*! + Determine if the element memo data has been successfully loaded and validated + @return True if the element memo data is loaded + */ + bool isMemoLoaded() const { return m_isLoaded && isPartValid(); } + /*! + Determine if the element memo content has been validated (elements must override according to requirements) + @return True if the element memo content is valid + */ + virtual bool isPartValid() const = 0; + /*! + Confirm that the element part data is loaded and valid (elements must override according to requirements) + @param filter Filter bits specifying memo requirements + @return True if the part data is ready to use + */ + virtual bool confirmPart(filter_bits filter) const; + /*! + Load the element memo structure (elements must override according to requirements) + @param filter Filter bits specifying memo requirements + */ + virtual void loadMemo(filter_bits filter, std::unique_ptr& memo) const = 0; + /*! + Set whether the element memo data has been loaded (does not establish validity, but prevents multiple attempts to reload) + @param state True if the element memo data is loaded + */ + void setMemoLoaded(bool state) const { m_isLoaded = state; } + + /*! + Send the element part back to a memo structure for storage (elements must override according to requirements) + @param memo The memo to carry the data + @return True if the data was successfully sent + */ + virtual bool send(Memo* memo) const = 0; + /*! + Receive the element memo data from a memo structure (elements must override according to requirements) + @param memo The memo carrying the data + @return True if the data was successfully received + */ + virtual bool receive(const Memo& memo) const = 0; + + private: + ///True if the memo data has been loaded into the element (mutable to support lazy loading) + mutable bool m_isLoaded = false; + }; + +} + +#endif //SPECKLE_RECORD_ELEMENT_PART diff --git a/SpeckleLib/Speckle/Record/Element/Interface/SegmentedColumn.cpp b/SpeckleLib/Speckle/Record/Element/Interface/SegmentedColumn.cpp new file mode 100644 index 0000000..e181fee --- /dev/null +++ b/SpeckleLib/Speckle/Record/Element/Interface/SegmentedColumn.cpp @@ -0,0 +1,158 @@ +#include "Speckle/Record/Element/Interface/SegmentedColumn.h" + +#include "Speckle/Record/Element/ColumnSegment.h" +#include "Speckle/Record/Element/Memo.h" +#include "Speckle/Record/Element/Interface/Assembly/Path.h" +#include "Speckle/Utility/BIMMemory.h" + +using namespace active::serialise; +using namespace speckle::record::attribute; +using namespace speckle::record::element; +using namespace speckle::utility; + +namespace speckle::record::element { + + class SegmentedColumn::Data { + public: + friend class SegmentedColumn; + + std::vector segments; + }; + +} + +/*-------------------------------------------------------------------- + Default constructor + --------------------------------------------------------------------*/ +SegmentedColumn::SegmentedColumn() { +} //SegmentedColumn::SegmentedColumn + + +/*-------------------------------------------------------------------- + Copy constructor + + source: The object to copy + --------------------------------------------------------------------*/ +SegmentedColumn::SegmentedColumn(const SegmentedColumn& source) : base{ source } { + m_data = source.m_data ? std::make_unique(*m_data) : nullptr; +} //SegmentedColumn::SegmentedColumn + + +/*-------------------------------------------------------------------- + Destructor + --------------------------------------------------------------------*/ +SegmentedColumn::~SegmentedColumn() {} + + +/*-------------------------------------------------------------------- + Get the number of segments + + return. The number of segments (0 on error) + --------------------------------------------------------------------*/ +size_t SegmentedColumn::getSegmentCount() const { + confirmPart(getPartFilter()); + return m_data ? m_data->segments.size() : 0; +} //SegmentedColumn::getSegmentCount + + +/*-------------------------------------------------------------------- + Get a column segment + + index: The index of the required segment + + return: The requested segment, nullptr on error + --------------------------------------------------------------------*/ +ColumnSegment* SegmentedColumn::getSegment(size_t index) const { + confirmPart(getPartFilter()); + return (m_data && (index < m_data->segments.size())) ? &m_data->segments[index] : nullptr; +} //SegmentedColumn::getSegment + + +/*-------------------------------------------------------------------- + Return the bits for the part filter required to load the data necessary to build this object + + return: The required filter bits + --------------------------------------------------------------------*/ +Part::filter_bits SegmentedColumn::getPartFilter() const { + return APIMemoMask_ColumnSegment | APIMemoMask_AssemblySegmentCut | APIMemoMask_AssemblySegmentScheme | APIMemoMask_AssemblySegmentProfile; +} //SegmentedColumn::getPartFilter + + +/*-------------------------------------------------------------------- + Determine if the element memo content has been validated (elements must override according to requirements) + + return: True if the element memo content is valid + --------------------------------------------------------------------*/ +bool SegmentedColumn::isPartValid() const { + return m_data && !m_data->segments.empty(); +} //SegmentedColumn::isPartValid + + +/*-------------------------------------------------------------------- + Load the element memo structure (elements must override according to requirements) + + filter: Filter bits specifying memo requirements + --------------------------------------------------------------------*/ +void SegmentedColumn::loadMemo(filter_bits filter, std::unique_ptr& memo) const { + +} //SegmentedColumn::loadMemo + + +/*-------------------------------------------------------------------- + Send the element part back to a memo structure for storage (elements must override according to requirements) + + memo: The memo to carry the data + + return: True if the data was successfully sent + --------------------------------------------------------------------*/ +bool SegmentedColumn::send(Memo* memo) const { + //TODO: Complete when required + return false; +} //SegmentedColumn::send + + +/*-------------------------------------------------------------------- + Receive the element memo data from a memo structure (elements must override according to requirements) + + memo: The memo carrying the data + + return: True if the data was successfully received + --------------------------------------------------------------------*/ +bool SegmentedColumn::receive(const Memo& memo) const { +#ifdef ARCHICAD + if (!memo || (memo.root()->columnSegments == nullptr)) + return false; + if (m_data) + m_data->segments.clear(); + else + m_data = std::make_unique(); + //Confirm that required data is present in the memo + auto segmentPtr = memo.root()->columnSegments; + auto cutPtr = memo.root()->assemblySegmentCuts; + auto schemePtr = memo.root()->assemblySegmentSchemes; + auto profilePtr = memo.root()->assemblySegmentProfiles; + if ((segmentPtr == nullptr) || (cutPtr == nullptr) || (schemePtr == nullptr) || (profilePtr == nullptr)) + return false; + //Determine available item count + auto segmentCount = BIMMemory::getPtrSize(segmentPtr) / sizeof(API_ColumnSegmentType); + auto cutCount = BIMMemory::getPtrSize(cutPtr) / sizeof(API_AssemblySegmentCutData); + auto schemeCount = BIMMemory::getPtrSize(schemePtr) / sizeof(API_AssemblySegmentSchemeData); + auto profileCount = BIMMemory::getPtrSize(profilePtr) / sizeof(API_AssemblySegmentProfileData); + if ((segmentCount == 0) || (cutCount != (segmentCount + 1)) || (schemeCount != segmentCount)) + return false; + auto path = dynamic_cast(this); + for (size_t n = 0 ; n < segmentCount; ++n) { + const API_AssemblySegmentProfileData* thisProfile = nullptr; + for (size_t i = 0; i < profileCount; ++i) { + if (profilePtr[i].segmentIndex == n) { + thisProfile = profilePtr + i; + break; + } + } + m_data->segments.push_back({segmentPtr[n], getTableID(), cutPtr[n], cutPtr[n + 1], schemePtr[n], thisProfile}); + m_data->segments.back().setPath(path); + } + setMemoLoaded(true); +#endif + return true; +} //SegmentedColumn::receive diff --git a/SpeckleLib/Speckle/Record/Element/Interface/SegmentedColumn.h b/SpeckleLib/Speckle/Record/Element/Interface/SegmentedColumn.h new file mode 100644 index 0000000..912cddb --- /dev/null +++ b/SpeckleLib/Speckle/Record/Element/Interface/SegmentedColumn.h @@ -0,0 +1,103 @@ +#ifndef SPECKLE_RECORD_ELEMENT_SEGMENTED_COLUMN +#define SPECKLE_RECORD_ELEMENT_SEGMENTED_COLUMN + +#include "Speckle/Database/Identity/BIMRecordID.h" +#include "Speckle/Record/Element/Interface/Part.h" + +namespace speckle::record::element { + + class ColumnSegment; + + /*! + Interface for a column type that is made up of consecutive segments + + Note that the child segments use lazy loading to avoid high overheads when accessing data relevant to the parent column only + */ + class SegmentedColumn : public Part { + public: + + // MARK: - Types + + using base = Part; + ///Unique pointer + using Unique = std::unique_ptr; + ///Shared pointer + using Shared = std::shared_ptr; + ///Optional + using Option = std::optional; + + // MARK: - Constructors + + /*! + Default constructor + */ + SegmentedColumn(); + /*! + Copy constructor + @param source The object to copy + */ + SegmentedColumn(const SegmentedColumn& source); + /*! + Destructor + */ + ~SegmentedColumn(); + + // MARK: - Functions (const) + + /*! + Get the BIM application parent table ID + @return The BIM table ID + */ + virtual database::BIMRecordID getTableID() const = 0; + /*! + Get the number of segments + @return The number of segments (0 on error) + */ + size_t getSegmentCount() const; + /*! + Get a column segment + @param index The index of the required segment + @return The requested segment, nullptr on error + */ + ColumnSegment* getSegment(size_t index) const; + + // MARK: - Functions (mutating) + + protected: + /*! + Return the bits for the part filter required to load the data necessary to build this object + @return The required filter bits */ + filter_bits getPartFilter() const; + /*! + Determine if the element part content has been validated (elements must override according to requirements) + @return True if the element part content is valid + */ + bool isPartValid() const override; + /*! + Load the element memo structure (elements must override according to requirements) + @param filter Filter bits specifying memo requirements + */ + void loadMemo(filter_bits filter, std::unique_ptr& memo) const override; + + /*! + Send the element part back to a memo structure for storage (elements must override according to requirements) + @param memo The memo to carry the data + @return True if the data was successfully sent + */ + bool send(Memo* memo) const override; + /*! + Receive the element memo data from a memo structure (elements must override according to requirements) + @param memo The memo carrying the data + @return True if the data was successfully received + */ + bool receive(const Memo& memo) const override; + + private: + class Data; + ///The segment data - mutable to support lazy loading + mutable std::unique_ptr m_data; + }; + +} + +#endif //SPECKLE_RECORD_ELEMENT_SEGMENTED_COLUMN diff --git a/SpeckleLib/Speckle/Record/Element/Memo.cpp b/SpeckleLib/Speckle/Record/Element/Memo.cpp new file mode 100644 index 0000000..d5bc00a --- /dev/null +++ b/SpeckleLib/Speckle/Record/Element/Memo.cpp @@ -0,0 +1,54 @@ +#include "Speckle/Record/Element/Memo.h" + +#include "Active/Utility/Memory.h" + +#ifdef ARCHICAD +#include +#endif + +using namespace speckle::record::element; + +namespace speckle::record::element { + API_Elem_Head Memo::m_dummy{}; +} + + +#ifdef ARCHICAD +/*-------------------------------------------------------------------- + Default constructor + + memo: A memo structure - this object will take ownership of anything passed to the constructor + --------------------------------------------------------------------*/ +Memo::Memo(std::unique_ptr memo) : m_data{std::move(memo)} { + if (!memo) { + //If no data was supplied, we still allocate an empty in the event that a new element is being constructed + m_data = std::make_unique(); + active::utility::Memory::erase(*m_data); + } +} //Memo::Memo +#endif + + +/*-------------------------------------------------------------------- + Default constructor + --------------------------------------------------------------------*/ +Memo::~Memo() { +#ifdef ARCHICAD + if (m_data) + ACAPI_DisposeElemMemoHdls(m_data.get()); +#endif +} //Memo::Memo + + +/*-------------------------------------------------------------------- + Conversion operator + + return: True if the memo contains data + --------------------------------------------------------------------*/ +Memo::operator bool() const { +#ifdef ARCHICAD + return m_data.operator bool(); +#else + return false; +#endif +} //Memo::operator bool diff --git a/SpeckleLib/Speckle/Record/Element/Memo.h b/SpeckleLib/Speckle/Record/Element/Memo.h new file mode 100644 index 0000000..644a5e0 --- /dev/null +++ b/SpeckleLib/Speckle/Record/Element/Memo.h @@ -0,0 +1,81 @@ +#ifndef SPECKLE_RECORD_ELEMENT_MEMO +#define SPECKLE_RECORD_ELEMENT_MEMO + +#include "Speckle/Record/Element/Element.h" + +#include +#include + +#ifdef ARCHICAD +struct API_ElementMemo; +#endif + +namespace speckle::record::element { + + /*! + Wrapper for Archicad memo data structure + + The main purpose for this wrapper is memory safely. In addition to maneging ownership of the memo structure, each handle/pointer allocation + within the structure must be released to prevent leaks. This wrapper will ensure these calls are made + */ + class Memo : public Element { + public: + + // MARK: - Types + + ///Unique pointer + using Unique = std::unique_ptr; + ///Shared pointer + using Shared = std::shared_ptr; + ///Optional + using Option = std::optional; + + // MARK: - Constructors + +#ifdef ARCHICAD + /*! + Default constructor + @param memo A memo structure - this object will take ownership of anything passed to the constructor + */ + Memo(std::unique_ptr memo = nullptr); +#endif + /*! + Destructor + */ + virtual ~Memo(); + + // MARK: - Operators + + /*! + Conversion operator + @return True if the memo contains data + */ + operator bool() const; + + // MARK: - Functions (const) + +#ifdef ARCHICAD + /*! + Get the memo root data + @return The memo root data (nullptr on failure) + */ + API_ElementMemo* root() const { return m_data.get(); } +#endif + + // MARK: - Functions (mutating) + + private: +#ifdef ARCHICAD + //NB: The following is functionally redundant for memos - requirement of base class + static API_Elem_Head m_dummy; + virtual const API_Elem_Head& getHead() const { return m_dummy; } + virtual API_Elem_Head& getHead() { return m_dummy; } + + ///The memo data + std::unique_ptr m_data; +#endif + }; + +} + +#endif //SPECKLE_RECORD_ELEMENT_MEMO diff --git a/SpeckleLib/Speckle/Utility/BIMMemory.cpp b/SpeckleLib/Speckle/Utility/BIMMemory.cpp new file mode 100644 index 0000000..c25a7bf --- /dev/null +++ b/SpeckleLib/Speckle/Utility/BIMMemory.cpp @@ -0,0 +1,39 @@ +#include "Speckle/Utility/BIMMemory.h" + +#ifdef ARCHICAD +#include "BM.hpp" +#endif + +using namespace speckle::utility; + +namespace { + +#ifdef ARCHICAD + /*! + Get the error code from the last memory operation + @return The last error + */ + GSErr getLastError() { + return BMError(); + } +#endif + +} + +/*-------------------------------------------------------------------- + Get the size of an allocated pointer block + + pointer: The target pointer + + return: The allocated pointer size + --------------------------------------------------------------------*/ +size_t BIMMemory::getPtrSize(void* pointer) { +#ifdef ARCHICAD + if (pointer == nullptr) + return 0; + auto size = BMGetPtrSize(reinterpret_cast(pointer)); + if (getLastError() != NoError) + throw; //TODO: Throw a specific exception type + return size; +#endif +} //BIMMemory::getPtrSize diff --git a/SpeckleLib/Speckle/Utility/BIMMemory.h b/SpeckleLib/Speckle/Utility/BIMMemory.h new file mode 100644 index 0000000..0dc5fed --- /dev/null +++ b/SpeckleLib/Speckle/Utility/BIMMemory.h @@ -0,0 +1,23 @@ +#ifndef SPECKLE_UTILITY_BIM_MEMORY +#define SPECKLE_UTILITY_BIM_MEMORY + +#include + +namespace speckle::utility { + + /*! + BIM memory functions + */ + class BIMMemory { + public: + /*! + Get the size of an allocated pointer block + @param pointer The target pointer + @return The allocated pointer size + */ + static size_t getPtrSize(void* pointer); + }; + +} + +#endif //SPECKLE_UTILITY_BIM_MEMORY diff --git a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj index 0781bc6..1d1ec4a 100644 --- a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj +++ b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj @@ -51,6 +51,24 @@ 21A0FBA42CB880690023F24E /* FinishCollector.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A0FB9F2CB880690023F24E /* FinishCollector.h */; }; 21A0FBB52CBA5E380023F24E /* Str256.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A0FBB42CBA5E380023F24E /* Str256.h */; }; 21A0FBBC2CBBC04C0023F24E /* ArchicadRGB.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A0FBB92CBBC04C0023F24E /* ArchicadRGB.h */; }; + 21A0FBEA2CBD6B1A0023F24E /* ColumnSegment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21A0FBDF2CBD6B1A0023F24E /* ColumnSegment.cpp */; }; + 21A0FBEB2CBD6B1A0023F24E /* ColumnSegment.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A0FBE22CBD6B1A0023F24E /* ColumnSegment.h */; }; + 21A0FBED2CBD6B1A0023F24E /* Part.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A0FBE42CBD6B1A0023F24E /* Part.h */; }; + 21A0FBF02CBD6B1A0023F24E /* Column.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21A0FBE82CBD6B1A0023F24E /* Column.cpp */; }; + 21A0FBF12CBD6B1A0023F24E /* Column.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A0FBE92CBD6B1A0023F24E /* Column.h */; }; + 21A0FBF42CBD6B700023F24E /* Memo.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A0FBF22CBD6B700023F24E /* Memo.h */; }; + 21A0FBF52CBD6B700023F24E /* Memo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21A0FBF32CBD6B700023F24E /* Memo.cpp */; }; + 21A0FBF82CBDB9A70023F24E /* BIMMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21A0FBF62CBDB9A70023F24E /* BIMMemory.cpp */; }; + 21A0FBF92CBDB9A70023F24E /* BIMMemory.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A0FBF72CBDB9A70023F24E /* BIMMemory.h */; }; + 21A0FC042CBE59A80023F24E /* SegmentedColumn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21A0FBFF2CBE59A80023F24E /* SegmentedColumn.cpp */; }; + 21A0FC052CBE59A80023F24E /* SegmentedColumn.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A0FC002CBE59A80023F24E /* SegmentedColumn.h */; }; + 21A0FC062CBE59A80023F24E /* Path.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21A0FC012CBE59A80023F24E /* Path.cpp */; }; + 21A0FC072CBE59A80023F24E /* Path.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A0FC022CBE59A80023F24E /* Path.h */; }; + 21A0FC0A2CBE5E220023F24E /* Segment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21A0FC082CBE5E220023F24E /* Segment.cpp */; }; + 21A0FC0B2CBE5E220023F24E /* Segment.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A0FC092CBE5E220023F24E /* Segment.h */; }; + 21A0FC0E2CBE92F10023F24E /* GenericElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21A0FC0C2CBE92F10023F24E /* GenericElement.cpp */; }; + 21A0FC0F2CBE92F10023F24E /* GenericElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A0FC0D2CBE92F10023F24E /* GenericElement.h */; }; + 21A0FC112CBEE5C30023F24E /* Part.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21A0FC102CBEE5C30023F24E /* Part.cpp */; }; 21AEF9BA2CA606B5000B8681 /* DetachedReference.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9B92CA606B4000B8681 /* DetachedReference.cpp */; }; 21AEF9BC2CA6DF84000B8681 /* DetachmentManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9BB2CA6DF84000B8681 /* DetachmentManager.cpp */; }; 21AEF9BE2CA6FDA4000B8681 /* DetachedWrap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9BD2CA6FDA4000B8681 /* DetachedWrap.cpp */; }; @@ -193,6 +211,24 @@ 21A0FBA92CB9324A0023F24E /* FinishProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FinishProxy.h; sourceTree = ""; }; 21A0FBB42CBA5E380023F24E /* Str256.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Str256.h; sourceTree = ""; }; 21A0FBB92CBBC04C0023F24E /* ArchicadRGB.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArchicadRGB.h; sourceTree = ""; }; + 21A0FBDF2CBD6B1A0023F24E /* ColumnSegment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ColumnSegment.cpp; sourceTree = ""; }; + 21A0FBE22CBD6B1A0023F24E /* ColumnSegment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ColumnSegment.h; sourceTree = ""; }; + 21A0FBE42CBD6B1A0023F24E /* Part.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Part.h; sourceTree = ""; }; + 21A0FBE82CBD6B1A0023F24E /* Column.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Column.cpp; sourceTree = ""; }; + 21A0FBE92CBD6B1A0023F24E /* Column.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Column.h; sourceTree = ""; }; + 21A0FBF22CBD6B700023F24E /* Memo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Memo.h; sourceTree = ""; }; + 21A0FBF32CBD6B700023F24E /* Memo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Memo.cpp; sourceTree = ""; }; + 21A0FBF62CBDB9A70023F24E /* BIMMemory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BIMMemory.cpp; sourceTree = ""; }; + 21A0FBF72CBDB9A70023F24E /* BIMMemory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BIMMemory.h; sourceTree = ""; }; + 21A0FBFF2CBE59A80023F24E /* SegmentedColumn.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SegmentedColumn.cpp; sourceTree = ""; }; + 21A0FC002CBE59A80023F24E /* SegmentedColumn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SegmentedColumn.h; sourceTree = ""; }; + 21A0FC012CBE59A80023F24E /* Path.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Path.cpp; sourceTree = ""; }; + 21A0FC022CBE59A80023F24E /* Path.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Path.h; sourceTree = ""; }; + 21A0FC082CBE5E220023F24E /* Segment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Segment.cpp; sourceTree = ""; }; + 21A0FC092CBE5E220023F24E /* Segment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Segment.h; sourceTree = ""; }; + 21A0FC0C2CBE92F10023F24E /* GenericElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GenericElement.cpp; sourceTree = ""; }; + 21A0FC0D2CBE92F10023F24E /* GenericElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GenericElement.h; sourceTree = ""; }; + 21A0FC102CBEE5C30023F24E /* Part.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Part.cpp; path = Speckle/Record/Element/Interface/Part.cpp; sourceTree = SOURCE_ROOT; }; 21AEF9B32CA5F7CF000B8681 /* DetachedWrap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedWrap.h; sourceTree = ""; }; 21AEF9B52CA5FA02000B8681 /* DetachedReference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedReference.h; sourceTree = ""; }; 21AEF9B72CA5FCB6000B8681 /* DetachmentManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachmentManager.h; sourceTree = ""; }; @@ -340,8 +376,17 @@ 215F087A2CA18E1400CD343B /* Element */ = { isa = PBXGroup; children = ( + 21A0FBE82CBD6B1A0023F24E /* Column.cpp */, + 21A0FBE92CBD6B1A0023F24E /* Column.h */, + 21A0FBDF2CBD6B1A0023F24E /* ColumnSegment.cpp */, + 21A0FBE22CBD6B1A0023F24E /* ColumnSegment.h */, 215F08782CA18E1400CD343B /* Element.cpp */, 215F08792CA18E1400CD343B /* Element.h */, + 21A0FC0C2CBE92F10023F24E /* GenericElement.cpp */, + 21A0FC0D2CBE92F10023F24E /* GenericElement.h */, + 21A0FBE72CBD6B1A0023F24E /* Interface */, + 21A0FBF32CBD6B700023F24E /* Memo.cpp */, + 21A0FBF22CBD6B700023F24E /* Memo.h */, ); path = Element; sourceTree = ""; @@ -429,6 +474,8 @@ 219351B02C62CC1A00E5A69C /* Utility */ = { isa = PBXGroup; children = ( + 21A0FBF62CBDB9A70023F24E /* BIMMemory.cpp */, + 21A0FBF72CBDB9A70023F24E /* BIMMemory.h */, 21B67CFE2C7CE15100FD64FC /* Exception.h */, 219351AC2C62CC1A00E5A69C /* Guid.cpp */, 219351AD2C62CC1A00E5A69C /* Guid.h */, @@ -499,6 +546,29 @@ path = Types; sourceTree = ""; }; + 21A0FBE72CBD6B1A0023F24E /* Interface */ = { + isa = PBXGroup; + children = ( + 21A0FC032CBE59A80023F24E /* Assembly */, + 21A0FC102CBEE5C30023F24E /* Part.cpp */, + 21A0FBE42CBD6B1A0023F24E /* Part.h */, + 21A0FBFF2CBE59A80023F24E /* SegmentedColumn.cpp */, + 21A0FC002CBE59A80023F24E /* SegmentedColumn.h */, + ); + path = Interface; + sourceTree = ""; + }; + 21A0FC032CBE59A80023F24E /* Assembly */ = { + isa = PBXGroup; + children = ( + 21A0FC012CBE59A80023F24E /* Path.cpp */, + 21A0FC022CBE59A80023F24E /* Path.h */, + 21A0FC082CBE5E220023F24E /* Segment.cpp */, + 21A0FC092CBE5E220023F24E /* Segment.h */, + ); + path = Assembly; + sourceTree = ""; + }; 21AEF9C72CA818EA000B8681 /* Detached */ = { isa = PBXGroup; children = ( @@ -705,6 +775,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 21A0FBF42CBD6B700023F24E /* Memo.h in Headers */, 215F088C2CA195EC00CD343B /* ArchicadDBaseCore.h in Headers */, 21D0BDE72C943D3F0077E104 /* RecordID.h in Headers */, 21D0BD212C86F0280077E104 /* AccountDatabase.h in Headers */, @@ -721,10 +792,15 @@ 21D0BD562C890B1C0077E104 /* ServerMigration.h in Headers */, 210CC88F2C81A98500610F58 /* Guid64.h in Headers */, 21AEF9DD2CAAA4EA000B8681 /* DetachedObjectStore.h in Headers */, + 21A0FBF12CBD6B1A0023F24E /* Column.h in Headers */, + 21A0FC072CBE59A80023F24E /* Path.h in Headers */, 21A0FBA42CB880690023F24E /* FinishCollector.h in Headers */, + 21A0FC0B2CBE5E220023F24E /* Segment.h in Headers */, 215F088D2CA195EC00CD343B /* ArchicadElementDBaseEngine.h in Headers */, 2196F2F42CB483D600450DFC /* Finish.h in Headers */, + 21A0FBED2CBD6B1A0023F24E /* Part.h in Headers */, 21B67D002C7CE15100FD64FC /* Exception.h in Headers */, + 21A0FBEB2CBD6B1A0023F24E /* ColumnSegment.h in Headers */, 21D0BD2C2C86FC350077E104 /* Record.h in Headers */, 21D0BDB42C8F8AB60077E104 /* DocumentStoreCore.h in Headers */, 215F087E2CA18E1400CD343B /* Element.h in Headers */, @@ -734,7 +810,10 @@ 210CC8802C80CD2A00610F58 /* BridgeChild.h in Headers */, 21D0BD4D2C8901A00077E104 /* ServerInfo.h in Headers */, 2196F3042CB57E8000450DFC /* Storey.h in Headers */, + 21A0FBF92CBDB9A70023F24E /* BIMMemory.h in Headers */, 21A0FBBC2CBBC04C0023F24E /* ArchicadRGB.h in Headers */, + 21A0FC052CBE59A80023F24E /* SegmentedColumn.h in Headers */, + 21A0FC0F2CBE92F10023F24E /* GenericElement.h in Headers */, 21D0BDB52C8F8AB60077E104 /* DocumentStoreEngine.h in Headers */, 21D0BDC52C9241940077E104 /* ProjectSubscriber.h in Headers */, 2196F2EC2CB4816B00450DFC /* ArchicadAttributeDBaseEngine.h in Headers */, @@ -863,6 +942,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 21A0FC0A2CBE5E220023F24E /* Segment.cpp in Sources */, 21D0BD552C890B1C0077E104 /* ServerMigration.cpp in Sources */, 21F69FA62C733EDA008B6A06 /* BridgeArgument.cpp in Sources */, 21F69F682C6DFB01008B6A06 /* RunMethod.cpp in Sources */, @@ -885,25 +965,33 @@ 2196F3052CB57E8000450DFC /* Storey.cpp in Sources */, 219245FE2CA2CC4300CF5703 /* BIMRecord.cpp in Sources */, 21AEF9BE2CA6FDA4000B8681 /* DetachedWrap.cpp in Sources */, + 21A0FC062CBE59A80023F24E /* Path.cpp in Sources */, 2196F2F52CB483D600450DFC /* Finish.cpp in Sources */, + 21A0FBEA2CBD6B1A0023F24E /* ColumnSegment.cpp in Sources */, 2193519B2C6278D900E5A69C /* SelectionSubscriber.cpp in Sources */, 21D0BD2B2C86FC350077E104 /* Record.cpp in Sources */, 219246042CA2CE2700CF5703 /* BIMLink.cpp in Sources */, 215F08952CA19AF800CD343B /* BIMElementDatabase.cpp in Sources */, + 21A0FC0E2CBE92F10023F24E /* GenericElement.cpp in Sources */, 219246122CA34DCE00CF5703 /* Mesh.cpp in Sources */, + 21A0FBF02CBD6B1A0023F24E /* Column.cpp in Sources */, 21D0BD592C8910400077E104 /* UserInfo.cpp in Sources */, 210CC8902C81A98500610F58 /* Guid64.cpp in Sources */, 21D0BDC42C9241940077E104 /* ProjectSubscriber.cpp in Sources */, 219351B32C62CC1A00E5A69C /* String.cpp in Sources */, 219351B12C62CC1A00E5A69C /* Guid.cpp in Sources */, 21F69F512C6CCC25008B6A06 /* BrowserBridge.cpp in Sources */, + 21A0FC112CBEE5C30023F24E /* Part.cpp in Sources */, 21AEF9BC2CA6DF84000B8681 /* DetachmentManager.cpp in Sources */, 215F08552C99DA8D00CD343B /* Project.cpp in Sources */, 21F69F3B2C6B880C008B6A06 /* JSBaseTransport.cpp in Sources */, 2196F2EB2CB4816B00450DFC /* ArchicadAttributeDBaseEngine.cpp in Sources */, + 21A0FC042CBE59A80023F24E /* SegmentedColumn.cpp in Sources */, 210CC89F2C81E34400610F58 /* Platform.cpp in Sources */, 21D0BD202C86F0280077E104 /* AccountDatabase.cpp in Sources */, 21F69F962C71087A008B6A06 /* Account.cpp in Sources */, + 21A0FBF82CBDB9A70023F24E /* BIMMemory.cpp in Sources */, + 21A0FBF52CBD6B700023F24E /* Memo.cpp in Sources */, 21AEF9BA2CA606B5000B8681 /* DetachedReference.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; From ffb9cf0cefe3519ead81fa1f17e703025f895eb9 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Tue, 15 Oct 2024 21:12:37 +0100 Subject: [PATCH 058/191] Updated VS projects --- SpeckleLib/SpeckleLib17.vcxproj | 18 ++++++++ SpeckleLib/SpeckleLib17.vcxproj.filters | 60 +++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/SpeckleLib/SpeckleLib17.vcxproj b/SpeckleLib/SpeckleLib17.vcxproj index 6dc6cba..22f73ca 100644 --- a/SpeckleLib/SpeckleLib17.vcxproj +++ b/SpeckleLib/SpeckleLib17.vcxproj @@ -71,7 +71,15 @@ + + + + + + + + @@ -84,6 +92,7 @@ + @@ -124,12 +133,21 @@ + + + + + + + + + diff --git a/SpeckleLib/SpeckleLib17.vcxproj.filters b/SpeckleLib/SpeckleLib17.vcxproj.filters index 42974d7..6550add 100644 --- a/SpeckleLib/SpeckleLib17.vcxproj.filters +++ b/SpeckleLib/SpeckleLib17.vcxproj.filters @@ -98,6 +98,12 @@ {7f43d4ea-b876-4587-a646-90eab81f7976} + + {b35abbfd-3c47-45dc-8dab-58911f233a87} + + + {8e7a76da-47ac-4105-9c09-7d7ed62d7136} + @@ -310,6 +316,33 @@ Speckle\Serialise\Types + + Speckle\Record\Element + + + Speckle\Record\Element + + + Speckle\Record\Element + + + Speckle\Record\Element\Interface + + + Speckle\Record\Element\Interface + + + Speckle\Record\Element\Interface\Assembly + + + Speckle\Record\Element\Interface\Assembly + + + Speckle\Utility + + + Speckle\Record\Element + @@ -438,6 +471,33 @@ Speckle\Serialise\Types\Units + + Speckle\Record\Element + + + Speckle\Record\Element + + + Speckle\Record\Element + + + Speckle\Record\Element\Interface + + + Speckle\Record\Element\Interface + + + Speckle\Record\Element\Interface\Assembly + + + Speckle\Record\Element\Interface\Assembly + + + Speckle\Utility + + + Speckle\Record\Element + From 2d23eb6b2878f069bf8a98fd01ddbdf5c0b931cc Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Tue, 15 Oct 2024 23:05:07 +0100 Subject: [PATCH 059/191] Fixes to Column and ColumnSegment classes --- SpeckleLib/Speckle/Database/Content/Record.cpp | 2 +- .../Element/ArchicadElementDBaseEngine.cpp | 7 +++++-- SpeckleLib/Speckle/Record/Element/ColumnSegment.cpp | 10 ++++++++++ SpeckleLib/Speckle/Record/Element/ColumnSegment.h | 5 +++++ SpeckleLib/Speckle/Record/Element/Element.cpp | 13 +++++++++++-- SpeckleLib/Speckle/Record/Element/Element.h | 5 +++++ .../Record/Element/Interface/SegmentedColumn.cpp | 4 ++-- SpeckleLib/Speckle/Record/Element/Memo.h | 13 ++++++++++++- 8 files changed, 51 insertions(+), 8 deletions(-) diff --git a/SpeckleLib/Speckle/Database/Content/Record.cpp b/SpeckleLib/Speckle/Database/Content/Record.cpp index 3df4c86..3d75448 100644 --- a/SpeckleLib/Speckle/Database/Content/Record.cpp +++ b/SpeckleLib/Speckle/Database/Content/Record.cpp @@ -40,7 +40,7 @@ bool Record::fillInventory(active::serialise::Inventory& inventory) const { }.withType(&typeid(base))); inventory.merge(Inventory{ { - { Identity{fieldID[speckleTypeID]}, speckleTypeID, element }, + { Identity{fieldID[speckleTypeID]}, speckleTypeID, attribute }, }, }.withType(&typeid(Record))); return true; diff --git a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.cpp b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.cpp index b6ed332..a1d7fd5 100644 --- a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.cpp +++ b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.cpp @@ -137,8 +137,11 @@ std::unique_ptr ArchicadElementDBaseEngine::getObject(const BIMRecordID 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 - return std::make_unique(std::move(memo)); + else { + auto result = std::make_unique(); + result->set(std::move(memo)); + return result; + } } if (!tableID) { //Use the active table if none is specified diff --git a/SpeckleLib/Speckle/Record/Element/ColumnSegment.cpp b/SpeckleLib/Speckle/Record/Element/ColumnSegment.cpp index f18b949..34d4cb2 100644 --- a/SpeckleLib/Speckle/Record/Element/ColumnSegment.cpp +++ b/SpeckleLib/Speckle/Record/Element/ColumnSegment.cpp @@ -86,6 +86,16 @@ ColumnSegment::ColumnSegment(const ColumnSegment& source) : base{ source } { } //ColumnSegment::ColumnSegment +/*-------------------------------------------------------------------- + Move constructor + + source: The object to move + --------------------------------------------------------------------*/ +ColumnSegment::ColumnSegment(ColumnSegment&& source) : base{source} { + m_data = std::move(source.m_data); +} //ColumnSegment::ColumnSegment + + /*-------------------------------------------------------------------- Destructor --------------------------------------------------------------------*/ diff --git a/SpeckleLib/Speckle/Record/Element/ColumnSegment.h b/SpeckleLib/Speckle/Record/Element/ColumnSegment.h index d16b414..85c731b 100644 --- a/SpeckleLib/Speckle/Record/Element/ColumnSegment.h +++ b/SpeckleLib/Speckle/Record/Element/ColumnSegment.h @@ -45,6 +45,11 @@ namespace speckle::record::element { @param source The object to copy */ ColumnSegment(const ColumnSegment& source); + /*! + Move constructor + @param source The object to move + */ + ColumnSegment(ColumnSegment&& source); /*! Destructor */ diff --git a/SpeckleLib/Speckle/Record/Element/Element.cpp b/SpeckleLib/Speckle/Record/Element/Element.cpp index d2a80ff..5aa28e4 100644 --- a/SpeckleLib/Speckle/Record/Element/Element.cpp +++ b/SpeckleLib/Speckle/Record/Element/Element.cpp @@ -87,6 +87,16 @@ Element::Element(const Element& source) : base{ source } { } //Element::Element +/*-------------------------------------------------------------------- + Move constructor + + source: The object to move + --------------------------------------------------------------------*/ +Element::Element(Element&& source) : base{source} { + m_data = std::move(source.m_data); +} //Element::Element + + /*-------------------------------------------------------------------- Destructor --------------------------------------------------------------------*/ @@ -277,8 +287,7 @@ void Element::loadMemo(Part::filter_bits filter, std::unique_ptr& memo) co auto project = addon()->getActiveProject().lock(); if (!project) return; - auto elementDatabase = project->getElementDatabase(); - if (auto loaded = elementDatabase->getMemo(getBIMID(), filter); loaded) + if (auto loaded = project->getElementDatabase()->getMemo(getBIMID(), filter); loaded) memo.reset(loaded.release()); } } //Element::loadMemo diff --git a/SpeckleLib/Speckle/Record/Element/Element.h b/SpeckleLib/Speckle/Record/Element/Element.h index 80e479d..8a2bef1 100644 --- a/SpeckleLib/Speckle/Record/Element/Element.h +++ b/SpeckleLib/Speckle/Record/Element/Element.h @@ -52,6 +52,11 @@ namespace speckle::record::element { @param source The object to copy */ Element(const Element& source); + /*! + Move constructor + @param source The object to move + */ + Element(Element&& source); /*! Destructor */ diff --git a/SpeckleLib/Speckle/Record/Element/Interface/SegmentedColumn.cpp b/SpeckleLib/Speckle/Record/Element/Interface/SegmentedColumn.cpp index e181fee..92bab68 100644 --- a/SpeckleLib/Speckle/Record/Element/Interface/SegmentedColumn.cpp +++ b/SpeckleLib/Speckle/Record/Element/Interface/SegmentedColumn.cpp @@ -131,7 +131,7 @@ bool SegmentedColumn::receive(const Memo& memo) const { auto cutPtr = memo.root()->assemblySegmentCuts; auto schemePtr = memo.root()->assemblySegmentSchemes; auto profilePtr = memo.root()->assemblySegmentProfiles; - if ((segmentPtr == nullptr) || (cutPtr == nullptr) || (schemePtr == nullptr) || (profilePtr == nullptr)) + if ((segmentPtr == nullptr) || (cutPtr == nullptr) || (schemePtr == nullptr)) return false; //Determine available item count auto segmentCount = BIMMemory::getPtrSize(segmentPtr) / sizeof(API_ColumnSegmentType); @@ -149,7 +149,7 @@ bool SegmentedColumn::receive(const Memo& memo) const { break; } } - m_data->segments.push_back({segmentPtr[n], getTableID(), cutPtr[n], cutPtr[n + 1], schemePtr[n], thisProfile}); + m_data->segments.emplace_back(ColumnSegment{segmentPtr[n], getTableID(), cutPtr[n], cutPtr[n + 1], schemePtr[n], thisProfile}); m_data->segments.back().setPath(path); } setMemoLoaded(true); diff --git a/SpeckleLib/Speckle/Record/Element/Memo.h b/SpeckleLib/Speckle/Record/Element/Memo.h index 644a5e0..b78e77b 100644 --- a/SpeckleLib/Speckle/Record/Element/Memo.h +++ b/SpeckleLib/Speckle/Record/Element/Memo.h @@ -63,7 +63,18 @@ namespace speckle::record::element { #endif // MARK: - Functions (mutating) - + +#ifdef ARCHICAD + /*! + Get the memo root data + @return The memo root data (nullptr on failure) + */ + Memo& set(std::unique_ptr memo) { + m_data = std::move(memo); + return *this; + } +#endif + private: #ifdef ARCHICAD //NB: The following is functionally redundant for memos - requirement of base class From 3e7b78e50db23dc39f8ec6a22377a1e2c0310253 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Wed, 16 Oct 2024 10:31:11 +0100 Subject: [PATCH 060/191] Allow SelectionSubscriber to start/stop outside initialisation phase --- .../Event/Subscriber/SelectionSubscriber.cpp | 13 ++++++++++--- .../Speckle/Event/Subscriber/SelectionSubscriber.h | 14 +++++++------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.cpp b/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.cpp index 48b5f04..a428000 100644 --- a/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.cpp +++ b/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.cpp @@ -69,12 +69,19 @@ bool SelectionSubscriber::receive(const Event& event) { return: True if the participant is able to continue --------------------------------------------------------------------*/ bool SelectionSubscriber::start() { - if (m_isStarted) - return true; - m_isStarted = true; #ifdef ARCHICAD return (ACAPI_Notification_CatchSelectionChange(selectionCallback) == NoError); #else return false; #endif } //SelectionSubscriber::start + + +/*-------------------------------------------------------------------- + Stop participation (release resources etc) + --------------------------------------------------------------------*/ +void SelectionSubscriber::stop() { +#ifdef ARCHICAD + ACAPI_Notification_CatchSelectionChange(nullptr); +#endif +} diff --git a/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.h b/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.h index 6ed904b..b4a7e64 100644 --- a/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.h +++ b/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.h @@ -35,7 +35,7 @@ namespace speckle::event { Get the event subscription list @return The subscription list (an empty list will put the subscriber into a suspended state) */ - virtual Subscription subscription() const override; + Subscription subscription() const override; // MARK: - Functions (mutating) @@ -44,24 +44,24 @@ namespace speckle::event { @param event The incoming event @return True if the event should be closed */ - virtual bool receive(const active::event::Event& event) override; + bool receive(const active::event::Event& event) override; protected: /*! Start the participant operation @return True if the participant is able to continue */ - virtual bool start() override; + bool start() override; + /*! + Stop participation (release resources etc) + */ + void stop() override; /*! Handle a selection change @param event The selection event @return True if the event should be closed */ virtual bool handle(const SelectionEvent& event) = 0; - - private: - ///True if a selection change subscriber has already started (only one is required - there are no variants) - static bool m_isStarted; }; } From ebed71a791ea0fa2510d389c21747a4b0d52d31d Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Wed, 16 Oct 2024 11:03:38 +0100 Subject: [PATCH 061/191] Removed unused static var from SelectionSubscriber --- SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.cpp b/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.cpp index a428000..e6bdee0 100644 --- a/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.cpp +++ b/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.cpp @@ -35,9 +35,6 @@ namespace { } - //True if a selection change subscriber has already started (only one is required - there are no variants) -bool speckle::event::SelectionSubscriber::m_isStarted = false; - /*-------------------------------------------------------------------- Get the event subscription list From 511311eb84eddfe1de035d2ebb5e2477caae69e5 Mon Sep 17 00:00:00 2001 From: David Kekesi Date: Wed, 16 Oct 2024 15:08:34 +0200 Subject: [PATCH 062/191] selectionBridge works --- SpeckleConnector/Connector.vcxproj | 2 + SpeckleConnector/Connector.vcxproj.filters | 6 +++ SpeckleConnector/Connector/Connector.cpp | 2 + .../Bridge/Selection/Arg/SelectionInfo.cpp | 37 ++++++++++++++- .../Bridge/Selection/Arg/SelectionInfo.h | 8 ++-- .../Browser/Bridge/Selection/GetSelection.cpp | 46 +------------------ .../Bridge/Selection/SelectionBridge.cpp | 11 ++++- .../Bridge/Selection/SelectionBridge.h | 8 +++- .../Selection/SelectionChangeHandler.cpp | 28 +++++++++++ .../Bridge/Selection/SelectionChangeHandler.h | 28 +++++++++++ .../Connector/Interface/ConnectorPalette.cpp | 36 +++------------ .../Event/Subscriber/SelectionSubscriber.cpp | 12 +++-- .../Event/Subscriber/SelectionSubscriber.h | 15 ++++-- .../Speckle/Event/Type/SelectionEvent.h | 2 +- .../Speckle/Interface/Browser/JSObject.h | 2 +- .../Speckle/Interface/Browser/JSPortal.h | 12 ++--- 16 files changed, 160 insertions(+), 95 deletions(-) create mode 100644 SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.cpp create mode 100644 SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.h diff --git a/SpeckleConnector/Connector.vcxproj b/SpeckleConnector/Connector.vcxproj index acf33d4..245709b 100644 --- a/SpeckleConnector/Connector.vcxproj +++ b/SpeckleConnector/Connector.vcxproj @@ -114,6 +114,7 @@ + @@ -169,6 +170,7 @@ + diff --git a/SpeckleConnector/Connector.vcxproj.filters b/SpeckleConnector/Connector.vcxproj.filters index 374c759..763dc5c 100644 --- a/SpeckleConnector/Connector.vcxproj.filters +++ b/SpeckleConnector/Connector.vcxproj.filters @@ -243,6 +243,9 @@ Connector\Interface\Browser\Bridge\Selection\Arg + + Connector\Interface\Browser\Bridge\Selection + @@ -411,5 +414,8 @@ Connector\Interface\Browser\Bridge\Selection\Arg + + Connector\Interface\Browser\Bridge\Selection + \ No newline at end of file diff --git a/SpeckleConnector/Connector/Connector.cpp b/SpeckleConnector/Connector/Connector.cpp index 23943be..4343b1e 100755 --- a/SpeckleConnector/Connector/Connector.cpp +++ b/SpeckleConnector/Connector/Connector.cpp @@ -1,6 +1,7 @@ #include "Active/File/Directory.h" #include "ConnectorResource.h" #include "Connector/Connector.h" +#include "Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.h" #include "Connector/Database/ModelCardDatabase.h" #include "Connector/Interface/ConnectorMenu.h" #include "Connector/Interface/ConnectorPalette.h" @@ -12,6 +13,7 @@ using namespace active::file; using namespace active::environment; using namespace connector; using namespace connector::database; +using namespace connector::interfac::browser::bridge; using namespace speckle::database; using namespace speckle::environment; using namespace speckle::utility; diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.cpp index 42611d6..b7126b9 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.cpp @@ -2,6 +2,14 @@ #include "Active/Serialise/Item/Wrapper/ValueWrap.h" #include "Active/Serialise/Package/Wrapper/PackageWrap.h" +#include "Active/Serialise/Package/Wrapper/ContainerWrap.h" + +#include "Connector/Connector.h" + +#include "Speckle/Database/BIMElementDatabase.h" +#include "Speckle/Environment/Project.h" +#include "Speckle/Record/Element/Element.h" +using namespace speckle::record::element; #include @@ -12,16 +20,40 @@ namespace { ///Serialisation fields enum FieldIndex { + selectedObjectIdsID, summaryID, }; ///Serialisation field IDs static std::array fieldID = { + Identity{"selectedObjectIds"}, Identity{"summary"}, }; } +SelectionInfo::SelectionInfo() { + initialize(); +} + +void SelectionInfo::initialize() { + auto project = connector()->getActiveProject().lock(); + if (!project) { + // TODO: handle + } + + auto elementDatabase = project->getElementDatabase(); + auto selected = elementDatabase->getSelection(); + + active::utility::String summary(selected.size()); + summary += " objects selected."; + m_summary = summary; + + for (const auto& link : selected) { + m_selectedElementIds.push_back(link); + } +} + /*-------------------------------------------------------------------- Fill an inventory with the package items @@ -33,6 +65,7 @@ bool SelectionInfo::fillInventory(Inventory& inventory) const { using enum Entry::Type; inventory.merge(Inventory{ { + { fieldID[selectedObjectIdsID], selectedObjectIdsID, element }, { fieldID[summaryID], summaryID, element }, }, }.withType(&typeid(SelectionInfo))); @@ -52,8 +85,10 @@ Cargo::Unique SelectionInfo::getCargo(const Inventory::Item& item) const { return nullptr; using namespace active::serialise; switch (item.index) { + case selectedObjectIdsID: + return std::make_unique>>(m_selectedElementIds); case summaryID: - return std::make_unique>(summary); + return std::make_unique>(m_summary); default: return nullptr; //Requested an unknown index } diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h index 2e81bea..12c9ec3 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h @@ -21,10 +21,12 @@ namespace connector::interfac::browser::bridge { /*! Default constructor */ - SelectionInfo() = default; + SelectionInfo(); - active::utility::String summary = "Nothing is selected"; - std::vector selectedElementIds; + active::utility::String m_summary = "No objects selected"; + std::vector m_selectedElementIds; + + void initialize(); // MARK: - Serialisation diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.cpp index fc239a7..6385c09 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.cpp @@ -1,30 +1,10 @@ #include "Connector/Interface/Browser/Bridge/Selection/GetSelection.h" - #include "Active/Serialise/CargoHold.h" -#include "Active/Serialise/Package/Wrapper/PackageWrap.h" #include "Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h" -#include "Connector/Connector.h" -#include "Connector/Record/Collection/ProjectCollection.h" - -#include "Speckle/Database/BIMElementDatabase.h" -#include "Speckle/Environment/Project.h" -#include "Speckle/Record/Element/Element.h" -using namespace speckle::record::element; - -#include - using namespace active::serialise; using namespace connector::interfac::browser::bridge; -using namespace speckle::utility; -using namespace connector::record; -namespace { - - ///Return type for retrieving the current configuration - using WrappedValue = CargoHold; - -} /*-------------------------------------------------------------------- Default constructor --------------------------------------------------------------------*/ @@ -39,30 +19,6 @@ GetSelection::GetSelection() : BridgeMethod{"GetSelection", [&]() { modelCardID: The ID of the model to send --------------------------------------------------------------------*/ std::unique_ptr GetSelection::run() const { - auto selectionInfo = std::make_unique(); - - auto project = connector()->getActiveProject().lock(); - if (!project) { - // TODO - } - - //Build a collection from the selected elements - auto collection = std::make_unique(project); - auto elementDatabase = project->getElementDatabase(); - auto selected = elementDatabase->getSelection(); - - active::utility::String summary(selected.size()); - summary += " objects selected."; - - selectionInfo->summary = summary; - - for (const auto& link : selected) { - if (auto element = elementDatabase->getElement(link); element) { - collection->addElement(*element); - selectionInfo->selectedElementIds.push_back(element->getBIMID()); - } - } - - return std::make_unique(std::move(selectionInfo)); + return std::make_unique>(std::move(selectionInfo)); } //GetSelection::run diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.cpp index 5fa969f..f31cc98 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.cpp @@ -1,7 +1,9 @@ #include "Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h" - #include "Connector/Interface/Browser/Bridge/Selection/GetSelection.h" +#include "Active/Serialise/CargoHold.h" +#include "Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h" +using namespace active::serialise; using namespace connector::interfac::browser::bridge; /*-------------------------------------------------------------------- @@ -11,3 +13,10 @@ SelectionBridge::SelectionBridge() : BrowserBridge{"selectionBinding"} { //Add bridge methods addMethod(); } //SelectionBridge::SelectionBridge + +bool SelectionBridge::handle(const speckle::event::SelectionEvent& event) { + auto selectionInfo = std::make_unique(); + auto wrapped = std::make_unique>(std::move(selectionInfo)); + sendEvent("setSelection", std::move(wrapped)); + return true; +} diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h index 053fba2..a92f213 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h @@ -2,13 +2,15 @@ #define CONNECTOR_INTERFACE_BRIDGE_SELECTION_BRIDGE #include "Speckle/Interface/Browser/Bridge/BrowserBridge.h" +#include "Speckle/Event/Subscriber/SelectionSubscriber.h" +#include "Speckle/Event/Type/SelectionEvent.h" namespace connector::interfac::browser::bridge { /*! A browser bridge to support sending model data to a Speckle server */ - class SelectionBridge : public speckle::interfac::browser::bridge::BrowserBridge { + class SelectionBridge : public speckle::interfac::browser::bridge::BrowserBridge, public speckle::event::SelectionSubscriber { public: // MARK: - Types @@ -22,6 +24,10 @@ namespace connector::interfac::browser::bridge { Default constructor */ SelectionBridge(); + + protected: + + bool handle(const speckle::event::SelectionEvent& event) override; }; } diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.cpp new file mode 100644 index 0000000..652b96d --- /dev/null +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.cpp @@ -0,0 +1,28 @@ +#include "Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.h" + +#include "Active/Event/Event.h" +#include "Connector/ConnectorResource.h" +#include "Connector/Event/ConnectorEventID.h" +#include "Speckle/Environment/Addon.h" + +using namespace connector::interfac::browser::bridge; + + +/*-------------------------------------------------------------------- + Default constructor + --------------------------------------------------------------------*/ +SelectionChangeHandler::SelectionChangeHandler() { + int i = 0; +} //SelectionChangeHandler::SelectionChangeHandler + +/*-------------------------------------------------------------------- + Handle the menu selection + + event: The menu event + + return: True if the event should be closed + --------------------------------------------------------------------*/ +bool SelectionChangeHandler::handle(const speckle::event::SelectionEvent& event) { + int i = 0; + return true; +} diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.h new file mode 100644 index 0000000..38cf52b --- /dev/null +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.h @@ -0,0 +1,28 @@ +#ifndef CONNECTOR_INTERFACE_BRIDGE_SELECTION_CHANGE_HANDLER +#define CONNECTOR_INTERFACE_BRIDGE_SELECTION_CHANGE_HANDLER + +#include "Speckle/Event/Subscriber/SelectionSubscriber.h" +#include "Speckle/Event/Type/SelectionEvent.h" + +namespace connector::interfac::browser::bridge { + + /*! + Configuration settings class + */ + class SelectionChangeHandler : public speckle::event::SelectionSubscriber { + public: + // MARK: - Constructors + + /*! + Default constructor + */ + SelectionChangeHandler(); + + + protected: + bool handle(const speckle::event::SelectionEvent& event) override; + }; + +} + +#endif //CONNECTOR_INTERFACE_BRIDGE_SELECTION_CHANGE_HANDLER diff --git a/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp b/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp index 0800691..da4a920 100644 --- a/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp +++ b/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp @@ -4,6 +4,7 @@ #include "Active/Utility/String.h" #include "Active/Serialise/JSON/JSONTransport.h" #include "Active/Utility/BufferOut.h" +#include "Connector/Connector.h" #include "Connector/ConnectorResource.h" #include "Connector/Event/ConnectorEventID.h" #include "Connector/Interface/Browser/Bridge/Account/AccountBridge.h" @@ -77,9 +78,6 @@ namespace { virtual void PanelResized(const DG::PanelResizeEvent& ev) override; virtual void PanelCloseRequested(const DG::PanelCloseRequestEvent& ev, bool* accepted) override; - static GS::Array GetSelectedElements(); - static void ModifySelection(const GS::UniString& elemGuidStr, SelectionModification modification); - static GSErrCode __ACENV_CALL PaletteControlCallBack(Int32 paletteId, API_PaletteMessageID messageID, GS::IntPtr param); static GS::Ref instance; @@ -171,7 +169,12 @@ BrowserPalette::BrowserPalette() : install(); install(); install(); - install(); + if (auto ref = install(); ref) { + if (auto selectionBridgeRef = std::dynamic_pointer_cast(ref); selectionBridgeRef) { + connector::connector()->addWeak(selectionBridgeRef); + selectionBridgeRef->start(); + } + } install(); InitBrowserControl(); } @@ -245,31 +248,6 @@ void BrowserPalette::PanelCloseRequested(const DG::PanelCloseRequestEvent&, bool *accepted = true; } -GS::Array BrowserPalette::GetSelectedElements() { - API_SelectionInfo selectionInfo; - GS::Array selNeigs; - ACAPI_Selection_Get(&selectionInfo, &selNeigs, false, false); - BMKillHandle((GSHandle*)&selectionInfo.marquee.coords); - - GS::Array selectedElements; - for(const API_Neig& neig : selNeigs) { - API_Elem_Head elemHead = {}; - elemHead.guid = neig.guid; - ACAPI_Element_GetHeader(&elemHead); - - ElementInfo elemInfo; - elemInfo.guidStr = APIGuidToString(elemHead.guid); - ACAPI_Element_GetElemTypeName(elemHead.type, elemInfo.typeName); - ACAPI_Element_GetElementInfoString(&elemHead.guid, &elemInfo.elemID); - selectedElements.Push(elemInfo); - } - return selectedElements; -} - -void BrowserPalette::ModifySelection(const GS::UniString& elemGuidStr, BrowserPalette::SelectionModification modification) { - ACAPI_Selection_Select({ API_Neig(APIGuidFromString(elemGuidStr.ToCStr().Get())) }, modification == AddToSelection); -} - GSErrCode __ACENV_CALL BrowserPalette::PaletteControlCallBack(Int32, API_PaletteMessageID messageID, GS::IntPtr param) { switch(messageID) { case APIPalMsg_OpenPalette: diff --git a/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.cpp b/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.cpp index 48b5f04..c6925b4 100644 --- a/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.cpp +++ b/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.cpp @@ -69,12 +69,18 @@ bool SelectionSubscriber::receive(const Event& event) { return: True if the participant is able to continue --------------------------------------------------------------------*/ bool SelectionSubscriber::start() { - if (m_isStarted) - return true; - m_isStarted = true; #ifdef ARCHICAD return (ACAPI_Notification_CatchSelectionChange(selectionCallback) == NoError); #else return false; #endif } //SelectionSubscriber::start + +/*-------------------------------------------------------------------- + Stop participation (release resources etc) + --------------------------------------------------------------------*/ +void SelectionSubscriber::stop() { +#ifdef ARCHICAD + ACAPI_Notification_CatchSelectionChange(nullptr); +#endif +} diff --git a/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.h b/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.h index 975eb0c..a5595b0 100644 --- a/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.h +++ b/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.h @@ -35,7 +35,7 @@ namespace speckle::event { Get the event subscription list @return The subscription list (an empty list will put the subscriber into a suspended state) */ - virtual Subscription subscription() const override; + Subscription subscription() const override; // MARK: - Functions (mutating) @@ -44,14 +44,21 @@ namespace speckle::event { @param event The incoming event @return True if the event should be closed */ - virtual bool receive(const active::event::Event& event) override; - - protected: + bool receive(const active::event::Event& event) override; + /*! Start the participant operation @return True if the participant is able to continue */ virtual bool start() override; + + /*! + Stop participation (release resources etc) + */ + void stop() override; + + protected: + /*! Handle the menu selection @param event The menu event diff --git a/SpeckleLib/Speckle/Event/Type/SelectionEvent.h b/SpeckleLib/Speckle/Event/Type/SelectionEvent.h index 396f698..365f70f 100644 --- a/SpeckleLib/Speckle/Event/Type/SelectionEvent.h +++ b/SpeckleLib/Speckle/Event/Type/SelectionEvent.h @@ -24,7 +24,7 @@ namespace speckle::event { Constructor @param selected A link to a selected element (nullopt if the selection is empty) */ - SelectionEvent(speckle::database::BIMLink::Option selected) : m_selectedLink{selected} {} + SelectionEvent(speckle::database::BIMLink::Option selected) : Event{ ID }, m_selectedLink{selected} {} /*! Copy constructor @param source The object to copy diff --git a/SpeckleLib/Speckle/Interface/Browser/JSObject.h b/SpeckleLib/Speckle/Interface/Browser/JSObject.h index 05732e6..46843e0 100644 --- a/SpeckleLib/Speckle/Interface/Browser/JSObject.h +++ b/SpeckleLib/Speckle/Interface/Browser/JSObject.h @@ -38,7 +38,7 @@ namespace speckle::interfac::browser { */ template explicit JSObject(const speckle::utility::String& name, const std::initializer_list& items) : base{items}, m_name{name} {} - + virtual ~JSObject() {} // MARK: - Functions (const) /*! diff --git a/SpeckleLib/Speckle/Interface/Browser/JSPortal.h b/SpeckleLib/Speckle/Interface/Browser/JSPortal.h index 14bcc26..159eeb7 100644 --- a/SpeckleLib/Speckle/Interface/Browser/JSPortal.h +++ b/SpeckleLib/Speckle/Interface/Browser/JSPortal.h @@ -48,14 +48,14 @@ namespace speckle::interfac::browser { @param object The object to install @return True if the object was successfully installed */ - bool install(std::shared_ptr> object); + std::shared_ptr> install(std::shared_ptr> object); /*! Install a JS function object @return True if the object was successfully installed @tparam T The type of object to install */ template requires std::is_base_of_v, T> - bool install() { return install(std::make_shared()); } + std::shared_ptr> install() { return install(std::make_shared()); } protected: #ifdef ARCHICAD @@ -101,12 +101,12 @@ namespace speckle::interfac::browser { return: True if the object was successfully installed --------------------------------------------------------------------*/ template - bool JSPortal::install(std::shared_ptr> object) { + std::shared_ptr> JSPortal::install(std::shared_ptr> object) { try { #ifdef ARCHICAD auto engine = getJSEngine(); if (!engine) - return false; + return nullptr; //Define the JS object JS::Object* acObject = new JS::Object(object->getName()); //Add all the functions supported by this object @@ -125,13 +125,13 @@ namespace speckle::interfac::browser { if (engine->RegisterAsynchJSObject(acObject)) { base::push_back(object); object->setPortal(*this); - return true; + return object; } #endif } catch(...) { ///TODO: Need to discuss the best course of action to notify of a failure } - return false; + return nullptr; } //JSPortal::install } From 5c1511e85076eaf3aa4f45326d4fae90e2507a79 Mon Sep 17 00:00:00 2001 From: David Kekesi Date: Wed, 16 Oct 2024 15:50:15 +0200 Subject: [PATCH 063/191] code cleanup --- SpeckleConnector/Connector.vcxproj | 2 -- SpeckleConnector/Connector.vcxproj.filters | 6 ---- SpeckleConnector/Connector/Connector.cpp | 2 -- .../Bridge/Selection/Arg/SelectionInfo.cpp | 15 ++++------ .../Bridge/Selection/Arg/SelectionInfo.h | 2 -- .../Browser/Bridge/Selection/GetSelection.cpp | 7 ++--- .../Browser/Bridge/Selection/GetSelection.h | 4 +-- .../Bridge/Selection/SelectionBridge.cpp | 9 ++++-- .../Bridge/Selection/SelectionBridge.h | 6 +++- .../Selection/SelectionChangeHandler.cpp | 28 ------------------- .../Bridge/Selection/SelectionChangeHandler.h | 28 ------------------- .../Event/Subscriber/SelectionSubscriber.h | 2 +- 12 files changed, 24 insertions(+), 87 deletions(-) delete mode 100644 SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.cpp delete mode 100644 SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.h diff --git a/SpeckleConnector/Connector.vcxproj b/SpeckleConnector/Connector.vcxproj index 245709b..acf33d4 100644 --- a/SpeckleConnector/Connector.vcxproj +++ b/SpeckleConnector/Connector.vcxproj @@ -114,7 +114,6 @@ - @@ -170,7 +169,6 @@ - diff --git a/SpeckleConnector/Connector.vcxproj.filters b/SpeckleConnector/Connector.vcxproj.filters index 763dc5c..374c759 100644 --- a/SpeckleConnector/Connector.vcxproj.filters +++ b/SpeckleConnector/Connector.vcxproj.filters @@ -243,9 +243,6 @@ Connector\Interface\Browser\Bridge\Selection\Arg - - Connector\Interface\Browser\Bridge\Selection - @@ -414,8 +411,5 @@ Connector\Interface\Browser\Bridge\Selection\Arg - - Connector\Interface\Browser\Bridge\Selection - \ No newline at end of file diff --git a/SpeckleConnector/Connector/Connector.cpp b/SpeckleConnector/Connector/Connector.cpp index 4343b1e..23943be 100755 --- a/SpeckleConnector/Connector/Connector.cpp +++ b/SpeckleConnector/Connector/Connector.cpp @@ -1,7 +1,6 @@ #include "Active/File/Directory.h" #include "ConnectorResource.h" #include "Connector/Connector.h" -#include "Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.h" #include "Connector/Database/ModelCardDatabase.h" #include "Connector/Interface/ConnectorMenu.h" #include "Connector/Interface/ConnectorPalette.h" @@ -13,7 +12,6 @@ using namespace active::file; using namespace active::environment; using namespace connector; using namespace connector::database; -using namespace connector::interfac::browser::bridge; using namespace speckle::database; using namespace speckle::environment; using namespace speckle::utility; diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.cpp index b7126b9..94d5453 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.cpp @@ -1,20 +1,16 @@ -#include "Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h" - #include "Active/Serialise/Item/Wrapper/ValueWrap.h" -#include "Active/Serialise/Package/Wrapper/PackageWrap.h" #include "Active/Serialise/Package/Wrapper/ContainerWrap.h" - #include "Connector/Connector.h" - +#include "Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h" #include "Speckle/Database/BIMElementDatabase.h" #include "Speckle/Environment/Project.h" #include "Speckle/Record/Element/Element.h" -using namespace speckle::record::element; #include using namespace active::serialise; using namespace connector::interfac::browser::bridge; +using namespace speckle::record::element; namespace { @@ -39,7 +35,8 @@ SelectionInfo::SelectionInfo() { void SelectionInfo::initialize() { auto project = connector()->getActiveProject().lock(); if (!project) { - // TODO: handle + // TODO: is thi OK? + return; } auto elementDatabase = project->getElementDatabase(); @@ -70,7 +67,7 @@ bool SelectionInfo::fillInventory(Inventory& inventory) const { }, }.withType(&typeid(SelectionInfo))); return true; -} //ConnectorConfig::fillInventory +} //SelectionInfo::fillInventory /*-------------------------------------------------------------------- @@ -92,4 +89,4 @@ Cargo::Unique SelectionInfo::getCargo(const Inventory::Item& item) const { default: return nullptr; //Requested an unknown index } -} //ConnectorConfig::getCargo +} //SelectionInfo::getCargo diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h index 12c9ec3..2ffb592 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h @@ -2,7 +2,6 @@ #define CONNECTOR_INTERFACE_BRIDGE_SELECTION_INFO #include "Active/Serialise/Package/Package.h" -#include "Speckle/Interface/Browser/Bridge/ArgumentBase.h" namespace connector::interfac::browser::bridge { @@ -43,7 +42,6 @@ namespace connector::interfac::browser::bridge { */ Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; }; - } #endif //CONNECTOR_INTERFACE_BRIDGE_SELECTION_INFO diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.cpp index 6385c09..37f918a 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.cpp @@ -1,5 +1,5 @@ -#include "Connector/Interface/Browser/Bridge/Selection/GetSelection.h" #include "Active/Serialise/CargoHold.h" +#include "Connector/Interface/Browser/Bridge/Selection/GetSelection.h" #include "Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h" using namespace active::serialise; @@ -14,9 +14,8 @@ GetSelection::GetSelection() : BridgeMethod{"GetSelection", [&]() { /*-------------------------------------------------------------------- - Send a specified model - - modelCardID: The ID of the model to send + Get the current selection info + based on the ArchiCAD mdoel selection --------------------------------------------------------------------*/ std::unique_ptr GetSelection::run() const { auto selectionInfo = std::make_unique(); diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.h index 8f9b73d..66e827f 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.h +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.h @@ -19,8 +19,8 @@ namespace connector::interfac::browser::bridge { // MARK: - Functions (const) /*! - Send a specified model - @param modelCardID The ID of the model to send + Get the current selection info + based on the ArchiCAD mdoel selection */ std::unique_ptr run() const; }; diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.cpp index f31cc98..33ce06b 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.cpp @@ -1,6 +1,6 @@ +#include "Active/Serialise/CargoHold.h" #include "Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h" #include "Connector/Interface/Browser/Bridge/Selection/GetSelection.h" -#include "Active/Serialise/CargoHold.h" #include "Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h" using namespace active::serialise; @@ -14,9 +14,14 @@ SelectionBridge::SelectionBridge() : BrowserBridge{"selectionBinding"} { addMethod(); } //SelectionBridge::SelectionBridge +/*! +Handle the menu selection +@param event The selection event +@return True if the event should be closed +*/ bool SelectionBridge::handle(const speckle::event::SelectionEvent& event) { auto selectionInfo = std::make_unique(); auto wrapped = std::make_unique>(std::move(selectionInfo)); sendEvent("setSelection", std::move(wrapped)); return true; -} +} //SelectionBridge::handle diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h index a92f213..7da2690 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h @@ -26,7 +26,11 @@ namespace connector::interfac::browser::bridge { SelectionBridge(); protected: - + /*! + Handle the menu selection + @param event The selection event + @return True if the event should be closed + */ bool handle(const speckle::event::SelectionEvent& event) override; }; diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.cpp deleted file mode 100644 index 652b96d..0000000 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.h" - -#include "Active/Event/Event.h" -#include "Connector/ConnectorResource.h" -#include "Connector/Event/ConnectorEventID.h" -#include "Speckle/Environment/Addon.h" - -using namespace connector::interfac::browser::bridge; - - -/*-------------------------------------------------------------------- - Default constructor - --------------------------------------------------------------------*/ -SelectionChangeHandler::SelectionChangeHandler() { - int i = 0; -} //SelectionChangeHandler::SelectionChangeHandler - -/*-------------------------------------------------------------------- - Handle the menu selection - - event: The menu event - - return: True if the event should be closed - --------------------------------------------------------------------*/ -bool SelectionChangeHandler::handle(const speckle::event::SelectionEvent& event) { - int i = 0; - return true; -} diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.h deleted file mode 100644 index 38cf52b..0000000 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionChangeHandler.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef CONNECTOR_INTERFACE_BRIDGE_SELECTION_CHANGE_HANDLER -#define CONNECTOR_INTERFACE_BRIDGE_SELECTION_CHANGE_HANDLER - -#include "Speckle/Event/Subscriber/SelectionSubscriber.h" -#include "Speckle/Event/Type/SelectionEvent.h" - -namespace connector::interfac::browser::bridge { - - /*! - Configuration settings class - */ - class SelectionChangeHandler : public speckle::event::SelectionSubscriber { - public: - // MARK: - Constructors - - /*! - Default constructor - */ - SelectionChangeHandler(); - - - protected: - bool handle(const speckle::event::SelectionEvent& event) override; - }; - -} - -#endif //CONNECTOR_INTERFACE_BRIDGE_SELECTION_CHANGE_HANDLER diff --git a/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.h b/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.h index a5595b0..b68f2ed 100644 --- a/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.h +++ b/SpeckleLib/Speckle/Event/Subscriber/SelectionSubscriber.h @@ -61,7 +61,7 @@ namespace speckle::event { /*! Handle the menu selection - @param event The menu event + @param event The selection event @return True if the event should be closed */ virtual bool handle(const SelectionEvent& event) = 0; From 3813c8740f4bc6f9259f9b17d24432daaddb7eb7 Mon Sep 17 00:00:00 2001 From: David Kekesi Date: Wed, 16 Oct 2024 15:53:59 +0200 Subject: [PATCH 064/191] SelectionInfo::initialize changed to private --- .../Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h index 2ffb592..e10bd6f 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h @@ -24,8 +24,6 @@ namespace connector::interfac::browser::bridge { active::utility::String m_summary = "No objects selected"; std::vector m_selectedElementIds; - - void initialize(); // MARK: - Serialisation @@ -41,6 +39,10 @@ namespace connector::interfac::browser::bridge { @return The requested cargo (nullptr on failure) */ Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + + private: + + void initialize(); }; } From 702f99eced1156c10518c37367c0e8513875d7c7 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Wed, 16 Oct 2024 15:06:06 +0100 Subject: [PATCH 065/191] Reduced the number of objects that define a name for 'speckle_type' (default to 'Base' instead) --- SpeckleLib/Speckle/Database/Content/Record.h | 2 +- SpeckleLib/Speckle/Record/Attribute/Attribute.h | 5 ----- SpeckleLib/Speckle/Record/Attribute/Storey.h | 5 ----- SpeckleLib/Speckle/Record/Element/Column.h | 5 ----- SpeckleLib/Speckle/Record/Element/ColumnSegment.h | 5 ----- SpeckleLib/Speckle/Record/Element/Element.h | 5 ----- SpeckleLib/Speckle/Record/Element/GenericElement.h | 5 ----- .../Speckle/Record/Element/Interface/SegmentedColumn.cpp | 2 ++ 8 files changed, 3 insertions(+), 31 deletions(-) diff --git a/SpeckleLib/Speckle/Database/Content/Record.h b/SpeckleLib/Speckle/Database/Content/Record.h index 6a1adfd..7be1790 100644 --- a/SpeckleLib/Speckle/Database/Content/Record.h +++ b/SpeckleLib/Speckle/Database/Content/Record.h @@ -43,7 +43,7 @@ namespace speckle::database { Get the speckle type identifier @return The speckle type (relevant objects should override as required, but "Base" is still considered a type on its own) */ - virtual speckle::utility::String getSpeckleType() const { return "speckle::database::Record"; } + virtual speckle::utility::String getSpeckleType() const { return "Base"; } // MARK: - Functions (mutating) diff --git a/SpeckleLib/Speckle/Record/Attribute/Attribute.h b/SpeckleLib/Speckle/Record/Attribute/Attribute.h index e1a13ed..ee6b1c7 100644 --- a/SpeckleLib/Speckle/Record/Attribute/Attribute.h +++ b/SpeckleLib/Speckle/Record/Attribute/Attribute.h @@ -62,11 +62,6 @@ namespace speckle::record::attribute { // MARK: - Functions (const) - /*! - Get the speckle type identifier - @return The speckle type (relevant objects should override as required) - */ - speckle::utility::String getSpeckleType() const override { return "speckle::record::attribute::Attribute"; } /*! Get the attribute name @return The attribute name diff --git a/SpeckleLib/Speckle/Record/Attribute/Storey.h b/SpeckleLib/Speckle/Record/Attribute/Storey.h index cbcf505..e009eec 100644 --- a/SpeckleLib/Speckle/Record/Attribute/Storey.h +++ b/SpeckleLib/Speckle/Record/Attribute/Storey.h @@ -67,11 +67,6 @@ namespace speckle::record::attribute { // MARK: - Functions (const) - /*! - Get the speckle type identifier - @return The speckle type (relevant objects should override as required) - */ - speckle::utility::String getSpeckleType() const override { return "speckle::record::attribute::Storey"; } #ifdef ARCHICAD /*! Get the (immutable) API attribute header data diff --git a/SpeckleLib/Speckle/Record/Element/Column.h b/SpeckleLib/Speckle/Record/Element/Column.h index a70185f..b75a706 100644 --- a/SpeckleLib/Speckle/Record/Element/Column.h +++ b/SpeckleLib/Speckle/Record/Element/Column.h @@ -61,11 +61,6 @@ namespace speckle::record::element { // MARK: - Functions (const) - /*! - Get the speckle type identifier - @return The speckle type (relevant objects should override as required) - */ - speckle::utility::String getSpeckleType() const override { return "Objects.BuiltElements.Element:Objects.BuiltElements.Column"; } /*! Get the BIM application parent table ID @return The BIM table ID diff --git a/SpeckleLib/Speckle/Record/Element/ColumnSegment.h b/SpeckleLib/Speckle/Record/Element/ColumnSegment.h index 85c731b..3f6678e 100644 --- a/SpeckleLib/Speckle/Record/Element/ColumnSegment.h +++ b/SpeckleLib/Speckle/Record/Element/ColumnSegment.h @@ -64,11 +64,6 @@ namespace speckle::record::element { // MARK: - Functions (const) - /*! - Get the speckle type identifier - @return The speckle type (relevant objects should override as required) - */ - speckle::utility::String getSpeckleType() const override { return "Objects.BuiltElements.Element:Objects.BuiltElements.ColumnSegment"; } #ifdef ARCHICAD /*! Get the (immutable) API element header data diff --git a/SpeckleLib/Speckle/Record/Element/Element.h b/SpeckleLib/Speckle/Record/Element/Element.h index 8a2bef1..fc5393a 100644 --- a/SpeckleLib/Speckle/Record/Element/Element.h +++ b/SpeckleLib/Speckle/Record/Element/Element.h @@ -64,11 +64,6 @@ namespace speckle::record::element { // MARK: - Functions (const) - /*! - Get the speckle type identifier - @return The speckle type (relevant objects should override as required) - */ - virtual speckle::utility::String getSpeckleType() const override { return "Objects.BuiltElements.Element:Objects.BuiltElements.Element"; } /*! Get the elmeent type name, e.g. "Wall", "Roof" etc @return The type name diff --git a/SpeckleLib/Speckle/Record/Element/GenericElement.h b/SpeckleLib/Speckle/Record/Element/GenericElement.h index a1d052e..0ffc7ca 100644 --- a/SpeckleLib/Speckle/Record/Element/GenericElement.h +++ b/SpeckleLib/Speckle/Record/Element/GenericElement.h @@ -59,11 +59,6 @@ namespace speckle::record::element { // MARK: - Functions (const) - /*! - Get the speckle type identifier - @return The speckle type (relevant objects should override as required) - */ - virtual speckle::utility::String getSpeckleType() const override { return "Objects.BuiltElements.GenericElement:Objects.BuiltElements.GenericElement"; } #ifdef ARCHICAD /*! Get the (immutable) API element header data diff --git a/SpeckleLib/Speckle/Record/Element/Interface/SegmentedColumn.cpp b/SpeckleLib/Speckle/Record/Element/Interface/SegmentedColumn.cpp index 92bab68..5e4d5c2 100644 --- a/SpeckleLib/Speckle/Record/Element/Interface/SegmentedColumn.cpp +++ b/SpeckleLib/Speckle/Record/Element/Interface/SegmentedColumn.cpp @@ -74,7 +74,9 @@ ColumnSegment* SegmentedColumn::getSegment(size_t index) const { return: The required filter bits --------------------------------------------------------------------*/ Part::filter_bits SegmentedColumn::getPartFilter() const { +#ifdef ARCHICAD return APIMemoMask_ColumnSegment | APIMemoMask_AssemblySegmentCut | APIMemoMask_AssemblySegmentScheme | APIMemoMask_AssemblySegmentProfile; +#endif } //SegmentedColumn::getPartFilter From b80b5aef94c8e4af09f1e7e95bf4bbd78946b02d Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Wed, 16 Oct 2024 16:44:38 +0100 Subject: [PATCH 066/191] Fixed ColumnSegment copy constructor --- SpeckleLib/Speckle/Record/Element/ColumnSegment.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SpeckleLib/Speckle/Record/Element/ColumnSegment.cpp b/SpeckleLib/Speckle/Record/Element/ColumnSegment.cpp index 34d4cb2..0b8ab9e 100644 --- a/SpeckleLib/Speckle/Record/Element/ColumnSegment.cpp +++ b/SpeckleLib/Speckle/Record/Element/ColumnSegment.cpp @@ -82,7 +82,7 @@ ColumnSegment::ColumnSegment(const API_ColumnSegmentType& segment, const speckle source: The object to copy --------------------------------------------------------------------*/ ColumnSegment::ColumnSegment(const ColumnSegment& source) : base{ source } { - m_data = source.m_data ? std::make_unique(*m_data) : nullptr; + m_data = source.m_data ? std::make_unique(*source.m_data) : nullptr; } //ColumnSegment::ColumnSegment From f44f0413d01141e48e5636504b58ab7c10ff0b1f Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Wed, 16 Oct 2024 17:00:03 +0100 Subject: [PATCH 067/191] ColumnSegment move constructor should be noexcept --- SpeckleLib/Speckle/Record/Element/ColumnSegment.cpp | 2 +- SpeckleLib/Speckle/Record/Element/ColumnSegment.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/SpeckleLib/Speckle/Record/Element/ColumnSegment.cpp b/SpeckleLib/Speckle/Record/Element/ColumnSegment.cpp index 0b8ab9e..469f2aa 100644 --- a/SpeckleLib/Speckle/Record/Element/ColumnSegment.cpp +++ b/SpeckleLib/Speckle/Record/Element/ColumnSegment.cpp @@ -91,7 +91,7 @@ ColumnSegment::ColumnSegment(const ColumnSegment& source) : base{ source } { source: The object to move --------------------------------------------------------------------*/ -ColumnSegment::ColumnSegment(ColumnSegment&& source) : base{source} { +ColumnSegment::ColumnSegment(ColumnSegment&& source) noexcept : base{source} { m_data = std::move(source.m_data); } //ColumnSegment::ColumnSegment diff --git a/SpeckleLib/Speckle/Record/Element/ColumnSegment.h b/SpeckleLib/Speckle/Record/Element/ColumnSegment.h index 3f6678e..54b98a1 100644 --- a/SpeckleLib/Speckle/Record/Element/ColumnSegment.h +++ b/SpeckleLib/Speckle/Record/Element/ColumnSegment.h @@ -49,7 +49,7 @@ namespace speckle::record::element { Move constructor @param source The object to move */ - ColumnSegment(ColumnSegment&& source); + ColumnSegment(ColumnSegment&& source) noexcept; /*! Destructor */ From 878988df95d5b2782fbe0a39ceba07eb3802b861 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Thu, 17 Oct 2024 17:22:51 +0100 Subject: [PATCH 068/191] Update Xcode project BIM core dbase engines should be able to react to project events Attribute dbase resets storey cache on project changes --- .../Connector.xcodeproj/project.pbxproj | 34 +++++++++++++++++++ .../Bridge/Selection/Arg/SelectionInfo.cpp | 5 +-- .../Bridge/Selection/Arg/SelectionInfo.h | 4 --- .../Bridge/Selection/SelectionBridge.cpp | 13 ++++--- .../Bridge/Selection/SelectionBridge.h | 4 +-- SpeckleLib/Speckle/Database/Content/Record.h | 2 +- .../Storage/ArchicadDBase/ArchicadDBaseCore.h | 11 +++--- .../ArchicadAttributeDBaseEngine.cpp | 21 ++++++++++++ .../Attribute/ArchicadAttributeDBaseEngine.h | 9 +++++ 9 files changed, 83 insertions(+), 20 deletions(-) diff --git a/SpeckleConnector/Connector.xcodeproj/project.pbxproj b/SpeckleConnector/Connector.xcodeproj/project.pbxproj index fc6c93a..ed016c3 100644 --- a/SpeckleConnector/Connector.xcodeproj/project.pbxproj +++ b/SpeckleConnector/Connector.xcodeproj/project.pbxproj @@ -32,6 +32,9 @@ 2192460D2CA3469D00CF5703 /* ProjectCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2192460B2CA3469D00CF5703 /* ProjectCollection.cpp */; }; 219F30422C769283009834E9 /* ConfigTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219F30402C769282009834E9 /* ConfigTests.cpp */; }; 21A0FB982CB723240023F24E /* FinishProxy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21A0FB942CB723240023F24E /* FinishProxy.cpp */; }; + 21A890BC2CC15C540087E732 /* SelectionInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21A890B22CC15C540087E732 /* SelectionInfo.cpp */; }; + 21A890BD2CC15C540087E732 /* GetSelection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21A890B52CC15C540087E732 /* GetSelection.cpp */; }; + 21A890BE2CC15C540087E732 /* SelectionBridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21A890B72CC15C540087E732 /* SelectionBridge.cpp */; }; 21AEF9EB2CAB56E5000B8681 /* SendError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9E32CAB56E5000B8681 /* SendError.cpp */; }; 21AEF9EC2CAB56E5000B8681 /* SendViaBrowserArgs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9E52CAB56E5000B8681 /* SendViaBrowserArgs.cpp */; }; 21AEF9EF2CAB5720000B8681 /* SendObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9EE2CAB5720000B8681 /* SendObject.cpp */; }; @@ -314,6 +317,12 @@ 219F30432C7693B6009834E9 /* Connector-AC27-Debug.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Connector-AC27-Debug.xctestplan"; sourceTree = SOURCE_ROOT; }; 21A0FB942CB723240023F24E /* FinishProxy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FinishProxy.cpp; sourceTree = ""; }; 21A0FB972CB723240023F24E /* FinishProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FinishProxy.h; sourceTree = ""; }; + 21A890B22CC15C540087E732 /* SelectionInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SelectionInfo.cpp; sourceTree = ""; }; + 21A890B32CC15C540087E732 /* SelectionInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SelectionInfo.h; sourceTree = ""; }; + 21A890B52CC15C540087E732 /* GetSelection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetSelection.cpp; sourceTree = ""; }; + 21A890B62CC15C540087E732 /* GetSelection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetSelection.h; sourceTree = ""; }; + 21A890B72CC15C540087E732 /* SelectionBridge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SelectionBridge.cpp; sourceTree = ""; }; + 21A890B82CC15C540087E732 /* SelectionBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SelectionBridge.h; sourceTree = ""; }; 21AEF9E32CAB56E5000B8681 /* SendError.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SendError.cpp; sourceTree = ""; }; 21AEF9E42CAB56E5000B8681 /* SendError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SendError.h; sourceTree = ""; }; 21AEF9E52CAB56E5000B8681 /* SendViaBrowserArgs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SendViaBrowserArgs.cpp; sourceTree = ""; }; @@ -963,6 +972,27 @@ path = ConnectorTests; sourceTree = ""; }; + 21A890B42CC15C540087E732 /* Arg */ = { + isa = PBXGroup; + children = ( + 21A890B22CC15C540087E732 /* SelectionInfo.cpp */, + 21A890B32CC15C540087E732 /* SelectionInfo.h */, + ); + path = Arg; + sourceTree = ""; + }; + 21A890B92CC15C540087E732 /* Selection */ = { + isa = PBXGroup; + children = ( + 21A890B42CC15C540087E732 /* Arg */, + 21A890B52CC15C540087E732 /* GetSelection.cpp */, + 21A890B62CC15C540087E732 /* GetSelection.h */, + 21A890B72CC15C540087E732 /* SelectionBridge.cpp */, + 21A890B82CC15C540087E732 /* SelectionBridge.h */, + ); + path = Selection; + sourceTree = ""; + }; 21AEF9E72CAB56E5000B8681 /* Arg */ = { isa = PBXGroup; children = ( @@ -1202,6 +1232,7 @@ 21B67CAB2C77329800FD64FC /* Base */, 21F69FB82C762EF0008B6A06 /* Config */, 21D0BD5D2C89BFEA0077E104 /* Send */, + 21A890B92CC15C540087E732 /* Selection */, 21B67CD82C78C83800FD64FC /* Test */, ); path = Bridge; @@ -1456,6 +1487,7 @@ 215F08462C9633A800CD343B /* EverythingSendFilter.cpp in Sources */, 21F69FBB2C762EF0008B6A06 /* ConfigBridge.cpp in Sources */, 21F69F8A2C70D2C4008B6A06 /* AccountBridge.cpp in Sources */, + 21A890BE2CC15C540087E732 /* SelectionBridge.cpp in Sources */, 21D0BD8E2C8EE4490077E104 /* Send.cpp in Sources */, 21D0BDCF2C92DAC60077E104 /* AddModel.cpp in Sources */, 21B67CF72C78D4DE00FD64FC /* GetComplexType.cpp in Sources */, @@ -1478,6 +1510,7 @@ 21FF70492CA1A7F400AAD99A /* RecordCollection.cpp in Sources */, 21B67CC02C775A0D00FD64FC /* GetDocumentInfo.cpp in Sources */, 21D0BDD42C935D1A0077E104 /* UpdateModel.cpp in Sources */, + 21A890BD2CC15C540087E732 /* GetSelection.cpp in Sources */, 21B67CE72C78D23B00FD64FC /* ConnectorConfig.cpp in Sources */, 21B67CAD2C77329800FD64FC /* GetSourceApplicationName.cpp in Sources */, 21D0BDE02C9393980077E104 /* SendFilter.cpp in Sources */, @@ -1485,6 +1518,7 @@ 215F082A2C947F4400CD343B /* CardMover.cpp in Sources */, 215F08372C95808B00CD343B /* ReceiverModelCard.cpp in Sources */, 21D0BDD72C935DAE0077E104 /* RemoveModel.cpp in Sources */, + 21A890BC2CC15C540087E732 /* SelectionInfo.cpp in Sources */, 21AEF9EF2CAB5720000B8681 /* SendObject.cpp in Sources */, 21B67CDC2C78C88000FD64FC /* SayHi.cpp in Sources */, 215F082E2C94C5C000CD343B /* FilterMover.cpp in Sources */, diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.cpp index 94d5453..f442735 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.cpp @@ -29,10 +29,6 @@ namespace { } SelectionInfo::SelectionInfo() { - initialize(); -} - -void SelectionInfo::initialize() { auto project = connector()->getActiveProject().lock(); if (!project) { // TODO: is thi OK? @@ -51,6 +47,7 @@ void SelectionInfo::initialize() { } } + /*-------------------------------------------------------------------- Fill an inventory with the package items diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h index e10bd6f..18bace9 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h @@ -39,10 +39,6 @@ namespace connector::interfac::browser::bridge { @return The requested cargo (nullptr on failure) */ Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; - - private: - - void initialize(); }; } diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.cpp index 33ce06b..cb05aed 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.cpp @@ -14,11 +14,14 @@ SelectionBridge::SelectionBridge() : BrowserBridge{"selectionBinding"} { addMethod(); } //SelectionBridge::SelectionBridge -/*! -Handle the menu selection -@param event The selection event -@return True if the event should be closed -*/ + +/*-------------------------------------------------------------------- + Handle a selection change + + event: The selection event + + return: True if the event should be closed + --------------------------------------------------------------------*/ bool SelectionBridge::handle(const speckle::event::SelectionEvent& event) { auto selectionInfo = std::make_unique(); auto wrapped = std::make_unique>(std::move(selectionInfo)); diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h index 7da2690..40b6c1b 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h @@ -8,7 +8,7 @@ namespace connector::interfac::browser::bridge { /*! - A browser bridge to support sending model data to a Speckle server + A browser bridge to manage element selection information passed between the JS UI and the BIM application */ class SelectionBridge : public speckle::interfac::browser::bridge::BrowserBridge, public speckle::event::SelectionSubscriber { public: @@ -27,7 +27,7 @@ namespace connector::interfac::browser::bridge { protected: /*! - Handle the menu selection + Handle a selection change @param event The selection event @return True if the event should be closed */ diff --git a/SpeckleLib/Speckle/Database/Content/Record.h b/SpeckleLib/Speckle/Database/Content/Record.h index 7be1790..ce47a93 100644 --- a/SpeckleLib/Speckle/Database/Content/Record.h +++ b/SpeckleLib/Speckle/Database/Content/Record.h @@ -37,7 +37,7 @@ namespace speckle::database { */ virtual ~Record() {} - // MARK: - Functions (const) + // MARK: - Functions (const) /*! Get the speckle type identifier diff --git a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/ArchicadDBaseCore.h b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/ArchicadDBaseCore.h index 2ac2f97..fb6f0fa 100644 --- a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/ArchicadDBaseCore.h +++ b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/ArchicadDBaseCore.h @@ -7,7 +7,6 @@ #include "Active/Setting/SettingList.h" #include "Active/Database/Storage/DBaseSchema.h" #include "Active/Utility/NameID.h" -#include "Speckle/Event/Subscriber/DocStoreSubscriber.h" #include "Speckle/Event/Subscriber/ProjectSubscriber.h" namespace speckle::database { @@ -19,7 +18,7 @@ namespace speckle::database { Currently implement for Archicad Add-On Objects */ - class ArchicadDBaseCore { + class ArchicadDBaseCore : public event::ProjectSubscriber { public: // MARK: - Types @@ -69,8 +68,12 @@ namespace speckle::database { // MARK: - Functions (mutating) - protected: - + /*! + Handle a project event + @param event The project event + @return True if the event should be closed + */ + bool handle(const event::ProjectEvent& event) override { return false; } private: ///The database schema diff --git a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.cpp b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.cpp index f16d675..d2584ef 100644 --- a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.cpp +++ b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.cpp @@ -295,3 +295,24 @@ std::optional ArchicadAttributeDBaseEngine::getStoreyID(short index return std::nullopt; } //ArchicadAttributeDBaseEngine::getStoreyID #endif + + +/*-------------------------------------------------------------------- + Handle a project event + + event: The project event + + return: True if the event should be closed + --------------------------------------------------------------------*/ +bool ArchicadAttributeDBaseEngine::handle(const event::ProjectEvent& event) { + using enum ProjectEvent::Type; + switch (event.getType()) { + case newDocument: case newAndReset: case open: case close: case quit: + //Reset the storey cache on any event that changes the active project + m_storeyCache.reset(); + break; + default: + break; + } + return false; +} //ArchicadAttributeDBaseEngine::handle diff --git a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.h b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.h index 0da60db..d3295c6 100644 --- a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.h +++ b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.h @@ -134,6 +134,15 @@ namespace speckle::database { */ std::optional getStoreyID(short index) const; #endif + + // MARK: - Functions (mutating) + + /*! + Handle a project event + @param event The project event + @return True if the event should be closed + */ + bool handle(const event::ProjectEvent& event) override; private: void setTable(std::optional tableID = std::nullopt, std::optional documentID = std::nullopt); From f5b5ff648787f7a84f813a2b4393cc722b9fb51f Mon Sep 17 00:00:00 2001 From: David Kekesi Date: Mon, 21 Oct 2024 09:41:55 +0200 Subject: [PATCH 069/191] create Beam and supporting classes --- .../Element/ArchicadElementDBaseEngine.cpp | 7 +- SpeckleLib/Speckle/Record/Element/Beam.cpp | 174 ++++++++++++++++++ SpeckleLib/Speckle/Record/Element/Beam.h | 137 ++++++++++++++ .../Speckle/Record/Element/BeamSegment.cpp | 159 ++++++++++++++++ .../Speckle/Record/Element/BeamSegment.h | 130 +++++++++++++ .../Element/Interface/SegmentedBeam.cpp | 160 ++++++++++++++++ .../Record/Element/Interface/SegmentedBeam.h | 103 +++++++++++ SpeckleLib/SpeckleLib17.vcxproj | 6 + SpeckleLib/SpeckleLib17.vcxproj.filters | 18 ++ 9 files changed, 893 insertions(+), 1 deletion(-) create mode 100644 SpeckleLib/Speckle/Record/Element/Beam.cpp create mode 100644 SpeckleLib/Speckle/Record/Element/Beam.h create mode 100644 SpeckleLib/Speckle/Record/Element/BeamSegment.cpp create mode 100644 SpeckleLib/Speckle/Record/Element/BeamSegment.h create mode 100644 SpeckleLib/Speckle/Record/Element/Interface/SegmentedBeam.cpp create mode 100644 SpeckleLib/Speckle/Record/Element/Interface/SegmentedBeam.h diff --git a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.cpp b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.cpp index a1d7fd5..bb22560 100644 --- a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.cpp +++ b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.cpp @@ -13,6 +13,8 @@ #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" @@ -76,11 +78,14 @@ namespace { return std::make_unique(elementData, tableID); case API_ColumnSegmentID: return std::make_unique(elementData, tableID); + case API_BeamID: + return std::make_unique(elementData, tableID); + case API_BeamSegmentID: + return std::make_unique(elementData, tableID); default: return std::make_unique(elementData, tableID); } } - } /*-------------------------------------------------------------------- diff --git a/SpeckleLib/Speckle/Record/Element/Beam.cpp b/SpeckleLib/Speckle/Record/Element/Beam.cpp new file mode 100644 index 0000000..1cad612 --- /dev/null +++ b/SpeckleLib/Speckle/Record/Element/Beam.cpp @@ -0,0 +1,174 @@ +#include "Speckle/Record/Element/Beam.h" + +#include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Active/Serialise/Package/Wrapper/PackageWrap.h" +#include "Active/Serialise/Package/Wrapper/ContainerWrap.h" +#include "Speckle/Environment/Addon.h" +#include "Speckle/Primitive/Mesh/Mesh.h" +#include "Speckle/SpeckleResource.h" +#include "Speckle/Utility/Guid.h" + +using namespace active::serialise; +using namespace speckle::environment; +using namespace speckle::record::attribute; +using namespace speckle::record::element; +using namespace speckle::utility; + +#include +#include + +namespace speckle::record::element { + + class Beam::Data { + public: + friend class Beam; + +#ifdef ARCHICAD + Data(const API_Element& elem) : root{ std::make_unique(elem.beam) } {} + Data(const Data& source) : root{ std::make_unique(*source.root) } {} +#endif + + private: + std::unique_ptr root; + }; + +} + +namespace { + + ///Serialisation fields + enum FieldIndex { + segmentID, + }; + + ///Serialisation field IDs + static std::array fieldID = { + Identity{"segments"}, + }; + +} + +/*-------------------------------------------------------------------- + Default constructor + --------------------------------------------------------------------*/ +Beam::Beam() { +} //Beam::Beam + + +#ifdef ARCHICAD +/*-------------------------------------------------------------------- + Constructor + + elemData: Archicad element data + tableID: The element table ID (AC database, e.g. floor plan, 3D) + --------------------------------------------------------------------*/ +Beam::Beam(const API_Element& elemData, const speckle::utility::Guid& tableID) : base{ elemData.header.guid, tableID } { + m_data = std::make_unique(elemData); +} //Beam::Beam +#endif + + +/*-------------------------------------------------------------------- + Copy constructor + + source: The object to copy + --------------------------------------------------------------------*/ +Beam::Beam(const Beam& source) : base{ source } { + m_data = source.m_data ? std::make_unique(*m_data) : nullptr; +} //Beam::Beam + + +/*-------------------------------------------------------------------- + Destructor + --------------------------------------------------------------------*/ +Beam::~Beam() {} + + +#ifdef ARCHICAD +/*-------------------------------------------------------------------- + Get the (immutable) API element header data + + return: The element header data (only use this data for low-level operations - for normal code, call getters/setters) + --------------------------------------------------------------------*/ +const API_Elem_Head& Beam::getHead() const { + return m_data->root->head; +} //Beam::getHead + +/*-------------------------------------------------------------------- + Get the (mutable) API element header data + + return: The element header data (only use this data for low-level operations - for normal code, call getters/setters) + --------------------------------------------------------------------*/ +API_Elem_Head& Beam::getHead() { + return m_data->root->head; +} //Beam::getHead + + +/*-------------------------------------------------------------------- + Load the element memo structure (elements must override according to requirements) + + filter: Filter bits specifying memo requirements + --------------------------------------------------------------------*/ +void Beam::loadMemo(filter_bits filter, std::unique_ptr& memo) const { + //Establish the memo filter for this element + if (!SegmentedBeam::isMemoLoaded()) + filter |= SegmentedBeam::getPartFilter(); + Element::loadMemo(filter, memo); + //Receive the memo data into the element (when available) + if (memo) { + if (filter & SegmentedBeam::getPartFilter()) + SegmentedBeam::receive(*memo); + } + SegmentedBeam::setMemoLoaded(true); //Always mark the data as loaded to prevent repeated attempts on error +} //Beam::loadMemo +#endif + + +/*-------------------------------------------------------------------- + Fill an inventory with the package items + + inventory: The inventory to receive the package items + + return: True if the package has added items to the inventory + --------------------------------------------------------------------*/ +bool Beam::fillInventory(Inventory& inventory) const { + using enum Entry::Type; + inventory.merge(Inventory{ + { + { fieldID[segmentID], segmentID, getSegmentCount(), std::nullopt }, //TODO: implement other fields + }, + }.withType(&typeid(Beam))); + return base::fillInventory(inventory); +} //Beam::fillInventory + + +/*-------------------------------------------------------------------- + Get the specified cargo + + item: The inventory item to retrieve + + return: The requested cargo (nullptr on failure) + --------------------------------------------------------------------*/ +Cargo::Unique Beam::getCargo(const Inventory::Item& item) const { + if (item.ownerType != &typeid(Beam)) + return base::getCargo(item); + using namespace active::serialise; + switch (item.index) { + case segmentID: + if (auto segment = getSegment(item.available); segment != nullptr) { + return Cargo::Unique{new PackageWrap{*segment}}; + } else + return nullptr; + default: + return nullptr; //Requested an unknown index + } +} //Beam::getCargo + + +/*-------------------------------------------------------------------- + Set to the default package content + --------------------------------------------------------------------*/ +void Beam::setDefault() { + base::setDefault(); + m_data.reset(); +} //Beam::setDefault diff --git a/SpeckleLib/Speckle/Record/Element/Beam.h b/SpeckleLib/Speckle/Record/Element/Beam.h new file mode 100644 index 0000000..3c3b062 --- /dev/null +++ b/SpeckleLib/Speckle/Record/Element/Beam.h @@ -0,0 +1,137 @@ +#ifndef SPECKLE_RECORD_ELEMENT_BEAM +#define SPECKLE_RECORD_ELEMENT_BEAM + +#include "Speckle/Record/Element/BeamSegment.h" +#include "Speckle/Record/Element/Element.h" +#include "Speckle/Record/Element/Interface/Assembly/Path.h" +#include "Speckle/Record/Element/Interface/SegmentedBeam.h" + +namespace speckle::record::element { + + class BeamSegment; + + /*! + BIM beam class + */ + class Beam : public Element, public SegmentedBeam, public assembly::Path { + public: + + // MARK: - Types + + using base = Element; + ///Unique pointer + using Unique = std::unique_ptr; + ///Shared pointer + using Shared = std::shared_ptr; + ///Optional + using Option = std::optional; + + // MARK: - Constructors + + using base::base; + + /*! + Default constructor + */ + Beam(); +#ifdef ARCHICAD + /*! + Constructor + @param elemData Archicad element data + @param tableID The beam element ID (AC database, e.g. floor plan, 3D) + */ + Beam(const API_Element& elemData, const speckle::utility::Guid& tableID); +#endif + /*! + Copy constructor + @param source The object to copy + */ + Beam(const Beam& source); + /*! + Destructor + */ + ~Beam(); + + /*! + Object cloning + @return A clone of this object + */ + Beam* clonePtr() const override { return new Beam{*this}; } + + + // MARK: - Functions (const) + + /*! + Get the BIM application parent table ID + @return The BIM table ID + */ + virtual database::BIMRecordID getTableID() const override { return Element::getTableID(); } + /*! + Get the element body + @return nullptr (Beams don't explicitly have a 3D body - this comes from its child segments) + */ + virtual Body* getBody() const override { return nullptr; } + /*! + Get the number of segments in the path (elements must override according to requirements) + @return The segment count + */ + virtual size_t getSegmentCount() const override { return SegmentedBeam::getSegmentCount(); } + /*! + Get a segment from the path (elements must override according to requirements) + @param index The index of the required segment + @return The requested segment (nullptr on failure) + */ + virtual BeamSegment* getSegment(size_t index) const override { return SegmentedBeam::getSegment(index); } +#ifdef ARCHICAD + /*! + Get the (immutable) API element header data + @return The element header data (only use this data for low-level operations - for normal code, call getters/setters) + */ + const API_Elem_Head& getHead() const override; +#endif + + // MARK: - Functions (mutating) + +#ifdef ARCHICAD + /*! + Get the (mutable) API element header data + @return The element header data (only use this data for low-level operations - for normal code, call getters/setters) + */ + API_Elem_Head& getHead() override; +#endif + + // MARK: - Serialisation + + /*! + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ + bool fillInventory(active::serialise::Inventory& inventory) const override; + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + /*! + Set to the default package content + */ + void setDefault() override; + + protected: + /*! + Load the element memo structure (elements must override according to requirements) + @param filter Filter bits specifying memo requirements + */ + virtual void loadMemo(filter_bits filter, std::unique_ptr& memo) const override; + + private: + class Data; + ///The beam data + std::unique_ptr m_data; + }; + +} + +#endif //SPECKLE_RECORD_ELEMENT_BEAM diff --git a/SpeckleLib/Speckle/Record/Element/BeamSegment.cpp b/SpeckleLib/Speckle/Record/Element/BeamSegment.cpp new file mode 100644 index 0000000..b9bf172 --- /dev/null +++ b/SpeckleLib/Speckle/Record/Element/BeamSegment.cpp @@ -0,0 +1,159 @@ +#include "Speckle/Record/Element/BeamSegment.h" + +#include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Active/Serialise/Package/Wrapper/PackageWrap.h" +#include "Active/Serialise/Package/Wrapper/ContainerWrap.h" +#include "Speckle/Environment/Addon.h" +#include "Speckle/Primitive/Mesh/Mesh.h" +#include "Speckle/SpeckleResource.h" +#include "Speckle/Utility/Guid.h" + +#ifdef ARCHICAD +#include +#endif + +using namespace active::serialise; +using namespace speckle::environment; +using namespace speckle::record::attribute; +using namespace speckle::record::element; +using namespace speckle::utility; + +#include +#include + +namespace speckle::record::element { + + class BeamSegment::Data { + public: + friend class BeamSegment; + +#ifdef ARCHICAD + Data(const API_BeamSegmentType& seg) : root{ std::make_unique(seg) } {} + Data(const Data& source) : root{ std::make_unique(*source.root) } {} + + private: + std::unique_ptr root; +#endif + }; + +} + +/*-------------------------------------------------------------------- + Default constructor + --------------------------------------------------------------------*/ +BeamSegment::BeamSegment() { +} //BeamSegment::BeamSegment + + +#ifdef ARCHICAD +/*-------------------------------------------------------------------- + Constructor + + elemData: Archicad element data + tableID: The element table ID (AC database, e.g. floor plan, 3D) + --------------------------------------------------------------------*/ +BeamSegment::BeamSegment(const API_Element& elemData, const speckle::utility::Guid& tableID) : base{ elemData.header.guid, tableID } { + m_data = std::make_unique(elemData.beamSegment); +} //BeamSegment::BeamSegment + + +/*-------------------------------------------------------------------- + Constructor + + segment: The segment element data + tableID: The parent table ID + cutOrigin: Cut at the segment origin + cutEnd: Cut at the segment end + scheme: The segment scheme + profile: The segment profile (nullptr = none) + --------------------------------------------------------------------*/ +BeamSegment::BeamSegment(const API_BeamSegmentType& segment, const speckle::utility::Guid& tableID, const API_AssemblySegmentCutData& cutOrigin, + const API_AssemblySegmentCutData& cutEnd, const API_AssemblySegmentSchemeData& scheme, + const API_AssemblySegmentProfileData* profile) : + base{segment.head.guid, tableID}, assembly::Segment{cutOrigin, cutEnd, scheme, profile} { + m_data = std::make_unique(segment); +} //BeamSegment::BeamSegment +#endif + + +/*-------------------------------------------------------------------- + Copy constructor + + source: The object to copy + --------------------------------------------------------------------*/ +BeamSegment::BeamSegment(const BeamSegment& source) : base{ source } { + m_data = source.m_data ? std::make_unique(*source.m_data) : nullptr; +} //BeamSegment::BeamSegment + + +/*-------------------------------------------------------------------- + Move constructor + + source: The object to move + --------------------------------------------------------------------*/ +BeamSegment::BeamSegment(BeamSegment&& source) noexcept : base{source} { + m_data = std::move(source.m_data); +} //BeamSegment::BeamSegment + + +/*-------------------------------------------------------------------- + Destructor + --------------------------------------------------------------------*/ +BeamSegment::~BeamSegment() {} + + +#ifdef ARCHICAD +/*-------------------------------------------------------------------- + Get the (immutable) API element header data + + return: The element header data (only use this data for low-level operations - for normal code, call getters/setters) + --------------------------------------------------------------------*/ +const API_Elem_Head& BeamSegment::getHead() const { + return m_data->root->head; +} //BeamSegment::getHead + + +/*-------------------------------------------------------------------- + Get the (mutable) API element header data + + return: The element header data (only use this data for low-level operations - for normal code, call getters/setters) + --------------------------------------------------------------------*/ +API_Elem_Head& BeamSegment::getHead() { + return m_data->root->head; +} //BeamSegment::getHead +#endif + + +/*-------------------------------------------------------------------- + Fill an inventory with the package items + + inventory: The inventory to receive the package items + + return: True if the package has added items to the inventory + --------------------------------------------------------------------*/ +bool BeamSegment::fillInventory(Inventory& inventory) const { + using enum Entry::Type; + //TODO: Implement other fields as required + return base::fillInventory(inventory); +} //BeamSegment::fillInventory + + +/*-------------------------------------------------------------------- + Get the specified cargo + + item: The inventory item to retrieve + + return: The requested cargo (nullptr on failure) + --------------------------------------------------------------------*/ +Cargo::Unique BeamSegment::getCargo(const Inventory::Item& item) const { + //TODO: Implement other fields as required + return base::getCargo(item); +} //BeamSegment::getCargo + + +/*-------------------------------------------------------------------- + Set to the default package content + --------------------------------------------------------------------*/ +void BeamSegment::setDefault() { + m_data.reset(); +} //BeamSegment::setDefault diff --git a/SpeckleLib/Speckle/Record/Element/BeamSegment.h b/SpeckleLib/Speckle/Record/Element/BeamSegment.h new file mode 100644 index 0000000..58020dc --- /dev/null +++ b/SpeckleLib/Speckle/Record/Element/BeamSegment.h @@ -0,0 +1,130 @@ +#ifndef SPECKLE_RECORD_ELEMENT_BEAM_SEGMENT +#define SPECKLE_RECORD_ELEMENT_BEAM_SEGMENT + +#include "Speckle/Record/Element/Element.h" +#include "Speckle/Record/Element/Interface/Assembly/Segment.h" + +namespace speckle::record::element { + + class SegmentedBeam; + + /*! + BIM beam class + */ + class BeamSegment : public Element, public assembly::Segment { + public: + + // MARK: - Types + + using base = Element; + ///Unique pointer + using Unique = std::unique_ptr; + ///Shared pointer + using Shared = std::shared_ptr; + ///Optional + using Option = std::optional; + + // MARK: - Constructors + + using base::base; + + /*! + Default constructor + */ + BeamSegment(); +#ifdef ARCHICAD + /*! + Constructor + @param elemData Archicad element data + @param tableID The element table ID (AC database, e.g. floor plan, 3D) + */ + BeamSegment(const API_Element& elemData, const speckle::utility::Guid& tableID); +#endif + /*! + Copy constructor + @param source The object to copy + */ + BeamSegment(const BeamSegment& source); + /*! + Move constructor + @param source The object to move + */ + BeamSegment(BeamSegment&& source) noexcept; + /*! + Destructor + */ + ~BeamSegment(); + + /*! + Object cloning + @return A clone of this object + */ + BeamSegment* clonePtr() const override { return new BeamSegment{*this}; } + + + // MARK: - Functions (const) + +#ifdef ARCHICAD + /*! + Get the (immutable) API element header data + @return The element header data (only use this data for low-level operations - for normal code, call getters/setters) + */ + const API_Elem_Head& getHead() const override; +#endif + + // MARK: - Functions (mutating) + +#ifdef ARCHICAD + /*! + Get the (mutable) API element header data + @return The element header data (only use this data for low-level operations - for normal code, call getters/setters) + */ + API_Elem_Head& getHead() override; +#endif + + // MARK: - Serialisation + + /*! + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ + bool fillInventory(active::serialise::Inventory& inventory) const override; + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + /*! + Set to the default package content + */ + void setDefault() override; + + protected: + friend class SegmentedBeam; + +#ifdef ARCHICAD + /*! + Constructor + @param segment The segment element data + @param tableID The parent table ID + @param cutOrigin Cut at the segment origin + @param cutEnd Cut at the segment end + @param scheme The segment scheme + @param profile The segment profile (nullptr = none) + */ + BeamSegment(const API_BeamSegmentType& segment, const speckle::utility::Guid& tableID, const API_AssemblySegmentCutData& cutOrigin, + const API_AssemblySegmentCutData& cutEnd, const API_AssemblySegmentSchemeData& scheme, + const API_AssemblySegmentProfileData* profile = nullptr); +#endif + + private: + class Data; + ///The beam data + std::unique_ptr m_data; + }; + +} + +#endif //SPECKLE_RECORD_ELEMENT_BEAM_SEGMENT diff --git a/SpeckleLib/Speckle/Record/Element/Interface/SegmentedBeam.cpp b/SpeckleLib/Speckle/Record/Element/Interface/SegmentedBeam.cpp new file mode 100644 index 0000000..8c14b60 --- /dev/null +++ b/SpeckleLib/Speckle/Record/Element/Interface/SegmentedBeam.cpp @@ -0,0 +1,160 @@ +#include "Speckle/Record/Element/Interface/SegmentedBeam.h" + +#include "Speckle/Record/Element/BeamSegment.h" +#include "Speckle/Record/Element/Memo.h" +#include "Speckle/Record/Element/Interface/Assembly/Path.h" +#include "Speckle/Utility/BIMMemory.h" + +using namespace active::serialise; +using namespace speckle::record::attribute; +using namespace speckle::record::element; +using namespace speckle::utility; + +namespace speckle::record::element { + + class SegmentedBeam::Data { + public: + friend class SegmentedBeam; + + std::vector segments; + }; + +} + +/*-------------------------------------------------------------------- + Default constructor + --------------------------------------------------------------------*/ +SegmentedBeam::SegmentedBeam() { +} //SegmentedBeam::SegmentedBeam + + +/*-------------------------------------------------------------------- + Copy constructor + + source: The object to copy + --------------------------------------------------------------------*/ +SegmentedBeam::SegmentedBeam(const SegmentedBeam& source) : base{ source } { + m_data = source.m_data ? std::make_unique(*m_data) : nullptr; +} //SegmentedBeam::SegmentedBeam + + +/*-------------------------------------------------------------------- + Destructor + --------------------------------------------------------------------*/ +SegmentedBeam::~SegmentedBeam() {} + + +/*-------------------------------------------------------------------- + Get the number of segments + + return. The number of segments (0 on error) + --------------------------------------------------------------------*/ +size_t SegmentedBeam::getSegmentCount() const { + confirmPart(getPartFilter()); + return m_data ? m_data->segments.size() : 0; +} //SegmentedBeam::getSegmentCount + + +/*-------------------------------------------------------------------- + Get a beam segment + + index: The index of the required segment + + return: The requested segment, nullptr on error + --------------------------------------------------------------------*/ +BeamSegment* SegmentedBeam::getSegment(size_t index) const { + confirmPart(getPartFilter()); + return (m_data && (index < m_data->segments.size())) ? &m_data->segments[index] : nullptr; +} //SegmentedBeam::getSegment + + +/*-------------------------------------------------------------------- + Return the bits for the part filter required to load the data necessary to build this object + + return: The required filter bits + --------------------------------------------------------------------*/ +Part::filter_bits SegmentedBeam::getPartFilter() const { +#ifdef ARCHICAD + return APIMemoMask_BeamSegment | APIMemoMask_AssemblySegmentCut | APIMemoMask_AssemblySegmentScheme | APIMemoMask_AssemblySegmentProfile; +#endif +} //SegmentedBeam::getPartFilter + + +/*-------------------------------------------------------------------- + Determine if the element memo content has been validated (elements must override according to requirements) + + return: True if the element memo content is valid + --------------------------------------------------------------------*/ +bool SegmentedBeam::isPartValid() const { + return m_data && !m_data->segments.empty(); +} //SegmentedBeam::isPartValid + + +/*-------------------------------------------------------------------- + Load the element memo structure (elements must override according to requirements) + + filter: Filter bits specifying memo requirements + --------------------------------------------------------------------*/ +void SegmentedBeam::loadMemo(filter_bits filter, std::unique_ptr& memo) const { + +} //SegmentedBeam::loadMemo + + +/*-------------------------------------------------------------------- + Send the element part back to a memo structure for storage (elements must override according to requirements) + + memo: The memo to carry the data + + return: True if the data was successfully sent + --------------------------------------------------------------------*/ +bool SegmentedBeam::send(Memo* memo) const { + //TODO: Complete when required + return false; +} //SegmentedBeam::send + + +/*-------------------------------------------------------------------- + Receive the element memo data from a memo structure (elements must override according to requirements) + + memo: The memo carrying the data + + return: True if the data was successfully received + --------------------------------------------------------------------*/ +bool SegmentedBeam::receive(const Memo& memo) const { +#ifdef ARCHICAD + if (!memo || (memo.root()->beamSegments == nullptr)) + return false; + if (m_data) + m_data->segments.clear(); + else + m_data = std::make_unique(); + //Confirm that required data is present in the memo + auto segmentPtr = memo.root()->beamSegments; + auto cutPtr = memo.root()->assemblySegmentCuts; + auto schemePtr = memo.root()->assemblySegmentSchemes; + auto profilePtr = memo.root()->assemblySegmentProfiles; + if ((segmentPtr == nullptr) || (cutPtr == nullptr) || (schemePtr == nullptr)) + return false; + //Determine available item count + auto segmentCount = BIMMemory::getPtrSize(segmentPtr) / sizeof(API_BeamSegmentType); + auto cutCount = BIMMemory::getPtrSize(cutPtr) / sizeof(API_AssemblySegmentCutData); + auto schemeCount = BIMMemory::getPtrSize(schemePtr) / sizeof(API_AssemblySegmentSchemeData); + auto profileCount = BIMMemory::getPtrSize(profilePtr) / sizeof(API_AssemblySegmentProfileData); + if ((segmentCount == 0) || (cutCount != (segmentCount + 1)) || (schemeCount != segmentCount)) + return false; + auto path = dynamic_cast(this); + for (size_t n = 0 ; n < segmentCount; ++n) { + const API_AssemblySegmentProfileData* thisProfile = nullptr; + for (size_t i = 0; i < profileCount; ++i) { + if (profilePtr[i].segmentIndex == n) { + thisProfile = profilePtr + i; + break; + } + } + m_data->segments.emplace_back(BeamSegment{segmentPtr[n], getTableID(), cutPtr[n], cutPtr[n + 1], schemePtr[n], thisProfile}); + m_data->segments.back().setPath(path); + } + setMemoLoaded(true); +#endif + return true; +} //SegmentedBeam::receive diff --git a/SpeckleLib/Speckle/Record/Element/Interface/SegmentedBeam.h b/SpeckleLib/Speckle/Record/Element/Interface/SegmentedBeam.h new file mode 100644 index 0000000..1c7a5fd --- /dev/null +++ b/SpeckleLib/Speckle/Record/Element/Interface/SegmentedBeam.h @@ -0,0 +1,103 @@ +#ifndef SPECKLE_RECORD_ELEMENT_SEGMENTED_BEAM +#define SPECKLE_RECORD_ELEMENT_SEGMENTED_BEAM + +#include "Speckle/Database/Identity/BIMRecordID.h" +#include "Speckle/Record/Element/Interface/Part.h" + +namespace speckle::record::element { + + class BeamSegment; + + /*! + Interface for a beam type that is made up of consecutive segments + + Note that the child segments use lazy loading to avoid high overheads when accessing data relevant to the parent beam only + */ + class SegmentedBeam : public Part { + public: + + // MARK: - Types + + using base = Part; + ///Unique pointer + using Unique = std::unique_ptr; + ///Shared pointer + using Shared = std::shared_ptr; + ///Optional + using Option = std::optional; + + // MARK: - Constructors + + /*! + Default constructor + */ + SegmentedBeam(); + /*! + Copy constructor + @param source The object to copy + */ + SegmentedBeam(const SegmentedBeam& source); + /*! + Destructor + */ + ~SegmentedBeam(); + + // MARK: - Functions (const) + + /*! + Get the BIM application parent table ID + @return The BIM table ID + */ + virtual database::BIMRecordID getTableID() const = 0; + /*! + Get the number of segments + @return The number of segments (0 on error) + */ + size_t getSegmentCount() const; + /*! + Get a beam segment + @param index The index of the required segment + @return The requested segment, nullptr on error + */ + BeamSegment* getSegment(size_t index) const; + + // MARK: - Functions (mutating) + + protected: + /*! + Return the bits for the part filter required to load the data necessary to build this object + @return The required filter bits */ + filter_bits getPartFilter() const; + /*! + Determine if the element part content has been validated (elements must override according to requirements) + @return True if the element part content is valid + */ + bool isPartValid() const override; + /*! + Load the element memo structure (elements must override according to requirements) + @param filter Filter bits specifying memo requirements + */ + void loadMemo(filter_bits filter, std::unique_ptr& memo) const override; + + /*! + Send the element part back to a memo structure for storage (elements must override according to requirements) + @param memo The memo to carry the data + @return True if the data was successfully sent + */ + bool send(Memo* memo) const override; + /*! + Receive the element memo data from a memo structure (elements must override according to requirements) + @param memo The memo carrying the data + @return True if the data was successfully received + */ + bool receive(const Memo& memo) const override; + + private: + class Data; + ///The segment data - mutable to support lazy loading + mutable std::unique_ptr m_data; + }; + +} + +#endif //SPECKLE_RECORD_ELEMENT_SEGMENTED_BEAM diff --git a/SpeckleLib/SpeckleLib17.vcxproj b/SpeckleLib/SpeckleLib17.vcxproj index 22f73ca..f452892 100644 --- a/SpeckleLib/SpeckleLib17.vcxproj +++ b/SpeckleLib/SpeckleLib17.vcxproj @@ -71,6 +71,8 @@ + + @@ -78,6 +80,7 @@ + @@ -133,6 +136,8 @@ + + @@ -140,6 +145,7 @@ + diff --git a/SpeckleLib/SpeckleLib17.vcxproj.filters b/SpeckleLib/SpeckleLib17.vcxproj.filters index 6550add..8388696 100644 --- a/SpeckleLib/SpeckleLib17.vcxproj.filters +++ b/SpeckleLib/SpeckleLib17.vcxproj.filters @@ -343,6 +343,15 @@ Speckle\Record\Element + + Speckle\Record\Element\Interface + + + Speckle\Record\Element + + + Speckle\Record\Element + @@ -498,6 +507,15 @@ Speckle\Record\Element + + Speckle\Record\Element\Interface + + + Speckle\Record\Element + + + Speckle\Record\Element + From 5363819e8de5b3776ba56a8f6bbd62011d481a2d Mon Sep 17 00:00:00 2001 From: David Kekesi Date: Mon, 21 Oct 2024 16:35:30 +0200 Subject: [PATCH 070/191] BaseBridge listens to project events --- .../Browser/Bridge/Base/BaseBridge.cpp | 20 ++++++++++++++++++- .../Browser/Bridge/Base/BaseBridge.h | 12 ++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/BaseBridge.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/BaseBridge.cpp index f40155f..881298f 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/BaseBridge.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/BaseBridge.cpp @@ -1,5 +1,4 @@ #include "Connector/Interface/Browser/Bridge/Base/BaseBridge.h" - #include "Connector/Interface/Browser/Bridge/Base/AddModel.h" #include "Connector/Interface/Browser/Bridge/Base/GetConnectorVersion.h" #include "Connector/Interface/Browser/Bridge/Base/GetDocumentInfo.h" @@ -25,3 +24,22 @@ BaseBridge::BaseBridge() : BrowserBridge{"baseBinding"} { addMethod(); addMethod(); } //BaseBridge::BaseBridge + +/*-------------------------------------------------------------------- + Handle a project event + + event: The project event + + return: True if the event should be closed + --------------------------------------------------------------------*/ +bool BaseBridge::handle(const speckle::event::ProjectEvent& event) { + using enum speckle::event::ProjectEvent::Type; + switch (event.getType()) { + case close: + sendEvent("documentChanged"); + break; + default: + break; + } + return false; +} //BaseBridge::handle diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/BaseBridge.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/BaseBridge.h index e7076a4..72e3d7e 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/BaseBridge.h +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/BaseBridge.h @@ -2,13 +2,15 @@ #define CONNECTOR_INTERFACE_BRIDGE_BASE_BRIDGE #include "Speckle/Interface/Browser/Bridge/BrowserBridge.h" +#include "Speckle/Event/Subscriber/ProjectSubscriber.h" +#include "Speckle/Event/Type/ProjectEvent.h" namespace connector::interfac::browser::bridge { /*! A browser bridge to provide configuration settings */ - class BaseBridge : public speckle::interfac::browser::bridge::BrowserBridge { + class BaseBridge : public speckle::interfac::browser::bridge::BrowserBridge, public speckle::event::ProjectSubscriber { public: // MARK: - Types @@ -22,6 +24,14 @@ namespace connector::interfac::browser::bridge { Default constructor */ BaseBridge(); + + protected: + /*! + Handle the project events + @param event The project event + @return True if the event should be closed + */ + bool handle(const speckle::event::ProjectEvent& event) override; }; } From 6d14607634a3e3e511b6612b4ab676bb36ed35ae Mon Sep 17 00:00:00 2001 From: David Kekesi Date: Mon, 21 Oct 2024 16:36:39 +0200 Subject: [PATCH 071/191] bridge listens to open event instead of close --- .../Connector/Interface/Browser/Bridge/Base/BaseBridge.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/BaseBridge.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/BaseBridge.cpp index 881298f..8b56236 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/BaseBridge.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/BaseBridge.cpp @@ -35,7 +35,7 @@ BaseBridge::BaseBridge() : BrowserBridge{"baseBinding"} { bool BaseBridge::handle(const speckle::event::ProjectEvent& event) { using enum speckle::event::ProjectEvent::Type; switch (event.getType()) { - case close: + case open: sendEvent("documentChanged"); break; default: From 35f4e58a5862b2fc0293e7e52834130a58565606 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Mon, 21 Oct 2024 16:25:23 +0100 Subject: [PATCH 072/191] Added BIM property database + engine Added property classes including: - templates - settings - values Added Classified interface for records supporting classification Added Propertied interface for records supporting attached properties Distinguished model elements from drawing elements (only model elements support classification/properties) with: - DrawingElement (2D only) - ModelElement (having a 3D/model presence) --- .../Speckle/Database/BIMAttributeDatabase.h | 5 - .../Speckle/Database/BIMPropertyDatabase.cpp | 141 +++++++++ .../Speckle/Database/BIMPropertyDatabase.h | 83 ++++++ .../Speckle/Database/Identity/BIMRecordID.h | 8 +- .../ArchicadAttributeDBaseEngine.cpp | 1 + .../Attribute/ArchicadAttributeDBaseEngine.h | 1 + .../Element/ArchicadElementDBaseEngine.cpp | 4 +- .../Element/ArchicadElementDBaseEngine.h | 1 + .../Property/ArchicadPropertyDBaseEngine.cpp | 256 +++++++++++++++++ .../Property/ArchicadPropertyDBaseEngine.h | 143 +++++++++ SpeckleLib/Speckle/Environment/Project.cpp | 4 +- SpeckleLib/Speckle/Environment/Project.h | 14 +- .../Record/Classification/Classified.cpp | 30 ++ .../Record/Classification/Classified.h | 48 ++++ SpeckleLib/Speckle/Record/Element/Column.cpp | 2 +- SpeckleLib/Speckle/Record/Element/Column.h | 8 +- .../Speckle/Record/Element/ColumnSegment.h | 6 +- ...{GenericElement.cpp => DrawingElement.cpp} | 79 ++--- .../{GenericElement.h => DrawingElement.h} | 29 +- SpeckleLib/Speckle/Record/Element/Element.cpp | 157 +--------- SpeckleLib/Speckle/Record/Element/Element.h | 13 - .../Record/Element/GenericDrawingElement.cpp | 122 ++++++++ .../Record/Element/GenericDrawingElement.h | 104 +++++++ .../Record/Element/GenericModelElement.cpp | 122 ++++++++ .../Record/Element/GenericModelElement.h | 103 +++++++ .../Speckle/Record/Element/ModelElement.cpp | 272 ++++++++++++++++++ .../Speckle/Record/Element/ModelElement.h | 119 ++++++++ .../Speckle/Record/Property/Propertied.cpp | 83 ++++++ .../Speckle/Record/Property/Propertied.h | 57 ++++ .../Speckle/Record/Property/Property.cpp | 132 +++++++++ SpeckleLib/Speckle/Record/Property/Property.h | 103 +++++++ .../Speckle/Record/Property/Setting.cpp | 87 ++++++ SpeckleLib/Speckle/Record/Property/Setting.h | 127 ++++++++ .../Speckle/Record/Property/Template.cpp | 210 ++++++++++++++ SpeckleLib/Speckle/Record/Property/Template.h | 192 +++++++++++++ SpeckleLib/Speckle/Record/Property/Value.cpp | 189 ++++++++++++ SpeckleLib/Speckle/Record/Property/Value.h | 140 +++++++++ SpeckleLib/Speckle/Utility/Guid.h | 16 ++ .../SpeckleLib.xcodeproj/project.pbxproj | 130 ++++++++- 39 files changed, 3070 insertions(+), 271 deletions(-) create mode 100644 SpeckleLib/Speckle/Database/BIMPropertyDatabase.cpp create mode 100644 SpeckleLib/Speckle/Database/BIMPropertyDatabase.h create mode 100644 SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Property/ArchicadPropertyDBaseEngine.cpp create mode 100644 SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Property/ArchicadPropertyDBaseEngine.h create mode 100644 SpeckleLib/Speckle/Record/Classification/Classified.cpp create mode 100644 SpeckleLib/Speckle/Record/Classification/Classified.h rename SpeckleLib/Speckle/Record/Element/{GenericElement.cpp => DrawingElement.cpp} (65%) rename SpeckleLib/Speckle/Record/Element/{GenericElement.h => DrawingElement.h} (70%) create mode 100644 SpeckleLib/Speckle/Record/Element/GenericDrawingElement.cpp create mode 100644 SpeckleLib/Speckle/Record/Element/GenericDrawingElement.h create mode 100644 SpeckleLib/Speckle/Record/Element/GenericModelElement.cpp create mode 100644 SpeckleLib/Speckle/Record/Element/GenericModelElement.h create mode 100644 SpeckleLib/Speckle/Record/Element/ModelElement.cpp create mode 100644 SpeckleLib/Speckle/Record/Element/ModelElement.h create mode 100644 SpeckleLib/Speckle/Record/Property/Propertied.cpp create mode 100644 SpeckleLib/Speckle/Record/Property/Propertied.h create mode 100644 SpeckleLib/Speckle/Record/Property/Property.cpp create mode 100644 SpeckleLib/Speckle/Record/Property/Property.h create mode 100644 SpeckleLib/Speckle/Record/Property/Setting.cpp create mode 100644 SpeckleLib/Speckle/Record/Property/Setting.h create mode 100644 SpeckleLib/Speckle/Record/Property/Template.cpp create mode 100644 SpeckleLib/Speckle/Record/Property/Template.h create mode 100644 SpeckleLib/Speckle/Record/Property/Value.cpp create mode 100644 SpeckleLib/Speckle/Record/Property/Value.h diff --git a/SpeckleLib/Speckle/Database/BIMAttributeDatabase.h b/SpeckleLib/Speckle/Database/BIMAttributeDatabase.h index 0a28b89..17fe657 100644 --- a/SpeckleLib/Speckle/Database/BIMAttributeDatabase.h +++ b/SpeckleLib/Speckle/Database/BIMAttributeDatabase.h @@ -31,11 +31,6 @@ namespace speckle::database { // MARK: - Functions (const) - /*! - Get the current user attribute selection - @return A list of selected attribute IDs - */ - BIMLinkList getSelection() const; /*! Get a specified attribute @param attributeID The ID of the target attribute diff --git a/SpeckleLib/Speckle/Database/BIMPropertyDatabase.cpp b/SpeckleLib/Speckle/Database/BIMPropertyDatabase.cpp new file mode 100644 index 0000000..ffb0f5f --- /dev/null +++ b/SpeckleLib/Speckle/Database/BIMPropertyDatabase.cpp @@ -0,0 +1,141 @@ +#include "Speckle/Database/BIMPropertyDatabase.h" + +#include "Active/Database/Storage/Storage.h" +#include "Active/Serialise/UnboxedTransport.h" +#include "Speckle/Database/Identity/RecordID.h" +#include "Speckle/Database/Storage/ArchicadDBase/Property/ArchicadPropertyDBaseEngine.h" +#include "Speckle/Record/Property/Setting.h" + +#include + +using namespace active::container; +using namespace active::database; +using namespace active::event; +using namespace active::serialise; +using namespace speckle::database; +using namespace speckle::record; +using namespace speckle::record::property; +using namespace speckle::database; +using namespace speckle::utility; + +namespace speckle::database { + + ///Define other platform engines here as required +#ifdef ARCHICAD + using PropertyDatabaseEngine = ArchicadPropertyDBaseEngine; +#endif + + ///Property database engine declaration + class BIMPropertyDatabase::Engine : public PropertyDatabaseEngine { + using base = ArchicadPropertyDBaseEngine; + using base::base; + }; + + ///Property database storage declaration + class BIMPropertyDatabase::Store : public Storage { + using base = Storage; + using base::base; + }; + +} + +namespace { + + ///The database storage identifier for properties + const char* propertyDBaseName = "speckle::database::BIMPropertyDatabase"; + ///The primary model table, e.g. floor plan in Archicad + const char* modelTableName = "Model"; + +} + +/*-------------------------------------------------------------------- + Constructor + --------------------------------------------------------------------*/ +BIMPropertyDatabase::BIMPropertyDatabase() { + m_engine = std::make_shared(propertyDBaseName, + //Schema + DBaseSchema{active::utility::String{propertyDBaseName}, + //Tables + { + //Model property table + { + modelTableName, 0, 0, {} //The primary model. Additonal tables could be linked to other drawings/layouts in future + } + } + } + ); + m_store = std::make_shared(m_engine); +} //BIMPropertyDatabase::BIMPropertyDatabase + + +/*-------------------------------------------------------------------- + Destructor + --------------------------------------------------------------------*/ +BIMPropertyDatabase::~BIMPropertyDatabase() {} + + +/*-------------------------------------------------------------------- + Get a specified property + + propertyID: The ID of the target property + + return: The requested property (nullptr on failure) + --------------------------------------------------------------------*/ +Template::Unique BIMPropertyDatabase::getProperty(const BIMRecordID& propertyID, std::optional tableID, + std::optional documentID) const { + return m_engine->getObject(propertyID, tableID, documentID); +} //BIMPropertyDatabase::getProperty + + +/*-------------------------------------------------------------------- + Get a specified property + + link: A link to the target property + + return: The requested property (nullptr on failure) + --------------------------------------------------------------------*/ +Template::Unique BIMPropertyDatabase::getProperty(const BIMLink& link) const { + return getProperty(link, link.tableID, link.docID); +} //BIMPropertyDatabase::getProperty + + +/*-------------------------------------------------------------------- + Get all properties + + return: All the properties + --------------------------------------------------------------------*/ +Vector