From 72cd75d2e645302739cd3e3af58910a983d09d07 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Fri, 4 Oct 2024 21:03:54 +0100 Subject: [PATCH] Added speckle_type and unit properties to Record, BIMRecord, Element and Mesh classes Defined (de)serialisation for LengthType --- .../Browser/Bridge/Base/Arg/DocumentInfo.h | 20 ++-- .../Speckle/Database/Content/BIMRecord.cpp | 20 +++- .../Speckle/Database/Content/BIMRecord.h | 23 ++-- .../Speckle/Database/Content/Record.cpp | 4 +- SpeckleLib/Speckle/Database/Content/Record.h | 6 +- SpeckleLib/Speckle/Primitive/Mesh/Mesh.h | 15 ++- SpeckleLib/Speckle/Record/Element/Element.h | 49 ++++---- .../Speckle/Serialise/Units/LengthUnit.cpp | 55 +++++++++ .../Speckle/Serialise/Units/LengthUnit.h | 107 ++++++++++++++++++ .../SpeckleLib.xcodeproj/project.pbxproj | 14 +++ 10 files changed, 262 insertions(+), 51 deletions(-) create mode 100644 SpeckleLib/Speckle/Serialise/Units/LengthUnit.cpp create mode 100644 SpeckleLib/Speckle/Serialise/Units/LengthUnit.h diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/Arg/DocumentInfo.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/Arg/DocumentInfo.h index 56ac1b5..84b9848 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/Arg/DocumentInfo.h +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/Arg/DocumentInfo.h @@ -39,20 +39,20 @@ namespace connector::interfac::browser::bridge { // MARK: - Serialisation /*! - Fill an inventory with the package items - @param inventory The inventory to receive the package items - @return True if the package has added items to the inventory - */ + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ bool fillInventory(active::serialise::Inventory& inventory) const override; /*! - Get the specified cargo - @param item The inventory item to retrieve - @return The requested cargo (nullptr on failure) - */ + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; /*! - Set to the default package content - */ + Set to the default package content + */ void setDefault() override; }; diff --git a/SpeckleLib/Speckle/Database/Content/BIMRecord.cpp b/SpeckleLib/Speckle/Database/Content/BIMRecord.cpp index b6a7100..dcc55d1 100644 --- a/SpeckleLib/Speckle/Database/Content/BIMRecord.cpp +++ b/SpeckleLib/Speckle/Database/Content/BIMRecord.cpp @@ -1,5 +1,7 @@ #include "Speckle/Database/Content/BIMRecord.h" +#include "Active/Serialise/Item/Wrapper/ValueOptionWrap.h" +#include "Speckle/Serialise/Units/LengthUnit.h" #include "Speckle/Utility/Guid.h" #include @@ -8,16 +10,20 @@ using namespace active::serialise; using namespace speckle::database; using namespace speckle::utility; +using enum active::measure::LengthType; + namespace { ///Serialisation fields enum FieldIndex { applicID, + unitID, }; ///Serialisation field IDs static std::array fieldID = { Identity{"applicationId"}, + Identity{"unit"}, }; } @@ -33,7 +39,8 @@ bool BIMRecord::fillInventory(Inventory& inventory) const { using enum Entry::Type; inventory.merge(Inventory{ { - { Identity{fieldID[applicID]}, applicID, element }, + { Identity{fieldID[applicID]}, applicID, element, !m_applicationID.empty() }, + { Identity{fieldID[unitID]}, unitID, element, m_unit.operator bool() }, }, }.withType(&typeid(BIMRecord))); return base::fillInventory(inventory); @@ -54,7 +61,18 @@ Cargo::Unique BIMRecord::getCargo(const Inventory::Item& item) const { switch (item.index) { case applicID: return std::make_unique>(m_applicationID); + case unitID: + return std::make_unique>(m_unit); default: return nullptr; //Requested an unknown index } } //BIMRecord::getCargo + + +/*-------------------------------------------------------------------- + Set to the default package content + --------------------------------------------------------------------*/ +void BIMRecord::setDefault() { + m_applicationID.clear(); + m_unit.reset(); +} //BIMRecord::setDefault diff --git a/SpeckleLib/Speckle/Database/Content/BIMRecord.h b/SpeckleLib/Speckle/Database/Content/BIMRecord.h index 133912a..c9bee26 100644 --- a/SpeckleLib/Speckle/Database/Content/BIMRecord.h +++ b/SpeckleLib/Speckle/Database/Content/BIMRecord.h @@ -1,6 +1,7 @@ #ifndef SPECKLE_DATABASE_BIM_RECORD #define SPECKLE_DATABASE_BIM_RECORD +#include "Active/Setting/Values/Measurement/Units/LengthUnit.h" #include "Speckle/Database/Content/Record.h" #include "Speckle/Database/Identity/Link.h" #include "Speckle/Database/Identity/BIMRecordID.h" @@ -58,21 +59,27 @@ namespace speckle::database { // MARK: - Serialisation /*! - Fill an inventory with the package items - @param inventory The inventory to receive the package items - @return True if the package has added items to the inventory - */ + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ bool fillInventory(active::serialise::Inventory& inventory) const override; /*! - Get the specified cargo - @param item The inventory item to retrieve - @return The requested cargo (nullptr on failure) - */ + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + /*! + Set to the default package content + */ + void setDefault() override; private: ///The BIM application record ID BIMRecordID m_applicationID; + ///The BIM record unit of length measurement + std::optional m_unit = active::measure::LengthType::metre; }; } diff --git a/SpeckleLib/Speckle/Database/Content/Record.cpp b/SpeckleLib/Speckle/Database/Content/Record.cpp index ea79570..e515c45 100644 --- a/SpeckleLib/Speckle/Database/Content/Record.cpp +++ b/SpeckleLib/Speckle/Database/Content/Record.cpp @@ -35,12 +35,12 @@ bool Record::fillInventory(active::serialise::Inventory& inventory) const { using enum Entry::Type; inventory.merge(Inventory{ { - { Identity{fieldID[speckleIDID]}, active::database::record::FieldIndex::idIndex, element }, + { Identity{fieldID[speckleIDID]}, active::database::record::FieldIndex::idIndex, element, !getID().empty() }, }, }.withType(&typeid(base))); inventory.merge(Inventory{ { - { Identity{fieldID[speckleTypeID]}, speckleTypeID, element }, + { Identity{fieldID[speckleTypeID]}, speckleTypeID, element, !m_type.operator bool() }, }, }.withType(&typeid(Record))); return true; diff --git a/SpeckleLib/Speckle/Database/Content/Record.h b/SpeckleLib/Speckle/Database/Content/Record.h index f609223..fa76191 100644 --- a/SpeckleLib/Speckle/Database/Content/Record.h +++ b/SpeckleLib/Speckle/Database/Content/Record.h @@ -31,8 +31,8 @@ namespace speckle::database { @param globID The global ID */ Record(speckle::utility::String::Option ID = std::nullopt, speckle::utility::String::Option globID = std::nullopt) : - base{ID.value_or(active::utility::Guid{true}.operator active::utility::String()), - globID.value_or(active::utility::Guid{true}.operator active::utility::String())} {} + base{ID.value_or(active::utility::Guid{}.operator active::utility::String()), + globID.value_or(active::utility::Guid{}.operator active::utility::String())} {} /*! Destructor */ @@ -44,7 +44,7 @@ namespace speckle::database { Get the speckle type identifier @return The speckle type (relevant objects should override as required, but "Base" is still considered a type on its own) */ - virtual speckle::utility::String getSpeckleType() const { return "Base"; } + virtual speckle::utility::String getSpeckleType() const { return "speckle::database::Record"; } // MARK: - Functions (mutating) diff --git a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h index 72035e2..1b56f13 100644 --- a/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h +++ b/SpeckleLib/Speckle/Primitive/Mesh/Mesh.h @@ -1,15 +1,15 @@ #ifndef SPECKLE_PRIMITIVE_MESH #define SPECKLE_PRIMITIVE_MESH -#include "Active/Serialise/Package/Package.h" +#include "Speckle/Database/Content/Record.h" #include "Speckle/Utility/String.h" namespace speckle::primitive { /*! Class for a 3D mesh - */ - class Mesh : public active::serialise::Package { + */ + class Mesh : public speckle::database::Record { public: // MARK: - Constructors @@ -24,6 +24,11 @@ namespace speckle::primitive { // MARK: - Functions (const) + /*! + Get the speckle type identifier + @return The speckle type (relevant objects should override as required) + */ + speckle::utility::String getSpeckleType() const override { return "speckle::primitive::Mesh"; } // MARK: - Serialisation @@ -31,13 +36,13 @@ namespace speckle::primitive { Fill an inventory with the package items @param inventory The inventory to receive the package items @return True if the package has added items to the inventory - */ + */ bool fillInventory(active::serialise::Inventory& inventory) const override; /*! Get the specified cargo @param item The inventory item to retrieve @return The requested cargo (nullptr on failure) - */ + */ active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; private: diff --git a/SpeckleLib/Speckle/Record/Element/Element.h b/SpeckleLib/Speckle/Record/Element/Element.h index 59990f4..26b26f2 100644 --- a/SpeckleLib/Speckle/Record/Element/Element.h +++ b/SpeckleLib/Speckle/Record/Element/Element.h @@ -55,24 +55,29 @@ namespace speckle::record::element { ~Element(); /*! - Object cloning - @return A clone of this object - */ + Object cloning + @return A clone of this object + */ Element* clonePtr() const override { return new Element{*this}; } // MARK: - Functions (const) /*! - Get the element body - @return An array of meshes from the element body (nullptr if no body data is available) - */ + Get the speckle type identifier + @return The speckle type (relevant objects should override as required) + */ + speckle::utility::String getSpeckleType() const override { return "speckle::record::element::Element"; } + /*! + Get the element body + @return An array of meshes from the element body (nullptr if no body data is available) + */ virtual Body* getBody() const; #ifdef ARCHICAD /*! - Get the (immutable) API element header data - @return The element header data (only use this data for low-level operations - for normal code, call getters/setters) - */ + Get the (immutable) API element header data + @return The element header data (only use this data for low-level operations - for normal code, call getters/setters) + */ virtual const API_Elem_Head& getHead() const; #endif @@ -80,29 +85,29 @@ namespace speckle::record::element { #ifdef ARCHICAD /*! - Get the (mutable) API element header data - @return The element header data (only use this data for low-level operations - for normal code, call getters/setters) - */ + Get the (mutable) API element header data + @return The element header data (only use this data for low-level operations - for normal code, call getters/setters) + */ virtual API_Elem_Head& getHead(); #endif // MARK: - Serialisation /*! - Fill an inventory with the package items - @param inventory The inventory to receive the package items - @return True if the package has added items to the inventory - */ + Fill an inventory with the package items + @param inventory The inventory to receive the package items + @return True if the package has added items to the inventory + */ bool fillInventory(active::serialise::Inventory& inventory) const override; /*! - Get the specified cargo - @param item The inventory item to retrieve - @return The requested cargo (nullptr on failure) - */ + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; /*! - Set to the default package content - */ + Set to the default package content + */ void setDefault() override; private: diff --git a/SpeckleLib/Speckle/Serialise/Units/LengthUnit.cpp b/SpeckleLib/Speckle/Serialise/Units/LengthUnit.cpp new file mode 100644 index 0000000..bc71613 --- /dev/null +++ b/SpeckleLib/Speckle/Serialise/Units/LengthUnit.cpp @@ -0,0 +1,55 @@ +#include "Speckle/Serialise/Units/LengthUnit.h" + +#include +#include + +using namespace active::measure; +using namespace active::utility; + +using enum LengthType; + +namespace { + + //All recognised encoding types + std::map lengthNames = { + { millimetre, "mm" }, + { centimetre, "cm" }, + { metre, "m" }, + { kilometre, "km" }, + { inch, "in" }, + { foot, "ft" }, + { yard, "yd" }, + { mile, "ml" }, + }; + +} // namespace + +/*-------------------------------------------------------------------- + Convert a length unit name to a type + + name: The length unit name + + return: The length unit type (nullopt if no match found) + --------------------------------------------------------------------*/ +std::optional speckle::serialise::lengthUnitFromName(const String& name) { + if (auto match = std::find_if(lengthNames.begin(), lengthNames.end(), [&](const auto& i){ return (i.second == name); }); + match != lengthNames.end()) { + return match->first; + } + return std::nullopt; +} //encodingFromName + + +/*-------------------------------------------------------------------- + Convert a length unit type to a name + + lengthType: The length unit type + + return: The name of the length unit type (nullopt if no match found) + --------------------------------------------------------------------*/ +std::optional speckle::serialise::nameFromLengthUnit(LengthType lengthType) { + if (auto match = lengthNames.find(lengthType); match != lengthNames.end()) { + return match->second; + } + return std::nullopt; +} //nameFromEncoding diff --git a/SpeckleLib/Speckle/Serialise/Units/LengthUnit.h b/SpeckleLib/Speckle/Serialise/Units/LengthUnit.h new file mode 100644 index 0000000..417e928 --- /dev/null +++ b/SpeckleLib/Speckle/Serialise/Units/LengthUnit.h @@ -0,0 +1,107 @@ +#ifndef SPECKLE_SERIALISE_LENGTH_UNIT +#define SPECKLE_SERIALISE_LENGTH_UNIT + +#include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Active/Serialise/Item/Wrapper/ValueOptionWrap.h" +#include "Active/Setting/Values/Measurement/Units/LengthUnit.h" + +namespace speckle::serialise { + + /*! + Convert a length unit name to a type + @param name The length unit name + @return The length unit type (nullopt if no match found) + */ + std::optional lengthUnitFromName(const active::utility::String& name); + + + /*! + Convert a length unit type to a name + @param lengthType The length unit type + @return The name of the length unit type (nullopt if no match found) + */ + std::optional nameFromLengthUnit(active::measure::LengthType lengthType); + +} + + +namespace active::serialise { + + // MARK: - Specialisations for length types + + /*! + Read a length type value from the specified string + @param source The string to read + @return True if the data was successfully read + */ + inline std::pair readLengthTypeRefValue(const utility::String& source) { + using enum active::measure::LengthType; + if (auto converted = speckle::serialise::lengthUnitFromName(source); converted) + return {*converted, true}; + return {metre, false}; + } //ValueWrap::read + + + /*! + Import the object from the specified string (specialisation for length type) + @param source The string to read + @return True if the data was successfully read + */ + template<> inline + bool ValueWrap::read(const utility::String& source) { + auto result = readLengthTypeRefValue(source); + if (result.second) + base::get() = result.first; + return result.second; + } //ValueWrap::read + + + /*! + Import the object from the specified string (specialisation for length type) + @param source The string to read + @return True if the data was successfully read + */ + template<> inline + bool ValueOptionWrap::read(const utility::String& source) { + auto result = readLengthTypeRefValue(source); + if (result.second) + base::get() = result.first; + return result.second; + } //ValueWrap::read + + + /*! + Export the object to the specified string (specialisation for length type) + @param dest The string to write the data to + @return True if the data was successfully written + */ + template<> inline + bool ValueWrap::write(utility::String& dest) const { + if (auto name = speckle::serialise::nameFromLengthUnit(base::get()); name) { + dest = *name; + return true; + } + return false; + } //ValueWrap::write + + + /*! + Export the object to the specified string (specialisation for length type) + @param dest The string to write the data to + @return True if the data was successfully written + */ + template<> inline + bool ValueOptionWrap::write(utility::String& dest) const { + if (!base::get()) + return false; + if (auto name = speckle::serialise::nameFromLengthUnit(*base::get()); name) { + dest = *name; + return true; + } + return false; + } //ValueOptionWrap::write + + +} + +#endif //SPECKLE_SERIALISE_LENGTH_UNIT diff --git a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj index d4d6ea1..d67b1b9 100644 --- a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj +++ b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj @@ -36,6 +36,7 @@ 2193519B2C6278D900E5A69C /* SelectionSubscriber.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219351992C6278D900E5A69C /* SelectionSubscriber.cpp */; }; 219351B12C62CC1A00E5A69C /* Guid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219351AC2C62CC1A00E5A69C /* Guid.cpp */; }; 219351B32C62CC1A00E5A69C /* String.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219351AE2C62CC1A00E5A69C /* String.cpp */; }; + 2196F2E32CB05BAF00450DFC /* LengthUnit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2196F2E22CB05BAF00450DFC /* LengthUnit.cpp */; }; 2199881E2BD833830035E5EA /* libArchicad27.a in CopyFiles */ = {isa = PBXBuildFile; fileRef = 21379E082AE47A6400A1584C /* libArchicad27.a */; }; 21AEF9BA2CA606B5000B8681 /* DetachedReference.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9B92CA606B4000B8681 /* DetachedReference.cpp */; }; 21AEF9BC2CA6DF84000B8681 /* DetachmentManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9BB2CA6DF84000B8681 /* DetachmentManager.cpp */; }; @@ -162,6 +163,8 @@ 219351AD2C62CC1A00E5A69C /* Guid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Guid.h; sourceTree = ""; }; 219351AE2C62CC1A00E5A69C /* String.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = String.cpp; sourceTree = ""; }; 219351AF2C62CC1A00E5A69C /* String.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = String.h; sourceTree = ""; }; + 2196F2DE2CB0566500450DFC /* LengthUnit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LengthUnit.h; sourceTree = ""; }; + 2196F2E22CB05BAF00450DFC /* LengthUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LengthUnit.cpp; sourceTree = ""; }; 219712682BE7E2D500D9EF7E /* Serialisation.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Serialisation.md; sourceTree = ""; }; 21AEF9B32CA5F7CF000B8681 /* DetachedWrap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedWrap.h; sourceTree = ""; }; 21AEF9B52CA5FA02000B8681 /* DetachedReference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedReference.h; sourceTree = ""; }; @@ -269,6 +272,7 @@ 2167E27C2C49121F000827D3 /* CMakeLists.txt */, 21AEF9C72CA818EA000B8681 /* Detached */, 21F69F3A2C6B880B008B6A06 /* JSBase */, + 2196F2DF2CB0566500450DFC /* Units */, 219712682BE7E2D500D9EF7E /* Serialisation.md */, ); path = Serialise; @@ -407,6 +411,15 @@ path = Utility; sourceTree = ""; }; + 2196F2DF2CB0566500450DFC /* Units */ = { + isa = PBXGroup; + children = ( + 2196F2E22CB05BAF00450DFC /* LengthUnit.cpp */, + 2196F2DE2CB0566500450DFC /* LengthUnit.h */, + ); + path = Units; + sourceTree = ""; + }; 219987FA2BD708BC0035E5EA /* SpeckleLibDoctest */ = { isa = PBXGroup; children = ( @@ -780,6 +793,7 @@ 21D0BDBD2C90F2830077E104 /* DocStoreSubscriber.cpp in Sources */, 21D0BDB32C8F8AB60077E104 /* DocumentStoreCore.cpp in Sources */, 219246082CA2ED2F00CF5703 /* ArchicadElementDBaseEngine.cpp in Sources */, + 2196F2E32CB05BAF00450DFC /* LengthUnit.cpp in Sources */, 21F93AEC2B2F406E009A2C5B /* Addon.cpp in Sources */, 215F087D2CA18E1400CD343B /* Element.cpp in Sources */, 21D0BD4E2C8901A00077E104 /* ServerInfo.cpp in Sources */,