From e54962e76fdf6e9d73e1f83c2b82eda959c09c70 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Tue, 15 Oct 2024 21:05:57 +0100 Subject: [PATCH 1/5] 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 2/5] 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 3/5] 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 4/5] 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 5/5] 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