Compare commits

...

43 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
David Kekesi 30163bfd9d export mesh, vertices, faces, colors 2024-10-11 12:44:55 +02:00
Ralph Wessel 21fc2cff25 Added FinishCollector interface as a serialisation manager to collect finishes from meshes as they are serialised
ProjectCollection is now a FinishCollector (accumulates the finishes to write the material proxies at the end)
2024-10-11 09:58:26 +01:00
Ralph Wessel 0c74a28982 Fixes to Storey attribute class 2024-10-10 13:45:36 +01:00
Ralph Wessel cc64d7df44 Added lookup for AC storeys using an element floor index 2024-10-10 13:02:57 +01:00
Ralph Wessel f7112a407c Set correct base class for RecordCollection
RecordCollection serialises name
2024-10-10 12:12:35 +01:00
Ralph Wessel 7ed4d8c807 Updated VS projects 2024-10-10 10:45:35 +01:00
Ralph Wessel b5447b263e NB: Interim commit - new code is untested at this point
Information sent to Speckle is now presented in hiearchical collections:
- Root level contains material proxies
- Second level is project storeys
- Third level is element type
Added database and record definitions for attributes including:
- Finishes (surface rendering material)
- Storeys
Element getters for storey and type name
Aligned some speckle_type names to Revit (where possible)
2024-10-10 08:52:18 +01:00
Ralph Wessel b51b0ecb13 Mesh serialises with speckle_type and units - now appears in 3D view 2024-10-04 22:13:32 +01:00
Ralph Wessel 72cd75d2e6 Added speckle_type and unit properties to Record, BIMRecord, Element and Mesh classes
Defined (de)serialisation for LengthType
2024-10-04 21:03:54 +01:00
Ralph Wessel 3e2777a38f Merge branch 'david/cnx-577-implement-mesh-class' into develop 2024-10-03 17:55:44 +01:00
87 changed files with 5636 additions and 454 deletions
+10 -2
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" />
@@ -127,8 +130,9 @@
<ClCompile Include="Connector\Interface\Browser\Bridge\Test\TriggerEvent.cpp" />
<ClCompile Include="Connector\Interface\ConnectorMenu.cpp" />
<ClCompile Include="Connector\Interface\ConnectorPalette.cpp" />
<ClCompile Include="Connector\Record\Collection\FinishProxy.cpp" />
<ClCompile Include="Connector\Record\Collection\ProjectCollection.cpp" />
<ClCompile Include="Connector\Record\Collection\RecordCollection.cpp" />
<ClCompile Include="Connector\Record\Collection\RootCollection.cpp" />
<ClCompile Include="Connector\Record\Model\CardMover.cpp" />
<ClCompile Include="Connector\Record\Model\CardSetting.cpp" />
<ClCompile Include="Connector\Record\Model\Filter\DirectSelectionSendFilter.cpp" />
@@ -162,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" />
@@ -178,8 +185,9 @@
<ClInclude Include="Connector\Interface\Browser\Bridge\Test\TriggerEvent.h" />
<ClInclude Include="Connector\Interface\ConnectorMenu.h" />
<ClInclude Include="Connector\Interface\ConnectorPalette.h" />
<ClInclude Include="Connector\Record\Collection\FinishProxy.h" />
<ClInclude Include="Connector\Record\Collection\ProjectCollection.h" />
<ClInclude Include="Connector\Record\Collection\RecordCollection.h" />
<ClInclude Include="Connector\Record\Collection\RootCollection.h" />
<ClInclude Include="Connector\Record\Model\CardMover.h" />
<ClInclude Include="Connector\Record\Model\CardSetting.h" />
<ClInclude Include="Connector\Record\Model\Filter\ArchicadEverythingFilter.h" />
+36 -6
View File
@@ -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">
@@ -207,9 +213,6 @@
<ClCompile Include="Connector\Record\Collection\RecordCollection.cpp">
<Filter>Connector\Record\Collection</Filter>
</ClCompile>
<ClCompile Include="Connector\Record\Collection\RootCollection.cpp">
<Filter>Connector\Record\Collection</Filter>
</ClCompile>
<ClCompile Include="Connector\Interface\Browser\Bridge\Send\Arg\ConversionResult.cpp">
<Filter>Connector\Interface\Browser\Bridge\Send\Arg</Filter>
</ClCompile>
@@ -225,6 +228,21 @@
<ClCompile Include="Connector\Interface\Browser\Bridge\Send\GetSendSettings.cpp">
<Filter>Connector\Interface\Browser\Bridge\Send</Filter>
</ClCompile>
<ClCompile Include="Connector\Record\Collection\FinishProxy.cpp">
<Filter>Connector\Record\Collection</Filter>
</ClCompile>
<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">
@@ -363,9 +381,6 @@
<ClInclude Include="Connector\Record\Collection\RecordCollection.h">
<Filter>Connector\Record\Collection</Filter>
</ClInclude>
<ClInclude Include="Connector\Record\Collection\RootCollection.h">
<Filter>Connector\Record\Collection</Filter>
</ClInclude>
<ClInclude Include="Connector\Interface\Browser\Bridge\Send\Arg\ConversionResult.h">
<Filter>Connector\Interface\Browser\Bridge\Send\Arg</Filter>
</ClInclude>
@@ -381,5 +396,20 @@
<ClInclude Include="Connector\Interface\Browser\Bridge\Send\GetSendSettings.h">
<Filter>Connector\Interface\Browser\Bridge\Send</Filter>
</ClInclude>
<ClInclude Include="Connector\Record\Collection\FinishProxy.h">
<Filter>Connector\Record\Collection</Filter>
</ClInclude>
<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>
@@ -29,8 +29,9 @@
215F082E2C94C5C000CD343B /* FilterMover.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 215F082C2C94C5C000CD343B /* FilterMover.cpp */; };
215F08372C95808B00CD343B /* ReceiverModelCard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 215F08362C95808B00CD343B /* ReceiverModelCard.cpp */; };
215F08462C9633A800CD343B /* EverythingSendFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 215F08452C9633A800CD343B /* EverythingSendFilter.cpp */; };
2192460D2CA3469D00CF5703 /* RootCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2192460B2CA3469D00CF5703 /* RootCollection.cpp */; };
2192460D2CA3469D00CF5703 /* ProjectCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2192460B2CA3469D00CF5703 /* ProjectCollection.cpp */; };
219F30422C769283009834E9 /* ConfigTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219F30402C769282009834E9 /* ConfigTests.cpp */; };
21A0FB982CB723240023F24E /* FinishProxy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21A0FB942CB723240023F24E /* FinishProxy.cpp */; };
21AEF9EB2CAB56E5000B8681 /* SendError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9E32CAB56E5000B8681 /* SendError.cpp */; };
21AEF9EC2CAB56E5000B8681 /* SendViaBrowserArgs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9E52CAB56E5000B8681 /* SendViaBrowserArgs.cpp */; };
21AEF9EF2CAB5720000B8681 /* SendObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9EE2CAB5720000B8681 /* SendObject.cpp */; };
@@ -305,12 +306,14 @@
215F08452C9633A800CD343B /* EverythingSendFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EverythingSendFilter.cpp; sourceTree = "<group>"; };
215F084A2C9782F100CD343B /* ArchicadEverythingFilter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ArchicadEverythingFilter.h; sourceTree = "<group>"; };
2161FD902BF2600C006D9527 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
2192460B2CA3469D00CF5703 /* RootCollection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RootCollection.cpp; sourceTree = "<group>"; };
2192460C2CA3469D00CF5703 /* RootCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RootCollection.h; sourceTree = "<group>"; };
2192460B2CA3469D00CF5703 /* ProjectCollection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProjectCollection.cpp; sourceTree = "<group>"; };
2192460C2CA3469D00CF5703 /* ProjectCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProjectCollection.h; sourceTree = "<group>"; };
219388682C4E5DE2002A0180 /* CMakeLists.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
219F30352C768F0A009834E9 /* Connector-AC27-Test.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Connector-AC27-Test.bundle"; sourceTree = BUILT_PRODUCTS_DIR; };
219F30402C769282009834E9 /* ConfigTests.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = ConfigTests.cpp; sourceTree = "<group>"; };
219F30432C7693B6009834E9 /* Connector-AC27-Debug.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Connector-AC27-Debug.xctestplan"; sourceTree = SOURCE_ROOT; };
21A0FB942CB723240023F24E /* FinishProxy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FinishProxy.cpp; sourceTree = "<group>"; };
21A0FB972CB723240023F24E /* FinishProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FinishProxy.h; sourceTree = "<group>"; };
21AEF9E32CAB56E5000B8681 /* SendError.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SendError.cpp; sourceTree = "<group>"; };
21AEF9E42CAB56E5000B8681 /* SendError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SendError.h; sourceTree = "<group>"; };
21AEF9E52CAB56E5000B8681 /* SendViaBrowserArgs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SendViaBrowserArgs.cpp; sourceTree = "<group>"; };
@@ -1231,10 +1234,12 @@
21FF70482CA1A7F400AAD99A /* Collection */ = {
isa = PBXGroup;
children = (
21A0FB942CB723240023F24E /* FinishProxy.cpp */,
21A0FB972CB723240023F24E /* FinishProxy.h */,
21FF70462CA1A7F400AAD99A /* RecordCollection.cpp */,
21FF70472CA1A7F400AAD99A /* RecordCollection.h */,
2192460B2CA3469D00CF5703 /* RootCollection.cpp */,
2192460C2CA3469D00CF5703 /* RootCollection.h */,
2192460B2CA3469D00CF5703 /* ProjectCollection.cpp */,
2192460C2CA3469D00CF5703 /* ProjectCollection.h */,
);
path = Collection;
sourceTree = "<group>";
@@ -1456,11 +1461,12 @@
21B67CF72C78D4DE00FD64FC /* GetComplexType.cpp in Sources */,
21D0BDDC2C93897B0077E104 /* SenderModelCard.cpp in Sources */,
21B67CAE2C77329800FD64FC /* GetSourceApplicationVersion.cpp in Sources */,
21A0FB982CB723240023F24E /* FinishProxy.cpp in Sources */,
21B67CC32C77649F00FD64FC /* GetDocumentState.cpp in Sources */,
21D0BD602C89BFEA0077E104 /* SendBridge.cpp in Sources */,
21D0BD972C8F13F30077E104 /* GetSendFilters.cpp in Sources */,
21B67CAC2C77329800FD64FC /* BaseBridge.cpp in Sources */,
2192460D2CA3469D00CF5703 /* RootCollection.cpp in Sources */,
2192460D2CA3469D00CF5703 /* ProjectCollection.cpp in Sources */,
21D0BD6A2C8A0DB40077E104 /* GetIsDevMode.cpp in Sources */,
210CC8832C80E6A300610F58 /* TriggerEvent.cpp in Sources */,
21B67CEB2C78D27200FD64FC /* DocumentInfo.cpp in Sources */,
@@ -28,6 +28,7 @@ enum StringResource {
enum TitleString {
addonNameID = 1,
addonDescriptionID,
noStoreyID,
};
@@ -39,20 +39,20 @@ namespace connector::interfac::browser::bridge {
// MARK: - Serialisation
/*!
Fill an inventory with the package items
@param inventory The inventory to receive the package items
@return True if the package has added items to the inventory
*/
Fill an inventory with the package items
@param inventory The inventory to receive the package items
@return True if the package has added items to the inventory
*/
bool fillInventory(active::serialise::Inventory& inventory) const override;
/*!
Get the specified cargo
@param item The inventory item to retrieve
@return The requested cargo (nullptr on failure)
*/
Get the specified cargo
@param item The inventory item to retrieve
@return The requested cargo (nullptr on failure)
*/
Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
/*!
Set to the default package content
*/
Set to the default package content
*/
void setDefault() override;
};
@@ -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(); }
};
}
@@ -7,6 +7,7 @@
#include "Connector/Database/ModelCardDatabase.h"
#include "Connector/Interface/Browser/Bridge/Send/Arg/SendError.h"
#include "Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h"
#include "Connector/Record/Collection/ProjectCollection.h"
#include "Speckle/Database/AccountDatabase.h"
#include "Speckle/Database/Content/BIMRecord.h"
#include "Speckle/Interface/Browser/Bridge/BrowserBridge.h"
@@ -23,6 +24,7 @@ using namespace speckle::record::element;
using namespace active::serialise;
using namespace connector::interfac::browser::bridge;
using namespace connector::record;
using namespace speckle::database;
using namespace speckle::serialise;
using namespace speckle::utility;
@@ -68,27 +70,20 @@ void Send::run(const String& modelCardID) const {
std::make_unique<SendError>(connector()->getLocalString(errorString, noProjectOpenID), modelCardID));
return;
}
//Collect targeted elements here
//NB: This is a testing placeholder
Element::Unique element;
if (auto project = connector::connector()->getActiveProject().lock(); project) {
auto elementDatabase = project->getElementDatabase();
auto selected = elementDatabase->getSelection();
for (const auto& link : selected)
if (element = elementDatabase->getElement(link); element)
break;
}
if (!element) {
//Build a collection from the selected elements
auto collection = std::make_unique<ProjectCollection>(project);
auto elementDatabase = project->getElementDatabase();
auto selected = elementDatabase->getSelection();
if (selected.empty()) {
getBridge()->sendEvent("setModelError",
std::make_unique<SendError>(connector()->getLocalString(errorString, noSelectedModelItemsID), modelCardID));
return;
}
for (const auto& link : selected) {
if (auto element = elementDatabase->getElement(link); element)
collection->addElement(*element);
}
//Send the collected information
auto result = std::make_unique<SendViaBrowserArgs>(*modelCard, *account, SendObject{std::move(element)}); //NB: Using a placeholder object for now
auto result = std::make_unique<SendViaBrowserArgs>(*modelCard, *account, SendObject{std::move(collection)});
getBridge()->sendEvent("sendByBrowser", std::move(result));
} //Send::run
@@ -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:
@@ -0,0 +1,68 @@
#include "Connector/Record/Collection/FinishProxy.h"
#include "Active/Serialise/Package/Wrapper/ContainerWrap.h"
#include "Active/Serialise/Package/Wrapper/PackageWrap.h"
#include <array>
using namespace active::serialise;
using namespace connector::record;
using namespace speckle::utility;
namespace {
///Serialisation fields
enum FieldIndex {
materialID,
linkedMeshID,
};
///Serialisation field IDs
static std::array fieldID = {
Identity{"value"},
Identity{"objects"},
};
}
/*--------------------------------------------------------------------
Fill an inventory with the package items
inventory: The inventory to receive the package items
return: True if the package has added items to the inventory
--------------------------------------------------------------------*/
bool FinishProxy::fillInventory(active::serialise::Inventory& inventory) const {
using enum Entry::Type;
inventory.merge(Inventory{
{
{ fieldID[materialID], materialID, element },
{ fieldID[linkedMeshID], linkedMeshID, element },
},
}.withType(&typeid(FinishProxy)));
return base::fillInventory(inventory);
} //FinishProxy::fillInventory
/*--------------------------------------------------------------------
Get the specified cargo
item: The inventory item to retrieve
return: The requested cargo (nullptr on failure)
--------------------------------------------------------------------*/
Cargo::Unique FinishProxy::getCargo(const active::serialise::Inventory::Item& item) const {
if (item.ownerType != &typeid(FinishProxy))
return base::getCargo(item);
using namespace active::serialise;
switch (item.index) {
case materialID:
return std::make_unique<PackageWrap>(m_finish);
case linkedMeshID: {
auto result = new ContainerWrap(m_meshID);
return Cargo::Unique{result};
}
default:
return nullptr; //Requested an unknown index
}
} //FinishProxy::getCargo
@@ -0,0 +1,60 @@
#ifndef CONNECTOR_RECORD_COLLECTION_MATERIAL_PROXY
#define CONNECTOR_RECORD_COLLECTION_MATERIAL_PROXY
#include "Speckle/Database/Content/BIMRecord.h"
#include "Speckle/Record/Attribute/Finish.h"
#include "Speckle/Utility/String.h"
namespace connector::record {
/*!
A proxy record binding a surface finishes to meshes
*/
class FinishProxy : public speckle::database::BIMRecord {
public:
using base = speckle::database::BIMRecord;
// MARK: - Constructors
/*!
Constructor
@param finish The proxy surface finish
@param meshID The list of mesh IDs the finish is applied to
*/
FinishProxy(const speckle::record::attribute::Finish& finish, const std::unordered_set<active::utility::Guid>& 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
/*!
Fill an inventory with the package items
@param inventory The inventory to receive the package items
@return True if the package has added items to the inventory
*/
bool fillInventory(active::serialise::Inventory& inventory) const override;
/*!
Get the specified cargo
@param item The inventory item to retrieve
@return The requested cargo (nullptr on failure)
*/
Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
private:
///The proxy surface finish
speckle::record::attribute::Finish m_finish;
///The list of mesh IDs the finish is applied to
std::vector<active::utility::Guid> m_meshID;
};
}
#endif //CONNECTOR_RECORD_COLLECTION_MATERIAL_PROXY
@@ -0,0 +1,198 @@
#include "Connector/Record/Collection/ProjectCollection.h"
#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"
#include "Connector/Record/Collection/FinishProxy.h"
#include "Speckle/Database/BIMAttributeDatabase.h"
#include "Speckle/Database/BIMElementDatabase.h"
#include "Speckle/Record/Element/Element.h"
#ifdef ARCHICAD
#include <ACAPinc.h>
#include <ModelMaterial.hpp>
#endif
using namespace active::serialise;
using namespace connector::record;
using namespace speckle::database;
using namespace speckle::record::attribute;
using namespace speckle::utility;
#ifdef ARCHICAD
namespace connector::record {
class ProjectCollection::FinishCache : public std::unordered_map<active::utility::Guid, Finish::Unique> {};
}
#endif
namespace {
///Serialisation fields
enum FieldIndex {
finishProxyID,
};
///Serialisation field IDs
static std::array fieldID = {
Identity{"renderMaterialProxies"},
};
using WrappedProxy = CargoHold<PackageWrap, FinishProxy>;
}
/*--------------------------------------------------------------------
Constructor
project: The source 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
/*--------------------------------------------------------------------
Destructor
--------------------------------------------------------------------*/
ProjectCollection::~ProjectCollection() {
} //ProjectCollection::~ProjectCollection
/*--------------------------------------------------------------------
Add an element to the collection hierarchy
index The index of the element to add
return: True if the element was added (false typically means the element already exists)
--------------------------------------------------------------------*/
bool ProjectCollection::addElement(const speckle::database::BIMIndex& index) {
//Lookup the element in the element database of the active project
auto elementDbase = m_project->getElementDatabase();
if (elementDbase == nullptr)
return false;
if (auto element = elementDbase->getElement(index); element) {
addElement(*element); //Add the element to the collection hierarchy
return true;
}
return false;
} //ProjectCollection::addElement
/*--------------------------------------------------------------------
Add an element to the collection hierarchy
element: The element to add
return: True if the element was added (false typically means the element already exists)
--------------------------------------------------------------------*/
bool ProjectCollection::addElement(const speckle::record::element::Element& element) {
std::vector<String> collectionNames;
//The first collection hierarchy level is the element storey/level
auto storey = element.getStorey();
collectionNames.emplace_back(storey ? storey->getName() : connector()->getLocalString(titleString, noStoreyID));
//The next level is the name of the element type
collectionNames.emplace_back(element.getTypeName());
//Add any future levels here as required
RecordCollection* collection = this;
for (const auto& childName : collectionNames)
collection = collection->getChild(childName);
return collection->addIndex(BIMIndex{element.getBIMID(), element.getTableID()});
} //ProjectCollection::addElement
/*--------------------------------------------------------------------
Add a material proxy record to the collection
materialIndex: The index of the material to add
objectID: The object the material is applied to
return: True if the material proxy was added (false typically means the record already exists)
--------------------------------------------------------------------*/
bool ProjectCollection::addMaterialProxy(const speckle::database::BIMIndex& materialIndex, const speckle::database::BIMRecordID& objectID) {
auto iter = m_finishProxies.find(materialIndex);
if (iter == m_finishProxies.end())
iter = m_finishProxies.insert({materialIndex, {}}).first;
return iter->second.insert(objectID).second;
} //ProjectCollection::addMaterialProxy
#ifdef ARCHICAD
/*--------------------------------------------------------------------
Add a ModelerAPI material to the collection (NB: These are not persistent so need to be captured by this method)
material: A material
objectID: The object the material is applied to
return: True if the material proxy was added (false typically means the record already exists)
--------------------------------------------------------------------*/
bool ProjectCollection::addMaterialProxy(const ModelerAPI::Material& material, const speckle::database::BIMRecordID& objectID) {
auto finishID = Guid::fromInt(material.GenerateHashValue());
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
/*--------------------------------------------------------------------
Fill an inventory with the package items
inventory: The inventory to receive the package items
return: True if the package has added items to the inventory
--------------------------------------------------------------------*/
bool ProjectCollection::fillInventory(active::serialise::Inventory& inventory) const {
using enum Entry::Type;
base::fillInventory(inventory);
inventory.merge(Inventory{
{
{ Identity{fieldID[finishProxyID]}, finishProxyID, 100, std::nullopt },
},
}.withType(&typeid(ProjectCollection)));
return true;
} //ProjectCollection::fillInventory
/*--------------------------------------------------------------------
Get the specified cargo
item: The inventory item to retrieve
return: The requested cargo (nullptr on failure)
--------------------------------------------------------------------*/
Cargo::Unique ProjectCollection::getCargo(const Inventory::Item& item) const {
if (item.ownerType != &typeid(ProjectCollection))
return base::getCargo(item);
using namespace active::serialise;
//TODO: This is only currently coded to write collection content - reading can be added as required in future
switch (item.index) {
case finishProxyID: {
if (item.available < m_finishProxies.size()) {
auto iter = m_finishProxies.begin();
std::advance(iter, item.available);
const Finish* finish = nullptr;
if (auto fin = m_finishes->find(iter->first); fin != m_finishes->end())
finish = fin->second.get();
else if (auto attribute = m_project->getAttributeDatabase()->getAttribute(iter->first, iter->first.tableID); attribute)
finish = dynamic_cast<const Finish*>(attribute.get());
if (finish != nullptr) {
auto proxy = std::make_unique<FinishProxy>(*finish, iter->second);
return std::make_unique<WrappedProxy>(std::move(proxy));
}
}
break;
}
default:
break;
}
return nullptr; //Requested an unknown index
} //ProjectCollection::getCargo
@@ -0,0 +1,113 @@
#ifndef CONNECTOR_RECORD_ROOT_COLLECTiON
#define CONNECTOR_RECORD_ROOT_COLLECTiON
#include "Connector/Record/Collection/RecordCollection.h"
#include "Speckle/Serialise/Collection/FinishCollector.h"
#include <stack>
namespace active::serialise {
class Management;
}
namespace speckle::record::element {
class Element;
}
namespace connector::record {
/*!
Root collection for sending a project model to a Speckle server
Additional information is anticipated at the root level that will not apply at any other level in the container hierarchy, e.g.:
- Classification hierarchy
- Layers
- Other attributes, e.g. materials
Add all this supplementary data to the root container as required
*/
class ProjectCollection : public RecordCollection, public speckle::serialise::FinishCollector {
public:
// MARK: - Types
using base = RecordCollection;
// MARK: - Constructors
/*!
Constructor
@param project The source project
*/
ProjectCollection(speckle::environment::Project::Shared project);
ProjectCollection(const ProjectCollection&) = delete;
/*!
Destructor
*/
~ProjectCollection();
using base::base;
// MARK: - Functions (const)
// MARK: - Functions (mutating)
/*!
Add an element to the collection hierarchy
@param index The index of the element to add
@return True if the element was added (false typically means the element already exists)
*/
bool addElement(const speckle::database::BIMIndex& index);
/*!
Add an element to the collection hierarchy
@param element The element to add
@return True if the element was added (false typically means the element already exists)
*/
bool addElement(const speckle::record::element::Element& element);
/*!
Add a material proxy record to the collection
@param materialIndex The index of the material to add
@param objectID The object the material is applied to
@return True if the material proxy was added (false typically means the record already exists)
*/
bool addMaterialProxy(const speckle::database::BIMIndex& materialIndex, const speckle::database::BIMRecordID& objectID) override;
#ifdef ARCHICAD
/*!
Add a ModelerAPI material to the collection (NB: These are not persistent so need to be captured by this method)
@param material A material
@param objectID The object the material is applied to
@return True if the material proxy was added (false typically means the record already exists)
*/
bool addMaterialProxy(const ModelerAPI::Material& material, const speckle::database::BIMRecordID& objectID) override;
#endif
// MARK: - Serialisation
/*!
Fill an inventory with the package items
@param inventory The inventory to receive the package items
@return True if the package has added items to the inventory
*/
bool fillInventory(active::serialise::Inventory& inventory) const override;
/*!
Get the specified cargo
@param item The inventory item to retrieve
@return The requested cargo (nullptr on failure)
*/
active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
private:
using FinishProxies = std::unordered_map<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
class FinishCache;
///Finishes cached from ModelerAPI materials
std::unique_ptr<FinishCache> m_finishes;
#endif
};
}
#endif //CONNECTOR_RECORD_ROOT_COLLECTiON
@@ -1,11 +1,15 @@
#include "Connector/Record/Collection/RecordCollection.h"
#include "Active/Serialise/CargoHold.h"
#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
#include "Active/Serialise/Package/Wrapper/PackageWrap.h"
#include "Speckle/Database/BIMElementDatabase.h"
using namespace active::serialise;
using namespace connector::record;
using namespace speckle::database;
using namespace speckle::environment;
using namespace speckle::record::element;
using namespace speckle::utility;
#include <array>
@@ -16,18 +20,55 @@ namespace {
enum FieldIndex {
nameID,
elementID,
childrenID,
};
///Serialisation field IDs
static std::array fieldID = {
Identity{"name"},
Identity{"element"},
Identity{"child"},
Identity{"elements"},
};
using WrappedElement = CargoHold<PackageWrap, Element>;
}
/*--------------------------------------------------------------------
Constructor
name: The collection name
project: The source project
--------------------------------------------------------------------*/
RecordCollection::RecordCollection(const speckle::utility::String& name, Project::Shared project) : m_name{name}, m_project{project} {
} //RecordCollection::RecordCollection
/*--------------------------------------------------------------------
Get a child collection by name (adding if missing)
name: The child name
return: A pointer to the requested child (nullptr on failure, caller does not take ownership)
--------------------------------------------------------------------*/
RecordCollection* RecordCollection::getChild(const speckle::utility::String& name) {
//Return an existing child if possible
if (auto iter = m_children.find(name); iter != m_children.end())
return &iter->second;
//Otherwise insert and return a new collection with the requested name
return &m_children.insert({name, RecordCollection{name, m_project}}).first->second;
} //RecordCollection::getChild
/*--------------------------------------------------------------------
Add an index to the collection
index: The index to add
return: True if the index was added (false typically means the index already exists)
--------------------------------------------------------------------*/
bool RecordCollection::addIndex(const speckle::database::BIMIndex& index) {
return m_indices.insert(index).second;
} //RecordCollection::addIndex
/*--------------------------------------------------------------------
Fill an inventory with the package items
@@ -36,13 +77,13 @@ namespace {
return: True if the package has added items to the inventory
--------------------------------------------------------------------*/
bool RecordCollection::fillInventory(Inventory& inventory) const {
bool RecordCollection::fillInventory(active::serialise::Inventory& inventory) const {
using enum Entry::Type;
base::fillInventory(inventory);
inventory.merge(Inventory{
{
{ fieldID[nameID], nameID, element },
{ fieldID[elementID], elementID, base::size(), std::nullopt, !base::empty() },
{ fieldID[childrenID], childrenID, m_children.size(), std::nullopt, !m_children.empty() },
{ Identity{fieldID[nameID]}, nameID, element },
{ Identity{fieldID[elementID]}, elementID, m_children.size() + m_indices.size(), std::nullopt },
},
}.withType(&typeid(RecordCollection)));
return true;
@@ -58,18 +99,29 @@ bool RecordCollection::fillInventory(Inventory& inventory) const {
--------------------------------------------------------------------*/
Cargo::Unique RecordCollection::getCargo(const Inventory::Item& item) const {
if (item.ownerType != &typeid(RecordCollection))
return nullptr;
return base::getCargo(item);
using namespace active::serialise;
//TODO: This is only currently coded to write collection content - reading can be added as required in future
switch (item.index) {
case nameID:
return std::make_unique<StringWrap>(m_name);
case elementID:
return nullptr; //TODO: Implement - need to interrogate BIM database for element and return as cargo
case childrenID:
if (item.available < m_children.size())
return std::make_unique<PackageWrap>(m_children[item.available]);
return nullptr;
case elementID: {
if (item.available < m_children.size()) {
auto iter = m_children.begin();
std::advance(iter, item.available);
return std::make_unique<PackageWrap>(iter->second);
}
auto index = item.available - m_children.size();
if (index < m_indices.size()) {
auto iter = m_indices.begin();
std::advance(iter, index);
if (auto element = m_project->getElementDatabase()->getElement(*iter, iter->tableID); element)
return std::make_unique<WrappedElement>(std::move(element));
}
break;
}
default:
return nullptr; //Requested an unknown index
break;
}
return nullptr; //Requested an unknown index
} //RecordCollection::getCargo
@@ -1,13 +1,18 @@
#ifndef CONNECTOR_RECORD_RECORD_COLLECTiON
#define CONNECTOR_RECORD_RECORD_COLLECTiON
#include "Active/Container/Vector.h"
#include "Active/Serialise/Package/Package.h"
#include "Speckle/Database/Identity/RecordID.h"
#include "Speckle/Database/Content/Record.h"
#include "Speckle/Database/Identity/BIMIndex.h"
#include "Speckle/Environment/Project.h"
#include "Speckle/Utility/String.h"
#include <unordered_set>
#include <unordered_map>
namespace connector::record {
class ProjectCollection;
/*!
Container for a collection of elements (and potentially tables of associated attributes) for Speckle commits
@@ -26,43 +31,38 @@ namespace connector::record {
Note that the serialisation is currently implemented for sending only. Receive can be added as required
*/
class RecordCollection : public std::vector<speckle::database::RecordID>, public active::serialise::Package {
class RecordCollection : public speckle::database::Record {
public:
// MARK: - Types
using base = std::vector<speckle::database::RecordID>;
using Children = std::vector<RecordCollection>;
using base = speckle::database::Record;
// MARK: - Constructors
using base::base;
/*!
Destructor
*/
~RecordCollection() {}
// MARK: - Functions (const)
/*!
Get the speckle type identifier
@return The speckle type (relevant objects should override as required, but "Base" is still considered a type on its own)
*/
speckle::utility::String getSpeckleType() const override { return "Speckle.Core.Models.Collections.Collection"; }
/*!
Get the container name
@return The container name
*/
const speckle::utility::String& getName() const { return m_name; }
/*!
Get the child collections
@return The child collections nested under this collection
Find a child by name
@param name The required child name
@return A pointer to the requested child (nullptr if not found)
*/
const Children& getChildren() const;
// MARK: - Functions (mutating)
/*!
Set the container name
@param name The container name
*/
void setName(const speckle::utility::String& name) { m_name = name; }
/*!
Add a child collection
@param child The child collection to add
*/
void addChild(RecordCollection&& child);
RecordCollection* findChild(const speckle::utility::String& name) const;
// MARK: - Serialisation
@@ -70,20 +70,51 @@ namespace connector::record {
Fill an inventory with the package items
@param inventory The inventory to receive the package items
@return True if the package has added items to the inventory
*/
*/
bool fillInventory(active::serialise::Inventory& inventory) const override;
/*!
Get the specified cargo
@param item The inventory item to retrieve
@return The requested cargo (nullptr on failure)
*/
*/
active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
private:
///Child nodes of this collection
Children m_children;
friend ProjectCollection;
// MARK: - Types
using Indices = std::unordered_set<speckle::database::BIMIndex>;
using Children = std::unordered_map<speckle::utility::String, RecordCollection>;
/*!
Constructor
@param name The collection name
@param project The source project
*/
RecordCollection(const speckle::utility::String& name, speckle::environment::Project::Shared project);
/*!
Get a child collection by name (adding if missing)
@param name The child name
@return A pointer to the requested child (nullptr on failure, caller does not take ownership)
*/
RecordCollection* getChild(const speckle::utility::String& name);
/*!
Add an index to the collection
@param index The index to add
@return True if the index was added (false typically means the index already exists)
*/
bool addIndex(const speckle::database::BIMIndex& index);
///The source project for the collection
speckle::environment::Project::Shared m_project;
///The collection name
speckle::utility::String m_name;
///Child nodes of this collection
Children m_children;
///Indices of records in this collection
Indices m_indices;
};
}
@@ -1,34 +0,0 @@
#include "Connector/Record/Collection/RootCollection.h"
#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
#include "Active/Serialise/Package/Wrapper/PackageWrap.h"
using namespace active::serialise;
using namespace connector::record;
using namespace speckle::database;
using namespace speckle::utility;
/*--------------------------------------------------------------------
Fill an inventory with the package items
inventory: The inventory to receive the package items
return: True if the package has added items to the inventory
--------------------------------------------------------------------*/
bool RootCollection::fillInventory(Inventory& inventory) const {
//Extend with supplementary data as required
return base::fillInventory(inventory);
} //RootCollection::fillInventory
/*--------------------------------------------------------------------
Get the specified cargo
item: The inventory item to retrieve
return: The requested cargo (nullptr on failure)
--------------------------------------------------------------------*/
Cargo::Unique RootCollection::getCargo(const Inventory::Item& item) const {
//Extend with supplementary data as required
return base::getCargo(item);
} //RootCollection::getCargo
@@ -1,52 +0,0 @@
#ifndef CONNECTOR_RECORD_ROOT_COLLECTiON
#define CONNECTOR_RECORD_ROOT_COLLECTiON
#include "Connector/Record/Collection/RecordCollection.h"
namespace connector::record {
/*!
Root container for sending model data to a Speckle server
Additional information is anticipated at the root level that will not apply at any other level in the container hierarchy, e.g.:
- Classification hierarchy
- Layers
- Other attributes, e.g. materials
Add all this supplementary data to the root container as required
*/
class RootCollection : public RecordCollection {
public:
// MARK: - Types
using base = RecordCollection;
// MARK: - Constructors
using base::base;
// MARK: - Functions (const)
// MARK: - Functions (mutating)
// MARK: - Serialisation
/*!
Fill an inventory with the package items
@param inventory The inventory to receive the package items
@return True if the package has added items to the inventory
*/
bool fillInventory(active::serialise::Inventory& inventory) const override;
/*!
Get the specified cargo
@param item The inventory item to retrieve
@return The requested cargo (nullptr on failure)
*/
active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
};
}
#endif //CONNECTOR_RECORD_ROOT_COLLECTiON
+1
View File
@@ -1,6 +1,7 @@
'STR#' 32600 "Title strings" {
/* [ 1] */ "Speckle Connector"
/* [ 2] */ "Connector to share model content with Speckle"
/* [ 3] */ "No level"
}
'STR#' 32604 "Error strings" {
+1
View File
@@ -1,3 +1,4 @@
'STR#' 32700 "Speckle Title strings" {
/* [ 1] */ "Untitled"
/* [ 2] */ "Unknown"
}
@@ -0,0 +1,155 @@
#include "Speckle/Database/BIMAttributeDatabase.h"
#include "Active/Database/Storage/Storage.h"
#include "Active/Serialise/UnboxedTransport.h"
#include "Speckle/Database/Identity/RecordID.h"
#include "Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.h"
#include "Speckle/Record/Attribute/Attribute.h"
#include <array>
using namespace active::container;
using namespace active::database;
using namespace active::event;
using namespace active::serialise;
using namespace speckle::database;
using namespace speckle::record;
using namespace speckle::record::attribute;
using namespace speckle::database;
using namespace speckle::utility;
namespace speckle::database {
///Define other platform engines here as required
#ifdef ARCHICAD
using AttributeDatabaseEngine = ArchicadAttributeDBaseEngine;
#endif
///Attribute database engine declaration
class BIMAttributeDatabase::Engine : public AttributeDatabaseEngine {
using base = ArchicadAttributeDBaseEngine;
using base::base;
};
///Attribute database storage declaration
class BIMAttributeDatabase::Store : public Storage<Attribute, UnboxedTransport, BIMRecordID, BIMRecordID, BIMRecordID, BIMRecordID> {
using base = Storage<Attribute, UnboxedTransport, BIMRecordID, BIMRecordID, BIMRecordID, BIMRecordID>;
using base::base;
};
}
namespace {
///The database storage identifier for attributes
const char* attributeDBaseName = "speckle::database::BIMAttributeDatabase";
///The primary model table, e.g. floor plan in Archicad
const char* modelTableName = "Model";
}
/*--------------------------------------------------------------------
Constructor
--------------------------------------------------------------------*/
BIMAttributeDatabase::BIMAttributeDatabase() {
m_engine = std::make_shared<Engine>(attributeDBaseName,
//Schema
DBaseSchema{active::utility::String{attributeDBaseName},
//Tables
{
//Model attribute table
{
modelTableName, 0, 0, {} //The primary model. Additonal tables could be linked to other drawings/layouts in future
}
}
}
);
m_store = std::make_shared<Store>(m_engine);
} //BIMAttributeDatabase::BIMAttributeDatabase
/*--------------------------------------------------------------------
Destructor
--------------------------------------------------------------------*/
BIMAttributeDatabase::~BIMAttributeDatabase() {}
/*--------------------------------------------------------------------
Get a specified attribute
attributeID: The ID of the target attribute
return: The requested attribute (nullptr on failure)
--------------------------------------------------------------------*/
Attribute::Unique BIMAttributeDatabase::getAttribute(const BIMRecordID& attributeID, std::optional<BIMRecordID> tableID,
std::optional<BIMRecordID> documentID) const {
return m_engine->getObject(attributeID, tableID, documentID);
} //BIMAttributeDatabase::getAttribute
/*--------------------------------------------------------------------
Get all attributes
return: All the attributes
--------------------------------------------------------------------*/
Vector<Attribute> BIMAttributeDatabase::getAttributes() const {
return m_store->getObjects();
} //BIMAttributeDatabase::getAttributes
/*--------------------------------------------------------------------
Write an attribute to storage
attribute: The attribute to write
--------------------------------------------------------------------*/
void BIMAttributeDatabase::write(const Attribute& attribute) const {
m_store->write(attribute);
} //BIMAttributeDatabase::write
/*--------------------------------------------------------------------
Erase an attribute
attributeID: The ID of the attribute to erase
--------------------------------------------------------------------*/
void BIMAttributeDatabase::erase(const Guid& attributeID) const {
m_store->erase(attributeID);
} //BIMAttributeDatabase::erase
#ifdef ARCHICAD
/*--------------------------------------------------------------------
Get attribute data direct from the AC API. For internal use - avoid direct use
link: A link to the required attribute
return: The AC API attribute data
--------------------------------------------------------------------*/
std::optional<API_Attribute> BIMAttributeDatabase::getAPIData(const BIMLink& link) const {
return m_engine->getAPIData(link);
} //BIMAttributeDatabase::getAPIData
/*--------------------------------------------------------------------
Get storey data direct from the AC API. For internal use - avoid direct use
link: A link to the required storey
return: The AC API storey data
--------------------------------------------------------------------*/
std::optional<API_StoryType> BIMAttributeDatabase::getAPIStorey(const BIMLink& link) const {
return m_engine->getAPIStorey(link);
} //BIMAttributeDatabase::getAPIData
/*--------------------------------------------------------------------
Get the ID of a storey from a specified index
index: The storey index
return: The storey ID (nullopt on failure)
--------------------------------------------------------------------*/
std::optional<BIMRecordID> BIMAttributeDatabase::getStoreyID(short index) const {
return m_engine->getStoreyID(index);
} //BIMAttributeDatabase::getStoreyID
#endif
@@ -0,0 +1,101 @@
#ifndef CONNECTOR_DATABASE_BIM_ATTRIBUTE_DATABASE
#define CONNECTOR_DATABASE_BIM_ATTRIBUTE_DATABASE
#include "Speckle/Database/Identity/BIMLink.h"
#include "Speckle/Record/Attribute/Attribute.h"
#include "Speckle/Utility/Guid.h"
namespace active::event {
class Subscriber;
}
namespace speckle::database {
/*!
Database of model attributes relating to a specific project
*/
class BIMAttributeDatabase {
public:
// MARK: - Constructors
/*!
Constructor
*/
BIMAttributeDatabase();
BIMAttributeDatabase(const BIMAttributeDatabase&) = delete;
/*!
Destructor
*/
~BIMAttributeDatabase();
// MARK: - Functions (const)
/*!
Get the current user attribute selection
@return A list of selected attribute IDs
*/
BIMLinkList getSelection() const;
/*!
Get a specified attribute
@param attributeID The ID of the target attribute
@param tableID Optional table ID (defaults to the floor plan)
@param documentID Optional document ID (when the object is bound to a specific document)
@return The requested attribute (nullptr on failure)
*/
record::attribute::Attribute::Unique getAttribute(const BIMRecordID& attributeID, std::optional<BIMRecordID> tableID = std::nullopt,
std::optional<BIMRecordID> documentID = std::nullopt) const;
/*!
Get a specified attribute
@param link A link to the target attribute
@return The requested attribute (nullptr on failure)
*/
record::attribute::Attribute::Unique getAttribute(const BIMLink& link) const { return getAttribute(link, link.tableID, link.docID); }
/*!
Get all model attributes
@return All the attributes
*/
active::container::Vector<record::attribute::Attribute> getAttributes() const;
/*!
Write an attribute to storage
@param attribute The attribute to write
*/
void write(const record::attribute::Attribute& attribute) const;
/*!
Erase an attribute
@param attributeID The ID of the attribute to erase
*/
void erase(const speckle::utility::Guid& attributeID) const;
#ifdef ARCHICAD
/*!
Get attribute data direct from the AC API. For internal use - avoid direct use
@param link A link to the required attribute
@return The AC API attribute data
*/
std::optional<API_Attribute> getAPIData(const BIMLink& link) const;
/*!
Get storey data direct from the AC API. For internal use - avoid direct use
@param link A link to the required storey
@return The AC API storey data
*/
std::optional<API_StoryType> getAPIStorey(const BIMLink& link) const;
/*!
Get the ID of a storey from a specified index
@param index The storey index
@return The storey ID (nullopt on failure)
*/
std::optional<BIMRecordID> getStoreyID(short index) const;
#endif
private:
class Engine;
class Store;
///Model attribute database storage
std::shared_ptr<Engine> m_engine;
std::shared_ptr<Store> m_store;
};
}
#endif //CONNECTOR_DATABASE_BIM_ATTRIBUTE_DATABASE
@@ -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
@@ -1,14 +1,19 @@
#ifndef CONNECTOR_DATABASE_BIM_DATABASE
#define CONNECTOR_DATABASE_BIM_DATABASE
#ifndef CONNECTOR_DATABASE_BIM_ELEMENT_DATABASE
#define CONNECTOR_DATABASE_BIM_ELEMENT_DATABASE
#include "Speckle/Database/Identity/BIMLink.h"
#include "Speckle/Record/Element/Element.h"
#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
@@ -77,4 +89,4 @@ namespace speckle::database {
}
#endif //CONNECTOR_DATABASE_BIM_DATABASE
#endif //CONNECTOR_DATABASE_BIM_ELEMENT_DATABASE
@@ -1,5 +1,7 @@
#include "Speckle/Database/Content/BIMRecord.h"
#include "Active/Serialise/Item/Wrapper/ValueOptionWrap.h"
#include "Speckle/Serialise/Types/Units/LengthUnit.h"
#include "Speckle/Utility/Guid.h"
#include <array>
@@ -8,16 +10,20 @@ using namespace active::serialise;
using namespace speckle::database;
using namespace speckle::utility;
using enum active::measure::LengthType;
namespace {
///Serialisation fields
enum FieldIndex {
applicID,
unitID,
};
///Serialisation field IDs
static std::array fieldID = {
Identity{"applicationId"},
Identity{"units"},
};
}
@@ -33,7 +39,8 @@ bool BIMRecord::fillInventory(Inventory& inventory) const {
using enum Entry::Type;
inventory.merge(Inventory{
{
{ Identity{fieldID[applicID]}, applicID, element },
{ Identity{fieldID[applicID]}, applicID, element, !m_applicationID.empty() },
{ Identity{fieldID[unitID]}, unitID, element, m_unit.operator bool() },
},
}.withType(&typeid(BIMRecord)));
return base::fillInventory(inventory);
@@ -54,7 +61,18 @@ Cargo::Unique BIMRecord::getCargo(const Inventory::Item& item) const {
switch (item.index) {
case applicID:
return std::make_unique<ValueWrap<BIMRecordID>>(m_applicationID);
case unitID:
return std::make_unique<ValueOptionWrap<active::measure::LengthType>>(m_unit);
default:
return nullptr; //Requested an unknown index
}
} //BIMRecord::getCargo
/*--------------------------------------------------------------------
Set to the default package content
--------------------------------------------------------------------*/
void BIMRecord::setDefault() {
m_applicationID.clear();
m_unit.reset();
} //BIMRecord::setDefault
+62 -12
View File
@@ -1,8 +1,10 @@
#ifndef SPECKLE_DATABASE_BIM_RECORD
#define SPECKLE_DATABASE_BIM_RECORD
#include "Active/Setting/Values/Measurement/Units/LengthUnit.h"
#include "Speckle/Database/Content/Record.h"
#include "Speckle/Database/Identity/Link.h"
#include "Speckle/Database/Identity/BIMIndex.h"
#include "Speckle/Database/Identity/BIMLink.h"
#include "Speckle/Database/Identity/BIMRecordID.h"
namespace speckle::database {
@@ -27,13 +29,18 @@ namespace speckle::database {
/*!
Default constructor
@param unit The recordc unit type
*/
BIMRecord() : base{} {}
BIMRecord(active::measure::LengthType unit = active::measure::LengthType::metre) : base{}, m_unit{unit} {}
/*!
Constructor
@param ID The record ID
@param tableID The parent table ID
@param unit The record unit type
*/
BIMRecord(speckle::utility::Guid ID) : base{}, m_applicationID{ID} {}
BIMRecord(const speckle::utility::Guid& ID, const speckle::utility::Guid& tableID,
std::optional<active::measure::LengthType> unit = active::measure::LengthType::metre) :
base{}, m_applicationID{ID}, m_applicationTableID{tableID}, m_unit{unit} {}
/*!
Destructor
*/
@@ -46,6 +53,21 @@ namespace speckle::database {
@return The BIM application ID
*/
BIMRecordID getBIMID() const { return m_applicationID; }
/*!
Get the BIM application parent table ID
@return The BIM table ID
*/
BIMRecordID getTableID() const { return m_applicationTableID; }
/*!
Get a link to the BIM record
@return The BIM record link
*/
BIMLink getBIMLink() const { return BIMLink{ 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)
@@ -54,25 +76,53 @@ namespace speckle::database {
@param ID The BIM application ID
*/
void setBIMID(const BIMRecordID& ID) { m_applicationID = ID; }
/*!
Set the BIM application parent table ID
@param tableID The BIM table ID
*/
void setTableID(const BIMRecordID& tableID) { m_applicationTableID = tableID; }
/*!
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
/*!
Fill an inventory with the package items
@param inventory The inventory to receive the package items
@return True if the package has added items to the inventory
*/
Fill an inventory with the package items
@param inventory The inventory to receive the package items
@return True if the package has added items to the inventory
*/
bool fillInventory(active::serialise::Inventory& inventory) const override;
/*!
Get the specified cargo
@param item The inventory item to retrieve
@return The requested cargo (nullptr on failure)
*/
Get the specified cargo
@param item The inventory item to retrieve
@return The requested cargo (nullptr on failure)
*/
active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
/*!
Set to the default package content
*/
void setDefault() override;
protected:
/*!
Reset the BIM index (used in lazy loading contexts where the index cannot otherwise be established)
@param index The BIM application index
*/
void resetIndex(const BIMIndex& index) const {
m_applicationID = index;
m_applicationTableID = index.tableID;
}
private:
///The BIM application record ID
BIMRecordID m_applicationID;
mutable BIMRecordID m_applicationID;
///The BIM application parent table ID
mutable BIMRecordID m_applicationTableID;
///The BIM record unit of length measurement
std::optional<active::measure::LengthType> m_unit = active::measure::LengthType::metre;
};
}
@@ -35,12 +35,12 @@ bool Record::fillInventory(active::serialise::Inventory& inventory) const {
using enum Entry::Type;
inventory.merge(Inventory{
{
{ Identity{fieldID[speckleIDID]}, active::database::record::FieldIndex::idIndex, element },
{ Identity{fieldID[speckleIDID]}, active::database::record::FieldIndex::idIndex, element, !getID().empty() },
},
}.withType(&typeid(base)));
inventory.merge(Inventory{
{
{ Identity{fieldID[speckleTypeID]}, speckleTypeID, element },
{ Identity{fieldID[speckleTypeID]}, speckleTypeID, attribute },
},
}.withType(&typeid(Record)));
return true;
+10 -11
View File
@@ -31,8 +31,7 @@ namespace speckle::database {
@param globID The global ID
*/
Record(speckle::utility::String::Option ID = std::nullopt, speckle::utility::String::Option globID = std::nullopt) :
base{ID.value_or(active::utility::Guid{true}.operator active::utility::String()),
globID.value_or(active::utility::Guid{true}.operator active::utility::String())} {}
base{ID.value_or(speckle::utility::String{}), globID.value_or(speckle::utility::String{})} {}
/*!
Destructor
*/
@@ -44,7 +43,7 @@ namespace speckle::database {
Get the speckle type identifier
@return The speckle type (relevant objects should override as required, but "Base" is still considered a type on its own)
*/
virtual speckle::utility::String getSpeckleType() const { return "Base"; }
virtual speckle::utility::String getSpeckleType() const { return "speckle::database::Record"; }
// MARK: - Functions (mutating)
@@ -52,16 +51,16 @@ namespace speckle::database {
// MARK: - Serialisation
/*!
Fill an inventory with the package items
@param inventory The inventory to receive the package items
@return True if the package has added items to the inventory
*/
Fill an inventory with the package items
@param inventory The inventory to receive the package items
@return True if the package has added items to the inventory
*/
bool fillInventory(active::serialise::Inventory& inventory) const override;
/*!
Get the specified cargo
@param item The inventory item to retrieve
@return The requested cargo (nullptr on failure)
*/
Get the specified cargo
@param item The inventory item to retrieve
@return The requested cargo (nullptr on failure)
*/
active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
/*!
Set to the default package content
+15 -10
View File
@@ -2,7 +2,7 @@
#define SPECKLE_DATABASE_BIM_INDEX
#include "Active/Database/Identity/Index.h"
#include "Speckle/Database/Identity/RecordID.h"
#include "Speckle/Database/Identity/BIMRecordID.h"
namespace speckle::database {
@@ -13,25 +13,30 @@ namespace speckle::database {
this is typically a guid, for Revit a string and for Vectorworks a handle. Note that this index is not necessarily persistent between
sessions.
*/
class BIMIndex : public active::database::Index<BIMRecordID> {
class BIMIndex : public active::database::Index<BIMRecordID, BIMRecordID> {
public:
// MARK: - Types
using base = active::database::Index<BIMRecordID>;
using base = active::database::Index<BIMRecordID, BIMRecordID>;
// MARK: - Constructors
using base::base;
// MARK: - Public variables
//The table identifier
BIMTableID table;
//The document identifier
BIMDocID document;
};
}
///Hashing for BIMIndex class, e.g. to use as a key in unordered_map
template<>
struct std::hash<speckle::database::BIMIndex> {
std::size_t operator() (const speckle::database::BIMIndex& index) const {
std::size_t h1 = std::hash<active::utility::Guid>{}(index);
std::size_t h2 = std::hash<active::utility::Guid>{}(index.tableID);
return h1 ^ (h2 << 1);
}
};
#endif //SPECKLE_DATABASE_BIM_INDEX
@@ -8,8 +8,9 @@ using namespace speckle::utility;
Constructor
selected: Information about a selected Archicad element
tableID: The ID of the parent table
--------------------------------------------------------------------*/
BIMLink::BIMLink(const API_Neig& selected) : base{Guid{selected.guid}} {
BIMLink::BIMLink(const API_Neig& selected, const BIMRecordID& tableID) : base{Guid{selected.guid}, tableID} {
//More info should be extracted from API_Neig in future (as required) - extract into link settings, e.g. selection target etc
} //Link::Link
#endif
@@ -34,8 +34,9 @@ namespace speckle::database {
/*!
Constructor
@param selected Information about a selected Archicad element
@param tableID The ID of the parent table
*/
BIMLink(const API_Neig& selected);
BIMLink(const API_Neig& selected, const BIMRecordID& tableID);
#endif
};
@@ -0,0 +1,297 @@
#include "Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.h"
#ifdef ARCHICAD
#include "Active/Utility/Defer.h"
#include "Active/Utility/Memory.h"
#include "Active/Utility/String.h"
#include "Speckle/Record/Attribute/Finish.h"
#include "Speckle/Record/Attribute/Storey.h"
#include "Speckle/Database/Identity/BIMLink.h"
#include "Speckle/Environment/Addon.h"
#include "Speckle/Environment/Project.h"
#include "Speckle/Event/Type/DocStoreMergeEvent.h"
#include "Speckle/Event/Type/ProjectEvent.h"
#include "Speckle/Utility/Guid.h"
#include "Speckle/Utility/String.h"
#include <ACAPinc.h>
#include <ACAPI_Database.h>
#include <BM.hpp>
using namespace active::event;
using namespace active::setting;
using namespace speckle::database;
using namespace speckle::environment;
using namespace speckle::event;
using namespace speckle::record::attribute;
using namespace speckle::utility;
using enum ArchicadDBaseCore::Status;
namespace speckle::database {
#ifdef ARCHICAD
/*!
A class to collect and manage a list of active Archicad storeys
NB: This list has to be rebuilt every time a storey has changed because Archicad reindexes storeys each time
This class also has to release memory used by the API to hold storey data
*/
class ArchicadAttributeDBaseEngine::StoreyCache : public std::vector<API_StoryType> {
public:
/*!
Constructor (NB: This automatically gathers information about the current storeys)
*/
StoreyCache() { rebuild(); }
/*!
Rebuild the current storey list
*/
void rebuild() {
clear();
API_StoryInfo storeyInfo;
active::utility::Memory::erase(storeyInfo);
ACAPI_ProjectSetting_GetStorySettings(&storeyInfo);
auto storeyCount = storeyInfo.lastStory - storeyInfo.firstStory + 1;
for (auto i = 0; i < storeyCount; ++i)
push_back((*storeyInfo.data)[i]);
BMKillHandle(reinterpret_cast<GSHandle*>(&storeyInfo.data));
}
/*!
Find a storey by unique ID
@param id The storey unique ID
@return An iterator pointing to the found storey (end() on failure)
*/
const_iterator find(const Guid& id) const {
auto floorID = static_cast<short>(Guid::toInt(id));
return std::find_if(begin(), end(), [&](auto storey){ return storey.floorId == floorID; });
}
/*!
Find a storey by index
@param index The storey index
@return An iterator pointing to the found storey (end() on failure)
*/
const_iterator find(short index) const {
return std::find_if(begin(), end(), [&](auto storey){ return storey.index == index; });
}
};
#endif
}
namespace {
///Attribute factory
std::unordered_map<active::utility::Guid, std::function<Attribute::Unique(API_Attribute, const active::utility::Guid&)>> attributeFactory;
#ifdef ARCHICAD
/*!
Make a new attribute object
@param attributeData The API attribute representation
@return A new attribute object (nullptr on failure)
*/
Attribute::Unique makeAttribute(const API_Attribute& attributeData) {
auto tableID = active::utility::Guid::fromInt(static_cast<uint64_t>(attributeData.header.typeID));
if (attributeFactory.empty()) {
attributeFactory[active::utility::Guid::fromInt(static_cast<uint64_t>(attributeData.header.typeID))] =
[](API_Attribute attrData, const active::utility::Guid& tableID){ return std::make_unique<Finish>(attrData, tableID); };
}
if (auto iter = attributeFactory.find(tableID); iter != attributeFactory.end())
return iter->second(attributeData, tableID);
return nullptr;
}
/*!
Get the AC API data for a specified attribute
@param ID The attribute ID
@param tableID The parent table ID
@return A new attribute object (nullptr on failure)
*/
std::optional<API_Attribute> getAPIData(const BIMRecordID& ID, std::optional<BIMRecordID> tableID) {
API_Attribute attribute;
active::utility::Memory::erase(attribute);
attribute.header.index = ACAPI_CreateAttributeIndex(static_cast<int32_t>(Guid::toInt(ID)));
attribute.header.typeID = static_cast<API_AttrTypeID>(Guid::toInt(*tableID));
if (ACAPI_Attribute_Get(&attribute) != NoError)
return std::nullopt;
return attribute;
}
#endif
}
/*--------------------------------------------------------------------
Constructor
id: The document storage identifier
--------------------------------------------------------------------*/
ArchicadAttributeDBaseEngine::ArchicadAttributeDBaseEngine(const active::utility::NameID& id, ArchicadDBaseSchema&& schema) :
ArchicadDBaseCore{id, std::move(schema)} {
} //ArchicadAttributeDBaseEngine::ArchicadAttributeDBaseEngine
/*--------------------------------------------------------------------
Destructor
--------------------------------------------------------------------*/
ArchicadAttributeDBaseEngine::~ArchicadAttributeDBaseEngine() {
} //ArchicadAttributeDBaseEngine::~ArchicadAttributeDBaseEngine
/*--------------------------------------------------------------------
Get an object by ID
objID: The object index
tableID: Optional table ID (defaults to the floor plan)
documentID: Optional document ID (when the object is bound to a specific document)
return: The requested object (nullptr on failure)
--------------------------------------------------------------------*/
std::unique_ptr<Attribute> ArchicadAttributeDBaseEngine::getObject(const BIMRecordID& objID, std::optional<BIMRecordID> tableID,
std::optional<BIMRecordID> documentID) const {
if (!tableID)
return nullptr;
if (auto attrData = ::getAPIData(objID, *tableID); attrData)
return makeAttribute(*attrData);
return nullptr;
} //ArchicadAttributeDBaseEngine::getObject
/*--------------------------------------------------------------------
Get an object in a transportable form, e.g. packaged for serialisation
index: The object index
tableID: Optional table ID (defaults to the floor plan)
documentID: Optional document ID (when the object is bound to a specific document)
return: The requested wrapped cargo (nullptr on failure)
--------------------------------------------------------------------*/
active::serialise::Cargo::Unique ArchicadAttributeDBaseEngine::getObjectCargo(const BIMRecordID& ID, std::optional<BIMRecordID> tableID,
std::optional<BIMRecordID> documentID) const {
return nullptr; //TODO: Implement
} //ArchicadAttributeDBaseEngine::getObject
/*--------------------------------------------------------------------
Get all objects
tableID: Optional table ID (defaults to the floor plan)
documentID: Optional document ID (filter for this document only - nullopt = all objects)
return: The requested objects (nullptr on failure)
--------------------------------------------------------------------*/
active::container::Vector<Attribute> ArchicadAttributeDBaseEngine::getObjects(std::optional<BIMRecordID> tableID,
std::optional<BIMRecordID> documentID) const {
return {}; //TODO: Implement
} //ArchicadAttributeDBaseEngine::getObjects
/*--------------------------------------------------------------------
Get all objects
filter: The object filter
tableID: Optional table ID (defaults to the floor plan)
documentID: Optional document ID (filter for this document only - nullopt = all objects)
return: The requested objects (nullptr on failure)
--------------------------------------------------------------------*/
active::container::Vector<Attribute> ArchicadAttributeDBaseEngine::getObjects(const Filter& filter, std::optional<BIMRecordID> tableID,
std::optional<BIMRecordID> documentID) const {
return {}; //TODO: Implement
} //ArchicadAttributeDBaseEngine::getObjects
/*--------------------------------------------------------------------
Write an object to the database
object: The object to write
objID: The object ID
objDocID: The object document-specific ID (unique within a specific document - nullopt if not document-bound)
tableID: Optional table ID (defaults to the floor plan)
documentID: Optional document ID (when the object is bound to a specific document)
--------------------------------------------------------------------*/
void ArchicadAttributeDBaseEngine::write(const Attribute& object, const BIMRecordID& objID, std::optional<BIMRecordID> objDocID,
std::optional<BIMRecordID> tableID, std::optional<BIMRecordID> documentID) const {
//TODO: Implement
} //ArchicadAttributeDBaseEngine::write
/*--------------------------------------------------------------------
Erase an object by index
objID: The object ID
tableID: Optional table ID (defaults to the floor plan)
documentID: Optional document ID (when the object is bound to a specific document)
return: True if the object was successfully erased
--------------------------------------------------------------------*/
void ArchicadAttributeDBaseEngine::erase(const BIMRecordID& ID, std::optional<BIMRecordID> tableID,
std::optional<BIMRecordID> documentID) const {
//TODO: Implement
} //ArchicadAttributeDBaseEngine::erase
/*--------------------------------------------------------------------
Erase all objects
tableID: Optional table ID (defaults to the floor plan)
documentID: Optional document ID (filter for this document only - nullopt = all objects)
--------------------------------------------------------------------*/
void ArchicadAttributeDBaseEngine::erase(std::optional<BIMRecordID> tableID, std::optional<BIMRecordID> documentID) const {
//TODO: Implement
} //ArchicadAttributeDBaseEngine::erase
/*--------------------------------------------------------------------
Get the database outline
return: The database outline
--------------------------------------------------------------------*/
ArchicadAttributeDBaseEngine::Outline ArchicadAttributeDBaseEngine::getOutline() const {
return {}; //TODO: Implement
} //ArchicadAttributeDBaseEngine::getOutline
/*--------------------------------------------------------------------
Get attribute data direct from the AC API. For internal use - avoid direct use
link: A link to the required attribute
return: The AC API attribute data
--------------------------------------------------------------------*/
std::optional<API_Attribute> ArchicadAttributeDBaseEngine::getAPIData(const BIMLink& link) const {
return ::getAPIData(link, link.tableID);
} //ArchicadAttributeDBaseEngine::getAPIData
/*--------------------------------------------------------------------
Get storey data direct from the AC API. For internal use - avoid direct use
link: A link to the required storey
return: The AC API storey data
--------------------------------------------------------------------*/
std::optional<API_StoryType> ArchicadAttributeDBaseEngine::getAPIStorey(const BIMLink& link) const {
if (!m_storeyCache)
m_storeyCache = std::make_unique<StoreyCache>();
if (auto iter = m_storeyCache->find(link); iter != m_storeyCache->end())
return *iter;
return std::nullopt;
} //ArchicadAttributeDBaseEngine::getAPIStorey
/*--------------------------------------------------------------------
Get the ID of a storey from a specified index
index: The storey index
return: The storey ID (nullopt on failure)
--------------------------------------------------------------------*/
std::optional<BIMRecordID> ArchicadAttributeDBaseEngine::getStoreyID(short index) const {
if (!m_storeyCache)
m_storeyCache = std::make_unique<StoreyCache>();
if (auto iter = m_storeyCache->find(index); iter != m_storeyCache->end())
return Guid::fromInt(iter->floorId);
return std::nullopt;
} //ArchicadAttributeDBaseEngine::getStoreyID
#endif
@@ -0,0 +1,148 @@
#ifndef SPECKLE_DATABASE_ARCHICAD_ATTRIBUTE_DBASE_ENGINE
#define SPECKLE_DATABASE_ARCHICAD_ATTRIBUTE_DBASE_ENGINE
#include "Active/Database/Storage/DBaseEngine.h"
#include "Active/Serialise/UnboxedTransport.h"
#include "Speckle/Database/Storage/ArchicadDBase/ArchicadDBaseCore.h"
#include "Speckle/Database/Identity/BIMLink.h"
#include "Speckle/Record/Attribute/Attribute.h"
#include "Speckle/Utility/Guid.h"
#include "Speckle/Utility/String.h"
#include <algorithm>
#include <ranges>
namespace speckle::database {
/*!
A database engine to read/write elements in an Archicad project database (local file or cloud-based)
For attribute indices:
- Each attribute type is considered to be stored in a dedicated table
- For Archicad:
- The table ID is typically the attribute type ID
- The record ID is the attribute index
- Storeys are also treated as an attribute (the API treats them separately, although application to elements is virtually the identical)
*/
class ArchicadAttributeDBaseEngine : public ArchicadDBaseCore,
public active::database::DBaseEngine<record::attribute::Attribute, BIMRecordID, BIMRecordID, BIMRecordID> {
public:
// MARK: - Types
using base = active::database::DBaseEngine<record::attribute::Attribute, BIMRecordID, BIMRecordID, BIMRecordID>;
using Attribute = record::attribute::Attribute;
using Filter = base::Filter;
using Outline = base::Outline;
// MARK: - Constructors
/*!
Constructor
@param id The document storage identifier
*/
ArchicadAttributeDBaseEngine(const active::utility::NameID& id, ArchicadDBaseSchema&& schema);
ArchicadAttributeDBaseEngine(const ArchicadAttributeDBaseEngine&) = delete;
/*!
Destructor
*/
~ArchicadAttributeDBaseEngine();
// MARK: - Functions (const)
/*!
Get an object by ID
@param objID The object ID
@param tableID Optional table ID (defaults to the floor plan)
@param documentID Optional document ID (when the object is bound to a specific document)
@return The requested object (nullptr on failure)
*/
std::unique_ptr<Attribute> getObject(const BIMRecordID& objID, std::optional<BIMRecordID> tableID = std::nullopt, std::optional<BIMRecordID> documentID = std::nullopt) const override;
/*!
Get an object in a transportable form, e.g. packaged for serialisation
@param objID The object ID
@param tableID Optional table ID (defaults to the floor plan)
@param documentID Optional document ID (when the object is bound to a specific document)
@return: The requested wrapped cargo (nullptr on failure)
*/
active::serialise::Cargo::Unique getObjectCargo(const BIMRecordID& objID, std::optional<BIMRecordID> tableID = std::nullopt, std::optional<BIMRecordID> documentID = std::nullopt) const override;
/*!
Get all objects
@param tableID Optional table ID (defaults to the floor plan)
@param documentID Optional document ID (filter for this document only - nullopt = all objects)
@return The requested objects (nullptr on failure)
*/
active::container::Vector<Attribute> getObjects(std::optional<BIMRecordID> tableID = std::nullopt, std::optional<BIMRecordID> documentID = std::nullopt) const override;
/*!
Get a filtered list of objects
@param filter The object filter
@param tableID Optional table ID (defaults to the floor plan)
@param documentID Optional document ID (filter for this document only - nullopt = all objects)
@return The filtered objects (nullptr on failure)
*/
active::container::Vector<Attribute> getObjects(const Filter& filter, std::optional<BIMRecordID> tableID = std::nullopt,
std::optional<BIMRecordID> documentID = std::nullopt) const override;
/*!
Write an object to the database
@param object The object to write
@param objID The object ID
@param objDocID The object document-specific ID (unique within a specific document - nullopt if not document-bound)
@param tableID Optional table ID (defaults to the floor plan)
@param documentID Optional document ID (when the object is bound to a specific document)
*/
void write(const Attribute& object, const BIMRecordID& objID, std::optional<BIMRecordID> objDocID = std::nullopt,
std::optional<BIMRecordID> tableID = std::nullopt, std::optional<BIMRecordID> documentID = std::nullopt) const override;
/*!
Erase an object by index
@param ID The object ID
@param tableID Optional table ID (defaults to the floor plan)
@param documentID Optional document ID (when the object is bound to a specific document)
@throw Exception thrown on SQL error
*/
void erase(const BIMRecordID& ID, std::optional<BIMRecordID> tableID = std::nullopt,
std::optional<BIMRecordID> documentID = std::nullopt) const override;
/*!
Erase all objects
@param tableID Optional table ID (defaults to the floor plan)
@param documentID Optional document ID (when the object is bound to a specific document)
@throw Exception thrown on SQL error
*/
void erase(std::optional<BIMRecordID> tableID = std::nullopt, std::optional<BIMRecordID> documentID = std::nullopt) const override;
/*!
Get the database outline
@return The database outline
*/
Outline getOutline() const override;
#ifdef ARCHICAD
/*!
Get attribute data direct from the AC API. For internal use - avoid direct use
@param link A link to the required attribute
@return The AC API attribute data
*/
std::optional<API_Attribute> getAPIData(const BIMLink& link) const;
/*!
Get storey data direct from the AC API. For internal use - avoid direct use
@param link A link to the required storey
@return The AC API storey data
*/
std::optional<API_StoryType> getAPIStorey(const BIMLink& link) const;
/*!
Get the ID of a storey from a specified index
@param index The storey index
@return The storey ID (nullopt on failure)
*/
std::optional<BIMRecordID> getStoreyID(short index) const;
#endif
private:
void setTable(std::optional<BIMRecordID> tableID = std::nullopt, std::optional<BIMRecordID> documentID = std::nullopt);
class StoreyCache;
///Cache of storeys in the database (saves repeated lookups)
mutable std::unique_ptr<StoreyCache> m_storeyCache;
};
}
#endif //SPECKLE_DATABASE_ARCHICAD_ATTRIBUTE_DBASE_ENGINE
@@ -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"
@@ -43,19 +47,6 @@ namespace {
} //getTableInfo
/*!
Get the ID of the active Archicad table
@return The active table ID (nullopt on failure)
*/
std::optional<BIMRecordID> getActiveTable() {
API_WindowInfo dbaseInfo;
active::utility::Memory::erase(dbaseInfo);
if (auto err = ACAPI_Database_GetCurrentDatabase(&dbaseInfo); err == NoError)
return dbaseInfo.databaseUnId.elemSetId;
return std::nullopt;
} //getActiveTable
/*!
Set the active Archicad table
@param tableID The target table ID
@@ -64,7 +55,7 @@ namespace {
bool setActiveTable(const BIMRecordID& tableID) {
if (!tableID)
return false; //Null guid doens't point to anything
if (auto activeTable = getActiveTable(); activeTable && *activeTable == tableID)
if (auto activeTable = ArchicadElementDBaseEngine::getActiveTable(); activeTable && *activeTable == tableID)
return true;
auto dbaseInfo = getTableInfo(tableID);
if (!dbaseInfo)
@@ -76,29 +67,52 @@ namespace {
/*!
Make a new element object
@param elementData The API element representation
@param tableID The ID of the parent table (defaults to the active drawing)
@return A new element object (nullptr on failure)
*/
Element::Unique makeElement(const API_Element& elementData) {
//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);
Element::Unique makeElement(const API_Element& elementData, const BIMRecordID& tableID) {
switch (elementData.header.type.typeID) {
case API_ColumnID:
return std::make_unique<Column>(elementData, tableID);
case API_ColumnSegmentID:
return std::make_unique<ColumnSegment>(elementData, tableID);
default:
return std::make_unique<GenericElement>(elementData, tableID);
}
}
}
/*--------------------------------------------------------------------
Get the ID of the active Archicad table
return; The active table ID (nullopt on failure)
--------------------------------------------------------------------*/
std::optional<BIMRecordID> ArchicadElementDBaseEngine::getActiveTable() {
API_WindowInfo dbaseInfo;
active::utility::Memory::erase(dbaseInfo);
if (auto err = ACAPI_Database_GetCurrentDatabase(&dbaseInfo); err == NoError)
return dbaseInfo.databaseUnId.elemSetId;
return std::nullopt;
} //ArchicadElementDBaseEngine::getActiveTable
/*--------------------------------------------------------------------
Get the current user element selection
return: A list of selected element IDs
--------------------------------------------------------------------*/
BIMLinkList ArchicadElementDBaseEngine::getSelection() const {
auto tableID = getActiveTable();
if (!tableID)
return {};
BIMLinkList result;
API_SelectionInfo selectionInfo;
active::utility::Memory::erase(selectionInfo);
GS::Array<API_Neig> selection;
if (auto err = ACAPI_Selection_Get(&selectionInfo, &selection, true); err == NoError) {
for (const auto& item : selection)
result.push_back(BIMLink{item});
result.push_back(BIMLink{item, *tableID});
}
return result;
} //ArchicadElementDBaseEngine::getSelection
@@ -115,12 +129,32 @@ 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;
}
API_Element element;
active::utility::Memory::erase(element);
API_Guid guid{ID.operator API_Guid()};
if (ACAPI_Element_GetElementFromAnywhere(&guid, &element) != NoError)
return nullptr;
return makeElement(element);
return makeElement(element, *tableID);
} //ArchicadElementDBaseEngine::getObject
@@ -18,16 +18,29 @@ 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
/*!
Get the ID of the active Archicad table
@return The active table ID (nullopt on failure)
*/
static std::optional<BIMRecordID> getActiveTable();
// MARK: - Constructors
/*!
@@ -1,5 +1,6 @@
#include "Speckle/Environment/Project.h"
#include "Speckle/Database/BIMAttributeDatabase.h"
#include "Speckle/Database/BIMElementDatabase.h"
#include "Speckle/Environment/Addon.h"
#include "Speckle/SpeckleResource.h"
@@ -23,6 +24,7 @@ namespace {
--------------------------------------------------------------------*/
Project::Project() {
m_element = std::make_unique<BIMElementDatabase>();
m_attribute = std::make_unique<BIMAttributeDatabase>();
} //Project::Project
+9
View File
@@ -5,6 +5,7 @@
#include "Speckle/Utility/String.h"
namespace speckle::database {
class BIMAttributeDatabase;
class BIMElementDatabase;
}
@@ -59,6 +60,11 @@ namespace speckle::environment {
@return The account database
*/
const database::BIMElementDatabase* getElementDatabase() const { return m_element.get(); }
/*!
Get the account database
@return The account database
*/
const database::BIMAttributeDatabase* getAttributeDatabase() const { return m_attribute.get(); }
// MARK: - Functions (mutating)
@@ -73,7 +79,10 @@ namespace speckle::environment {
Project();
private:
///The BIM element database
std::unique_ptr<database::BIMElementDatabase> m_element;
///The BIM attribute database
std::unique_ptr<database::BIMAttributeDatabase> m_attribute;
};
}
@@ -2,6 +2,7 @@
#include "Speckle/Environment/Addon.h"
#include "Speckle/Database/Identity/BIMLink.h"
#include "Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.h"
#include "Speckle/Event/Type/SelectionEvent.h"
#ifdef ARCHICAD
@@ -23,8 +24,10 @@ namespace {
*/
GSErrCode __ACENV_CALL selectionCallback(const API_Neig* params) {
if (addon() != nullptr) {
auto selection = (params == nullptr) ? BIMLink{} : BIMLink{*params};
addon()->publishExternal(SelectionEvent{selection});
if (auto tableID = ArchicadElementDBaseEngine::getActiveTable(); tableID) {
auto selection = (params == nullptr) ? BIMLink{} : BIMLink{*params, *tableID};
addon()->publishExternal(SelectionEvent{selection});
}
}
return NoError;
}
@@ -32,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
@@ -66,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
}
+21 -5
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 {
@@ -44,7 +46,7 @@ bool Mesh::fillInventory(Inventory& inventory) const {
{ fieldID[colorID], colorID, element },
},
}.withType(&typeid(Mesh)));
return true;
return base::fillInventory(inventory);
} //Mesh::fillInventory
@@ -57,16 +59,30 @@ bool Mesh::fillInventory(Inventory& inventory) const {
--------------------------------------------------------------------*/
Cargo::Unique Mesh::getCargo(const Inventory::Item& item) const {
if (item.ownerType != &typeid(Mesh))
return nullptr;
return base::getCargo(item);
using namespace active::serialise;
switch (item.index) {
case vertexID:
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
+41 -13
View File
@@ -1,29 +1,50 @@
#ifndef SPECKLE_PRIMITIVE_MESH
#define SPECKLE_PRIMITIVE_MESH
#include "Active/Serialise/Package/Package.h"
#include "Speckle/Database/Content/BIMRecord.h"
#include "Speckle/Utility/String.h"
#ifdef ARCHICAD
#include "ModelMaterial.hpp"
#endif
namespace speckle::primitive {
/*!
Class for a 3D mesh
*/
class Mesh : public active::serialise::Package {
*/
class Mesh : public speckle::database::BIMRecord {
public:
// MARK: - Types
using base = speckle::database::BIMRecord;
// MARK: - Constructors
/*!
Default constructor
@param unit The mesh unit type
*/
Mesh() {}
Mesh(std::vector<double>&& vertices, std::vector<int>&& faces, std::vector<int>&& colors, utility::String units = "m")
: vertices{ std::move(vertices) }, faces{ std::move(faces) }, colors{ std::move(colors) }, units{ units } {}
Mesh(active::measure::LengthType unit = active::measure::LengthType::metre) : base{utility::Guid{true}, utility::Guid{}, unit} {}
/*!
Constructor
@param vertices The mesh vertices
@param faces The mesh faces (the number of indices in the face followed by the vertex indices)
@param colors The mesh face colours
@param unit The mesh unit type
*/
Mesh(std::vector<double>&& vertices, std::vector<int>&& faces, std::vector<int>&& colors, const ModelerAPI::Material& material,
active::measure::LengthType unit = active::measure::LengthType::metre) :
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)
/*!
Get the speckle type identifier
@return The speckle type (relevant objects should override as required)
*/
speckle::utility::String getSpeckleType() const override { return "Objects.Geometry.Mesh"; }
// MARK: - Serialisation
@@ -31,20 +52,27 @@ namespace speckle::primitive {
Fill an inventory with the package items
@param inventory The inventory to receive the package items
@return True if the package has added items to the inventory
*/
*/
bool fillInventory(active::serialise::Inventory& inventory) const override;
/*!
Get the specified cargo
@param item The inventory item to retrieve
@return The requested cargo (nullptr on failure)
*/
*/
active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
/*!
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;
utility::String units;
std::vector<double> m_vertices;
std::vector<int> m_faces;
std::vector<int> m_colors;
#ifdef ARCHICAD
ModelerAPI::Material m_material;
#endif
};
}
@@ -0,0 +1,105 @@
#include "Speckle/Record/Attribute/Attribute.h"
#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;
using namespace speckle::environment;
using namespace speckle::record::attribute;
using namespace speckle::utility;
#include <array>
#include <memory>
namespace {
///Serialisation fields
enum FieldIndex {
nameID,
};
///Serialisation field IDs
static std::array fieldID = {
Identity{"name"},
};
}
/*--------------------------------------------------------------------
Default constructor
--------------------------------------------------------------------*/
Attribute::Attribute() {
} //Attribute::Attribute
/*--------------------------------------------------------------------
Get the attribute name
return: The attribute name
--------------------------------------------------------------------*/
speckle::utility::String Attribute::getName() const {
#ifdef ARCHICAD
return getHead().name;
#endif
} //Attribute::getName
/*--------------------------------------------------------------------
Fill an inventory with the package items
inventory: The inventory to receive the package items
return: True if the package has added items to the inventory
--------------------------------------------------------------------*/
bool Attribute::fillInventory(Inventory& inventory) const {
using enum Entry::Type;
inventory.merge(Inventory{
{
{ fieldID[nameID], nameID, element },
},
}.withType(&typeid(Attribute)));
return base::fillInventory(inventory);
} //Attribute::fillInventory
/*--------------------------------------------------------------------
Get the specified cargo
item: The inventory item to retrieve
return: The requested cargo (nullptr on failure)
--------------------------------------------------------------------*/
Cargo::Unique Attribute::getCargo(const Inventory::Item& item) const {
if (item.ownerType != &typeid(Attribute))
return base::getCargo(item);
using namespace active::serialise;
switch (item.index) {
case nameID:
#ifdef ARCHICAD
return std::make_unique<ValueWrap<Str256>>(reinterpret_cast<const Str256&>(getHead().name));
#endif
default:
return nullptr; //Requested an unknown index
}
} //Attribute::getCargo
#ifdef ARCHICAD
/*--------------------------------------------------------------------
Get the attribute data from the host BIM application
return: The attribute data (for internal use to populate derived classes)
--------------------------------------------------------------------*/
API_Attribute Attribute::getData() const {
if (auto project = addon()->getActiveProject().lock(); project) {
if (auto attr = project->getAttributeDatabase()->getAPIData(getBIMLink()); attr)
return *attr;
}
API_Attribute attr;
active::utility::Memory::erase(attr);
return attr;
} //Attribute::getData
#endif
@@ -0,0 +1,120 @@
#ifndef SPECKLE_RECORD_ATTRIBUTE
#define SPECKLE_RECORD_ATTRIBUTE
#include "Speckle/Database/Content/BIMRecord.h"
#include "Speckle/Utility/String.h"
namespace speckle::record::attribute {
/*!
Base BIM attribute class
*/
class Attribute : public speckle::database::BIMRecord {
public:
// MARK: - Types
using base = speckle::database::BIMRecord;
///Unique pointer
using Unique = std::unique_ptr<Attribute>;
///Shared pointer
using Shared = std::shared_ptr<Attribute>;
///Optional
using Option = std::optional<Attribute>;
// MARK: - Constants
#ifdef ARCHICAD
///Archicad type identifier for a storey attribute table
static constexpr int32_t storeyTableID = 0x200;
/*!
Get an attribute type ID from a table ID
@param tableID The table ID
@return The attribute type ID (NB: not strictly API_AttrTypeID - can be storeyTypeID)
*/
static API_AttrTypeID getTypeID(const active::utility::Guid& tableID) {
return static_cast<API_AttrTypeID>(active::utility::Guid::toInt(tableID));
}
/*!
Get an Archicad attribute index from a record ID
@param recordID The record ID
@return An attribute index
*/
static API_AttributeIndex getIndex(const active::utility::Guid& recordID) {
return ACAPI_CreateAttributeIndex(static_cast<int32_t>(active::utility::Guid::toInt(recordID)));
}
#endif
// MARK: - Constructors
using base::base;
/*!
Default constructor
*/
Attribute();
/*!
Constructor
@param ID The attribute ID
@param tableID The attribute table ID (attribute type)
*/
Attribute(const database::BIMRecordID& ID, const speckle::utility::Guid& tableID) : base{ID, tableID} {}
// MARK: - Functions (const)
/*!
Get the speckle type identifier
@return The speckle type (relevant objects should override as required)
*/
speckle::utility::String getSpeckleType() const override { return "speckle::record::attribute::Attribute"; }
/*!
Get the attribute name
@return The attribute name
*/
speckle::utility::String getName() const;
#ifdef ARCHICAD
/*!
Get the (immutable) API attribute header data
@return The attribute header data (only use this data for low-level operations - for normal code, call getters/setters)
*/
virtual const API_Attr_Head& getHead() const = 0;
#endif
// MARK: - Functions (mutating)
#ifdef ARCHICAD
/*!
Get the (mutable) API attribute header data
@return The attribute header data (only use this data for low-level operations - for normal code, call getters/setters)
*/
virtual API_Attr_Head& getHead() = 0;
#endif
// MARK: - Serialisation
/*!
Fill an inventory with the package items
@param inventory The inventory to receive the package items
@return True if the package has added items to the inventory
*/
bool fillInventory(active::serialise::Inventory& inventory) const override;
/*!
Get the specified cargo
@param item The inventory item to retrieve
@return The requested cargo (nullptr on failure)
*/
Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
protected:
#ifdef ARCHICAD
/*!
Get the attribute data from the host BIM application
@return The attribute data (for internal use to populate derived classes)
*/
API_Attribute getData() const;
#endif
};
}
#endif //SPECKLE_RECORD_ATTRIBUTE
@@ -0,0 +1,269 @@
#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>
#include <memory>
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
/*!
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;
};
}
namespace {
///Serialisation fields
enum FieldIndex {
diffuseID,
opacityID,
emissiveID,
metalnessID,
roughnessID,
};
///Serialisation field IDs
static std::array fieldID = {
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;
}
#endif
}
/*--------------------------------------------------------------------
Default constructor
--------------------------------------------------------------------*/
Finish::Finish() {
} //Finish::Finish
/*--------------------------------------------------------------------
Constructor
ID: The attribute ID
--------------------------------------------------------------------*/
Finish::Finish(const database::BIMRecordID& ID) : base{ID, Finish::table} {
} //Finish::Finish
#ifdef ARCHICAD
/*--------------------------------------------------------------------
Constructor
attrData: Archicad attribute data
tableID: The ID of the parent table
--------------------------------------------------------------------*/
Finish::Finish(const API_Attribute& attrData, const BIMRecordID& tableID) : base{attrData.header.guid, Finish::table} {
m_data = std::make_unique<Data>(attrData);
setUnit(std::nullopt); //Finishes have no unit
}
/*--------------------------------------------------------------------
Constructor
material: A ModelerAPI material definition
--------------------------------------------------------------------*/
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 = getBIMID();
attr.material.mtype = static_cast<API_MaterTypeID>(material.GetType());
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
/*--------------------------------------------------------------------
Copy constructor
source: The object to copy
--------------------------------------------------------------------*/
Finish::Finish(const Finish& source) : base{source} {
m_data = source.m_data ? std::make_unique<Data>(*source.m_data) : nullptr;
} //Finish::Finish
/*--------------------------------------------------------------------
Destructor
--------------------------------------------------------------------*/
Finish::~Finish() {}
#ifdef ARCHICAD
/*--------------------------------------------------------------------
Get the (immutable) API attribute header data
return: The attribute header data (only use this data for low-level operations - for normal code, call getters/setters)
--------------------------------------------------------------------*/
const API_Attr_Head& Finish::getHead() const {
confirmData();
return m_data->root.head;
} //Finish::getHead
/*--------------------------------------------------------------------
Get the (mutable) API attribute header data
return: The attribute header data (only use this data for low-level operations - for normal code, call getters/setters)
--------------------------------------------------------------------*/
API_Attr_Head& Finish::getHead() {
confirmData();
return m_data->root.head;
} //Finish::getHead
#endif
/*--------------------------------------------------------------------
Fill an inventory with the package items
inventory: The inventory to receive the package items
return: True if the package has added items to the inventory
--------------------------------------------------------------------*/
bool Finish::fillInventory(Inventory& inventory) const {
using enum Entry::Type;
inventory.merge(Inventory{
{
{ fieldID[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);
} //Finish::fillInventory
/*--------------------------------------------------------------------
Get the specified cargo
item: The inventory item to retrieve
return: The requested cargo (nullptr on failure)
--------------------------------------------------------------------*/
Cargo::Unique Finish::getCargo(const Inventory::Item& item) const {
if (item.ownerType != &typeid(Finish))
return base::getCargo(item);
confirmData();
using namespace active::serialise;
switch (item.index) {
case 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
}
} //Finish::getCargo
/*--------------------------------------------------------------------
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
--------------------------------------------------------------------*/
void Finish::confirmData() const {
if (m_data)
return;
m_data = std::make_unique<Data>(getData());
} //Finish::confirmData
@@ -0,0 +1,144 @@
#ifndef SPECKLE_RECORD_ATTRIBUTE_FINISH
#define SPECKLE_RECORD_ATTRIBUTE_FINISH
#include "Speckle/Record/Attribute/Attribute.h"
#ifdef ARCHICAD
namespace ModelerAPI {
class Material;
}
#endif
namespace speckle::record::attribute {
/*!
Class to represent the rendered finish on a 3D body, i.e. the surface colour/texture etc.
In Archicad this attribute is represented by `API_MaterialType`
*/
class Finish : public Attribute {
public:
// MARK: - Types
using base = Attribute;
///Unique pointer
using Unique = std::unique_ptr<Finish>;
///Shared pointer
using Shared = std::shared_ptr<Finish>;
///Optional
using Option = std::optional<Finish>;
// MARK: - Constants
#ifdef ARCHICAD
///The finishes table identifier
static constexpr active::utility::Guid table{active::utility::Guid::fromInt(API_MaterialID)};
#endif
// MARK: - Constructors
using base::base;
/*!
Default constructor
*/
Finish();
/*!
Constructor
@param ID The attribute ID
*/
Finish(const database::BIMRecordID& ID);
#ifdef ARCHICAD
/*!
Constructor
@param attrData Archicad attribute data
@param tableID The ID of the parent table
*/
Finish(const API_Attribute& attrData, const database::BIMRecordID& tableID);
/*!
Constructor
@param material A ModelerAPI material definition
*/
Finish(const ModelerAPI::Material& material);
#endif
/*!
Copy constructor
@param source The object to copy
*/
Finish(const Finish& source);
/*!
Destructor
*/
~Finish();
/*!
Object cloning
@return A clone of this object
*/
Finish* clonePtr() const override { return new Finish{*this}; }
// MARK: - Functions (const)
/*!
Get the speckle type identifier
@return The speckle type (relevant objects should override as required)
*/
speckle::utility::String getSpeckleType() const override { return "Objects.Other.RenderMaterial"; }
#ifdef ARCHICAD
/*!
Get the (immutable) API attribute header data
@return The attribute header data (only use this data for low-level operations - for normal code, call getters/setters)
*/
const API_Attr_Head& getHead() const override;
#endif
// MARK: - Functions (mutating)
#ifdef ARCHICAD
/*!
Get the (mutable) API attribute header data
@return The attribute header data (only use this data for low-level operations - for normal code, call getters/setters)
*/
API_Attr_Head& getHead() override;
#endif
// MARK: - Serialisation
/*!
Fill an inventory with the package items
@param inventory The inventory to receive the package items
@return True if the package has added items to the inventory
*/
bool fillInventory(active::serialise::Inventory& inventory) const override;
/*!
Get the specified cargo
@param item The inventory item to retrieve
@return The requested cargo (nullptr on failure)
*/
Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
/*!
Set to the default package content
*/
void setDefault() override;
/*!
Validate the cargo data
@return True if the data has been validated
*/
bool validate() override;
private:
/*!
Confirm the internal data, either loading from the BIM application or setting a default
*/
void confirmData() const;
class Data;
///The attribute data - mutable to support lazy loading
mutable std::unique_ptr<Data> m_data;
};
}
#endif //SPECKLE_RECORD_ATTRIBUTE_FINISH
@@ -0,0 +1,221 @@
#include "Speckle/Record/Attribute/Storey.h"
#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
#include "Active/Utility/BufferOut.h"
#include "Speckle/Database/BIMAttributeDatabase.h"
#include "Speckle/Environment/Addon.h"
#include "Speckle/Environment/Project.h"
#include "Speckle/Utility/Guid.h"
using namespace active::serialise;
using namespace speckle::database;
using namespace speckle::environment;
using namespace speckle::record::attribute;
using namespace speckle::utility;
#include <array>
#include <memory>
namespace speckle::record::attribute {
class Storey::Data {
public:
#ifdef ARCHICAD
Data(const API_StoryType& storey) : root{storey} {}
Data(const Data& source) : root{source.root} {}
API_StoryType root;
API_Attr_Head header;
#endif
};
}
namespace {
///Serialisation fields
enum FieldIndex {
levelID,
};
///Serialisation field IDs
static std::array fieldID = {
Identity{"level"},
};
#ifdef ARCHICAD
/*!
Fill in an Archicad API attribute header based on a storey
@param header The attribute header to be populated
@param storey The storey to be copied into the header
*/
void fillHeader(API_Attr_Head& header, const API_StoryType& storey) {
active::utility::Memory::erase(header);
//NB: This is not intended to be used for API attribute calls - it only transports core properties within this framework, e.g. name
header.typeID = static_cast<API_AttrTypeID>(Attribute::storeyTableID);
header.index = ACAPI_CreateAttributeIndex(storey.index);
header.guid = Guid{Guid::fromInt(storey.floorId)};
String{storey.uName}.writeUTF8(active::utility::BufferOut{header.name}, true);
}
#endif
}
/*--------------------------------------------------------------------
Default constructor
--------------------------------------------------------------------*/
Storey::Storey() {
} //Storey::Storey
#ifdef ARCHICAD
/*--------------------------------------------------------------------
Constructor
index: An index into the Archicad storey array
--------------------------------------------------------------------*/
Storey::Storey(short index) {
m_storeyIndex = index;
} //Storey::Storey
#endif
/*--------------------------------------------------------------------
Constructor
ID: The attribute ID
--------------------------------------------------------------------*/
Storey::Storey(const database::BIMRecordID& ID) : base{ID, storeyTableID} {
} //Storey::Storey
/*--------------------------------------------------------------------
Copy constructor
source: The object to copy
--------------------------------------------------------------------*/
Storey::Storey(const Storey& source) : base{source} {
m_data = source.m_data ? std::make_unique<Data>(*m_data) : nullptr;
#ifdef ARCHICAD
m_storeyIndex = source.m_storeyIndex;
#endif
} //Storey::Storey
/*--------------------------------------------------------------------
Destructor
--------------------------------------------------------------------*/
Storey::~Storey() {}
#ifdef ARCHICAD
/*--------------------------------------------------------------------
Get the (immutable) API attribute header data
return: The attribute header data (only use this data for low-level operations - for normal code, call getters/setters)
--------------------------------------------------------------------*/
const API_Attr_Head& Storey::getHead() const {
confirmData();
fillHeader(m_data->header, m_data->root);
return m_data->header;
} //Storey::getHead
/*--------------------------------------------------------------------
Get the (mutable) API attribute header data
return: The attribute header data (only use this data for low-level operations - for normal code, call getters/setters)
--------------------------------------------------------------------*/
API_Attr_Head& Storey::getHead() {
confirmData();
fillHeader(m_data->header, m_data->root);
return m_data->header;
} //Storey::getHead
#endif
/*--------------------------------------------------------------------
Fill an inventory with the package items
inventory: The inventory to receive the package items
return: True if the package has added items to the inventory
--------------------------------------------------------------------*/
bool Storey::fillInventory(Inventory& inventory) const {
using enum Entry::Type;
inventory.merge(Inventory{
{
{ fieldID[levelID], levelID, element }, //TODO: implement other fields
},
}.withType(&typeid(Storey)));
return base::fillInventory(inventory);
} //Storey::fillInventory
/*--------------------------------------------------------------------
Get the specified cargo
item: The inventory item to retrieve
return: The requested cargo (nullptr on failure)
--------------------------------------------------------------------*/
Cargo::Unique Storey::getCargo(const Inventory::Item& item) const {
if (item.ownerType != &typeid(Storey))
return base::getCargo(item);
confirmData();
using namespace active::serialise;
switch (item.index) {
case levelID:
return std::make_unique<DoubleWrap>(m_data->root.level);
default:
return nullptr; //Requested an unknown index
}
} //Storey::getCargo
/*--------------------------------------------------------------------
Set to the default package content
--------------------------------------------------------------------*/
void Storey::setDefault() {
} //Storey::setDefault
/*--------------------------------------------------------------------
Confirm the internal data, either loading from the BIM application or setting a default
--------------------------------------------------------------------*/
void Storey::confirmData() const {
if (m_data)
return;
#ifdef ARCHICAD
m_data = std::make_unique<Data>(getStoreyData());
#endif
} //Storey::confirmData
#ifdef ARCHICAD
/*--------------------------------------------------------------------
Get the storey data from the host BIM application
return: The storey data (for internal use to populate derived classes)
--------------------------------------------------------------------*/
API_StoryType Storey::getStoreyData() const {
do {
if (auto project = addon()->getActiveProject().lock(); project) {
auto attributeDatabase = project->getAttributeDatabase();
if (m_storeyIndex) {
auto storeyID = attributeDatabase->getStoreyID(*m_storeyIndex);
m_storeyIndex.reset();
if (!storeyID)
break;
resetIndex({*storeyID, Attribute::storeyTableID});
}
if (auto storey = attributeDatabase->getAPIStorey(getBIMLink()); storey)
return *storey;
}
} while (false);
API_StoryType storey;
active::utility::Memory::erase(storey);
return storey;
} //Storey::getStoreyData
#endif
@@ -0,0 +1,135 @@
#ifndef SPECKLE_RECORD_ATTRIBUTE_STOREY
#define SPECKLE_RECORD_ATTRIBUTE_STOREY
#include "Speckle/Record/Attribute/Attribute.h"
namespace speckle::record::attribute {
/*!
A storey or level in a building
Represented in Archicad by `API_StoryType`
*/
class Storey : public Attribute {
public:
// MARK: - Types
using base = Attribute;
///Unique pointer
using Unique = std::unique_ptr<Storey>;
///Shared pointer
using Shared = std::shared_ptr<Storey>;
///Optional
using Option = std::optional<Storey>;
// MARK: - Constructors
using base::base;
/*!
Default constructor
*/
Storey();
/*!
Constructor
@param ID The attribute ID
*/
Storey(const database::BIMRecordID& ID);
#ifdef ARCHICAD
/*!
Constructor
@param index An index into the Archicad storey array
*/
Storey(short index);
/*!
Constructor
@param attrData Archicad attribute data
*/
Storey(const API_StoryType& attrData);
#endif
/*!
Copy constructor
@param source The object to copy
*/
Storey(const Storey& source);
/*!
Destructor
*/
~Storey();
/*!
Object cloning
@return A clone of this object
*/
Storey* clonePtr() const override { return new Storey{*this}; }
// MARK: - Functions (const)
/*!
Get the speckle type identifier
@return The speckle type (relevant objects should override as required)
*/
speckle::utility::String getSpeckleType() const override { return "speckle::record::attribute::Storey"; }
#ifdef ARCHICAD
/*!
Get the (immutable) API attribute header data
@return The attribute header data (only use this data for low-level operations - for normal code, call getters/setters)
*/
const API_Attr_Head& getHead() const override;
#endif
// MARK: - Functions (mutating)
#ifdef ARCHICAD
/*!
Get the (mutable) API attribute header data
@return The attribute header data (only use this data for low-level operations - for normal code, call getters/setters)
*/
API_Attr_Head& getHead() override;
#endif
// MARK: - Serialisation
/*!
Fill an inventory with the package items
@param inventory The inventory to receive the package items
@return True if the package has added items to the inventory
*/
bool fillInventory(active::serialise::Inventory& inventory) const override;
/*!
Get the specified cargo
@param item The inventory item to retrieve
@return The requested cargo (nullptr on failure)
*/
Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
/*!
Set to the default package content
*/
void setDefault() override;
private:
/*!
Confirm the internal data, either loading from the BIM application or setting a default
*/
void confirmData() const;
#ifdef ARCHICAD
/*!
Get the storey data from the host BIM application
@return The storey data (for internal use to populate derived classes)
*/
API_StoryType getStoreyData() const;
///An index into the Archicad storey array - used temporarily for looking up the storey data on demand
mutable std::optional<short> m_storeyIndex;
#endif
class Data;
///The attribute data - mutable to support lazy loading
mutable std::unique_ptr<Data> m_data;
};
}
#endif //SPECKLE_RECORD_ATTRIBUTE_STOREY
@@ -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
+169 -109
View File
@@ -3,10 +3,27 @@
#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
#include "Active/Serialise/Package/Wrapper/PackageWrap.h"
#include "Active/Serialise/Package/Wrapper/ContainerWrap.h"
#include "Speckle/Database/BIMElementDatabase.h"
#include "Speckle/Environment/Addon.h"
#include "Speckle/Environment/Project.h"
#include "Speckle/Primitive/Mesh/Mesh.h"
#include "Speckle/Record/Element/Memo.h"
#include "Speckle/SpeckleResource.h"
#include "Speckle/Utility/Guid.h"
#ifdef ARCHICAD
#include <Sight.hpp>
#include <Model.hpp>
#include <ModelMaterial.hpp>
#include <ModelElement.hpp>
#include <exp.h>
#include <ModelMeshBody.hpp>
#include <ConvexPolygon.hpp>
#endif
using namespace active::serialise;
using namespace speckle::environment;
using namespace speckle::record::attribute;
using namespace speckle::record::element;
using namespace speckle::utility;
@@ -14,41 +31,31 @@ using namespace speckle::utility;
#include <memory>
namespace speckle::record::element {
class Element::Data {
public:
friend class Element;
Data(const API_Element& elem) : root{std::make_unique<API_Element>(elem)} {}
Data(const Data& source) : root{std::make_unique<API_Element>(*source.root)} {}
Data() {}
Data(const Data& source) {}
private:
std::unique_ptr<API_Element> root;
std::unique_ptr<Element::Body> m_cache;
};
}
namespace {
///Serialisation fields
///Serialisation fields
enum FieldIndex {
bodyID,
};
///Serialisation field IDs
///Serialisation field IDs
static std::array fieldID = {
Identity{"displayValue"},
};
void GetComponent(API_Component3D& component, API_3DTypeID typeId, Int32 index) {
component.header.typeID = typeId;
component.header.index = index;
if (ACAPI_ModelAccess_GetComponent(&component) != NoError) {
// TODO: throw
}
}
}
/*--------------------------------------------------------------------
@@ -61,136 +68,173 @@ Element::Element() {
/*--------------------------------------------------------------------
Constructor
elemData: Archicad element data
ID: The record ID
tableID: The parent table ID
unit: The record unit type
--------------------------------------------------------------------*/
Element::Element(const API_Element& elemData) : base{elemData.header.guid} {
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
/*--------------------------------------------------------------------
Copy constructor
source: The object to copy
source: The object to copy
--------------------------------------------------------------------*/
Element::Element(const Element& source) : base{source} {
Element::Element(const Element& source) : base{ source } {
m_data = source.m_data ? std::make_unique<Data>(*m_data) : nullptr;
} //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
--------------------------------------------------------------------*/
Element::~Element() {}
Element::Body* Element::getBody() const {
/*--------------------------------------------------------------------
Get the element storey
return: The element storey (nullopt if the element isn't linked to a storey)
--------------------------------------------------------------------*/
Storey::Option Element::getStorey() const {
#ifdef ARCHICAD
return Storey{ getHead().floorInd };
#endif
} //Element::getStorey
/*--------------------------------------------------------------------
Get the element type name, e.g. "Wall", "Roof" etc
return: The type name
--------------------------------------------------------------------*/
String Element::getTypeName() const {
#ifdef ARCHICAD
GS::UniString typeName;
if (auto err = ACAPI_Element_GetElemTypeName(getHead().type, typeName); err != NoError)
return addon()->getLocalString(titleStringLib, unknownElementTypeID);
return typeName;
#endif
} //Element::getTypeName
/*--------------------------------------------------------------------
Get the element body as a list of faces or Meshes
return: A pointer to the element body
--------------------------------------------------------------------*/
Element::Body* Element::getBody() const {
#ifdef ARCHICAD
if (m_data->m_cache) {
return m_data->m_cache.get();
}
auto elementBody = new Element::Body();
std::map<int, int> vertexIndexMap;
int currentVertexIndex = 0;
API_ElemInfo3D info3D = {};
if (ACAPI_ModelAccess_Get3DInfo(getHead(), &info3D) != NoError) {
// TODO: throw
void* dummy = nullptr;
GSErrCode err = ACAPI_Sight_GetCurrentWindowSight(&dummy);
if (err != NoError)
{
// TODO: should this throw?
}
for (Int32 ib = info3D.fbody; ib <= info3D.lbody; ib++) {
API_Component3D component = {};
GetComponent(component, API_BodyID, ib);
Modeler::SightPtr currentSightPtr((Modeler::Sight*)dummy); // init the shared ptr with the raw pointer
ModelerAPI::Model acModel;
Modeler::IAttributeReader* attrReader = ACAPI_Attribute_GetCurrentAttributeSetReader();
std::vector<double> vertices;
std::vector<int> faces;
std::vector<int> colors;
err = EXPGetModel(currentSightPtr, &acModel, attrReader);
if (err != NoError)
{
// TODO: should this throw?
}
vertices.clear();
faces.clear();
colors.clear();
auto elementBody = new Element::Body();
Int32 nPgon = component.body.nPgon;
for (Int32 ip = 1; ip <= nPgon; ip++) {
GetComponent(component, API_PgonID, ip);
Int32 nElements = acModel.GetElementCount();
for (Int32 iElement = 1; iElement <= nElements; iElement++)
{
ModelerAPI::Element elem{};
acModel.GetElement(iElement, &elem);
if (elem.GetElemGuid() != getHead().guid)
continue;
Int32 fpedg = component.pgon.fpedg;
Int32 lpedg = component.pgon.lpedg;
Int32 faceSize = lpedg - fpedg + 1;
faces.push_back(faceSize);
for (Int32 ie = fpedg; ie <= lpedg; ie++)
Int32 nBodies = elem.GetTessellatedBodyCount();
for (Int32 bodyIndex = 1; bodyIndex <= nBodies; ++bodyIndex)
{
ModelerAPI::MeshBody body{};
elem.GetTessellatedBody(bodyIndex, &body);
Int32 polyCount = body.GetPolygonCount();
for (Int32 polyIndex = 1; polyIndex <= polyCount; ++polyIndex)
{
GetComponent(component, API_PedgID, ie);
ModelerAPI::Polygon polygon{};
body.GetPolygon(polyIndex, &polygon);
// TODO is this needed? need review, not sure how ACAPI_ModelAccess works
bool wasNegative = component.pedg.pedg < 0;
Int32 edgeIndex = std::abs(component.pedg.pedg);
GetComponent(component, API_EdgeID, edgeIndex);
ModelerAPI::Material material{};
polygon.GetMaterial(&material);
Int32 convexPolyCount = polygon.GetConvexPolygonCount();
// TODO is this needed? need review, not sure how ACAPI_ModelAccess works
Int32 vertexIndex = wasNegative ? component.edge.vert2 : component.edge.vert1;
/*auto materialIndex = component.pgon.iumat;
GetComponent(component, API_UmatID, materialIndex);
double R = component.umat.mater.surfaceRGB.f_red;
double G = component.umat.mater.surfaceRGB.f_green;
double B = component.umat.mater.surfaceRGB.f_blue;*/
// TODO: other material stuff
for (Int32 convPolyIndex = 1; convPolyIndex <= convexPolyCount; ++convPolyIndex)
{
std::vector<double> vertices;
std::vector<int> faces;
std::vector<int> colors;
GetComponent(component, API_VertID, vertexIndex);
ModelerAPI::ConvexPolygon convexPolygon{};
polygon.GetConvexPolygon(convPolyIndex, &convexPolygon);
Int32 vertexCount = convexPolygon.GetVertexCount();
if (vertexIndexMap.find(vertexIndex) == vertexIndexMap.end()) {
faces.push_back(currentVertexIndex);
vertexIndexMap[vertexIndex] = currentVertexIndex++;
faces.push_back(vertexCount);
for (Int32 vertexIndex = 1; vertexIndex <= vertexCount; ++vertexIndex)
{
ModelerAPI::Vertex vertex{};
body.GetVertex(convexPolygon.GetVertexIndex(vertexIndex), &vertex);
vertices.push_back(component.vert.x);
vertices.push_back(component.vert.y);
vertices.push_back(component.vert.z);
}
else {
faces.push_back(vertexIndexMap[vertexIndex]);
// TODO: change vertices array to hold Vertex instead of double values
vertices.push_back(vertex.x);
vertices.push_back(vertex.y);
vertices.push_back(vertex.z);
//double alpha = material.GetTransparency();
//ModelerAPI::Color color = material.GetSurfaceColor();
//colors.push_back(ARGBToInt(alpha, color.red, color.green, color.blue));
faces.push_back(vertexIndex - 1);
}
elementBody->push_back(primitive::Mesh(std::move(vertices), std::move(faces), std::move(colors), material));
}
}
}
elementBody->push_back(primitive::Mesh(std::move(vertices), std::move(faces), std::move(colors)));
}
m_data->m_cache.reset(elementBody);
return m_data->m_cache.get();
#endif
}
/*--------------------------------------------------------------------
Get the (immutable) API element header data
return: The element header data (only use this data for low-level operations - for normal code, call getters/setters)
--------------------------------------------------------------------*/
const API_Elem_Head& Element::getHead() const {
return m_data->root->header;
} //Element::getHead
/*--------------------------------------------------------------------
Get the (mutable) API element header data
return: The element header data (only use this data for low-level operations - for normal code, call getters/setters)
--------------------------------------------------------------------*/
API_Elem_Head& Element::getHead() {
return m_data->root->header;
} //Element::getHead
/*--------------------------------------------------------------------
Fill an inventory with the package items
inventory: The inventory to receive the package items
return: True if the package has added items to the inventory
--------------------------------------------------------------------*/
bool Element::fillInventory(Inventory& inventory) const {
using enum Entry::Type;
auto body = getBody();
inventory.merge(Inventory{
{
{ fieldID[bodyID], bodyID, body == nullptr ? 0 : static_cast<uint32_t>(body->size()) }, //TODO: implement other fields
{ fieldID[bodyID], bodyID, element }, //TODO: implement other fields
},
}.withType(&typeid(Element)));
return base::fillInventory(inventory);
@@ -199,9 +243,9 @@ bool Element::fillInventory(Inventory& inventory) const {
/*--------------------------------------------------------------------
Get the specified cargo
item: The inventory item to retrieve
return: The requested cargo (nullptr on failure)
--------------------------------------------------------------------*/
Cargo::Unique Element::getCargo(const Inventory::Item& item) const {
@@ -209,17 +253,16 @@ Cargo::Unique Element::getCargo(const Inventory::Item& item) const {
return base::getCargo(item);
using namespace active::serialise;
switch (item.index) {
case bodyID:
if (auto body = getBody(); body != nullptr)
{
//return std::make_unique<active::serialise::ContainerWrap>(*body);
return Cargo::Unique{ new active::serialise::ContainerWrap{ *body } };
}
else
return nullptr;
default:
return nullptr; //Requested an unknown index
case bodyID:
if (auto body = getBody(); body != nullptr)
{
return Cargo::Unique{ new active::serialise::ContainerWrap{*body} };
}
else
return nullptr;
default:
return nullptr; //Requested an unknown index
}
} //Element::getCargo
@@ -231,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
+57 -34
View File
@@ -2,6 +2,8 @@
#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"
namespace speckle::primitive {
@@ -10,6 +12,8 @@ namespace speckle::primitive {
namespace speckle::record::element {
class Memo;
/*!
Base BIM element class
*/
@@ -31,80 +35,99 @@ namespace speckle::record::element {
// MARK: - Constructors
using base::base;
/*!
Default constructor
*/
Element();
#ifdef ARCHICAD
/*!
Constructor
@param elemData Archicad element data
@param ID The record ID
@param tableID The parent table ID
@param unit The record unit type
*/
Element(const API_Element& elemData);
#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)
/*!
Get the element body
@return An array of meshes from the element body (nullptr if no body data is available)
*/
Get the speckle type identifier
@return The speckle type (relevant objects should override as required)
*/
virtual speckle::utility::String getSpeckleType() const override { return "Objects.BuiltElements.Element:Objects.BuiltElements.Element"; }
/*!
Get the elmeent type name, e.g. "Wall", "Roof" etc
@return The type name
*/
virtual speckle::utility::String getTypeName() const;
/*!
Get the element storey
@return The element storey (nullopt if the element isn't linked to a storey)
*/
virtual attribute::Storey::Option getStorey() const;
/*!
Get the element body
@return An array of meshes from the element body (nullptr if no body data is available)
*/
virtual Body* getBody() const;
#ifdef ARCHICAD
/*!
Get the (immutable) API element header data
@return The element header data (only use this data for low-level operations - for normal code, call getters/setters)
*/
virtual const API_Elem_Head& getHead() const;
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 = 0;
#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();
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() = 0;
#endif
// MARK: - Serialisation
/*!
Fill an inventory with the package items
@param inventory The inventory to receive the package items
@return True if the package has added items to the inventory
*/
Fill an inventory with the package items
@param inventory The inventory to receive the package items
@return True if the package has added items to the inventory
*/
bool fillInventory(active::serialise::Inventory& inventory) const override;
/*!
Get the specified cargo
@param item The inventory item to retrieve
@return The requested cargo (nullptr on failure)
*/
Get the specified cargo
@param item The inventory item to retrieve
@return The requested cargo (nullptr on failure)
*/
Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
/*!
Set to the default package content
*/
Set to the default package content
*/
void setDefault() override;
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,48 @@
#ifndef SPECKLE_SERIALISE_FINISH_COLLECTOR
#define SPECKLE_SERIALISE_FINISH_COLLECTOR
#include "Active/Serialise/Management/Manager.h"
#ifdef ARCHICAD
namespace ModelerAPI {
class Material;
}
#endif
namespace speckle::serialise {
/*!
Collector for object finishes
Used as a serialisation manager to collect finishes from serialised objects
*/
class FinishCollector : public active::serialise::Manager {
public:
/*!
Destructor
*/
virtual ~FinishCollector() {}
// MARK: - Functions (mutating)
/*!
Add a material proxy record to the collection
@param materialIndex The index of the material to add
@param objectID The object the material is applied to
@return True if the material proxy was added (false typically means the record already exists)
*/
virtual bool addMaterialProxy(const speckle::database::BIMIndex& materialIndex, const speckle::database::BIMRecordID& objectID) = 0;
#ifdef ARCHICAD
/*!
Add a ModelerAPI material to the collection (NB: These are not persistent so need to be captured by this method)
@param material A material
@param objectID The object the material is applied to
@return True if the material proxy was added (false typically means the record already exists)
*/
virtual bool addMaterialProxy(const ModelerAPI::Material& material, const speckle::database::BIMRecordID& objectID) = 0;
#endif
};
}
#endif //SPECKLE_SERIALISE_FINISH_COLLECTOR
@@ -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
@@ -64,7 +64,7 @@ Cargo::Unique DetachedReference::getCargo(const Inventory::Item& item) const {
//If we don't have an allocated string for receiving a reference (from 'setDefault') then we need to create one
if (!m_reference) {
//Ask a manager to send the detached data and provide a reference
auto detachmentManager = getManager<DetachmentManager>();
auto detachmentManager = (management() == nullptr) ? nullptr : management()->get<DetachmentManager>();
if (detachmentManager == nullptr)
return nullptr; //TODO: Discuss if this is a serious error - possibly throwing an exception is warranted
m_reference = detachmentManager->send(std::forward<Package&&>(base::get()), item.identity());
@@ -1,7 +1,7 @@
#ifndef SPECKLE_SERIALISE_DETACHMENT_MANAGER
#define SPECKLE_SERIALISE_DETACHMENT_MANAGER
#include "Active/Serialise/Manager.h"
#include "Active/Serialise/Management/Manager.h"
#include "Active/Serialise/Transport.h"
#include "Speckle/Database/Identity/RecordID.h"
@@ -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
@@ -0,0 +1,55 @@
#include "Speckle/Serialise/Types/Units/LengthUnit.h"
#include <algorithm>
#include <map>
using namespace active::measure;
using namespace active::utility;
using enum LengthType;
namespace {
//All recognised encoding types
std::map<LengthType, String> lengthNames = {
{ millimetre, "mm" },
{ centimetre, "cm" },
{ metre, "m" },
{ kilometre, "km" },
{ inch, "in" },
{ foot, "ft" },
{ yard, "yd" },
{ mile, "ml" },
};
} // namespace
/*--------------------------------------------------------------------
Convert a length unit name to a type
name: The length unit name
return: The length unit type (nullopt if no match found)
--------------------------------------------------------------------*/
std::optional<LengthType> speckle::serialise::lengthUnitFromName(const String& name) {
if (auto match = std::find_if(lengthNames.begin(), lengthNames.end(), [&](const auto& i){ return (i.second == name); });
match != lengthNames.end()) {
return match->first;
}
return std::nullopt;
} //encodingFromName
/*--------------------------------------------------------------------
Convert a length unit type to a name
lengthType: The length unit type
return: The name of the length unit type (nullopt if no match found)
--------------------------------------------------------------------*/
std::optional<String> speckle::serialise::nameFromLengthUnit(LengthType lengthType) {
if (auto match = lengthNames.find(lengthType); match != lengthNames.end()) {
return match->second;
}
return std::nullopt;
} //nameFromEncoding
@@ -0,0 +1,107 @@
#ifndef SPECKLE_SERIALISE_LENGTH_UNIT
#define SPECKLE_SERIALISE_LENGTH_UNIT
#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
#include "Active/Serialise/Item/Wrapper/ValueOptionWrap.h"
#include "Active/Setting/Values/Measurement/Units/LengthUnit.h"
namespace speckle::serialise {
/*!
Convert a length unit name to a type
@param name The length unit name
@return The length unit type (nullopt if no match found)
*/
std::optional<active::measure::LengthType> lengthUnitFromName(const active::utility::String& name);
/*!
Convert a length unit type to a name
@param lengthType The length unit type
@return The name of the length unit type (nullopt if no match found)
*/
std::optional<active::utility::String> nameFromLengthUnit(active::measure::LengthType lengthType);
}
namespace active::serialise {
// MARK: - Specialisations for length types
/*!
Read a length type value from the specified string
@param source The string to read
@return True if the data was successfully read
*/
inline std::pair<active::measure::LengthType, bool> readLengthTypeRefValue(const utility::String& source) {
using enum active::measure::LengthType;
if (auto converted = speckle::serialise::lengthUnitFromName(source); converted)
return {*converted, true};
return {metre, false};
} //ValueWrap<active::measure::LengthType>::read
/*!
Import the object from the specified string (specialisation for length type)
@param source The string to read
@return True if the data was successfully read
*/
template<> inline
bool ValueWrap<active::measure::LengthType>::read(const utility::String& source) {
auto result = readLengthTypeRefValue(source);
if (result.second)
base::get() = result.first;
return result.second;
} //ValueWrap<active::measure::LengthType>::read
/*!
Import the object from the specified string (specialisation for length type)
@param source The string to read
@return True if the data was successfully read
*/
template<> inline
bool ValueOptionWrap<active::measure::LengthType>::read(const utility::String& source) {
auto result = readLengthTypeRefValue(source);
if (result.second)
base::get() = result.first;
return result.second;
} //ValueWrap<active::measure::LengthType>::read
/*!
Export the object to the specified string (specialisation for length type)
@param dest The string to write the data to
@return True if the data was successfully written
*/
template<> inline
bool ValueWrap<active::measure::LengthType>::write(utility::String& dest) const {
if (auto name = speckle::serialise::nameFromLengthUnit(base::get()); name) {
dest = *name;
return true;
}
return false;
} //ValueWrap<active::measure::LengthType>::write
/*!
Export the object to the specified string (specialisation for length type)
@param dest The string to write the data to
@return True if the data was successfully written
*/
template<> inline
bool ValueOptionWrap<active::measure::LengthType>::write(utility::String& dest) const {
if (!base::get())
return false;
if (auto name = speckle::serialise::nameFromLengthUnit(*base::get()); name) {
dest = *name;
return true;
}
return false;
} //ValueOptionWrap<active::measure::LengthType>::write
}
#endif //SPECKLE_SERIALISE_LENGTH_UNIT
+1
View File
@@ -14,6 +14,7 @@ enum SpeckleStringResource {
//Title strings (UI title/label for dialogs, controls, menu items etc)
enum SpeckleTitleString {
untitledProjectID = 1,
unknownElementTypeID,
};
+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
@@ -36,7 +36,39 @@
2193519B2C6278D900E5A69C /* SelectionSubscriber.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219351992C6278D900E5A69C /* SelectionSubscriber.cpp */; };
219351B12C62CC1A00E5A69C /* Guid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219351AC2C62CC1A00E5A69C /* Guid.cpp */; };
219351B32C62CC1A00E5A69C /* String.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219351AE2C62CC1A00E5A69C /* String.cpp */; };
2196F2E32CB05BAF00450DFC /* LengthUnit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2196F2E22CB05BAF00450DFC /* LengthUnit.cpp */; };
2196F2EB2CB4816B00450DFC /* ArchicadAttributeDBaseEngine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2196F2E82CB4816B00450DFC /* ArchicadAttributeDBaseEngine.cpp */; };
2196F2EC2CB4816B00450DFC /* ArchicadAttributeDBaseEngine.h in Headers */ = {isa = PBXBuildFile; fileRef = 2196F2E92CB4816B00450DFC /* ArchicadAttributeDBaseEngine.h */; };
2196F2F02CB4823C00450DFC /* Attribute.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2196F2ED2CB4823C00450DFC /* Attribute.cpp */; };
2196F2F12CB4823C00450DFC /* Attribute.h in Headers */ = {isa = PBXBuildFile; fileRef = 2196F2EE2CB4823C00450DFC /* Attribute.h */; };
2196F2F42CB483D600450DFC /* Finish.h in Headers */ = {isa = PBXBuildFile; fileRef = 2196F2F22CB483D600450DFC /* Finish.h */; };
2196F2F52CB483D600450DFC /* Finish.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2196F2F32CB483D600450DFC /* Finish.cpp */; };
2196F2F82CB51ED400450DFC /* BIMAttributeDatabase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2196F2F62CB51ED400450DFC /* BIMAttributeDatabase.cpp */; };
2196F2F92CB51ED400450DFC /* BIMAttributeDatabase.h in Headers */ = {isa = PBXBuildFile; fileRef = 2196F2F72CB51ED400450DFC /* BIMAttributeDatabase.h */; };
2196F3042CB57E8000450DFC /* Storey.h in Headers */ = {isa = PBXBuildFile; fileRef = 2196F3022CB57E7F00450DFC /* Storey.h */; };
2196F3052CB57E8000450DFC /* Storey.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2196F3032CB57E7F00450DFC /* Storey.cpp */; };
2199881E2BD833830035E5EA /* libArchicad27.a in CopyFiles */ = {isa = PBXBuildFile; fileRef = 21379E082AE47A6400A1584C /* libArchicad27.a */; };
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 */; };
@@ -162,7 +194,41 @@
219351AD2C62CC1A00E5A69C /* Guid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Guid.h; sourceTree = "<group>"; };
219351AE2C62CC1A00E5A69C /* String.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = String.cpp; sourceTree = "<group>"; };
219351AF2C62CC1A00E5A69C /* String.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = String.h; sourceTree = "<group>"; };
2196F2DE2CB0566500450DFC /* LengthUnit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LengthUnit.h; sourceTree = "<group>"; };
2196F2E22CB05BAF00450DFC /* LengthUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LengthUnit.cpp; sourceTree = "<group>"; };
2196F2E82CB4816B00450DFC /* ArchicadAttributeDBaseEngine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArchicadAttributeDBaseEngine.cpp; sourceTree = "<group>"; };
2196F2E92CB4816B00450DFC /* ArchicadAttributeDBaseEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArchicadAttributeDBaseEngine.h; sourceTree = "<group>"; };
2196F2ED2CB4823C00450DFC /* Attribute.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Attribute.cpp; sourceTree = "<group>"; };
2196F2EE2CB4823C00450DFC /* Attribute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Attribute.h; sourceTree = "<group>"; };
2196F2F22CB483D600450DFC /* Finish.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Finish.h; sourceTree = "<group>"; };
2196F2F32CB483D600450DFC /* Finish.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Finish.cpp; sourceTree = "<group>"; };
2196F2F62CB51ED400450DFC /* BIMAttributeDatabase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BIMAttributeDatabase.cpp; sourceTree = "<group>"; };
2196F2F72CB51ED400450DFC /* BIMAttributeDatabase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BIMAttributeDatabase.h; sourceTree = "<group>"; };
2196F3022CB57E7F00450DFC /* Storey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Storey.h; sourceTree = "<group>"; };
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>"; };
@@ -267,9 +333,11 @@
isa = PBXGroup;
children = (
2167E27C2C49121F000827D3 /* CMakeLists.txt */,
21A0FBA02CB880690023F24E /* Collection */,
21AEF9C72CA818EA000B8681 /* Detached */,
21F69F3A2C6B880B008B6A06 /* JSBase */,
219712682BE7E2D500D9EF7E /* Serialisation.md */,
21A0FBB12CBA5E0E0023F24E /* Types */,
);
path = Serialise;
sourceTree = "<group>";
@@ -308,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>";
@@ -319,6 +396,7 @@
children = (
215F08872CA195EC00CD343B /* ArchicadDBaseCore.cpp */,
215F08882CA195EC00CD343B /* ArchicadDBaseCore.h */,
2196F2EA2CB4816B00450DFC /* Attribute */,
219246062CA2D22D00CF5703 /* Element */,
);
path = ArchicadDBase;
@@ -396,6 +474,8 @@
219351B02C62CC1A00E5A69C /* Utility */ = {
isa = PBXGroup;
children = (
21A0FBF62CBDB9A70023F24E /* BIMMemory.cpp */,
21A0FBF72CBDB9A70023F24E /* BIMMemory.h */,
21B67CFE2C7CE15100FD64FC /* Exception.h */,
219351AC2C62CC1A00E5A69C /* Guid.cpp */,
219351AD2C62CC1A00E5A69C /* Guid.h */,
@@ -407,6 +487,37 @@
path = Utility;
sourceTree = "<group>";
};
2196F2DF2CB0566500450DFC /* Units */ = {
isa = PBXGroup;
children = (
2196F2E22CB05BAF00450DFC /* LengthUnit.cpp */,
2196F2DE2CB0566500450DFC /* LengthUnit.h */,
);
path = Units;
sourceTree = "<group>";
};
2196F2EA2CB4816B00450DFC /* Attribute */ = {
isa = PBXGroup;
children = (
2196F2E82CB4816B00450DFC /* ArchicadAttributeDBaseEngine.cpp */,
2196F2E92CB4816B00450DFC /* ArchicadAttributeDBaseEngine.h */,
);
path = Attribute;
sourceTree = "<group>";
};
2196F2EF2CB4823C00450DFC /* Attribute */ = {
isa = PBXGroup;
children = (
2196F2ED2CB4823C00450DFC /* Attribute.cpp */,
2196F2EE2CB4823C00450DFC /* Attribute.h */,
2196F2F32CB483D600450DFC /* Finish.cpp */,
2196F2F22CB483D600450DFC /* Finish.h */,
2196F3032CB57E7F00450DFC /* Storey.cpp */,
2196F3022CB57E7F00450DFC /* Storey.h */,
);
path = Attribute;
sourceTree = "<group>";
};
219987FA2BD708BC0035E5EA /* SpeckleLibDoctest */ = {
isa = PBXGroup;
children = (
@@ -416,6 +527,48 @@
path = SpeckleLibDoctest;
sourceTree = "<group>";
};
21A0FBA02CB880690023F24E /* Collection */ = {
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 = (
@@ -444,6 +597,8 @@
children = (
21D0BD1D2C86F0280077E104 /* AccountDatabase.cpp */,
21D0BD1E2C86F0280077E104 /* AccountDatabase.h */,
2196F2F62CB51ED400450DFC /* BIMAttributeDatabase.cpp */,
2196F2F72CB51ED400450DFC /* BIMAttributeDatabase.h */,
215F08932CA19AF800CD343B /* BIMElementDatabase.cpp */,
215F08942CA19AF800CD343B /* BIMElementDatabase.h */,
21D0BD272C86FC350077E104 /* Content */,
@@ -580,6 +735,7 @@
21F69F952C71087A008B6A06 /* Record */ = {
isa = PBXGroup;
children = (
2196F2EF2CB4823C00450DFC /* Attribute */,
215F087A2CA18E1400CD343B /* Element */,
21F69F942C71087A008B6A06 /* Credentials */,
);
@@ -619,31 +775,48 @@
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 */,
219246032CA2CE2700CF5703 /* BIMLink.h in Headers */,
21B67D0D2C7E0E8D00FD64FC /* ErrorReport.h in Headers */,
215F08962CA19AF800CD343B /* BIMElementDatabase.h in Headers */,
2196F2F12CB4823C00450DFC /* Attribute.h in Headers */,
21D0BD332C86FE090077E104 /* Link.h in Headers */,
21D0BD5A2C8910400077E104 /* UserInfo.h in Headers */,
21D0BD562C890B1C0077E104 /* ServerMigration.h in Headers */,
210CC88F2C81A98500610F58 /* Guid64.h in Headers */,
21AEF9DD2CAAA4EA000B8681 /* DetachedObjectStore.h in Headers */,
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 */,
2196F2F92CB51ED400450DFC /* BIMAttributeDatabase.h in Headers */,
215F08562C99DA8D00CD343B /* Project.h in Headers */,
219245FF2CA2CC4300CF5703 /* BIMRecord.h in Headers */,
210CC8802C80CD2A00610F58 /* BridgeChild.h in Headers */,
21D0BD4D2C8901A00077E104 /* ServerInfo.h in Headers */,
2196F3042CB57E8000450DFC /* Storey.h in Headers */,
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 */,
21D0BD312C86FE090077E104 /* Index.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -769,41 +942,56 @@
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 */,
21F69F812C6FF3B0008B6A06 /* BridgeArgumentWrap.cpp in Sources */,
215F088B2CA195EC00CD343B /* ArchicadDBaseCore.cpp in Sources */,
2193517B2C624FC100E5A69C /* MenuSubscriber.cpp in Sources */,
2196F2F02CB4823C00450DFC /* Attribute.cpp in Sources */,
21F69F612C6D0286008B6A06 /* GetBindingsMethodNames.cpp in Sources */,
215F08662C9B006800CD343B /* ProjectEvent.cpp in Sources */,
21D0BDBD2C90F2830077E104 /* DocStoreSubscriber.cpp in Sources */,
21D0BDB32C8F8AB60077E104 /* DocumentStoreCore.cpp in Sources */,
219246082CA2ED2F00CF5703 /* ArchicadElementDBaseEngine.cpp in Sources */,
2196F2E32CB05BAF00450DFC /* LengthUnit.cpp in Sources */,
21F93AEC2B2F406E009A2C5B /* Addon.cpp in Sources */,
215F087D2CA18E1400CD343B /* Element.cpp in Sources */,
2196F2F82CB51ED400450DFC /* BIMAttributeDatabase.cpp in Sources */,
21D0BD4E2C8901A00077E104 /* ServerInfo.cpp in Sources */,
21B67D0E2C7E0E8D00FD64FC /* ErrorReport.cpp in Sources */,
21F69F7E2C6FD9FC008B6A06 /* GetCallResult.cpp in Sources */,
2196F3052CB57E8000450DFC /* Storey.cpp in Sources */,
219245FE2CA2CC4300CF5703 /* BIMRecord.cpp in Sources */,
21AEF9BE2CA6FDA4000B8681 /* DetachedWrap.cpp in Sources */,
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;
+35
View File
@@ -20,6 +20,7 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="Speckle\Database\AccountDatabase.h" />
<ClInclude Include="Speckle\Database\BIMAttributeDatabase.h" />
<ClInclude Include="Speckle\Database\BIMElementDatabase.h" />
<ClInclude Include="Speckle\Database\Content\BIMRecord.h" />
<ClInclude Include="Speckle\Database\Content\Record.h" />
@@ -29,6 +30,7 @@
<ClInclude Include="Speckle\Database\Identity\Index.h" />
<ClInclude Include="Speckle\Database\Identity\Link.h" />
<ClInclude Include="Speckle\Database\Storage\ArchicadDBase\ArchicadDBaseCore.h" />
<ClInclude Include="Speckle\Database\Storage\ArchicadDBase\Attribute\ArchicadAttributeDBaseEngine.h" />
<ClInclude Include="Speckle\Database\Storage\ArchicadDBase\Element\ArchicadElementDBaseEngine.h" />
<ClInclude Include="Speckle\Database\Storage\DocumentStore\DocumentStoreCore.h" />
<ClInclude Include="Speckle\Database\Storage\DocumentStore\DocumentStoreEngine.h" />
@@ -62,18 +64,35 @@
<ClInclude Include="Speckle\Interface\Browser\NamedFunction.h" />
<ClInclude Include="Speckle\Interface\Browser\PlatformBinding.h" />
<ClInclude Include="Speckle\Primitive\Mesh\Mesh.h" />
<ClInclude Include="Speckle\Record\Attribute\Attribute.h" />
<ClInclude Include="Speckle\Record\Attribute\Finish.h" />
<ClInclude Include="Speckle\Record\Attribute\Storey.h" />
<ClInclude Include="Speckle\Record\Credentials\Account.h" />
<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\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" />
@@ -82,11 +101,13 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="Speckle\Database\AccountDatabase.cpp" />
<ClCompile Include="Speckle\Database\BIMAttributeDatabase.cpp" />
<ClCompile Include="Speckle\Database\BIMElementDatabase.cpp" />
<ClCompile Include="Speckle\Database\Content\BIMRecord.cpp" />
<ClCompile Include="Speckle\Database\Content\Record.cpp" />
<ClCompile Include="Speckle\Database\Identity\BIMLink.cpp" />
<ClCompile Include="Speckle\Database\Storage\ArchicadDBase\ArchicadDBaseCore.cpp" />
<ClCompile Include="Speckle\Database\Storage\ArchicadDBase\Attribute\ArchicadAttributeDBaseEngine.cpp" />
<ClCompile Include="Speckle\Database\Storage\ArchicadDBase\Element\ArchicadElementDBaseEngine.cpp" />
<ClCompile Include="Speckle\Database\Storage\DocumentStore\DocumentStoreCore.cpp" />
<ClCompile Include="Speckle\Environment\Addon.cpp" />
@@ -105,15 +126,28 @@
<ClCompile Include="Speckle\Interface\Browser\Bridge\Functions\GetCallResult.cpp" />
<ClCompile Include="Speckle\Interface\Browser\Bridge\Functions\RunMethod.cpp" />
<ClCompile Include="Speckle\Primitive\Mesh\Mesh.cpp" />
<ClCompile Include="Speckle\Record\Attribute\Attribute.cpp" />
<ClCompile Include="Speckle\Record\Attribute\Finish.cpp" />
<ClCompile Include="Speckle\Record\Attribute\Storey.cpp" />
<ClCompile Include="Speckle\Record\Credentials\Account.cpp" />
<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\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" />
@@ -269,6 +303,7 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<TreatAngleIncludeAsExternal>true</TreatAngleIncludeAsExternal>
<ExternalWarningLevel>TurnOffAllWarnings</ExternalWarningLevel>
<PreprocessToFile>false</PreprocessToFile>
</ClCompile>
<Link>
<SubSystem>
+123
View File
@@ -83,6 +83,27 @@
<Filter Include="Speckle\Serialise\Detached\Storage">
<UniqueIdentifier>{cb77e795-e8d8-4e31-9773-dd32beb694d3}</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">
@@ -265,6 +286,63 @@
<ClInclude Include="Speckle\Serialise\Detached\Storage\DetachedObjectStore.h">
<Filter>Speckle\Serialise\Detached\Storage</Filter>
</ClInclude>
<ClInclude Include="Speckle\Database\BIMAttributeDatabase.h">
<Filter>Speckle\Database</Filter>
</ClInclude>
<ClInclude Include="Speckle\Database\Storage\ArchicadDBase\Attribute\ArchicadAttributeDBaseEngine.h">
<Filter>Speckle\Database\Storage\ArchicadDBase\Attribute</Filter>
</ClInclude>
<ClInclude Include="Speckle\Record\Attribute\Attribute.h">
<Filter>Speckle\Record\Attribute</Filter>
</ClInclude>
<ClInclude Include="Speckle\Record\Attribute\Finish.h">
<Filter>Speckle\Record\Attribute</Filter>
</ClInclude>
<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">
@@ -375,6 +453,51 @@
<ClCompile Include="Speckle\Serialise\Detached\DetachmentManager.cpp">
<Filter>Speckle\Serialise\Detached</Filter>
</ClCompile>
<ClCompile Include="Speckle\Database\BIMAttributeDatabase.cpp">
<Filter>Speckle\Database</Filter>
</ClCompile>
<ClCompile Include="Speckle\Database\Storage\ArchicadDBase\Attribute\ArchicadAttributeDBaseEngine.cpp">
<Filter>Speckle\Database\Storage\ArchicadDBase\Attribute</Filter>
</ClCompile>
<ClCompile Include="Speckle\Record\Attribute\Attribute.cpp">
<Filter>Speckle\Record\Attribute</Filter>
</ClCompile>
<ClCompile Include="Speckle\Record\Attribute\Finish.cpp">
<Filter>Speckle\Record\Attribute</Filter>
</ClCompile>
<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">