Compare commits

...

33 Commits

Author SHA1 Message Date
Ralph Wessel 8e80d5ddd5 Merge branch 'develop' into david/cnx-150-implement-selectionbinding 2024-10-16 15:04:07 +01:00
David Kekesi 3813c8740f SelectionInfo::initialize changed to private 2024-10-16 15:53:59 +02:00
David Kekesi 5c1511e850 code cleanup 2024-10-16 15:50:15 +02:00
David Kekesi 511311eb84 selectionBridge works 2024-10-16 15:08:34 +02:00
Ralph Wessel ebed71a791 Removed unused static var from SelectionSubscriber 2024-10-16 11:03:38 +01:00
Ralph Wessel 3e7b78e50d Allow SelectionSubscriber to start/stop outside initialisation phase 2024-10-16 10:31:11 +01:00
Ralph Wessel 2d23eb6b28 Fixes to Column and ColumnSegment classes 2024-10-15 23:05:07 +01:00
Ralph Wessel ffb9cf0cef Updated VS projects 2024-10-15 21:12:37 +01:00
Ralph Wessel e54962e76f 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
2024-10-15 21:05:57 +01:00
David Kekesi def9162e4c added SelectionBridge, SelectionInfo, GetSelection 2024-10-15 17:13:06 +02:00
Ralph Wessel 9c10300f01 Merge pull request #6 from specklesystems/FinishProxies_WIP
Finish proxies wip
2024-10-14 16:04:52 +01:00
David Kekesi 902fb0f626 changed ArchicadRGB::write to export ARGB colors instead of RGB 2024-10-14 15:46:12 +02:00
Ralph Wessel 432e5a0b0b Merge branch 'FinishProxies_WIP' of https://github.com/specklesystems/speckle-cpp-connectors into FinishProxies_WIP 2024-10-14 11:25:32 +01:00
Ralph Wessel a67361c903 FinishProxy should call base object when (de)serialising 2024-10-14 11:25:09 +01:00
Ralph Wessel e82698ac3a Shininess in Modeler::Material is 1-100 scale (NB: looks logarithmic but will resolve on advice from GS) 2024-10-14 11:18:48 +01:00
Ralph Wessel 2fab7da57d Update FinishProxy to be a BIMRecord, i.e. export speckle_type and applicaiton ID
BIMRecord constructor should allow units to be initialised to nullopt
2024-10-14 11:17:17 +01:00
Ralph Wessel 36b95436ae Finishes have no unit of measurement 2024-10-14 10:13:23 +01:00
Ralph Wessel 24f6a6349a Capture ID of Modeler::Material in Finish 2024-10-14 10:00:23 +01:00
Ralph Wessel bd54ae3995 Change JSON tag from "unit" to "units" 2024-10-14 09:50:07 +01:00
Ralph Wessel 7e742796f5 Corrected Mesh speckle_type
Mesh constructor failed to set BIM ID
2024-10-13 22:27:59 +01:00
Ralph Wessel 373179fa65 Assigned serialisation type for Str256
Linked mesh IDs in finish proxies is a single array
2024-10-13 22:16:52 +01:00
Ralph Wessel 11bfb9333f Updated VS projects 2024-10-13 21:35:10 +01:00
Ralph Wessel 45c0705a60 #include <ACAPinc.h> prior to other includes 2024-10-13 19:57:01 +01:00
Ralph Wessel 7f4b7112ae Finishes incorporates all Archicad material properties
Serialisation wrapper for Archicad colour rgb colour
2024-10-13 17:49:17 +01:00
Ralph Wessel 05c2cdc47a Updated VS projects
Using Str256 for AC attribute name
WIP - using fixed size for material proxy serialisation count (actual count not known at this point - may need to use something like max size_t)
2024-10-12 09:19:09 +01:00
Ralph Wessel dbc2c79f2a Added serilaisation wrapper for 256-byte char array (used for some AC string types) 2024-10-12 09:06:32 +01:00
Ralph Wessel 36e50bb63e SendObject and SendViaBrowserArgs forward the wrapped object management to the serialiser
ProjectCollection defines itself as a serialisation manager (to collect material proxies)
2024-10-11 17:44:41 +01:00
Ralph Wessel d3492512cd Update SendObject and SendViaBrowserArgs to use serialisation management (to support collection of material proxies) 2024-10-11 17:19:04 +01:00
Ralph Wessel 65b636accb Mesh serialisation now directly engages with management to populate material proxies rather than using a "dummy" field 2024-10-11 16:53:42 +01:00
David Kekesi 791e9f072f finish proxies wip 2024-10-11 17:10:05 +02:00
kekesidavid 68c98abde9 Merge pull request #5 from specklesystems/david/cnx-576-implement-element-getbody
David/cnx 576 implement element getbody
2024-10-11 13:20:44 +02:00
Ralph Wessel a117e327c7 Updated VS project 2024-10-11 11:47:35 +01:00
Ralph Wessel de46d899b0 Added FinishProxy to collect mesh finishes (to build 'material proxy collection) 2024-10-11 11:45:10 +01:00
60 changed files with 2785 additions and 193 deletions
+6
View File
@@ -111,6 +111,9 @@
<ClCompile Include="Connector\Interface\Browser\Bridge\Config\GetConfig.cpp" />
<ClCompile Include="Connector\Interface\Browser\Bridge\Config\GetIsDevMode.cpp" />
<ClCompile Include="Connector\Interface\Browser\Bridge\Config\UpdateConfig.cpp" />
<ClCompile Include="Connector\Interface\Browser\Bridge\Selection\Arg\SelectionInfo.cpp" />
<ClCompile Include="Connector\Interface\Browser\Bridge\Selection\GetSelection.cpp" />
<ClCompile Include="Connector\Interface\Browser\Bridge\Selection\SelectionBridge.cpp" />
<ClCompile Include="Connector\Interface\Browser\Bridge\Send\Arg\ConversionResult.cpp" />
<ClCompile Include="Connector\Interface\Browser\Bridge\Send\Arg\SendError.cpp" />
<ClCompile Include="Connector\Interface\Browser\Bridge\Send\Arg\SendObject.cpp" />
@@ -163,6 +166,9 @@
<ClInclude Include="Connector\Interface\Browser\Bridge\Config\GetConfig.h" />
<ClInclude Include="Connector\Interface\Browser\Bridge\Config\GetIsDevMode.h" />
<ClInclude Include="Connector\Interface\Browser\Bridge\Config\UpdateConfig.h" />
<ClInclude Include="Connector\Interface\Browser\Bridge\Selection\Arg\SelectionInfo.h" />
<ClInclude Include="Connector\Interface\Browser\Bridge\Selection\GetSelection.h" />
<ClInclude Include="Connector\Interface\Browser\Bridge\Selection\SelectionBridge.h" />
<ClInclude Include="Connector\Interface\Browser\Bridge\Send\Arg\ConversionResult.h" />
<ClInclude Include="Connector\Interface\Browser\Bridge\Send\Arg\SendError.h" />
<ClInclude Include="Connector\Interface\Browser\Bridge\Send\Arg\SendObject.h" />
@@ -65,6 +65,12 @@
<Filter Include="Connector\Interface\Browser\Bridge\Send\Arg">
<UniqueIdentifier>{6693f9a9-5ece-4853-b008-4064d1c551ab}</UniqueIdentifier>
</Filter>
<Filter Include="Connector\Interface\Browser\Bridge\Selection">
<UniqueIdentifier>{806f4af5-fa02-49b8-ac01-297991fe90ea}</UniqueIdentifier>
</Filter>
<Filter Include="Connector\Interface\Browser\Bridge\Selection\Arg">
<UniqueIdentifier>{8bb3df60-affe-4b66-8d78-f1b98e6ba8df}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="RFIX.win\Connector.rc2">
@@ -228,6 +234,15 @@
<ClCompile Include="Connector\Record\Collection\ProjectCollection.cpp">
<Filter>Connector\Record\Collection</Filter>
</ClCompile>
<ClCompile Include="Connector\Interface\Browser\Bridge\Selection\GetSelection.cpp">
<Filter>Connector\Interface\Browser\Bridge\Selection</Filter>
</ClCompile>
<ClCompile Include="Connector\Interface\Browser\Bridge\Selection\SelectionBridge.cpp">
<Filter>Connector\Interface\Browser\Bridge\Selection</Filter>
</ClCompile>
<ClCompile Include="Connector\Interface\Browser\Bridge\Selection\Arg\SelectionInfo.cpp">
<Filter>Connector\Interface\Browser\Bridge\Selection\Arg</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Connector\ConnectorResource.h">
@@ -387,5 +402,14 @@
<ClInclude Include="Connector\Record\Collection\ProjectCollection.h">
<Filter>Connector\Record\Collection</Filter>
</ClInclude>
<ClInclude Include="Connector\Interface\Browser\Bridge\Selection\GetSelection.h">
<Filter>Connector\Interface\Browser\Bridge\Selection</Filter>
</ClInclude>
<ClInclude Include="Connector\Interface\Browser\Bridge\Selection\SelectionBridge.h">
<Filter>Connector\Interface\Browser\Bridge\Selection</Filter>
</ClInclude>
<ClInclude Include="Connector\Interface\Browser\Bridge\Selection\Arg\SelectionInfo.h">
<Filter>Connector\Interface\Browser\Bridge\Selection\Arg</Filter>
</ClInclude>
</ItemGroup>
</Project>
@@ -0,0 +1,92 @@
#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
#include "Active/Serialise/Package/Wrapper/ContainerWrap.h"
#include "Connector/Connector.h"
#include "Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h"
#include "Speckle/Database/BIMElementDatabase.h"
#include "Speckle/Environment/Project.h"
#include "Speckle/Record/Element/Element.h"
#include <array>
using namespace active::serialise;
using namespace connector::interfac::browser::bridge;
using namespace speckle::record::element;
namespace {
///Serialisation fields
enum FieldIndex {
selectedObjectIdsID,
summaryID,
};
///Serialisation field IDs
static std::array fieldID = {
Identity{"selectedObjectIds"},
Identity{"summary"},
};
}
SelectionInfo::SelectionInfo() {
initialize();
}
void SelectionInfo::initialize() {
auto project = connector()->getActiveProject().lock();
if (!project) {
// TODO: is thi OK?
return;
}
auto elementDatabase = project->getElementDatabase();
auto selected = elementDatabase->getSelection();
active::utility::String summary(selected.size());
summary += " objects selected.";
m_summary = summary;
for (const auto& link : selected) {
m_selectedElementIds.push_back(link);
}
}
/*--------------------------------------------------------------------
Fill an inventory with the package items
inventory: The inventory to receive the package items
return: True if the package has added items to the inventory
--------------------------------------------------------------------*/
bool SelectionInfo::fillInventory(Inventory& inventory) const {
using enum Entry::Type;
inventory.merge(Inventory{
{
{ fieldID[selectedObjectIdsID], selectedObjectIdsID, element },
{ fieldID[summaryID], summaryID, element },
},
}.withType(&typeid(SelectionInfo)));
return true;
} //SelectionInfo::fillInventory
/*--------------------------------------------------------------------
Get the specified cargo
item: The inventory item to retrieve
return: The requested cargo (nullptr on failure)
--------------------------------------------------------------------*/
Cargo::Unique SelectionInfo::getCargo(const Inventory::Item& item) const {
if (item.ownerType != &typeid(SelectionInfo))
return nullptr;
using namespace active::serialise;
switch (item.index) {
case selectedObjectIdsID:
return std::make_unique<ContainerWrap<std::vector<active::utility::Guid>>>(m_selectedElementIds);
case summaryID:
return std::make_unique<ValueWrap<active::utility::String>>(m_summary);
default:
return nullptr; //Requested an unknown index
}
} //SelectionInfo::getCargo
@@ -0,0 +1,49 @@
#ifndef CONNECTOR_INTERFACE_BRIDGE_SELECTION_INFO
#define CONNECTOR_INTERFACE_BRIDGE_SELECTION_INFO
#include "Active/Serialise/Package/Package.h"
namespace connector::interfac::browser::bridge {
/*!
Configuration settings class
*/
class SelectionInfo : public active::serialise::Package {
public:
// MARK: - Types
using base = active::serialise::Package;
// MARK: - Constructors
/*!
Default constructor
*/
SelectionInfo();
active::utility::String m_summary = "No objects selected";
std::vector<active::utility::Guid> m_selectedElementIds;
// MARK: - Serialisation
/*!
Fill an inventory with the package items
@param inventory The inventory to receive the package items
@return True if the package has added items to the inventory
*/
bool fillInventory(active::serialise::Inventory& inventory) const override;
/*!
Get the specified cargo
@param item The inventory item to retrieve
@return The requested cargo (nullptr on failure)
*/
Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
private:
void initialize();
};
}
#endif //CONNECTOR_INTERFACE_BRIDGE_SELECTION_INFO
@@ -0,0 +1,23 @@
#include "Active/Serialise/CargoHold.h"
#include "Connector/Interface/Browser/Bridge/Selection/GetSelection.h"
#include "Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h"
using namespace active::serialise;
using namespace connector::interfac::browser::bridge;
/*--------------------------------------------------------------------
Default constructor
--------------------------------------------------------------------*/
GetSelection::GetSelection() : BridgeMethod{"GetSelection", [&]() {
return run();
}} {}
/*--------------------------------------------------------------------
Get the current selection info
based on the ArchiCAD mdoel selection
--------------------------------------------------------------------*/
std::unique_ptr<Cargo> GetSelection::run() const {
auto selectionInfo = std::make_unique<SelectionInfo>();
return std::make_unique<CargoHold<PackageWrap, SelectionInfo>>(std::move(selectionInfo));
} //GetSelection::run
@@ -0,0 +1,30 @@
#ifndef CONNECTOR_INTERFACE_BRIDGE_GETSELECTION
#define CONNECTOR_INTERFACE_BRIDGE_GETSELECTION
#include "Speckle/Interface/Browser/Bridge/BridgeMethod.h"
namespace connector::interfac::browser::bridge {
class GetSelection : public speckle::interfac::browser::bridge::BridgeMethod<void, active::serialise::Cargo> {
public:
// MARK: - Constructors
/*!
Constructor
@param bridge The parent bridge object (provides access to bridge methods)
*/
GetSelection();
// MARK: - Functions (const)
/*!
Get the current selection info
based on the ArchiCAD mdoel selection
*/
std::unique_ptr<active::serialise::Cargo> run() const;
};
}
#endif //CONNECTOR_INTERFACE_BRIDGE_GETSELECTION
@@ -0,0 +1,27 @@
#include "Active/Serialise/CargoHold.h"
#include "Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h"
#include "Connector/Interface/Browser/Bridge/Selection/GetSelection.h"
#include "Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h"
using namespace active::serialise;
using namespace connector::interfac::browser::bridge;
/*--------------------------------------------------------------------
Default constructor
--------------------------------------------------------------------*/
SelectionBridge::SelectionBridge() : BrowserBridge{"selectionBinding"} {
//Add bridge methods
addMethod<GetSelection>();
} //SelectionBridge::SelectionBridge
/*!
Handle the menu selection
@param event The selection event
@return True if the event should be closed
*/
bool SelectionBridge::handle(const speckle::event::SelectionEvent& event) {
auto selectionInfo = std::make_unique<SelectionInfo>();
auto wrapped = std::make_unique<CargoHold<PackageWrap, SelectionInfo>>(std::move(selectionInfo));
sendEvent("setSelection", std::move(wrapped));
return true;
} //SelectionBridge::handle
@@ -0,0 +1,39 @@
#ifndef CONNECTOR_INTERFACE_BRIDGE_SELECTION_BRIDGE
#define CONNECTOR_INTERFACE_BRIDGE_SELECTION_BRIDGE
#include "Speckle/Interface/Browser/Bridge/BrowserBridge.h"
#include "Speckle/Event/Subscriber/SelectionSubscriber.h"
#include "Speckle/Event/Type/SelectionEvent.h"
namespace connector::interfac::browser::bridge {
/*!
A browser bridge to support sending model data to a Speckle server
*/
class SelectionBridge : public speckle::interfac::browser::bridge::BrowserBridge, public speckle::event::SelectionSubscriber {
public:
// MARK: - Types
using base = speckle::interfac::browser::bridge::BrowserBridge;
// MARK: - Constructors
using base::base;
/*!
Default constructor
*/
SelectionBridge();
protected:
/*!
Handle the menu selection
@param event The selection event
@return True if the event should be closed
*/
bool handle(const speckle::event::SelectionEvent& event) override;
};
}
#endif //CONNECTOR_INTERFACE_BRIDGE_SELECTION_BRIDGE
@@ -43,6 +43,16 @@ namespace connector::interfac::browser::bridge {
@return The requested cargo (nullptr on failure)
*/
Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
/*!
Use a manager in (de)serialisation processes
@param management The management to use
*/
void useManagement(active::serialise::Management* management) const override { m_object->useManagement(management); }
/*!
Get the cargo management
@return The active management
*/
active::serialise::Management* management() const override { return m_object->management(); }
private:
///The object to send
@@ -72,6 +72,16 @@ namespace connector::interfac::browser::bridge {
@return The requested cargo (nullptr on failure)
*/
Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
/*!
Use a manager in (de)serialisation processes
@param management The management to use
*/
void useManagement(active::serialise::Management* management) const override { sendObject.useManagement(management); }
/*!
Get the cargo management
@return The active management
*/
active::serialise::Management* management() const override { return sendObject.management(); }
};
}
@@ -4,12 +4,14 @@
#include "Active/Utility/String.h"
#include "Active/Serialise/JSON/JSONTransport.h"
#include "Active/Utility/BufferOut.h"
#include "Connector/Connector.h"
#include "Connector/ConnectorResource.h"
#include "Connector/Event/ConnectorEventID.h"
#include "Connector/Interface/Browser/Bridge/Account/AccountBridge.h"
#include "Connector/Interface/Browser/Bridge/Base/BaseBridge.h"
#include "Connector/Interface/Browser/Bridge/Config/ConfigBridge.h"
#include "Connector/Interface/Browser/Bridge/Send/SendBridge.h"
#include "Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h"
#include "Connector/Interface/Browser/Bridge/Test/TestBridge.h"
#include "Speckle/Environment/Addon.h"
#include "Speckle/Event/Type/MenuEvent.h"
@@ -76,9 +78,6 @@ namespace {
virtual void PanelResized(const DG::PanelResizeEvent& ev) override;
virtual void PanelCloseRequested(const DG::PanelCloseRequestEvent& ev, bool* accepted) override;
static GS::Array<BrowserPalette::ElementInfo> GetSelectedElements();
static void ModifySelection(const GS::UniString& elemGuidStr, SelectionModification modification);
static GSErrCode __ACENV_CALL PaletteControlCallBack(Int32 paletteId, API_PaletteMessageID messageID, GS::IntPtr param);
static GS::Ref<BrowserPalette> instance;
@@ -170,6 +169,12 @@ BrowserPalette::BrowserPalette() :
install<BaseBridge>();
install<ConfigBridge>();
install<SendBridge>();
if (auto ref = install<SelectionBridge>(); ref) {
if (auto selectionBridgeRef = std::dynamic_pointer_cast<SelectionBridge>(ref); selectionBridgeRef) {
connector::connector()->addWeak(selectionBridgeRef);
selectionBridgeRef->start();
}
}
install<TestBridge>();
InitBrowserControl();
}
@@ -243,31 +248,6 @@ void BrowserPalette::PanelCloseRequested(const DG::PanelCloseRequestEvent&, bool
*accepted = true;
}
GS::Array<BrowserPalette::ElementInfo> BrowserPalette::GetSelectedElements() {
API_SelectionInfo selectionInfo;
GS::Array<API_Neig> selNeigs;
ACAPI_Selection_Get(&selectionInfo, &selNeigs, false, false);
BMKillHandle((GSHandle*)&selectionInfo.marquee.coords);
GS::Array<BrowserPalette::ElementInfo> selectedElements;
for(const API_Neig& neig : selNeigs) {
API_Elem_Head elemHead = {};
elemHead.guid = neig.guid;
ACAPI_Element_GetHeader(&elemHead);
ElementInfo elemInfo;
elemInfo.guidStr = APIGuidToString(elemHead.guid);
ACAPI_Element_GetElemTypeName(elemHead.type, elemInfo.typeName);
ACAPI_Element_GetElementInfoString(&elemHead.guid, &elemInfo.elemID);
selectedElements.Push(elemInfo);
}
return selectedElements;
}
void BrowserPalette::ModifySelection(const GS::UniString& elemGuidStr, BrowserPalette::SelectionModification modification) {
ACAPI_Selection_Select({ API_Neig(APIGuidFromString(elemGuidStr.ToCStr().Get())) }, modification == AddToSelection);
}
GSErrCode __ACENV_CALL BrowserPalette::PaletteControlCallBack(Int32, API_PaletteMessageID messageID, GS::IntPtr param) {
switch(messageID) {
case APIPalMsg_OpenPalette:
@@ -37,10 +37,10 @@ bool FinishProxy::fillInventory(active::serialise::Inventory& inventory) const {
inventory.merge(Inventory{
{
{ fieldID[materialID], materialID, element },
{ fieldID[linkedMeshID], linkedMeshID, m_meshID.size(), std::nullopt },
{ fieldID[linkedMeshID], linkedMeshID, element },
},
}.withType(&typeid(FinishProxy)));
return true;
return base::fillInventory(inventory);
} //FinishProxy::fillInventory
@@ -53,13 +53,15 @@ bool FinishProxy::fillInventory(active::serialise::Inventory& inventory) const {
--------------------------------------------------------------------*/
Cargo::Unique FinishProxy::getCargo(const active::serialise::Inventory::Item& item) const {
if (item.ownerType != &typeid(FinishProxy))
return nullptr;
return base::getCargo(item);
using namespace active::serialise;
switch (item.index) {
case materialID:
return std::make_unique<PackageWrap>(m_finish);
case linkedMeshID:
return std::make_unique<ContainerWrap<std::vector<active::utility::Guid>>>(m_meshID);
case linkedMeshID: {
auto result = new ContainerWrap(m_meshID);
return Cargo::Unique{result};
}
default:
return nullptr; //Requested an unknown index
}
@@ -1,7 +1,7 @@
#ifndef CONNECTOR_RECORD_COLLECTION_MATERIAL_PROXY
#define CONNECTOR_RECORD_COLLECTION_MATERIAL_PROXY
#include "Active/Serialise/Package/Package.h"
#include "Speckle/Database/Content/BIMRecord.h"
#include "Speckle/Record/Attribute/Finish.h"
#include "Speckle/Utility/String.h"
@@ -10,9 +10,11 @@ namespace connector::record {
/*!
A proxy record binding a surface finishes to meshes
*/
class FinishProxy : public active::serialise::Package {
class FinishProxy : public speckle::database::BIMRecord {
public:
using base = speckle::database::BIMRecord;
// MARK: - Constructors
/*!
@@ -21,8 +23,16 @@ namespace connector::record {
@param meshID The list of mesh IDs the finish is applied to
*/
FinishProxy(const speckle::record::attribute::Finish& finish, const std::unordered_set<active::utility::Guid>& meshID) :
m_finish{finish} { std::copy(meshID.begin(), meshID.end(), std::back_inserter(m_meshID)); }
base{speckle::utility::Guid{true}, speckle::utility::Guid{}, std::nullopt}, m_finish{finish} {
std::copy(meshID.begin(), meshID.end(), std::back_inserter(m_meshID));
}
/*!
Get the speckle type identifier
@return The speckle type (relevant objects should override as required, but "Base" is still considered a type on its own)
*/
speckle::utility::String getSpeckleType() const override { return "Objects.Other.RenderMaterialProxy"; }
// MARK: - Serialisation
/*!
@@ -2,6 +2,7 @@
#include "Active/Serialise/CargoHold.h"
#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
#include "Active/Serialise/Management/Management.h"
#include "Active/Serialise/Package/Wrapper/PackageWrap.h"
#include "Connector/Connector.h"
#include "Connector/ConnectorResource.h"
@@ -11,6 +12,7 @@
#include "Speckle/Record/Element/Element.h"
#ifdef ARCHICAD
#include <ACAPinc.h>
#include <ModelMaterial.hpp>
#endif
@@ -47,8 +49,11 @@ namespace {
project: The source project
--------------------------------------------------------------------*/
ProjectCollection::ProjectCollection(speckle::environment::Project::Shared project) : base{project->getInfo().name, project} {
ProjectCollection::ProjectCollection(speckle::environment::Project::Shared project) : base{project->getInfo().name, project},
m_management{std::make_unique<Management>()} {
m_management->push_back(this);
m_finishes = std::make_unique<FinishCache>();
base::useManagement(m_management.get());
} //ProjectCollection::ProjectCollection
@@ -128,10 +133,12 @@ bool ProjectCollection::addMaterialProxy(const speckle::database::BIMIndex& mate
--------------------------------------------------------------------*/
bool ProjectCollection::addMaterialProxy(const ModelerAPI::Material& material, const speckle::database::BIMRecordID& objectID) {
auto finishID = Guid::fromInt(material.GenerateHashValue());
if (m_finishes->find(finishID) != m_finishes->end())
return false;
auto finish = std::make_unique<Finish>(material);
return m_finishes->insert({finishID, std::move(finish)}).second;
auto iter = m_finishes->find(finishID);
if (iter == m_finishes->end()) {
auto finish = std::make_unique<Finish>(material);
iter = m_finishes->insert({ finishID, std::move(finish) }).first;
}
return addMaterialProxy(finishID, objectID);
} //ProjectCollection::addMaterialProxy
#endif
@@ -148,7 +155,7 @@ bool ProjectCollection::fillInventory(active::serialise::Inventory& inventory) c
base::fillInventory(inventory);
inventory.merge(Inventory{
{
{ Identity{fieldID[finishProxyID]}, finishProxyID, m_finishProxies.size(), std::nullopt },
{ Identity{fieldID[finishProxyID]}, finishProxyID, 100, std::nullopt },
},
}.withType(&typeid(ProjectCollection)));
return true;
@@ -6,6 +6,10 @@
#include <stack>
namespace active::serialise {
class Management;
}
namespace speckle::record::element {
class Element;
}
@@ -94,6 +98,7 @@ namespace connector::record {
private:
using FinishProxies = std::unordered_map<speckle::database::BIMIndex, std::unordered_set<active::utility::Guid>>;
std::unique_ptr<active::serialise::Management> m_management;
///Finish proxies accumulated from meshes generated from the collection elements
FinishProxies m_finishProxies;
#ifdef ARCHICAD
@@ -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 <array>
@@ -107,6 +108,25 @@ Vector<Element> 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<Memo*>(result.get()); memo != nullptr) {
result.release();
return Memo::Unique{memo};
}
return nullptr;
} //BIMElementDatabase::getMemo
/*--------------------------------------------------------------------
Write an element to storage
@@ -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<BIMRecordID> tableID = std::nullopt,
std::unique_ptr<record::element::Element> getElement(const BIMRecordID& elementID, std::optional<BIMRecordID> tableID = std::nullopt,
std::optional<BIMRecordID> 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<record::element::Element> getElement(const BIMLink& link) const { return getElement(link, link.tableID, link.docID); }
/*!
Get all model elements
@return All the elements
*/
active::container::Vector<record::element::Element> 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<record::element::Memo> getMemo(const BIMRecordID& elementID, record::element::Part::filter_bits filter) const;
/*!
Write an element to storage
@param element The element to write
@@ -1,7 +1,7 @@
#include "Speckle/Database/Content/BIMRecord.h"
#include "Active/Serialise/Item/Wrapper/ValueOptionWrap.h"
#include "Speckle/Serialise/Units/LengthUnit.h"
#include "Speckle/Serialise/Types/Units/LengthUnit.h"
#include "Speckle/Utility/Guid.h"
#include <array>
@@ -23,7 +23,7 @@ namespace {
///Serialisation field IDs
static std::array fieldID = {
Identity{"applicationId"},
Identity{"unit"},
Identity{"units"},
};
}
@@ -39,7 +39,7 @@ namespace speckle::database {
@param unit The record unit type
*/
BIMRecord(const speckle::utility::Guid& ID, const speckle::utility::Guid& tableID,
active::measure::LengthType unit = active::measure::LengthType::metre) :
std::optional<active::measure::LengthType> unit = active::measure::LengthType::metre) :
base{}, m_applicationID{ID}, m_applicationTableID{tableID}, m_unit{unit} {}
/*!
Destructor
@@ -63,6 +63,11 @@ namespace speckle::database {
@return The BIM record link
*/
BIMLink getBIMLink() const { return BIMLink{ BIMLink::base{m_applicationID, m_applicationTableID} }; }
/*!
Get the record unit type
@return The record unit type (nullopt if the record has no applicable unit type)
*/
std::optional<active::measure::LengthType> getUnit() const { return m_unit; }
// MARK: - Functions (mutating)
@@ -76,6 +81,11 @@ namespace speckle::database {
@param tableID The BIM table ID
*/
void setTableID(const BIMRecordID& tableID) { m_applicationTableID = tableID; }
/*!
Set the record unit type
@param unit The record unit type (nullopt if the record has no applicable unit type)
*/
void setUnit(std::optional<active::measure::LengthType> unit) { m_unit = unit; }
// MARK: - Serialisation
@@ -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;
@@ -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<Element>(elementData, tableID);
switch (elementData.header.type.typeID) {
case API_ColumnID:
return std::make_unique<Column>(elementData, tableID);
case API_ColumnSegmentID:
return std::make_unique<ColumnSegment>(elementData, tableID);
default:
return std::make_unique<GenericElement>(elementData, tableID);
}
}
}
@@ -120,7 +129,22 @@ BIMLinkList ArchicadElementDBaseEngine::getSelection() const {
--------------------------------------------------------------------*/
std::unique_ptr<Element> ArchicadElementDBaseEngine::getObject(const BIMRecordID& ID, std::optional<BIMRecordID> tableID,
std::optional<BIMRecordID> documentID) const {
//Check for memo table requests
if (tableID == memoTable) {
auto memo = std::make_unique<API_ElementMemo>();
active::utility::Memory::erase(*memo);
//Use memo filtering when requested
uint64_t filter = documentID ? Guid::toInt(*documentID) : APIMemoMask_All;
if (auto err = ACAPI_Element_GetMemo(ID, memo.get(), filter); err != NoError)
ACAPI_DisposeElemMemoHdls(memo.get());
else {
auto result = std::make_unique<Memo>();
result->set(std::move(memo));
return result;
}
}
if (!tableID) {
//Use the active table if none is specified
tableID = getActiveTable();
if (!tableID)
return nullptr;
@@ -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<record::element::Element,BIMRecordID, BIMRecordID, BIMRecordID> {
public active::database::DBaseEngine<record::element::Element, BIMRecordID, BIMRecordID, BIMRecordID> {
public:
// MARK: - Types
using base = active::database::DBaseEngine<record::element::Element,BIMRecordID, BIMRecordID, BIMRecordID>;
using base = active::database::DBaseEngine<record::element::Element, BIMRecordID, BIMRecordID, BIMRecordID>;
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
/*!
@@ -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
@@ -69,12 +66,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
}
@@ -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,25 @@ namespace speckle::event {
@param event The incoming event
@return True if the event should be closed
*/
virtual bool receive(const active::event::Event& event) override;
protected:
bool receive(const active::event::Event& event) override;
/*!
Start the participant operation
@return True if the participant is able to continue
*/
virtual bool start() override;
/*!
Handle the menu selection
@param event The menu event
Stop participation (release resources etc)
*/
void stop() override;
protected:
/*!
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;
};
}
@@ -24,7 +24,7 @@ namespace speckle::event {
Constructor
@param selected A link to a selected element (nullopt if the selection is empty)
*/
SelectionEvent(speckle::database::BIMLink::Option selected) : m_selectedLink{selected} {}
SelectionEvent(speckle::database::BIMLink::Option selected) : Event{ ID }, m_selectedLink{selected} {}
/*!
Copy constructor
@param source The object to copy
@@ -38,7 +38,7 @@ namespace speckle::interfac::browser {
*/
template<class Derived>
explicit JSObject(const speckle::utility::String& name, const std::initializer_list<Derived>& items) : base{items}, m_name{name} {}
virtual ~JSObject() {}
// MARK: - Functions (const)
/*!
@@ -48,14 +48,14 @@ namespace speckle::interfac::browser {
@param object The object to install
@return True if the object was successfully installed
*/
bool install(std::shared_ptr<JSObject<FunctionBinding>> object);
std::shared_ptr<JSObject<FunctionBinding>> install(std::shared_ptr<JSObject<FunctionBinding>> object);
/*!
Install a JS function object
@return True if the object was successfully installed
@tparam T The type of object to install
*/
template<typename T> requires std::is_base_of_v<JSObject<FunctionBinding>, T>
bool install() { return install(std::make_shared<T>()); }
std::shared_ptr<JSObject<FunctionBinding>> install() { return install(std::make_shared<T>()); }
protected:
#ifdef ARCHICAD
@@ -101,12 +101,12 @@ namespace speckle::interfac::browser {
return: True if the object was successfully installed
--------------------------------------------------------------------*/
template<typename FunctionBinding>
bool JSPortal<FunctionBinding>::install(std::shared_ptr<JSObject<FunctionBinding>> object) {
std::shared_ptr<JSObject<FunctionBinding>> JSPortal<FunctionBinding>::install(std::shared_ptr<JSObject<FunctionBinding>> object) {
try {
#ifdef ARCHICAD
auto engine = getJSEngine();
if (!engine)
return false;
return nullptr;
//Define the JS object
JS::Object* acObject = new JS::Object(object->getName());
//Add all the functions supported by this object
@@ -125,13 +125,13 @@ namespace speckle::interfac::browser {
if (engine->RegisterAsynchJSObject(acObject)) {
base::push_back(object);
object->setPortal(*this);
return true;
return object;
}
#endif
} catch(...) {
///TODO: Need to discuss the best course of action to notify of a failure
}
return false;
return nullptr;
} //JSPortal<FunctionBinding>::install
}
+19 -3
View File
@@ -4,11 +4,13 @@
#include "Active/Serialise/Package/Wrapper/PackageWrap.h"
#include "Active/Serialise/Package/Wrapper/ContainerWrap.h"
#include "Active/Serialise/Inventory/Identity.h"
#include "Speckle/Serialise/Collection/FinishProxy.h"
#include <array>
using namespace active::serialise;
using namespace speckle::primitive;
using namespace speckle::serialise;
namespace {
@@ -61,12 +63,26 @@ Cargo::Unique Mesh::getCargo(const Inventory::Item& item) const {
using namespace active::serialise;
switch (item.index) {
case vertexID:
return std::make_unique<ContainerWrap<std::vector<double>>>(vertices);
return std::make_unique<ContainerWrap<std::vector<double>>>(m_vertices);
case faceID:
return std::make_unique<ContainerWrap<std::vector<int>>>(faces);
return std::make_unique<ContainerWrap<std::vector<int>>>(m_faces);
case colorID:
return std::make_unique<ContainerWrap<std::vector<int>>>(colors);
return std::make_unique<ContainerWrap<std::vector<int>>>(m_colors);
default:
return nullptr; //Requested an unknown index
}
} //Mesh::getCargo
/*--------------------------------------------------------------------
Use a manager in (de)serialisation processes
management: The management to use
--------------------------------------------------------------------*/
void Mesh::useManagement(Management* management) const {
//NB: This object only exists to populate the finish collection - it doesn't carry any serialisable content
if (management != nullptr) {
if (auto collector = management->get<FinishCollector>(); collector != nullptr)
collector->addMaterialProxy(m_material, getBIMID());
}
} //Mesh::useManagement
+19 -7
View File
@@ -4,6 +4,10 @@
#include "Speckle/Database/Content/BIMRecord.h"
#include "Speckle/Utility/String.h"
#ifdef ARCHICAD
#include "ModelMaterial.hpp"
#endif
namespace speckle::primitive {
/*!
@@ -22,7 +26,7 @@ namespace speckle::primitive {
Default constructor
@param unit The mesh unit type
*/
Mesh(active::measure::LengthType unit = active::measure::LengthType::metre) : base{unit} {}
Mesh(active::measure::LengthType unit = active::measure::LengthType::metre) : base{utility::Guid{true}, utility::Guid{}, unit} {}
/*!
Constructor
@param vertices The mesh vertices
@@ -30,9 +34,9 @@ namespace speckle::primitive {
@param colors The mesh face colours
@param unit The mesh unit type
*/
Mesh(std::vector<double>&& vertices, std::vector<int>&& faces, std::vector<int>&& colors,
Mesh(std::vector<double>&& vertices, std::vector<int>&& faces, std::vector<int>&& colors, const ModelerAPI::Material& material,
active::measure::LengthType unit = active::measure::LengthType::metre) :
base{unit}, vertices {std::move(vertices)}, faces{std::move(faces)}, colors{std::move(colors)} {}
base{utility::Guid{true}, utility::Guid{}, unit}, m_vertices{std::move(vertices)}, m_faces{std::move(faces)}, m_colors{std::move(colors)}, m_material{material} {}
// MARK: - Functions (const)
@@ -40,7 +44,7 @@ namespace speckle::primitive {
Get the speckle type identifier
@return The speckle type (relevant objects should override as required)
*/
speckle::utility::String getSpeckleType() const override { return "speckle::primitive::Mesh"; }
speckle::utility::String getSpeckleType() const override { return "Objects.Geometry.Mesh"; }
// MARK: - Serialisation
@@ -56,11 +60,19 @@ namespace speckle::primitive {
@return The requested cargo (nullptr on failure)
*/
active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
/*!
Use a manager in (de)serialisation processes
@param management The management to use
*/
void useManagement(active::serialise::Management* management) const override;
private:
std::vector<double> vertices;
std::vector<int> faces;
std::vector<int> colors;
std::vector<double> m_vertices;
std::vector<int> m_faces;
std::vector<int> m_colors;
#ifdef ARCHICAD
ModelerAPI::Material m_material;
#endif
};
}
@@ -3,6 +3,7 @@
#include "Speckle/Database/BIMAttributeDatabase.h"
#include "Speckle/Environment/Addon.h"
#include "Speckle/Environment/Project.h"
#include "Speckle/Serialise/Types/Str256.h"
using namespace active::serialise;
using namespace speckle::database;
@@ -77,8 +78,9 @@ Cargo::Unique Attribute::getCargo(const Inventory::Item& item) const {
using namespace active::serialise;
switch (item.index) {
case nameID:
//return std::make_unique<active::serialise::ContainerWrap>(*body);
return std::make_unique<StringWrap>(getHead().name);
#ifdef ARCHICAD
return std::make_unique<ValueWrap<Str256>>(reinterpret_cast<const Str256&>(getHead().name));
#endif
default:
return nullptr; //Requested an unknown index
}
+83 -19
View File
@@ -1,16 +1,22 @@
#include "Speckle/Record/Attribute/Finish.h"
#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
#include "Active/Serialise/Management/Management.h"
#include "Active/Serialise/CargoHold.h"
#include "Active/Utility/BufferOut.h"
#include "Speckle/Serialise/Collection/FinishCollector.h"
#include "Speckle/Serialise/Types/ArchicadRGB.h"
#include "Speckle/Utility/Guid.h"
#ifdef ARCHICAD
#include <ACAPinc.h>
#include <ModelMaterial.hpp>
#endif
using namespace active::serialise;
using namespace speckle::database;
using namespace speckle::record::attribute;
using namespace speckle::serialise;
using namespace speckle::utility;
#include <array>
@@ -18,14 +24,28 @@ using namespace speckle::utility;
namespace speckle::record::attribute {
///Internal representation of a rendered finish on a 3D body, i.e. the surface colour/texture etc.
class Finish::Data {
public:
#ifdef ARCHICAD
Data(const API_Attribute& attr) : root{attr.material} {}
Data(const Data& source) : root{source.root} {}
/*!
Constructor from Archicad surface material
@param attr An Archicad attribute
*/
Data(const API_Attribute& attr) : root{attr.material} {
opacity = 1.0 - (static_cast<double>(attr.material.transpPc) / 100.0);
roughness = 1.0 - (static_cast<double>(attr.material.shine) / 10000.0);
}
///Archicad representation of a surface material
API_MaterialType root;
#endif
//Opacity (0.0 -> 1.0)
double opacity = 1.0;
//Roughness (0.0 -> 1.0)
double roughness = 0.0;
//Metalness (0.0 -> 1.0)
double metalness = 0.0;
};
}
@@ -34,23 +54,33 @@ namespace {
///Serialisation fields
enum FieldIndex {
surfaceColourID,
diffuseID,
opacityID,
emissiveID,
metalnessID,
roughnessID,
};
///Serialisation field IDs
static std::array fieldID = {
Identity{"surfaceColour"},
Identity{"diffuse"},
Identity{"opacity"},
Identity{"emissive"},
Identity{"metalness"},
Identity{"roughness"},
};
#ifdef ARCHICAD
/*!
Copy a ModelerAPI colour to an AC RGB colour
@param modelColour The modeler API colour
@param colour The attribute API colour
*/
void copyModelerColor(const ModelerAPI::Color& modelColour, API_RGBColor& colour) {
colour.f_red = modelColour.red;
colour.f_green = modelColour.green;
colour.f_blue = modelColour.blue;
} //copyModelerColor
}
#endif
}
@@ -79,6 +109,7 @@ Finish::Finish(const database::BIMRecordID& ID) : base{ID, Finish::table} {
--------------------------------------------------------------------*/
Finish::Finish(const API_Attribute& attrData, const BIMRecordID& tableID) : base{attrData.header.guid, Finish::table} {
m_data = std::make_unique<Data>(attrData);
setUnit(std::nullopt); //Finishes have no unit
}
@@ -87,23 +118,24 @@ Finish::Finish(const API_Attribute& attrData, const BIMRecordID& tableID) : base
material: A ModelerAPI material definition
--------------------------------------------------------------------*/
Finish::Finish(const ModelerAPI::Material& material) {
Finish::Finish(const ModelerAPI::Material& material) : base{Guid{Guid::fromInt(material.GenerateHashValue())}, Finish::table} {
API_Attribute attr;
active::utility::Memory::erase(attr);
String{material.GetName()}.writeUTF8(active::utility::BufferOut{attr.header.name});
attr.header.guid = Guid{Guid::fromInt(material.GenerateHashValue())};
attr.header.guid = getBIMID();
attr.material.mtype = static_cast<API_MaterTypeID>(material.GetType());
attr.material.ambientPc = material.GetAmbientReflection();
attr.material.diffusePc = material.GetDiffuseReflection();
attr.material.specularPc = material.GetSpecularReflection();
attr.material.transpPc = material.GetTransparency();
attr.material.shine = material.GetShining();
attr.material.transpAtt = material.GetTransparencyAttenuation();
attr.material.emissionAtt = material.GetEmissionAttenuation();
attr.material.ambientPc = static_cast<short>(material.GetAmbientReflection() * 100);
attr.material.diffusePc = static_cast<short>(material.GetDiffuseReflection() * 100);
attr.material.specularPc = static_cast<short>(material.GetSpecularReflection() * 100);
attr.material.transpPc = static_cast<short>(material.GetTransparency() * 100);
attr.material.shine = static_cast<short>(material.GetShining() * 100);
attr.material.transpAtt = static_cast<short>(material.GetTransparencyAttenuation() * 400);
attr.material.emissionAtt = static_cast<short>(material.GetEmissionAttenuation() * 65535);
copyModelerColor(material.GetSurfaceColor(), attr.material.surfaceRGB);
copyModelerColor(material.GetSpecularColor(), attr.material.specularRGB);
copyModelerColor(material.GetEmissionColor(), attr.material.emissionRGB);
m_data = std::make_unique<Data>(attr);
setUnit(std::nullopt); //Finishes have no unit
} //Finish::Finish
#endif
@@ -114,7 +146,7 @@ Finish::Finish(const ModelerAPI::Material& material) {
source: The object to copy
--------------------------------------------------------------------*/
Finish::Finish(const Finish& source) : base{source} {
m_data = source.m_data ? std::make_unique<Data>(*m_data) : nullptr;
m_data = source.m_data ? std::make_unique<Data>(*source.m_data) : nullptr;
} //Finish::Finish
@@ -159,7 +191,11 @@ bool Finish::fillInventory(Inventory& inventory) const {
using enum Entry::Type;
inventory.merge(Inventory{
{
{ fieldID[surfaceColourID], surfaceColourID, element }, //TODO: implement other fields
{ fieldID[diffuseID], diffuseID, element },
{ fieldID[opacityID], opacityID, element },
{ fieldID[emissiveID], emissiveID, element },
{ fieldID[metalnessID], metalnessID, element },
{ fieldID[roughnessID], roughnessID, element },
},
}.withType(&typeid(Finish)));
return base::fillInventory(inventory);
@@ -179,8 +215,20 @@ Cargo::Unique Finish::getCargo(const Inventory::Item& item) const {
confirmData();
using namespace active::serialise;
switch (item.index) {
case surfaceColourID:
return nullptr; //TODO: lookup surface colour
case diffuseID:
#ifdef ARCHICAD
return std::make_unique<ValueWrap<API_RGBColor>>(m_data->root.surfaceRGB);
#endif
case opacityID:
return std::make_unique<DoubleWrap>(m_data->opacity);
case emissiveID:
#ifdef ARCHICAD
return std::make_unique<ValueWrap<API_RGBColor>>(m_data->root.emissionRGB);
#endif
case metalnessID:
return std::make_unique<DoubleWrap>(m_data->metalness);
case roughnessID:
return std::make_unique<DoubleWrap>(m_data->roughness);
default:
return nullptr; //Requested an unknown index
}
@@ -191,10 +239,26 @@ Cargo::Unique Finish::getCargo(const Inventory::Item& item) const {
Set to the default package content
--------------------------------------------------------------------*/
void Finish::setDefault() {
m_data->root = {};
m_data->opacity = 0.0;
m_data->roughness = 1.0;
m_data->metalness = 0.0;
} //Finish::setDefault
/*--------------------------------------------------------------------
Validate the cargo data
return: True if the data has been validated
--------------------------------------------------------------------*/
bool Finish::validate() {
m_data->root.transpPc = static_cast<short>(100 * (1.0 - m_data->opacity));
m_data->root.shine = static_cast<short>(10000 * (1.0 - m_data->roughness));
//NB: Archicad has no metalness value - currently discarded
return true;
} //Finish::validate
/*--------------------------------------------------------------------
Confirm the internal data, either loading from the BIM application or setting a default
--------------------------------------------------------------------*/
@@ -122,6 +122,11 @@ namespace speckle::record::attribute {
Set to the default package content
*/
void setDefault() override;
/*!
Validate the cargo data
@return True if the data has been validated
*/
bool validate() override;
private:
/*!
@@ -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 <array>
#include <memory>
namespace speckle::record::element {
class Column::Data {
public:
friend class Column;
#ifdef ARCHICAD
Data(const API_Element& elem) : root{ std::make_unique<API_ColumnType>(elem.column) } {}
Data(const Data& source) : root{ std::make_unique<API_ColumnType>(*source.root) } {}
#endif
private:
std::unique_ptr<API_ColumnType> 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<Data>(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<Data>(*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>& 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
+142
View File
@@ -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<Column>;
///Shared pointer
using Shared = std::shared_ptr<Column>;
///Optional
using Option = std::optional<Column>;
// 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>& memo) const override;
private:
class Data;
///The column data
std::unique_ptr<Data> m_data;
};
}
#endif //SPECKLE_RECORD_ELEMENT_COLUMN
@@ -0,0 +1,159 @@
#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 <ACAPinc.h>
#endif
using namespace active::serialise;
using namespace speckle::environment;
using namespace speckle::record::attribute;
using namespace speckle::record::element;
using namespace speckle::utility;
#include <array>
#include <memory>
namespace speckle::record::element {
class ColumnSegment::Data {
public:
friend class ColumnSegment;
#ifdef ARCHICAD
Data(const API_ColumnSegmentType& seg) : root{ std::make_unique<API_ColumnSegmentType>(seg) } {}
Data(const Data& source) : root{ std::make_unique<API_ColumnSegmentType>(*source.root) } {}
private:
std::unique_ptr<API_ColumnSegmentType> 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<Data>(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<Data>(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<Data>(*m_data) : nullptr;
} //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
--------------------------------------------------------------------*/
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
@@ -0,0 +1,135 @@
#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<ColumnSegment>;
///Shared pointer
using Shared = std::shared_ptr<ColumnSegment>;
///Optional
using Option = std::optional<ColumnSegment>;
// 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);
/*!
Move constructor
@param source The object to move
*/
ColumnSegment(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<Data> m_data;
};
}
#endif //SPECKLE_RECORD_ELEMENT_COLUMN_SEGMENT
+53 -56
View File
@@ -3,18 +3,23 @@
#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"
#include "Sight.hpp"
#include "Model.hpp"
#include "ModelMaterial.hpp"
#include "ModelElement.hpp"
#include "exp.h"
#include "ModelMeshBody.hpp"
#include "ConvexPolygon.hpp"
#ifdef ARCHICAD
#include <Sight.hpp>
#include <Model.hpp>
#include <ModelMaterial.hpp>
#include <ModelElement.hpp>
#include <exp.h>
#include <ModelMeshBody.hpp>
#include <ConvexPolygon.hpp>
#endif
using namespace active::serialise;
using namespace speckle::environment;
@@ -30,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<API_Element>(elem) } {}
Data(const Data& source) : root{ std::make_unique<API_Element>(*source.root) } {}
#endif
Data() {}
Data(const Data& source) {}
private:
std::unique_ptr<API_Element> root;
std::unique_ptr<Element::Body> m_cache;
};
@@ -55,16 +56,6 @@ namespace {
Identity{"displayValue"},
};
int32_t ARGBToInt(double alpha, double red, double green, double blue) {
// Convert double (0.0 - 1.0) to uint8_t (0 - 255)
uint8_t a = static_cast<uint8_t>(std::round(alpha * 255.0));
uint8_t r = static_cast<uint8_t>(std::round(red * 255.0));
uint8_t g = static_cast<uint8_t>(std::round(green * 255.0));
uint8_t b = static_cast<uint8_t>(std::round(blue * 255.0));
// Pack ARGB into a single 32-bit integer
return (a << 24) | (r << 16) | (g << 8) | b;
}
}
/*--------------------------------------------------------------------
@@ -76,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<Data>(elemData);
Element::Element(const Guid& ID, const Guid& tableID, std::optional<active::measure::LengthType> unit) : base{ID, tableID, unit} {
m_data = std::make_unique<Data>();
} //Element::Element
@@ -95,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
--------------------------------------------------------------------*/
@@ -204,13 +206,13 @@ Element::Body* Element::getBody() const {
vertices.push_back(vertex.y);
vertices.push_back(vertex.z);
double alpha = material.GetTransparency();
ModelerAPI::Color color = material.GetSurfaceColor();
colors.push_back(ARGBToInt(alpha, color.red, color.green, color.blue));
//double alpha = material.GetTransparency();
//ModelerAPI::Color color = material.GetSurfaceColor();
//colors.push_back(ARGBToInt(alpha, color.red, color.green, color.blue));
faces.push_back(vertexIndex - 1);
}
elementBody->push_back(primitive::Mesh(std::move(vertices), std::move(faces), std::move(colors)));
elementBody->push_back(primitive::Mesh(std::move(vertices), std::move(faces), std::move(colors), material));
}
}
}
@@ -221,27 +223,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
@@ -251,12 +232,11 @@ API_Elem_Head& Element::getHead() {
--------------------------------------------------------------------*/
bool Element::fillInventory(Inventory& inventory) const {
using enum Entry::Type;
auto body = getBody();
inventory.merge(Inventory{
{
{ fieldID[bodyID], bodyID, element }, //TODO: implement other fields
},
}.withType(&typeid(Element)));
}.withType(&typeid(Element)));
return base::fillInventory(inventory);
} //Element::fillInventory
@@ -276,7 +256,7 @@ Cargo::Unique Element::getCargo(const Inventory::Item& item) const {
case bodyID:
if (auto body = getBody(); body != nullptr)
{
return Cargo::Unique{ new active::serialise::ContainerWrap{ *body } };
return Cargo::Unique{ new active::serialise::ContainerWrap{*body} };
}
else
return nullptr;
@@ -294,3 +274,20 @@ 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>& memo) const {
//If the memo data isn't loaded, fetch it now
if (!memo) {
auto project = addon()->getActiveProject().lock();
if (!project)
return;
if (auto loaded = project->getElementDatabase()->getMemo(getBIMID(), filter); loaded)
memo.reset(loaded.release());
}
} //Element::loadMemo
+22 -16
View File
@@ -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,37 +35,33 @@ 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<active::measure::LengthType> unit = active::measure::LengthType::metre);
/*!
Copy constructor
@param source The object to copy
*/
Element(const Element& source);
/*!
Move constructor
@param source The object to move
*/
Element(Element&& source);
/*!
Destructor
*/
~Element();
/*!
Object cloning
@return A clone of this object
*/
Element* clonePtr() const override { return new Element{*this}; }
// MARK: - Functions (const)
/*!
@@ -90,7 +89,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 +99,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 +121,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>& memo) const;
private:
class Data;
///The element data
@@ -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 <array>
#include <memory>
namespace speckle::record::element {
class GenericElement::Data {
public:
friend class GenericElement;
#ifdef ARCHICAD
Data(const API_Element& elem) : root{ std::make_unique<API_Element>(elem) } {}
Data(const Data& source) : root{ std::make_unique<API_Element>(*source.root) } {}
#endif
private:
std::unique_ptr<API_Element> root;
std::unique_ptr<GenericElement::Body> 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<Data>(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<Data>(*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
@@ -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<primitive::Mesh>;
// MARK: - Types
using base = Element;
///Unique pointer
using Unique = std::unique_ptr<GenericElement>;
///Shared pointer
using Shared = std::shared_ptr<GenericElement>;
///Optional
using Option = std::optional<GenericElement>;
// 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<Data> m_data;
};
}
#endif //SPECKLE_RECORD_GENERIC_ELEMENT
@@ -0,0 +1,23 @@
#include "Speckle/Record/Element/Interface/Assembly/Path.h"
#include "Active/Geometry/PolyEdge.h"
#ifdef ARCHICAD
#include <ACAPinc.h>
#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<active::geometry::PolyEdge> Path::getSegmentEdge(const database::BIMIndex& index) const {
//TODO: Complete when required
return nullptr;
}
@@ -0,0 +1,48 @@
#ifndef SPECKLE_RECORD_ELEMENT_ASSEMBLY_PATH
#define SPECKLE_RECORD_ELEMENT_ASSEMBLY_PATH
#include "Speckle/Database/Identity/BIMIndex.h"
#include <memory>
#include <optional>
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<active::geometry::PolyEdge> 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
@@ -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 <ACAPinc.h>
#include <APIdefs_Elements.h>
#include <ProfileVectorImage.hpp>
#endif
using namespace active::geometry;
using namespace speckle::record::element::assembly;
/*--------------------------------------------------------------------
Default constructor
--------------------------------------------------------------------*/
Segment::Segment() :
m_cutOrigin{std::make_unique<API_AssemblySegmentCutData>()},
m_cutEnd{std::make_unique<API_AssemblySegmentCutData>()},
m_scheme{std::make_unique<API_AssemblySegmentSchemeData>()} {
} //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<API_AssemblySegmentCutData>(cutOrigin)},
m_cutEnd{std::make_unique<API_AssemblySegmentCutData>(cutEnd)},
m_scheme{std::make_unique<API_AssemblySegmentSchemeData>(scheme)} {
if (profile != nullptr) {
if (profile->customOrigProfile != nullptr)
m_customProfile = std::make_unique<ProfileVectorImage>(*profile->customOrigProfile);
if (profile->stretchedProfile != nullptr)
m_stretchedProfile = std::make_unique<ProfileVectorImage>(*profile->stretchedProfile);
}
} //Segment::Segment
/*--------------------------------------------------------------------
Copy constructor
source: The object to copy
--------------------------------------------------------------------*/
Segment::Segment(const Segment& source) :
m_cutOrigin{std::make_unique<API_AssemblySegmentCutData>(*source.m_cutOrigin)},
m_cutEnd{std::make_unique<API_AssemblySegmentCutData>(*source.m_cutEnd)},
m_scheme{std::make_unique<API_AssemblySegmentSchemeData>(*source.m_scheme)},
m_edge{source.m_edge ? std::make_unique<PolyEdge>(*source.m_edge) : nullptr},
m_customProfile{source.m_customProfile ? std::make_unique<ProfileVectorImage>(*source.m_customProfile) : nullptr},
m_stretchedProfile{source.m_stretchedProfile ? std::make_unique<ProfileVectorImage>(*source.m_stretchedProfile) : nullptr} {
m_path = source.m_path;
} //Segment::Segment
/*--------------------------------------------------------------------
Destructor
--------------------------------------------------------------------*/
Segment::~Segment() {}
@@ -0,0 +1,91 @@
#ifndef SPECKLE_RECORD_ELEMENT_ASSEMBLY_SEGMENT
#define SPECKLE_RECORD_ELEMENT_ASSEMBLY_SEGMENT
#include "Speckle/Database/Identity/BIMIndex.h"
#include <memory>
#include <optional>
#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<API_AssemblySegmentCutData> m_cutOrigin;
///Cut at the segment end
mutable std::unique_ptr<API_AssemblySegmentCutData> m_cutEnd;
///The segment scheme
mutable std::unique_ptr<API_AssemblySegmentSchemeData> m_scheme;
///An optional custom profile (nullptr = none)
mutable std::unique_ptr<ProfileVectorImage> m_customProfile;
///An optional stretched profile (nullptr = none)
mutable std::unique_ptr<ProfileVectorImage> m_stretchedProfile;
#endif
//The segment edge
mutable std::unique_ptr<active::geometry::PolyEdge> m_edge;
//The segment path
mutable const assembly::Path* m_path = nullptr;
};
}
#endif //SPECKLE_RECORD_ELEMENT_ASSEMBLY_SEGMENT
@@ -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> memo;
loadMemo(filter, memo);
}
return isMemoLoaded();
} //Part::confirmPart
@@ -0,0 +1,92 @@
#ifndef SPECKLE_RECORD_ELEMENT_PART
#define SPECKLE_RECORD_ELEMENT_PART
#include <memory>
#include <optional>
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<Part>;
///Shared pointer
using Shared = std::shared_ptr<Part>;
///Optional
using Option = std::optional<Part>;
// 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>& 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
@@ -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<ColumnSegment> 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<Data>(*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>& 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<Data>();
//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))
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<const assembly::Path*>(this);
for (size_t n = 0 ; n < segmentCount; ++n) {
const API_AssemblySegmentProfileData* thisProfile = nullptr;
for (size_t i = 0; i < profileCount; ++i) {
if (profilePtr[i].segmentIndex == n) {
thisProfile = profilePtr + i;
break;
}
}
m_data->segments.emplace_back(ColumnSegment{segmentPtr[n], getTableID(), cutPtr[n], cutPtr[n + 1], schemePtr[n], thisProfile});
m_data->segments.back().setPath(path);
}
setMemoLoaded(true);
#endif
return true;
} //SegmentedColumn::receive
@@ -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<SegmentedColumn>;
///Shared pointer
using Shared = std::shared_ptr<SegmentedColumn>;
///Optional
using Option = std::optional<SegmentedColumn>;
// 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>& 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<Data> m_data;
};
}
#endif //SPECKLE_RECORD_ELEMENT_SEGMENTED_COLUMN
@@ -0,0 +1,54 @@
#include "Speckle/Record/Element/Memo.h"
#include "Active/Utility/Memory.h"
#ifdef ARCHICAD
#include <ACAPinc.h>
#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<API_ElementMemo> 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<API_ElementMemo>();
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
+92
View File
@@ -0,0 +1,92 @@
#ifndef SPECKLE_RECORD_ELEMENT_MEMO
#define SPECKLE_RECORD_ELEMENT_MEMO
#include "Speckle/Record/Element/Element.h"
#include <memory>
#include <optional>
#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<Memo>;
///Shared pointer
using Shared = std::shared_ptr<Memo>;
///Optional
using Option = std::optional<Memo>;
// 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<API_ElementMemo> 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)
#ifdef ARCHICAD
/*!
Get the memo root data
@return The memo root data (nullptr on failure)
*/
Memo& set(std::unique_ptr<API_ElementMemo> memo) {
m_data = std::move(memo);
return *this;
}
#endif
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<API_ElementMemo> m_data;
#endif
};
}
#endif //SPECKLE_RECORD_ELEMENT_MEMO
@@ -0,0 +1,54 @@
#ifndef SPECKLE_SERIALISE_FINISH_PROXY
#define SPECKLE_SERIALISE_FINISH_PROXY
#include "Active/Serialise/Management/Management.h"
#include "Speckle/Serialise/Collection/FinishCollector.h"
#ifdef ARCHICAD
namespace ModelerAPI {
class Material;
}
#endif
namespace speckle::serialise {
/*!
Proxy cargo for tranporting a mesh finish
Mesh finishes are currently not serialised with the mesh - instead, they are gathered into a 'material proxy' container that points back to
the target meshes. This proxy allows the mesh to inform the finishes collector (acting as a serialisation manager) to link the mesh with
its finish so the manager can build the 'material proxies' at the end of the project collection.
*/
class FinishProxy : public active::serialise::Package {
public:
FinishProxy(const database::BIMRecordID& meshID, const ModelerAPI::Material& material) : m_objectID{meshID}, m_material{material} {}
/*!
Fill an inventory with the package items
@param inventory The inventory to receive the package items
@return: True if the package has added items to the inventory
*/
bool fillInventory(active::serialise::Inventory& inventory) const {
//NB: This object only exists to populate the finish collection - it doesn't carry any serialisable content
if (management() != nullptr) {
if (auto collector = management()->get<FinishCollector>(); collector != nullptr)
collector->addMaterialProxy(m_material, m_objectID);
}
return true;
} //DocumentInfo::fillInventory
/*!
Get the specified cargo
@param item The inventory item to retrieve
@return The requested cargo (nullptr on failure)
*/
active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const { return nullptr; } //Empty placeholder
private:
const database::BIMRecordID& m_objectID;
const ModelerAPI::Material& m_material;
};
}
#endif //SPECKLE_SERIALISE_FINISH_PROXY
@@ -0,0 +1,82 @@
#ifndef SPECKLE_SERIALISE_ARCHICAD_RGB
#define SPECKLE_SERIALISE_ARCHICAD_RGB
#ifdef ARCHICAD
#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
#include "Active/Serialise/Item/Wrapper/ValueOptionWrap.h"
#include "Active/Utility/BufferOut.h"
#ifdef ARCHICAD
#include <ACAPinc.h>
#include <ModelMaterial.hpp>
#endif
namespace active::serialise {
// MARK: - Specialisations for API_RGBColor
/*!
Convert a string (encoding a 32-bit unsigned integer) to an Archicad RGB colour structure
@param source The source string to convert
@return The equivalent colour (nullopt on failure)
*/
std::optional<API_RGBColor> convertToAPI_RGBColor(const utility::String& source) {
auto intValue = source.toUInt32();
if (!intValue)
return std::nullopt;
API_RGBColor result{};
*intValue >>= 8;
result.f_red = static_cast<double>(*intValue & 0xFF) / 255.0;
*intValue >>= 8;
result.f_green = static_cast<double>(*intValue & 0xFF) / 255.0;
*intValue >>= 8;
result.f_blue = static_cast<double>(*intValue & 0xFF) / 255.0;
return result;
}
/*!
Import the object from the specified string (specialisation for API_RGBColor)
@param source The string to read
@return True if the data was successfully read
*/
template<> inline
bool ValueWrap<API_RGBColor>::read(const utility::String& source) {
if (auto colour = convertToAPI_RGBColor(source); colour) {
get() = *colour;
return true;
}
return false;
} //ValueWrap<API_RGBColor>::read
/*!
Import the object from the specified string (specialisation for API_RGBColor)
@param source The string to read
@return True if the data was successfully read
*/
template<> inline
bool ValueWrap<std::optional<API_RGBColor>>::read(const utility::String& source) {
if (auto colour = convertToAPI_RGBColor(source); colour)
get() = colour;
return true;
} //ValueWrap<API_RGBColor>::read
/*!
Export the object to the specified string (specialisation for API_RGBColor)
@param dest The string to write the data to
@return True if the data was successfully written
*/
template<> inline
bool ValueWrap<API_RGBColor>::write(utility::String& dest) const {
dest = speckle::utility::String{(static_cast<uint32_t>(get().f_red * 255.0) << 16) |
((static_cast<uint32_t>(get().f_green * 255.0)) << 8) |
((static_cast<uint32_t>(get().f_blue * 255.0)))};
return true;
} //ValueWrap<API_RGBColor>::write
}
#endif //ARCHICAD
#endif //SPECKLE_SERIALISE_ARCHICAD_RGB
@@ -0,0 +1,65 @@
#ifndef SPECKLE_SERIALISE_STR256
#define SPECKLE_SERIALISE_STR256
#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
#include "Active/Serialise/Item/Wrapper/ValueOptionWrap.h"
#include "Active/Utility/BufferOut.h"
namespace active::serialise {
constexpr size_t str256Size = 256;
///NB: This is primarily for Archicad that still uses fixed 256-bytes char array strings in some contexts
using Str256 = std::array<char, str256Size>;
// MARK: - Specialisations for Str256
/*!
Import the object from the specified string (specialisation for Str256)
@param source The string to read
@return True if the data was successfully read
*/
template<> inline
bool ValueWrap<Str256>::read(const utility::String& source) {
source.writeUTF8(active::utility::BufferOut{get()});
return true;
} //ValueWrap<Str256>::read
/*!
Import the object from the specified string (specialisation for Str256)
@param source The string to read
@return True if the data was successfully read
*/
template<> inline
bool ValueWrap<std::optional<Str256>>::read(const utility::String& source) {
base::get() = Str256{};
source.writeUTF8(active::utility::BufferOut{*base::get()});
return true;
} //ValueWrap<Str256>::read
/*!
Export the object to the specified string (specialisation for Str256)
@param dest The string to write the data to
@return True if the data was successfully written
*/
template<> inline
bool ValueWrap<Str256>::write(utility::String& dest) const {
dest.assign(reinterpret_cast<const char*>(&get()), str256Size);
return true;
} //ValueWrap<Str256>::write
/*!
Get the serialisation type for the item value
@return The item value serialisation type (nullopt = unspecified, i.e. a default is acceptable)
*/
template<> inline
std::optional<Item::Type> ValueWrap<Str256>::type() const {
return Item::Type::text;
} //ValueWrap<Str256>::type
}
#endif //SPECKLE_SERIALISE_STR256
@@ -1,4 +1,4 @@
#include "Speckle/Serialise/Units/LengthUnit.h"
#include "Speckle/Serialise/Types/Units/LengthUnit.h"
#include <algorithm>
#include <map>
+39
View File
@@ -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<GSConstPtr>(pointer));
if (getLastError() != NoError)
throw; //TODO: Throw a specific exception type
return size;
#endif
} //BIMMemory::getPtrSize
+23
View File
@@ -0,0 +1,23 @@
#ifndef SPECKLE_UTILITY_BIM_MEMORY
#define SPECKLE_UTILITY_BIM_MEMORY
#include <memory>
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
+107 -1
View File
@@ -49,6 +49,26 @@
2196F3052CB57E8000450DFC /* Storey.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2196F3032CB57E7F00450DFC /* Storey.cpp */; };
2199881E2BD833830035E5EA /* libArchicad27.a in CopyFiles */ = {isa = PBXBuildFile; fileRef = 21379E082AE47A6400A1584C /* libArchicad27.a */; };
21A0FBA42CB880690023F24E /* FinishCollector.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A0FB9F2CB880690023F24E /* FinishCollector.h */; };
21A0FBB52CBA5E380023F24E /* Str256.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A0FBB42CBA5E380023F24E /* Str256.h */; };
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 */; };
@@ -188,6 +208,27 @@
2196F3032CB57E7F00450DFC /* Storey.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Storey.cpp; sourceTree = "<group>"; };
219712682BE7E2D500D9EF7E /* Serialisation.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Serialisation.md; sourceTree = "<group>"; };
21A0FB9F2CB880690023F24E /* FinishCollector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FinishCollector.h; sourceTree = "<group>"; };
21A0FBA92CB9324A0023F24E /* FinishProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FinishProxy.h; sourceTree = "<group>"; };
21A0FBB42CBA5E380023F24E /* Str256.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Str256.h; sourceTree = "<group>"; };
21A0FBB92CBBC04C0023F24E /* ArchicadRGB.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArchicadRGB.h; sourceTree = "<group>"; };
21A0FBDF2CBD6B1A0023F24E /* ColumnSegment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ColumnSegment.cpp; sourceTree = "<group>"; };
21A0FBE22CBD6B1A0023F24E /* ColumnSegment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ColumnSegment.h; sourceTree = "<group>"; };
21A0FBE42CBD6B1A0023F24E /* Part.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Part.h; sourceTree = "<group>"; };
21A0FBE82CBD6B1A0023F24E /* Column.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Column.cpp; sourceTree = "<group>"; };
21A0FBE92CBD6B1A0023F24E /* Column.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Column.h; sourceTree = "<group>"; };
21A0FBF22CBD6B700023F24E /* Memo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Memo.h; sourceTree = "<group>"; };
21A0FBF32CBD6B700023F24E /* Memo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Memo.cpp; sourceTree = "<group>"; };
21A0FBF62CBDB9A70023F24E /* BIMMemory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BIMMemory.cpp; sourceTree = "<group>"; };
21A0FBF72CBDB9A70023F24E /* BIMMemory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BIMMemory.h; sourceTree = "<group>"; };
21A0FBFF2CBE59A80023F24E /* SegmentedColumn.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SegmentedColumn.cpp; sourceTree = "<group>"; };
21A0FC002CBE59A80023F24E /* SegmentedColumn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SegmentedColumn.h; sourceTree = "<group>"; };
21A0FC012CBE59A80023F24E /* Path.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Path.cpp; sourceTree = "<group>"; };
21A0FC022CBE59A80023F24E /* Path.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Path.h; sourceTree = "<group>"; };
21A0FC082CBE5E220023F24E /* Segment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Segment.cpp; sourceTree = "<group>"; };
21A0FC092CBE5E220023F24E /* Segment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Segment.h; sourceTree = "<group>"; };
21A0FC0C2CBE92F10023F24E /* GenericElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GenericElement.cpp; sourceTree = "<group>"; };
21A0FC0D2CBE92F10023F24E /* GenericElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GenericElement.h; sourceTree = "<group>"; };
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 = "<group>"; };
21AEF9B52CA5FA02000B8681 /* DetachedReference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedReference.h; sourceTree = "<group>"; };
21AEF9B72CA5FCB6000B8681 /* DetachmentManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachmentManager.h; sourceTree = "<group>"; };
@@ -295,8 +336,8 @@
21A0FBA02CB880690023F24E /* Collection */,
21AEF9C72CA818EA000B8681 /* Detached */,
21F69F3A2C6B880B008B6A06 /* JSBase */,
2196F2DF2CB0566500450DFC /* Units */,
219712682BE7E2D500D9EF7E /* Serialisation.md */,
21A0FBB12CBA5E0E0023F24E /* Types */,
);
path = Serialise;
sourceTree = "<group>";
@@ -335,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 = "<group>";
@@ -424,6 +474,8 @@
219351B02C62CC1A00E5A69C /* Utility */ = {
isa = PBXGroup;
children = (
21A0FBF62CBDB9A70023F24E /* BIMMemory.cpp */,
21A0FBF72CBDB9A70023F24E /* BIMMemory.h */,
21B67CFE2C7CE15100FD64FC /* Exception.h */,
219351AC2C62CC1A00E5A69C /* Guid.cpp */,
219351AD2C62CC1A00E5A69C /* Guid.h */,
@@ -479,10 +531,44 @@
isa = PBXGroup;
children = (
21A0FB9F2CB880690023F24E /* FinishCollector.h */,
21A0FBA92CB9324A0023F24E /* FinishProxy.h */,
);
path = Collection;
sourceTree = "<group>";
};
21A0FBB12CBA5E0E0023F24E /* Types */ = {
isa = PBXGroup;
children = (
21A0FBB92CBBC04C0023F24E /* ArchicadRGB.h */,
21A0FBB42CBA5E380023F24E /* Str256.h */,
2196F2DF2CB0566500450DFC /* Units */,
);
path = Types;
sourceTree = "<group>";
};
21A0FBE72CBD6B1A0023F24E /* Interface */ = {
isa = PBXGroup;
children = (
21A0FC032CBE59A80023F24E /* Assembly */,
21A0FC102CBEE5C30023F24E /* Part.cpp */,
21A0FBE42CBD6B1A0023F24E /* Part.h */,
21A0FBFF2CBE59A80023F24E /* SegmentedColumn.cpp */,
21A0FC002CBE59A80023F24E /* SegmentedColumn.h */,
);
path = Interface;
sourceTree = "<group>";
};
21A0FC032CBE59A80023F24E /* Assembly */ = {
isa = PBXGroup;
children = (
21A0FC012CBE59A80023F24E /* Path.cpp */,
21A0FC022CBE59A80023F24E /* Path.h */,
21A0FC082CBE5E220023F24E /* Segment.cpp */,
21A0FC092CBE5E220023F24E /* Segment.h */,
);
path = Assembly;
sourceTree = "<group>";
};
21AEF9C72CA818EA000B8681 /* Detached */ = {
isa = PBXGroup;
children = (
@@ -689,9 +775,11 @@
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 */,
21A0FBB52CBA5E380023F24E /* Str256.h in Headers */,
210CC86F2C7E879700610F58 /* ArgumentBase.h in Headers */,
210CC8A02C81E34400610F58 /* Platform.h in Headers */,
219246132CA34DCE00CF5703 /* Mesh.h in Headers */,
@@ -704,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 */,
@@ -717,6 +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 */,
@@ -845,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 */,
@@ -867,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;
+25 -2
View File
@@ -71,15 +71,28 @@
<ClInclude Include="Speckle\Record\Credentials\ServerInfo.h" />
<ClInclude Include="Speckle\Record\Credentials\ServerMigration.h" />
<ClInclude Include="Speckle\Record\Credentials\UserInfo.h" />
<ClInclude Include="Speckle\Record\Element\Column.h" />
<ClInclude Include="Speckle\Record\Element\ColumnSegment.h" />
<ClInclude Include="Speckle\Record\Element\Element.h" />
<ClInclude Include="Speckle\Record\Element\GenericElement.h" />
<ClInclude Include="Speckle\Record\Element\Interface\Assembly\Path.h" />
<ClInclude Include="Speckle\Record\Element\Interface\Assembly\Segment.h" />
<ClInclude Include="Speckle\Record\Element\Interface\Part.h" />
<ClInclude Include="Speckle\Record\Element\Interface\SegmentedColumn.h" />
<ClInclude Include="Speckle\Record\Element\Memo.h" />
<ClInclude Include="Speckle\Serialise\Collection\FinishCollector.h" />
<ClInclude Include="Speckle\Serialise\Collection\FinishProxy.h" />
<ClInclude Include="Speckle\Serialise\Detached\DetachedReference.h" />
<ClInclude Include="Speckle\Serialise\Detached\DetachedWrap.h" />
<ClInclude Include="Speckle\Serialise\Detached\DetachmentManager.h" />
<ClInclude Include="Speckle\Serialise\Detached\Storage\DetachedMemoryStore.h" />
<ClInclude Include="Speckle\Serialise\Detached\Storage\DetachedObjectStore.h" />
<ClInclude Include="Speckle\Serialise\JSBase\JSBaseTransport.h" />
<ClInclude Include="Speckle\Serialise\Units\LengthUnit.h" />
<ClInclude Include="Speckle\Serialise\Types\ArchicadRGB.h" />
<ClInclude Include="Speckle\Serialise\Types\Str256.h" />
<ClInclude Include="Speckle\Serialise\Types\Units\LengthUnit.h" />
<ClInclude Include="Speckle\SpeckleResource.h" />
<ClInclude Include="Speckle\Utility\BIMMemory.h" />
<ClInclude Include="Speckle\Utility\Exception.h" />
<ClInclude Include="Speckle\Utility\Guid.h" />
<ClInclude Include="Speckle\Utility\Guid64.h" />
@@ -120,12 +133,21 @@
<ClCompile Include="Speckle\Record\Credentials\ServerInfo.cpp" />
<ClCompile Include="Speckle\Record\Credentials\ServerMigration.cpp" />
<ClCompile Include="Speckle\Record\Credentials\UserInfo.cpp" />
<ClCompile Include="Speckle\Record\Element\Column.cpp" />
<ClCompile Include="Speckle\Record\Element\ColumnSegment.cpp" />
<ClCompile Include="Speckle\Record\Element\Element.cpp" />
<ClCompile Include="Speckle\Record\Element\GenericElement.cpp" />
<ClCompile Include="Speckle\Record\Element\Interface\Assembly\Path.cpp" />
<ClCompile Include="Speckle\Record\Element\Interface\Assembly\Segment.cpp" />
<ClCompile Include="Speckle\Record\Element\Interface\Part.cpp" />
<ClCompile Include="Speckle\Record\Element\Interface\SegmentedColumn.cpp" />
<ClCompile Include="Speckle\Record\Element\Memo.cpp" />
<ClCompile Include="Speckle\Serialise\Detached\DetachedReference.cpp" />
<ClCompile Include="Speckle\Serialise\Detached\DetachedWrap.cpp" />
<ClCompile Include="Speckle\Serialise\Detached\DetachmentManager.cpp" />
<ClCompile Include="Speckle\Serialise\JSBase\JSBaseTransport.cpp" />
<ClCompile Include="Speckle\Serialise\Units\LengthUnit.cpp" />
<ClCompile Include="Speckle\Serialise\Types\Units\LengthUnit.cpp" />
<ClCompile Include="Speckle\Utility\BIMMemory.cpp" />
<ClCompile Include="Speckle\Utility\Guid.cpp" />
<ClCompile Include="Speckle\Utility\Guid64.cpp" />
<ClCompile Include="Speckle\Utility\String.cpp" />
@@ -281,6 +303,7 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<TreatAngleIncludeAsExternal>true</TreatAngleIncludeAsExternal>
<ExternalWarningLevel>TurnOffAllWarnings</ExternalWarningLevel>
<PreprocessToFile>false</PreprocessToFile>
</ClCompile>
<Link>
<SubSystem>
+87 -9
View File
@@ -83,15 +83,27 @@
<Filter Include="Speckle\Serialise\Detached\Storage">
<UniqueIdentifier>{cb77e795-e8d8-4e31-9773-dd32beb694d3}</UniqueIdentifier>
</Filter>
<Filter Include="Speckle\Serialise\Units">
<UniqueIdentifier>{7d5ec9ba-bc7e-412c-9b14-16c37b183409}</UniqueIdentifier>
</Filter>
<Filter Include="Speckle\Database\Storage\ArchicadDBase\Attribute">
<UniqueIdentifier>{490a65bd-28e3-4282-bb33-67823e81e825}</UniqueIdentifier>
</Filter>
<Filter Include="Speckle\Record\Attribute">
<UniqueIdentifier>{525b6bd6-96e4-48c8-91e9-9710e1e54389}</UniqueIdentifier>
</Filter>
<Filter Include="Speckle\Serialise\Collection">
<UniqueIdentifier>{b5733e9f-b72a-4162-9fc7-8feeec594e5b}</UniqueIdentifier>
</Filter>
<Filter Include="Speckle\Serialise\Types">
<UniqueIdentifier>{b992941c-66d5-4f16-89b2-82e27a22e229}</UniqueIdentifier>
</Filter>
<Filter Include="Speckle\Serialise\Types\Units">
<UniqueIdentifier>{7f43d4ea-b876-4587-a646-90eab81f7976}</UniqueIdentifier>
</Filter>
<Filter Include="Speckle\Record\Element\Interface">
<UniqueIdentifier>{b35abbfd-3c47-45dc-8dab-58911f233a87}</UniqueIdentifier>
</Filter>
<Filter Include="Speckle\Record\Element\Interface\Assembly">
<UniqueIdentifier>{8e7a76da-47ac-4105-9c09-7d7ed62d7136}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Speckle\Environment\Addon.h">
@@ -274,9 +286,6 @@
<ClInclude Include="Speckle\Serialise\Detached\Storage\DetachedObjectStore.h">
<Filter>Speckle\Serialise\Detached\Storage</Filter>
</ClInclude>
<ClInclude Include="Speckle\Serialise\Units\LengthUnit.h">
<Filter>Speckle\Serialise\Units</Filter>
</ClInclude>
<ClInclude Include="Speckle\Database\BIMAttributeDatabase.h">
<Filter>Speckle\Database</Filter>
</ClInclude>
@@ -292,6 +301,48 @@
<ClInclude Include="Speckle\Record\Attribute\Storey.h">
<Filter>Speckle\Record\Attribute</Filter>
</ClInclude>
<ClInclude Include="Speckle\Serialise\Collection\FinishCollector.h">
<Filter>Speckle\Serialise\Collection</Filter>
</ClInclude>
<ClInclude Include="Speckle\Serialise\Collection\FinishProxy.h">
<Filter>Speckle\Serialise\Collection</Filter>
</ClInclude>
<ClInclude Include="Speckle\Serialise\Types\Str256.h">
<Filter>Speckle\Serialise\Types</Filter>
</ClInclude>
<ClInclude Include="Speckle\Serialise\Types\Units\LengthUnit.h">
<Filter>Speckle\Serialise\Types\Units</Filter>
</ClInclude>
<ClInclude Include="Speckle\Serialise\Types\ArchicadRGB.h">
<Filter>Speckle\Serialise\Types</Filter>
</ClInclude>
<ClInclude Include="Speckle\Record\Element\Column.h">
<Filter>Speckle\Record\Element</Filter>
</ClInclude>
<ClInclude Include="Speckle\Record\Element\ColumnSegment.h">
<Filter>Speckle\Record\Element</Filter>
</ClInclude>
<ClInclude Include="Speckle\Record\Element\Memo.h">
<Filter>Speckle\Record\Element</Filter>
</ClInclude>
<ClInclude Include="Speckle\Record\Element\Interface\Part.h">
<Filter>Speckle\Record\Element\Interface</Filter>
</ClInclude>
<ClInclude Include="Speckle\Record\Element\Interface\SegmentedColumn.h">
<Filter>Speckle\Record\Element\Interface</Filter>
</ClInclude>
<ClInclude Include="Speckle\Record\Element\Interface\Assembly\Path.h">
<Filter>Speckle\Record\Element\Interface\Assembly</Filter>
</ClInclude>
<ClInclude Include="Speckle\Record\Element\Interface\Assembly\Segment.h">
<Filter>Speckle\Record\Element\Interface\Assembly</Filter>
</ClInclude>
<ClInclude Include="Speckle\Utility\BIMMemory.h">
<Filter>Speckle\Utility</Filter>
</ClInclude>
<ClInclude Include="Speckle\Record\Element\GenericElement.h">
<Filter>Speckle\Record\Element</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Speckle\Environment\Addon.cpp">
@@ -402,9 +453,6 @@
<ClCompile Include="Speckle\Serialise\Detached\DetachmentManager.cpp">
<Filter>Speckle\Serialise\Detached</Filter>
</ClCompile>
<ClCompile Include="Speckle\Serialise\Units\LengthUnit.cpp">
<Filter>Speckle\Serialise\Units</Filter>
</ClCompile>
<ClCompile Include="Speckle\Database\BIMAttributeDatabase.cpp">
<Filter>Speckle\Database</Filter>
</ClCompile>
@@ -420,6 +468,36 @@
<ClCompile Include="Speckle\Record\Attribute\Storey.cpp">
<Filter>Speckle\Record\Attribute</Filter>
</ClCompile>
<ClCompile Include="Speckle\Serialise\Types\Units\LengthUnit.cpp">
<Filter>Speckle\Serialise\Types\Units</Filter>
</ClCompile>
<ClCompile Include="Speckle\Record\Element\Column.cpp">
<Filter>Speckle\Record\Element</Filter>
</ClCompile>
<ClCompile Include="Speckle\Record\Element\ColumnSegment.cpp">
<Filter>Speckle\Record\Element</Filter>
</ClCompile>
<ClCompile Include="Speckle\Record\Element\Memo.cpp">
<Filter>Speckle\Record\Element</Filter>
</ClCompile>
<ClCompile Include="Speckle\Record\Element\Interface\Part.cpp">
<Filter>Speckle\Record\Element\Interface</Filter>
</ClCompile>
<ClCompile Include="Speckle\Record\Element\Interface\SegmentedColumn.cpp">
<Filter>Speckle\Record\Element\Interface</Filter>
</ClCompile>
<ClCompile Include="Speckle\Record\Element\Interface\Assembly\Path.cpp">
<Filter>Speckle\Record\Element\Interface\Assembly</Filter>
</ClCompile>
<ClCompile Include="Speckle\Record\Element\Interface\Assembly\Segment.cpp">
<Filter>Speckle\Record\Element\Interface\Assembly</Filter>
</ClCompile>
<ClCompile Include="Speckle\Utility\BIMMemory.cpp">
<Filter>Speckle\Utility</Filter>
</ClCompile>
<ClCompile Include="Speckle\Record\Element\GenericElement.cpp">
<Filter>Speckle\Record\Element</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Text Include="Speckle\CMakeLists.txt">