Compare commits

..

60 Commits

Author SHA1 Message Date
David Kekesi a330baf5da cleanup 2024-11-07 11:08:56 +01:00
David Kekesi ea103f3849 disabled sending grid elements, disabled element change subscription on new element event 2024-11-07 11:05:16 +01:00
Ralph Wessel 664fdaf39a Merge pull request #17 from specklesystems/david/cnx-716-documentless-state-in-archicad
cnx 716 documentless state in archicad
2024-11-06 19:35:38 +00:00
David Kekesi a6f15e9a53 review comments fixed 2024-11-06 20:34:46 +01:00
David Kekesi 0e0dc7da2d switching to 3D window before send operation implemented 2024-11-06 20:24:03 +01:00
Ralph Wessel cdd4df09ca Added setDefaultTable and getDefaultTable for BIMElementDatabase 2024-11-06 19:18:37 +00:00
David Kekesi e612ed1192 attaching observer to all elements is too slow, commented out for now 2024-11-06 20:18:36 +01:00
David Kekesi ed75c2110c Merge branch 'develop' into david/cnx-716-documentless-state-in-archicad 2024-11-06 19:44:40 +01:00
David Kekesi 96759f7e9e very slow in a 3D view - attaching element observers to all elements 2024-11-06 19:43:01 +01:00
Ralph Wessel 902ddcc8f1 Updated VS projects 2024-11-06 18:11:45 +00:00
Ralph Wessel b62201cf95 BIMElementDatabase::getTables and bringToFront added
BIMElementDatabase::getElements allows a target table to be specified
2024-11-06 18:03:26 +00:00
Ralph Wessel 4e60d95ce9 DocumentID is now generated, saved and recalled using ModelCardDatabase 2024-11-06 16:25:13 +00:00
Ralph Wessel 03ad5a80af Merge branch 'develop' of https://github.com/specklesystems/speckle-cpp-connectors into develop 2024-11-06 13:06:38 +00:00
Ralph Wessel fbbf559e83 ConnectorProject should add its model card database to the add-on as a subscriber in order to receive document events, e.g. merge 2024-11-06 13:06:25 +00:00
David Kekesi da457a3438 subscribing all elements to element events 2024-11-06 11:51:29 +01:00
Ralph Wessel 767e379ff3 Updated Windows resources 2024-11-05 19:05:30 +00:00
Ralph Wessel 08c15c87a2 Updated menu icons 2024-11-05 18:50:14 +00:00
Ralph Wessel 1827323712 Added Speckle menu icon 2024-11-05 18:30:17 +00:00
Ralph Wessel 653824c498 Updated VS projects
GetDocumentInfo returns null if no project open
2024-11-05 17:01:51 +00:00
Ralph Wessel 0dc823785d Removed test code from ConnectorPalette 2024-11-05 16:37:27 +00:00
Ralph Wessel bacdbc4d61 Added ConnectorProject as a container for ModelCardDatabase
Moved ownership of ModelCardDatabase from Addon to ConnectorProject
Tools requiring access to the model card database now need to check for an open project first and then obtain the database from it (prevents attempts to access model cards when no project is open)
2024-11-05 16:34:49 +00:00
Ralph Wessel ef989ad8c7 Merge pull request #16 from specklesystems/david/cnx-720-no-objects-were-found-to-convert-please-update-your-publish
cnx 720 no objects were found to convert please update your publish
2024-11-05 11:53:44 +00:00
David Kekesi 8d8934657c get the selected element ids from the modelcard instead of the application during a send operation 2024-11-05 12:46:14 +01:00
Ralph Wessel d7a95fd37c Added BIMElementDatabase::findObjects 2024-11-05 11:25:33 +00:00
Ralph Wessel 74d4871fbd Added ArchicadElementDBaseEngine::find
Implemented ArchicadElementDBaseEngine::getObjects
2024-11-05 11:15:53 +00:00
Ralph Wessel f634f158f9 Use FastDoubleWrap for serialising Mesh vertices 2024-11-05 08:33:53 +00:00
Ralph Wessel 48988fbe53 Updated VS projects
Renamed Element/Mesh.cpp for VS compilation
2024-11-01 23:25:49 +00:00
Ralph Wessel 2c0d53c186 Added materials quants for mesh, morph, roof, shell, slab and wall 2024-11-01 22:57:47 +00:00
Ralph Wessel 51370ababc Updated VS projects 2024-11-01 22:56:39 +00:00
Ralph Wessel 8132eec03e Material quantities add, implement for column and beam segments
Added Material class
Renamed variables for finishes from "material" to "finish"
Fixed major memory leak in ModelElement::getBody
Updated element BIMLink to include a type identifier
2024-11-01 17:01:56 +00:00
Ralph Wessel 82bd96de61 Updated Xcode project 2024-10-30 22:55:23 +00:00
Ralph Wessel 51ed951d7d Added Platform::openURL to open a URL cross-platform 2024-10-30 22:54:17 +00:00
Ralph Wessel cc6c884f47 Merge pull request #15 from specklesystems/david/wire-in-view-button
view button on modelcard works
2024-10-30 22:42:57 +00:00
David Kekesi 4afed92ba9 view button on modelcard works 2024-10-30 19:34:27 +01:00
Ralph Wessel ca2df4c020 Finish assignment operator did not call assignment operator for bae class 2024-10-30 12:38:20 +00:00
Ralph Wessel 764b548900 Updated VS projects 2024-10-30 11:48:54 +00:00
Ralph Wessel 71dac48830 Updated Xcode project
Implemented caching to avoid slow API material lookup
Some minor fixes
Eliminated some warnings
2024-10-30 11:47:48 +00:00
Ralph Wessel 5684364119 Merge pull request #14 from specklesystems/david/cnx-693-archicad-missing-elements
cnx 693 archicad missing elements
2024-10-30 10:25:18 +00:00
David Kekesi 45c4311d95 temporary hack to send DisplayValues of Stairs, Rails, CurtainWalls 2024-10-30 10:51:08 +01:00
kekesidavid ae521de698 Merge pull request #12 from specklesystems/david/cnx-665-object-tracking
cnx 665 object tracking
2024-10-29 17:02:08 +01:00
kekesidavid 0ff87576da Merge branch 'develop' into david/cnx-665-object-tracking 2024-10-29 17:01:27 +01:00
Ralph Wessel 63c3c9befa Fixed applicationId tag 2024-10-29 13:16:41 +00:00
David Kekesi 281a2654c9 comment 2024-10-29 12:48:57 +01:00
David Kekesi 8fdbaaa52d ElementChangedSubscriber renamed to ElementSubscriber 2024-10-29 11:03:21 +01:00
David Kekesi 67b12ae353 ElementChangedEvent renamed to ElementEvent 2024-10-29 10:54:47 +01:00
David Kekesi 690e527b81 attach element observer to existing elements 2024-10-29 10:48:43 +01:00
David Kekesi 8f2e31c16e searching for expired ModelCards, naive, not efficient solution for now 2024-10-29 10:32:26 +01:00
Ralph Wessel e9b768daec Updated JSBaseTransport for new read/writeSetting functions
Updated VS projects
2024-10-29 09:05:38 +00:00
David Kekesi e5bf001590 handling Begin, End event types, sending setModelsExpired event to UI 2024-10-28 21:58:07 +01:00
Ralph Wessel 7c0ac2e8f6 Updated Xcode projects
Added environment Host to represent host BIM application
Updated for latest ActiveLib
2024-10-28 17:27:46 +00:00
David Kekesi 0969026f39 ElementChangedSubscriber, ElementChangedEvent added 2024-10-28 11:22:27 +01:00
Ralph Wessel 3d2aab8862 Updated documentation 2024-10-24 18:06:18 +01:00
Ralph Wessel bdea330c2e Moved include file to implementation
Fixed docs typo
2024-10-24 16:50:58 +01:00
Ralph Wessel b066b4ba3c Merge pull request #11 from specklesystems/david/cnx-660-document-switch-and-model-cards
cnx 660 document switch and model cards
2024-10-24 15:38:40 +01:00
David Kekesi 3f772150ff no need to start project subscriber after installation 2024-10-24 16:28:57 +02:00
David Kekesi e00fd99d3c modelcards are loaded on document switch 2024-10-24 16:25:27 +02:00
David Kekesi 72e8ea78d9 Merge branch 'develop' into david/cnx-660-document-switch-and-model-cards 2024-10-24 15:50:42 +02:00
Ralph Wessel ede131ca0b Merge pull request #10 from specklesystems/david/cnx-667-model-card-highlighting
cnx 667 model card highlighting
2024-10-24 13:03:32 +01:00
David Kekesi 6d14607634 bridge listens to open event instead of close 2024-10-21 16:36:39 +02:00
David Kekesi 5363819e8d BaseBridge listens to project events 2024-10-21 16:35:30 +02:00
127 changed files with 4992 additions and 426 deletions
+1
View File
@@ -3,6 +3,7 @@ build/
Documents/
ResourceObjects/
Install/
enc_temp_folder/
.vs/
.vscode/
xcuserdata/
+4
View File
@@ -94,6 +94,7 @@
<ItemGroup>
<ClCompile Include="Connector\Connector.cpp" />
<ClCompile Include="Connector\Database\ModelCardDatabase.cpp" />
<ClCompile Include="Connector\Environment\ConnectorProject.cpp" />
<ClCompile Include="Connector\Interface\Browser\Bridge\Account\AccountBridge.cpp" />
<ClCompile Include="Connector\Interface\Browser\Bridge\Account\GetAccounts.cpp" />
<ClCompile Include="Connector\Interface\Browser\Bridge\Base\AddModel.cpp" />
@@ -105,6 +106,7 @@
<ClCompile Include="Connector\Interface\Browser\Bridge\Base\GetSourceApplicationName.cpp" />
<ClCompile Include="Connector\Interface\Browser\Bridge\Base\GetSourceApplicationVersion.cpp" />
<ClCompile Include="Connector\Interface\Browser\Bridge\Base\HighlightModel.cpp" />
<ClCompile Include="Connector\Interface\Browser\Bridge\Base\OpenUrl.cpp" />
<ClCompile Include="Connector\Interface\Browser\Bridge\Base\RemoveModel.cpp" />
<ClCompile Include="Connector\Interface\Browser\Bridge\Base\UpdateModel.cpp" />
<ClCompile Include="Connector\Interface\Browser\Bridge\Config\Arg\ConnectorConfig.cpp" />
@@ -149,6 +151,7 @@
<ClInclude Include="Connector\ConnectorResource.h" />
<ClInclude Include="Connector\Database\Identity\RecordID.h" />
<ClInclude Include="Connector\Database\ModelCardDatabase.h" />
<ClInclude Include="Connector\Environment\ConnectorProject.h" />
<ClInclude Include="Connector\Event\ConnectorEventID.h" />
<ClInclude Include="Connector\Interface\Browser\Bridge\Account\AccountBridge.h" />
<ClInclude Include="Connector\Interface\Browser\Bridge\Account\GetAccounts.h" />
@@ -161,6 +164,7 @@
<ClInclude Include="Connector\Interface\Browser\Bridge\Base\GetSourceApplicationName.h" />
<ClInclude Include="Connector\Interface\Browser\Bridge\Base\GetSourceApplicationVersion.h" />
<ClInclude Include="Connector\Interface\Browser\Bridge\Base\HighlightModel.h" />
<ClInclude Include="Connector\Interface\Browser\Bridge\Base\OpenUrl.h" />
<ClInclude Include="Connector\Interface\Browser\Bridge\Base\RemoveModel.h" />
<ClInclude Include="Connector\Interface\Browser\Bridge\Base\UpdateModel.h" />
<ClInclude Include="Connector\Interface\Browser\Bridge\Config\Arg\ConnectorConfig.h" />
@@ -71,6 +71,9 @@
<Filter Include="Connector\Interface\Browser\Bridge\Selection\Arg">
<UniqueIdentifier>{8bb3df60-affe-4b66-8d78-f1b98e6ba8df}</UniqueIdentifier>
</Filter>
<Filter Include="Connector\Environment">
<UniqueIdentifier>{1d9a10c3-cac6-4b15-afb9-f117b99b3a24}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="RFIX.win\Connector.rc2">
@@ -246,6 +249,12 @@
<ClCompile Include="Connector\Interface\Browser\Bridge\Base\HighlightModel.cpp">
<Filter>Connector\Interface\Browser\Bridge\Base</Filter>
</ClCompile>
<ClCompile Include="Connector\Interface\Browser\Bridge\Base\OpenUrl.cpp">
<Filter>Connector\Interface\Browser\Bridge\Base</Filter>
</ClCompile>
<ClCompile Include="Connector\Environment\ConnectorProject.cpp">
<Filter>Connector\Environment</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Connector\ConnectorResource.h">
@@ -417,5 +426,11 @@
<ClInclude Include="Connector\Interface\Browser\Bridge\Base\HighlightModel.h">
<Filter>Connector\Interface\Browser\Bridge\Base</Filter>
</ClInclude>
<ClInclude Include="Connector\Interface\Browser\Bridge\Base\OpenUrl.h">
<Filter>Connector\Interface\Browser\Bridge\Base</Filter>
</ClInclude>
<ClInclude Include="Connector\Environment\ConnectorProject.h">
<Filter>Connector\Environment</Filter>
</ClInclude>
</ItemGroup>
</Project>
@@ -23,6 +23,7 @@
/* Begin PBXBuildFile section */
210CC8832C80E6A300610F58 /* TriggerEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 210CC8812C80E6A300610F58 /* TriggerEvent.cpp */; };
21384BCD2CD2EE7400D4602B /* OpenUrl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21384BC92CD2EE7400D4602B /* OpenUrl.cpp */; };
213CC39C2B1101F500088049 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2151077C2AEDB9070022CD24 /* Cocoa.framework */; };
214B7A372C764BCD00D586C1 /* UpdateConfig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21F69FBD2C7630B3008B6A06 /* UpdateConfig.cpp */; };
215F082A2C947F4400CD343B /* CardMover.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 215F08262C947F4400CD343B /* CardMover.cpp */; };
@@ -30,8 +31,10 @@
215F08372C95808B00CD343B /* ReceiverModelCard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 215F08362C95808B00CD343B /* ReceiverModelCard.cpp */; };
215F08462C9633A800CD343B /* EverythingSendFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 215F08452C9633A800CD343B /* EverythingSendFilter.cpp */; };
2192460D2CA3469D00CF5703 /* ProjectCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2192460B2CA3469D00CF5703 /* ProjectCollection.cpp */; };
2199BB552CDA4B1700A4BEEC /* ConnectorProject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2199BB522CDA4B1700A4BEEC /* ConnectorProject.cpp */; };
219F30422C769283009834E9 /* ConfigTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219F30402C769282009834E9 /* ConfigTests.cpp */; };
21A0FB982CB723240023F24E /* FinishProxy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21A0FB942CB723240023F24E /* FinishProxy.cpp */; };
21A79EC92CCDA45C001754E4 /* HighlightModel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21A79EC52CCDA45C001754E4 /* HighlightModel.cpp */; };
21A890BC2CC15C540087E732 /* SelectionInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21A890B22CC15C540087E732 /* SelectionInfo.cpp */; };
21A890BD2CC15C540087E732 /* GetSelection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21A890B52CC15C540087E732 /* GetSelection.cpp */; };
21A890BE2CC15C540087E732 /* SelectionBridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21A890B72CC15C540087E732 /* SelectionBridge.cpp */; };
@@ -295,6 +298,8 @@
/* Begin PBXFileReference section */
210CC8812C80E6A300610F58 /* TriggerEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TriggerEvent.cpp; sourceTree = "<group>"; };
210CC8822C80E6A300610F58 /* TriggerEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TriggerEvent.h; sourceTree = "<group>"; };
21384BC92CD2EE7400D4602B /* OpenUrl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OpenUrl.cpp; sourceTree = "<group>"; };
21384BCC2CD2EE7400D4602B /* OpenUrl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenUrl.h; sourceTree = "<group>"; };
213CC3A52B1101F500088049 /* Speckle Connector.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Speckle Connector.bundle"; sourceTree = BUILT_PRODUCTS_DIR; };
2151077C2AEDB9070022CD24 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
215F08262C947F4400CD343B /* CardMover.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CardMover.cpp; sourceTree = "<group>"; };
@@ -312,11 +317,17 @@
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>"; };
2199BB512CDA481A00A4BEEC /* ConnectorFix.grc */ = {isa = PBXFileReference; lastKnownFileType = text; name = ConnectorFix.grc; path = RFIX/ConnectorFix.grc; sourceTree = "<group>"; };
2199BB522CDA4B1700A4BEEC /* ConnectorProject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConnectorProject.cpp; sourceTree = "<group>"; };
2199BB532CDA4B1700A4BEEC /* ConnectorProject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConnectorProject.h; sourceTree = "<group>"; };
2199BB5C2CDA93CE00A4BEEC /* ConnectorImagesFix.grc */ = {isa = PBXFileReference; lastKnownFileType = text; name = ConnectorImagesFix.grc; path = RFIX/ConnectorImagesFix.grc; 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>"; };
21A79EC52CCDA45C001754E4 /* HighlightModel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HighlightModel.cpp; sourceTree = "<group>"; };
21A79EC82CCDA45C001754E4 /* HighlightModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HighlightModel.h; sourceTree = "<group>"; };
21A890B22CC15C540087E732 /* SelectionInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SelectionInfo.cpp; sourceTree = "<group>"; };
21A890B32CC15C540087E732 /* SelectionInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SelectionInfo.h; sourceTree = "<group>"; };
21A890B52CC15C540087E732 /* GetSelection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetSelection.cpp; sourceTree = "<group>"; };
@@ -542,7 +553,6 @@
21D1E9AC2BF14AF200957EAA /* TeamworkProductVersion.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TeamworkProductVersion.framework; path = "../Archicad 27/Support/Frameworks/TeamworkProductVersion.framework"; sourceTree = "<group>"; };
21D1EA452BF14B0700957EAA /* VWMM.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = VWMM.framework; path = "../Vectorworks 2024/SDKLib/LibMac/Release/VWMM.framework"; sourceTree = "<group>"; };
21D1EA4A2BF14BBC00957EAA /* Connector.grc */ = {isa = PBXFileReference; lastKnownFileType = text; name = Connector.grc; path = RINT/Connector.grc; sourceTree = "<group>"; };
21D1EA4B2BF14BC700957EAA /* ConnectorFix.grc */ = {isa = PBXFileReference; lastKnownFileType = text; name = ConnectorFix.grc; path = RFIX/ConnectorFix.grc; sourceTree = "<group>"; };
21D1EA4C2BF14BF000957EAA /* Module-Info27.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Module-Info27.plist"; path = "RINT.Archicad/EN-GB/Module-Info27.plist"; sourceTree = "<group>"; };
21F69EC62C64C035008B6A06 /* SpeckleLib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SpeckleLib.xcodeproj; path = ../SpeckleLib/SpeckleLib.xcodeproj; sourceTree = "<group>"; };
21F69EDB2C64ED10008B6A06 /* ConnectorMenu.grc */ = {isa = PBXFileReference; lastKnownFileType = text; name = ConnectorMenu.grc; path = RINT/ConnectorMenu.grc; sourceTree = "<group>"; };
@@ -962,6 +972,24 @@
path = Identity;
sourceTree = "<group>";
};
2199BB4E2CDA47F900A4BEEC /* Fixed */ = {
isa = PBXGroup;
children = (
2199BB512CDA481A00A4BEEC /* ConnectorFix.grc */,
2199BB5C2CDA93CE00A4BEEC /* ConnectorImagesFix.grc */,
);
name = Fixed;
sourceTree = "<group>";
};
2199BB542CDA4B1700A4BEEC /* Environment */ = {
isa = PBXGroup;
children = (
2199BB522CDA4B1700A4BEEC /* ConnectorProject.cpp */,
2199BB532CDA4B1700A4BEEC /* ConnectorProject.h */,
);
path = Environment;
sourceTree = "<group>";
};
219F30412C769282009834E9 /* ConnectorTests */ = {
isa = PBXGroup;
children = (
@@ -1026,6 +1054,10 @@
21B67CA82C77329800FD64FC /* GetSourceApplicationName.h */,
21B67CA92C77329800FD64FC /* GetSourceApplicationVersion.cpp */,
21B67CAA2C77329800FD64FC /* GetSourceApplicationVersion.h */,
21A79EC52CCDA45C001754E4 /* HighlightModel.cpp */,
21A79EC82CCDA45C001754E4 /* HighlightModel.h */,
21384BC92CD2EE7400D4602B /* OpenUrl.cpp */,
21384BCC2CD2EE7400D4602B /* OpenUrl.h */,
21D0BDD52C935DAE0077E104 /* RemoveModel.cpp */,
21D0BDD62C935DAE0077E104 /* RemoveModel.h */,
21D0BDD22C935D1A0077E104 /* UpdateModel.cpp */,
@@ -1153,7 +1185,6 @@
isa = PBXGroup;
children = (
21D1EA4A2BF14BBC00957EAA /* Connector.grc */,
21D1EA4B2BF14BC700957EAA /* ConnectorFix.grc */,
21F69EDB2C64ED10008B6A06 /* ConnectorMenu.grc */,
21D1EA4C2BF14BF000957EAA /* Module-Info27.plist */,
21F69EFE2C66AD55008B6A06 /* SpecklePalette.grc */,
@@ -1206,6 +1237,7 @@
21B67CCD2C77694500FD64FC /* Connector.h */,
21F69F102C677BC0008B6A06 /* ConnectorResource.h */,
21B67CCB2C77670400FD64FC /* Database */,
2199BB542CDA4B1700A4BEEC /* Environment */,
21F69F092C677BC0008B6A06 /* Event */,
21F69F0E2C677BC0008B6A06 /* Interface */,
21D0BDD82C9387E60077E104 /* Record */,
@@ -1286,6 +1318,7 @@
81494D9D09DA5892006864FB /* Resource */ = {
isa = PBXGroup;
children = (
2199BB4E2CDA47F900A4BEEC /* Fixed */,
7EA5F91E157FA18400693CEA /* EN-GB */,
);
name = Resource;
@@ -1508,6 +1541,7 @@
214B7A372C764BCD00D586C1 /* UpdateConfig.cpp in Sources */,
21AEF9EC2CAB56E5000B8681 /* SendViaBrowserArgs.cpp in Sources */,
21FF70492CA1A7F400AAD99A /* RecordCollection.cpp in Sources */,
21A79EC92CCDA45C001754E4 /* HighlightModel.cpp in Sources */,
21B67CC02C775A0D00FD64FC /* GetDocumentInfo.cpp in Sources */,
21D0BDD42C935D1A0077E104 /* UpdateModel.cpp in Sources */,
21A890BD2CC15C540087E732 /* GetSelection.cpp in Sources */,
@@ -1519,7 +1553,9 @@
215F08372C95808B00CD343B /* ReceiverModelCard.cpp in Sources */,
21D0BDD72C935DAE0077E104 /* RemoveModel.cpp in Sources */,
21A890BC2CC15C540087E732 /* SelectionInfo.cpp in Sources */,
2199BB552CDA4B1700A4BEEC /* ConnectorProject.cpp in Sources */,
21AEF9EF2CAB5720000B8681 /* SendObject.cpp in Sources */,
21384BCD2CD2EE7400D4602B /* OpenUrl.cpp in Sources */,
21B67CDC2C78C88000FD64FC /* SayHi.cpp in Sources */,
215F082E2C94C5C000CD343B /* FilterMover.cpp in Sources */,
21F69F122C677BC0008B6A06 /* ConnectorMenu.cpp in Sources */,
@@ -2065,7 +2101,7 @@
);
LOCALISATION_SUFFIX = "EN-GB";
MACH_O_TYPE = mh_bundle;
MACOSX_DEPLOYMENT_TARGET = 11.0;
MACOSX_DEPLOYMENT_TARGET = 13.3;
NNA_WARNING_CPLUSPLUSFLAGS = "-Wno-deprecated";
OBJROOT = "";
ONLY_ACTIVE_ARCH = YES;
@@ -2172,7 +2208,7 @@
);
LOCALISATION_SUFFIX = "EN-GB";
MACH_O_TYPE = mh_bundle;
MACOSX_DEPLOYMENT_TARGET = 11.0;
MACOSX_DEPLOYMENT_TARGET = 13.3;
NNA_WARNING_CPLUSPLUSFLAGS = "-Wno-deprecated";
OBJROOT = "";
PLUGIN_FOLDER = "";
+9 -8
View File
@@ -1,7 +1,7 @@
#include "Active/File/Directory.h"
#include "ConnectorResource.h"
#include "Connector/Connector.h"
#include "Connector/Database/ModelCardDatabase.h"
#include "Connector/Environment/ConnectorProject.h"
#include "Connector/Interface/ConnectorMenu.h"
#include "Connector/Interface/ConnectorPalette.h"
#include "Speckle/Database/AccountDatabase.h"
@@ -11,7 +11,7 @@
using namespace active::file;
using namespace active::environment;
using namespace connector;
using namespace connector::database;
using namespace connector::environment;
using namespace speckle::database;
using namespace speckle::environment;
using namespace speckle::utility;
@@ -29,8 +29,6 @@ namespace {
ConnectorInstance(const String& name) : ConnectorAddon{name} {
add<ConnectorMenu>();
add<ConnectorPalette>();
//The connector 'owns' the model card database, so the publisher list should only hold a weak reference
addWeak(m_modelCards.getSubscription());
}
// MARK: Functions (const)
@@ -40,15 +38,18 @@ namespace {
@return The account database
*/
const AccountDatabase* getAccountDatabase() const override;
protected:
/*!
Get the model card database
@return The model card database
Make a new new project. Allows Addon subclasses to define a Project subclass with additional functions/databases
@return A new project instance
*/
const ModelCardDatabase* getModelCardDatabase() const override { return &m_modelCards; }
virtual std::shared_ptr<Project> makeProject() const override {
return std::dynamic_pointer_cast<Project>(std::make_shared<ConnectorProject>());
}
private:
mutable std::unique_ptr<AccountDatabase> m_account;
ModelCardDatabase m_modelCards;
};
///The active addon instance
-9
View File
@@ -3,10 +3,6 @@
namespace speckle::database {
class AccountDatabase;
class BIMElementDatabase;
}
namespace connector::database {
class ModelCardDatabase;
}
namespace connector {
@@ -22,11 +18,6 @@ namespace connector {
@return The account database
*/
const virtual speckle::database::AccountDatabase* getAccountDatabase() const = 0;
/*!
Get the model card database
@return The model card database
*/
const virtual database::ModelCardDatabase* getModelCardDatabase() const = 0;
protected:
/*!
@@ -0,0 +1,33 @@
#include "Connector/Environment/ConnectorProject.h"
#include "Connector/Connector.h"
#include "Connector/Database/ModelCardDatabase.h"
using namespace active::event;
using namespace connector::database;
using namespace connector::environment;
using namespace speckle::utility;
/*--------------------------------------------------------------------
Default constructor
--------------------------------------------------------------------*/
ConnectorProject::ConnectorProject() {
m_modelCards = std::make_shared<ModelCardDatabase>();
connector()->addWeak(m_modelCards->getSubscription());
}
/*--------------------------------------------------------------------
Destructor
--------------------------------------------------------------------*/
ConnectorProject::~ConnectorProject() {}
/*--------------------------------------------------------------------
Get the model card database
return; The model card database
--------------------------------------------------------------------*/
const ModelCardDatabase* ConnectorProject::getModelCardDatabase() const {
return m_modelCards.get();
} //ConnectorProject::getModelCardDatabase
@@ -0,0 +1,53 @@
#ifndef CONNECTOR_ENVIRONMENT_CONNECTOR_PROJECT
#define CONNECTOR_ENVIRONMENT_CONNECTOR_PROJECT
#include "Speckle/Environment/Project.h"
namespace connector::database {
class ModelCardDatabase;
}
namespace connector::environment {
/*!
A BIM project contained Speckle connector data, e.g. a model card database
*/
class ConnectorProject : public speckle::environment::Project {
public:
// MARK: - Types
///Shared pointer
using Shared = std::shared_ptr<ConnectorProject>;
///Weak pointer
using Weak = std::weak_ptr<ConnectorProject>;
// MARK: - Constructors
/*!
Default constructor
*/
ConnectorProject();
ConnectorProject(const ConnectorProject&) = delete;
/*!
Destructor
*/
~ConnectorProject();
// MARK: - Functions (const)
/*!
Get the model card database
@return The model card database
*/
const connector::database::ModelCardDatabase* getModelCardDatabase() const;
private:
///The model card database
std::shared_ptr<connector::database::ModelCardDatabase> m_modelCards;
};
}
#endif //CONNECTOR_ENVIRONMENT_CONNECTOR_PROJECT
@@ -14,7 +14,7 @@ using namespace speckle::utility;
namespace {
using WrappedValue = active::serialise::CargoHold<ContainerWrap<Vector<Account>>, Vector<Account>>;
using WrappedValue = CargoHold<ContainerWrap<Vector<Account>>, Vector<Account>>;
}
@@ -6,7 +6,7 @@
namespace connector::interfac::browser::bridge {
/*!
JS Function class to retrieve the names of the methods supported by the bridge
JS Function class to retrieve the user's account(s)
*/
class GetAccounts : public speckle::interfac::browser::bridge::BridgeMethod<void, active::serialise::Cargo> {
public:
@@ -1,11 +1,12 @@
#include "Connector/Interface/Browser/Bridge/Base/AddModel.h"
#include "Connector/Connector.h"
#include "Connector/Environment/ConnectorProject.h"
#include "Connector/Database/ModelCardDatabase.h"
#include "Connector/Interface/Browser/Bridge/Base/Arg/DocumentInfo.h"
using namespace active::container;
using namespace active::serialise;
using namespace connector::environment;
using namespace connector::record;
using namespace connector::interfac::browser::bridge;
using namespace speckle::utility;
@@ -24,6 +25,10 @@ AddModel::AddModel() : BridgeMethod{"AddModel", [&](const ModelCardEventWrapper&
card: The card to add
--------------------------------------------------------------------*/
void AddModel::run(const ModelCard& card) const {
if (auto modelCardDBase = connector()->getModelCardDatabase(); modelCardDBase != nullptr)
auto project = connector()->getActiveProject().lock();
auto connectorProject = dynamic_cast<ConnectorProject*>(project.get());
if (!connectorProject)
return;
if (auto modelCardDBase = connectorProject->getModelCardDatabase(); modelCardDBase != nullptr)
modelCardDBase->write(card);
} //AddModel::run
@@ -8,7 +8,7 @@
namespace connector::interfac::browser::bridge {
///Argument parameter for a string
///Argument parameter for a model card
using CardHold = active::serialise::CargoHold<connector::record::CardMover, connector::record::ModelCard>;
///Argument type for this method
using ModelCardEventWrapper = speckle::interfac::browser::bridge::JSArgType<CardHold>;
@@ -1,5 +1,4 @@
#include "Connector/Interface/Browser/Bridge/Base/BaseBridge.h"
#include "Connector/Interface/Browser/Bridge/Base/AddModel.h"
#include "Connector/Interface/Browser/Bridge/Base/GetConnectorVersion.h"
#include "Connector/Interface/Browser/Bridge/Base/GetDocumentInfo.h"
@@ -9,9 +8,40 @@
#include "Connector/Interface/Browser/Bridge/Base/RemoveModel.h"
#include "Connector/Interface/Browser/Bridge/Base/UpdateModel.h"
#include "Connector/Interface/Browser/Bridge/Base/HighlightModel.h"
#include "Connector/Interface/Browser/Bridge/Base/OpenUrl.h"
#include "Speckle/Event/Type/ProjectEvent.h"
#include "Speckle/Environment/Project.h"
#include "Speckle/Record/Element/Element.h"
#include "Connector/Connector.h"
#include "Connector/ConnectorResource.h"
#include "Speckle/Database/Identity/RecordID.h"
#include "Speckle/Database/BIMElementDatabase.h"
#include "Connector/Record/Model/SenderModelCard.h"
#include "Connector/Record/Model/Filter/SendFilter.h"
#include "Connector/Database/ModelCardDatabase.h"
using namespace connector::interfac::browser::bridge;
namespace {
#ifdef ARCHICAD
void subscribeAllElementsToElementChangeEvents()
{
auto project = connector::connector()->getActiveProject().lock();
if (!project)
return;
auto elementDatabase = project->getElementDatabase();
//auto table = elementDatabase->getTables(speckle::database::ElementStorage::TableType::primary2D);
//auto allElements = elementDatabase->findElements(nullptr, *table.begin());
auto allElements = elementDatabase->findElements();
for (const auto& id : allElements)
ACAPI_Element_AttachObserver(id);
}
#endif
}
/*--------------------------------------------------------------------
Default constructor
--------------------------------------------------------------------*/
@@ -26,4 +56,30 @@ BaseBridge::BaseBridge() : BrowserBridge{"baseBinding"} {
addMethod<RemoveModel>();
addMethod<UpdateModel>();
addMethod<HighlightModel>();
addMethod<OpenUrl>();
// POC: Attaching Observer to all elements is too slow, registration is commented out for now
// subscribeAllElementsToElementChangeEvents();
} //BaseBridge::BaseBridge
/*--------------------------------------------------------------------
Handle a project event
event: The project event
return: True if the event should be closed
--------------------------------------------------------------------*/
bool BaseBridge::handle(const speckle::event::ProjectEvent& event) {
using enum speckle::event::ProjectEvent::Type;
switch (event.getType()) {
case open: {
sendEvent("documentChanged");
// POC: Attaching Observer to all elements is too slow, registration is commented out for now
// subscribeAllElementsToElementChangeEvents();
} break;
default:
break;
}
return false;
} //BaseBridge::handle
@@ -2,13 +2,14 @@
#define CONNECTOR_INTERFACE_BRIDGE_BASE_BRIDGE
#include "Speckle/Interface/Browser/Bridge/BrowserBridge.h"
#include "Speckle/Event/Subscriber/ProjectSubscriber.h"
namespace connector::interfac::browser::bridge {
/*!
A browser bridge to provide configuration settings
A browser bridge to manage document settings
*/
class BaseBridge : public speckle::interfac::browser::bridge::BrowserBridge {
class BaseBridge : public speckle::interfac::browser::bridge::BrowserBridge, public speckle::event::ProjectSubscriber {
public:
// MARK: - Types
@@ -22,6 +23,14 @@ namespace connector::interfac::browser::bridge {
Default constructor
*/
BaseBridge();
protected:
/*!
Handle the project events
@param event The project event
@return True if the event should be closed
*/
bool handle(const speckle::event::ProjectEvent& event) override;
};
}
@@ -25,13 +25,13 @@ GetConnectorVersion::GetConnectorVersion() : BridgeMethod{"GetConnectorVersion",
/*--------------------------------------------------------------------
Get the host application version
Get the connector software version
return: The application version
return: The connector software version
--------------------------------------------------------------------*/
std::unique_ptr<Cargo> GetConnectorVersion::run() const {
//Implement other platforms as required
String result{active::utility::String{connector::versionMajor} + "." + active::utility::String{connector::versionMinor} + "." +
active::utility::String{connector::versionPatch}};
String result{String{connector::versionMajor} + "." + String{connector::versionMinor} + "." +
String{connector::versionPatch}};
return std::make_unique<WrappedValue>(result);
} //GetConnectorVersion::run
@@ -8,7 +8,7 @@ namespace connector::interfac::browser::bridge {
class ConnectorConfig;
/*!
JS Function class to retrieve the names of the methods supported by the bridge
JS Function class to get the connector software version
*/
class GetConnectorVersion : public speckle::interfac::browser::bridge::BridgeMethod<void, active::serialise::Cargo> {
public:
@@ -23,8 +23,8 @@ namespace connector::interfac::browser::bridge {
// MARK: - Functions (const)
/*!
Get the host application version
@return The application version
Get the connector software version
@return The connector software version
*/
std::unique_ptr<active::serialise::Cargo> run() const;
};
@@ -2,6 +2,7 @@
#include "Active/Serialise/CargoHold.h"
#include "Connector/Connector.h"
#include "Connector/Environment/ConnectorProject.h"
#include "Connector/Database/ModelCardDatabase.h"
#include "Connector/Interface/Browser/Bridge/Base/Arg/DocumentInfo.h"
#include "Speckle/Environment/Project.h"
@@ -9,6 +10,7 @@
using namespace active::container;
using namespace active::serialise;
using namespace connector::environment;
using namespace connector::interfac::browser::bridge;
using namespace speckle::utility;
@@ -33,14 +35,17 @@ GetDocumentInfo::GetDocumentInfo() : BridgeMethod{"GetDocumentInfo", [&]() {
--------------------------------------------------------------------*/
std::unique_ptr<Cargo> GetDocumentInfo::run() const {
auto docInfo = std::make_unique<DocumentInfo>();
if (auto project = connector()->getActiveProject().lock(); project) {
auto info = project->getInfo();
docInfo->name = info.name;
if (info.path)
docInfo->location = *info.path;
if (auto cardDatabase = connector()->getModelCardDatabase(); cardDatabase != nullptr)
docInfo->ID = cardDatabase->getStoreID();
auto project = connector()->getActiveProject().lock();
auto connectorProject = dynamic_cast<ConnectorProject*>(project.get());
if (!connectorProject)
return nullptr;
auto info = connectorProject->getInfo();
docInfo->name = info.name;
if (info.path)
docInfo->location = *info.path;
if (auto cardDatabase = connectorProject->getModelCardDatabase(); cardDatabase != nullptr)
docInfo->ID = cardDatabase->getStoreID();
else
docInfo->ID = Guid{true}.operator String();
}
return std::make_unique<WrappedValue>(std::move(docInfo));
} //GetDocumentInfo::run
@@ -1,15 +1,13 @@
#include "Connector/Interface/Browser/Bridge/Base/GetDocumentState.h"
#include "Active/Serialise/CargoHold.h"
#include "Connector/Connector.h"
#include "Connector/Record/Model/ModelCard.h"
#include "Connector/Environment/ConnectorProject.h"
#include "Connector/Database/ModelCardDatabase.h"
using namespace active::container;
using namespace active::serialise;
using namespace connector::environment;
using namespace connector::interfac::browser::bridge;
using namespace connector::database;
using namespace connector::record;
using namespace speckle::utility;
/*--------------------------------------------------------------------
@@ -21,12 +19,16 @@ GetDocumentState::GetDocumentState() : BridgeMethod{"GetDocumentState", [&]() {
/*--------------------------------------------------------------------
Get the document info
Get the document model cards
return: The document info
return: The document model cards
--------------------------------------------------------------------*/
std::unique_ptr<Cargo> GetDocumentState::run() const {
if (auto modelCardDBase = connector()->getModelCardDatabase(); modelCardDBase != nullptr) {
auto project = connector()->getActiveProject().lock();
auto connectorProject = dynamic_cast<ConnectorProject*>(project.get());
if (!connectorProject)
return nullptr;
if (auto modelCardDBase = connectorProject->getModelCardDatabase(); modelCardDBase != nullptr) {
return modelCardDBase->wrapper();
}
return nullptr;
@@ -6,7 +6,7 @@
namespace connector::interfac::browser::bridge {
/*!
JS Function class to retrieve the information about the active document
JS Function class to retrieve model cards stored in the current document
*/
class GetDocumentState : public speckle::interfac::browser::bridge::BridgeMethod<void, active::serialise::Cargo> {
public:
@@ -21,8 +21,8 @@ namespace connector::interfac::browser::bridge {
// MARK: - Functions (const)
/*!
Get the document info
@return The document info
Get the document model cards
@return The document model cards
*/
std::unique_ptr<active::serialise::Cargo> run() const;
};
@@ -1,6 +1,7 @@
#include "Connector/Interface/Browser/Bridge/Base/HighlightModel.h"
#include "Connector/Connector.h"
#include "Connector/ConnectorResource.h"
#include "Connector/Environment/ConnectorProject.h"
#include "Connector/Database/ModelCardDatabase.h"
#include "Connector/Interface/Browser/Bridge/Send/Arg/SendError.h"
#include "Connector/Record/Model/SenderModelCard.h"
@@ -10,17 +11,12 @@
#include "Speckle/Database/BIMElementDatabase.h"
#include "Speckle/Environment/Project.h"
#include <array>
using namespace speckle::record::element;
using namespace connector::environment;
using namespace connector::interfac::browser::bridge;
using namespace connector::record;
using namespace speckle::utility;
namespace {
}
/*--------------------------------------------------------------------
Default constructor
--------------------------------------------------------------------*/
@@ -30,13 +26,17 @@ HighlightModel::HighlightModel() : BridgeMethod{"HighlightModel", [&](const Send
/*--------------------------------------------------------------------
Higlight the model card selection
Highlight elements linked to the model card selection
modelCardID: The ID of the model to send
modelCardID: The ID of the target model card
--------------------------------------------------------------------*/
void HighlightModel::run(const String& modelCardID) const {
// Find the specified model card
auto modelCardDatabase = connector()->getModelCardDatabase();
auto project = connector()->getActiveProject().lock();
auto connectorProject = dynamic_cast<ConnectorProject*>(project.get());
if (!connectorProject)
return;
//Find the specified model card
auto modelCardDatabase = connectorProject->getModelCardDatabase();
auto modelCard = modelCardDatabase->getCard(modelCardID);
if (!modelCard) {
getBridge()->sendEvent("setModelError",
@@ -16,7 +16,7 @@ namespace connector::interfac::browser::bridge {
using SendArgs = speckle::interfac::browser::bridge::JSArgType<StringHold>;
/*!
JS Function class to send a specified model
JS Function class to highlight elements from the selected model card in the open document
*/
class HighlightModel : public speckle::interfac::browser::bridge::BridgeMethod<SendArgs, void> {
public:
@@ -31,8 +31,8 @@ namespace connector::interfac::browser::bridge {
// MARK: - Functions (const)
/*!
Higlight the model card selection
@param modelCardID The ID of the model to send
Highlight elements linked to the model card selection
@param modelCardID The ID of the target model card
*/
void run(const speckle::utility::String& modelCardID) const;
};
@@ -0,0 +1,24 @@
#include "Connector/Interface/Browser/Bridge/Base/OpenUrl.h"
#include "Speckle/Environment/Platform.h"
using namespace connector::interfac::browser::bridge;
using namespace speckle::environment;
using namespace speckle::utility;
/*--------------------------------------------------------------------
Default constructor
--------------------------------------------------------------------*/
OpenUrl::OpenUrl() : BridgeMethod{"OpenUrl", [&](const SendArgs& args) {
run(args);
}} {}
/*--------------------------------------------------------------------
Opens an url
url: The URL to open
--------------------------------------------------------------------*/
void OpenUrl::run(const String& url) const {
platform()->openURL(url);
} //OpenUrl::run
@@ -0,0 +1,41 @@
#ifndef CONNECTOR_INTERFACE_BRIDGE_OPEN_URL
#define CONNECTOR_INTERFACE_BRIDGE_OPEN_URL
#include "Active/Serialise/CargoHold.h"
#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
#include "Speckle/Interface/Browser/Bridge/BridgeMethod.h"
namespace connector::interfac::browser::bridge {
class ConnectorConfig;
///Argument parameter for a string
using StringHold = active::serialise::CargoHold<active::serialise::ValueWrap<speckle::utility::String>, speckle::utility::String>;
///Argument type for this method
using SendArgs = speckle::interfac::browser::bridge::JSArgType<StringHold>;
/*!
JS Function class to highlight elements from the selected model card in the open document
*/
class OpenUrl : public speckle::interfac::browser::bridge::BridgeMethod<SendArgs, void> {
public:
// MARK: - Constructors
/*!
Constructor
*/
OpenUrl();
// MARK: - Functions (const)
/*!
Opens an url
@param url The URL to open
*/
void run(const speckle::utility::String& url) const;
};
}
#endif //CONNECTOR_INTERFACE_BRIDGE_OPEN_URL
@@ -1,22 +1,16 @@
#include "Connector/Interface/Browser/Bridge/Base/RemoveModel.h"
#include "Connector/Connector.h"
#include "Connector/Environment/ConnectorProject.h"
#include "Connector/Database/ModelCardDatabase.h"
#include "Connector/Interface/Browser/Bridge/Base/Arg/DocumentInfo.h"
using namespace active::container;
using namespace active::serialise;
using namespace connector::database;
using namespace connector::environment;
using namespace connector::record;
using namespace connector::interfac::browser::bridge;
using namespace speckle::utility;
namespace {
using WrappedValue = active::serialise::CargoHold<PackageWrap, DocumentInfo>;
}
/*--------------------------------------------------------------------
Default constructor
--------------------------------------------------------------------*/
@@ -31,6 +25,10 @@ RemoveModel::RemoveModel() : BridgeMethod{"RemoveModel", [&](const ModelCardEven
card: The card to add
--------------------------------------------------------------------*/
void RemoveModel::run(const ModelCard& card) const {
if (auto modelCardDBase = connector()->getModelCardDatabase(); modelCardDBase != nullptr)
auto project = connector()->getActiveProject().lock();
auto connectorProject = dynamic_cast<ConnectorProject*>(project.get());
if (!connectorProject)
return;
if (auto modelCardDBase = connectorProject->getModelCardDatabase(); modelCardDBase != nullptr)
modelCardDBase->erase(card.getID());
} //RemoveModel::run
@@ -8,13 +8,13 @@
namespace connector::interfac::browser::bridge {
///Argument parameter for a string
///Argument parameter for a model card
using CardHold = active::serialise::CargoHold<connector::record::CardMover, connector::record::ModelCard>;
///Argument type for this method
using ModelCardEventWrapper = speckle::interfac::browser::bridge::JSArgType<CardHold>;
/*!
JS Function class to add a model card to the document storage
JS Function class to remove a model card from the document storage
*/
class RemoveModel : public speckle::interfac::browser::bridge::BridgeMethod<ModelCardEventWrapper, void> {
public:
@@ -29,8 +29,8 @@ namespace connector::interfac::browser::bridge {
// MARK: - Functions (const)
/*!
Add a model card to document storage
@param card The card to add
Remove a model card from document storage
@param card The card to remove
*/
void run(const connector::record::ModelCard& card) const;
};
@@ -2,11 +2,12 @@
#include "Connector/Connector.h"
#include "Connector/Database/ModelCardDatabase.h"
#include "Connector/Environment/ConnectorProject.h"
#include "Connector/Interface/Browser/Bridge/Base/Arg/DocumentInfo.h"
using namespace active::container;
using namespace active::serialise;
using namespace connector::database;
using namespace connector::environment;
using namespace connector::record;
using namespace connector::interfac::browser::bridge;
using namespace speckle::utility;
@@ -26,11 +27,15 @@ UpdateModel::UpdateModel() : BridgeMethod{"UpdateModel", [&](const ModelCardEven
/*--------------------------------------------------------------------
Add a model card to document storage
Update a model card in document storage
card: The card to add
card: The card to update
--------------------------------------------------------------------*/
void UpdateModel::run(const ModelCard& card) const {
if (auto modelCardDBase = connector()->getModelCardDatabase(); modelCardDBase != nullptr)
auto project = connector()->getActiveProject().lock();
auto connectorProject = dynamic_cast<ConnectorProject*>(project.get());
if (!connectorProject)
return;
if (auto modelCardDBase = connectorProject->getModelCardDatabase(); modelCardDBase != nullptr)
modelCardDBase->write(card);
} //UpdateModel::run
@@ -8,13 +8,13 @@
namespace connector::interfac::browser::bridge {
///Argument parameter for a string
///Argument parameter for a model card
using CardHold = active::serialise::CargoHold<connector::record::CardMover, connector::record::ModelCard>;
///Argument type for this method
using ModelCardEventWrapper = speckle::interfac::browser::bridge::JSArgType<CardHold>;
/*!
JS Function class to add a model card to the document storage
JS Function class to update a model card in document storage
*/
class UpdateModel : public speckle::interfac::browser::bridge::BridgeMethod<ModelCardEventWrapper, void> {
public:
@@ -29,8 +29,8 @@ namespace connector::interfac::browser::bridge {
// MARK: - Functions (const)
/*!
Add a model card to document storage
@param card The card to add
Update a model card in document storage
@param card The card to update
*/
void run(const connector::record::ModelCard& card) const;
};
@@ -6,7 +6,7 @@
namespace connector::interfac::browser::bridge {
/*!
JS Function class to retrieve the names of the methods supported by the bridge
JS Function class to retrieve the current display configuration settings
*/
class GetConfig : public speckle::interfac::browser::bridge::BridgeMethod<void, active::serialise::Cargo> {
public:
@@ -9,11 +9,11 @@ namespace connector::interfac::browser::bridge {
class ConnectorConfig;
///Argument for a JS call to update the configuration
///Argument for a JS call to update the display configuration settings
using UpdateArgs = speckle::interfac::browser::bridge::JSArgType<ConnectorConfig>;
/*!
JS Function class to retrieve the names of the methods supported by the bridge
JS Function class to update the display configuration settings
*/
class UpdateConfig : public speckle::interfac::browser::bridge::BridgeMethod<UpdateArgs, void> {
public:
@@ -22,7 +22,6 @@ namespace connector::interfac::browser::bridge {
/*!
Constructor
@param bridge The parent bridge object (provides access to bridge methods)
*/
UpdateConfig();
@@ -12,7 +12,6 @@ namespace connector::interfac::browser::bridge {
/*!
Constructor
@param bridge The parent bridge object (provides access to bridge methods)
*/
GetSelection();
@@ -18,7 +18,6 @@ namespace connector::interfac::browser::bridge {
/*!
Constructor
@param bridge The parent bridge object (provides access to bridge methods)
*/
GetSendFilters();
@@ -13,7 +13,7 @@ using namespace speckle::utility;
namespace {
using WrappedValue = active::serialise::CargoHold<ContainerWrap<Vector<CardSetting>, PackageWrap>, Vector<CardSetting>>;
using WrappedValue = CargoHold<ContainerWrap<Vector<CardSetting>, PackageWrap>, Vector<CardSetting>>;
}
@@ -26,9 +26,9 @@ GetSendSettings::GetSendSettings() : BridgeMethod{"GetSendSettings", [&]() {
/*--------------------------------------------------------------------
Get the send filters
Get send settings relevant to the host BIM application
return: The send filters
return: The send settings
--------------------------------------------------------------------*/
std::unique_ptr<Cargo> GetSendSettings::run() const {
auto filters = std::make_unique<Vector<CardSetting>>();
@@ -9,7 +9,7 @@ namespace connector::interfac::browser::bridge {
class ConnectorConfig;
/*!
JS Function class to retrieve the send filters
JS Function class to retrieve the send settings relevant to the host BIM application
*/
class GetSendSettings : public speckle::interfac::browser::bridge::BridgeMethod<void, active::serialise::Cargo> {
public:
@@ -18,15 +18,14 @@ namespace connector::interfac::browser::bridge {
/*!
Constructor
@param bridge The parent bridge object (provides access to bridge methods)
*/
GetSendSettings();
// MARK: - Functions (const)
/*!
Get the send filters
@return The send filters
Get send settings relevant to the host BIM application
@return The send settings
*/
std::unique_ptr<active::serialise::Cargo> run() const;
};
@@ -5,34 +5,31 @@
#include "Connector/Connector.h"
#include "Connector/ConnectorResource.h"
#include "Connector/Database/ModelCardDatabase.h"
#include "Connector/Environment/ConnectorProject.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 "Connector/Record/Model/SenderModelCard.h"
#include "Connector/Record/Model/Filter/SendFilter.h"
#include "Speckle/Database/AccountDatabase.h"
#include "Speckle/Database/Content/BIMRecord.h"
#include "Speckle/Interface/Browser/Bridge/BrowserBridge.h"
#include "Speckle/Record/Credentials/Account.h"
#include "Speckle/Serialise/Detached/Storage/DetachedMemoryStore.h"
#include "Speckle/Utility/Exception.h"
#include "Speckle/Database/BIMElementDatabase.h"
#include "Speckle/Environment/Project.h"
#include "Speckle/Record/Element/Element.h"
using namespace speckle::record::element;
#include <array>
using namespace active::serialise;
using namespace connector::environment;
using namespace connector::interfac::browser::bridge;
using namespace connector::record;
using namespace speckle::database;
using namespace speckle::serialise;
using namespace speckle::utility;
namespace {
}
/*--------------------------------------------------------------------
Default constructor
--------------------------------------------------------------------*/
@@ -44,11 +41,28 @@ Send::Send() : BridgeMethod{"Send", [&](const SendArgs& args) {
/*--------------------------------------------------------------------
Send a specified model
modelCardID: The ID of the model to send
modelCardID: The ID of the model card identifying the objects to send
--------------------------------------------------------------------*/
void Send::run(const String& modelCardID) const {
#ifdef ARCHICAD
// we currently rely on the ModelerAPI instead of the ModelAccessAPI
// we have to open a 3D window to get the Mesh data of the model elements
ACAPI_View_ShowAllIn3D();
#endif
//Get the active project
auto project = connector()->getActiveProject().lock();
if (!project) {
getBridge()->sendEvent("setModelError",
std::make_unique<SendError>(connector()->getLocalString(errorString, noProjectOpenID), modelCardID));
return;
}
auto connectorProject = dynamic_cast<ConnectorProject*>(project.get());
if (!connectorProject)
return;
//Find the specified model card
auto modelCardDatabase = connector()->getModelCardDatabase();
auto modelCardDatabase = connectorProject->getModelCardDatabase();
auto modelCard = modelCardDatabase->getCard(modelCardID);
if (!modelCard) {
getBridge()->sendEvent("setModelError",
@@ -63,22 +77,15 @@ void Send::run(const String& modelCardID) const {
std::make_unique<SendError>(connector()->getLocalString(errorString, accountNotFoundID), modelCardID));
return;
}
//Get the active project
auto project = connector()->getActiveProject().lock();
if (!project) {
getBridge()->sendEvent("setModelError",
std::make_unique<SendError>(connector()->getLocalString(errorString, noProjectOpenID), modelCardID));
return;
//Get the selected elements from the modelcard
auto elementDatabase = project->getElementDatabase();
ElementIDList selected{};
if (auto senderCard = dynamic_cast<SenderModelCard*>(modelCard.get())) {
selected = senderCard->getFilter().getElementIDs();
}
//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);
@@ -25,7 +25,6 @@ namespace connector::interfac::browser::bridge {
/*!
Constructor
@param bridge The parent bridge object (provides access to bridge methods)
*/
Send();
@@ -33,7 +32,7 @@ namespace connector::interfac::browser::bridge {
/*!
Send a specified model
@param modelCardID The ID of the model to send
@param modelCardID The ID of the model card identifying the objects to send
*/
void run(const speckle::utility::String& modelCardID) const;
};
@@ -1,10 +1,28 @@
#include "Connector/Interface/Browser/Bridge/Send/SendBridge.h"
#include "Connector/Interface/Browser/Bridge/Send/GetSendFilters.h"
#include "Connector/Interface/Browser/Bridge/Send/GetSendSettings.h"
#include "Connector/Interface/Browser/Bridge/Send/Send.h"
#include "Connector/Connector.h"
#include "Connector/ConnectorResource.h"
#include "Connector/Database/ModelCardDatabase.h"
#include "Connector/Environment/ConnectorProject.h"
#include "Speckle/Event/Type/ElementEvent.h"
#include "Speckle/Record/Element/Element.h"
#include "Speckle/Database/BIMElementDatabase.h"
#include "Speckle/Environment/Project.h"
#include "Speckle/Database/Identity/RecordID.h"
#include "Active/Serialise/CargoHold.h"
#include "Active/Serialise/Package/Wrapper/ContainerWrap.h"
#include "Connector/Record/Model/SenderModelCard.h"
#include "Connector/Record/Model/Filter/SendFilter.h"
using namespace speckle::database;
using namespace connector::environment;
using namespace connector::interfac::browser::bridge;
using namespace speckle::utility;
using namespace speckle::event;
using namespace active::serialise;
using namespace connector::record;
/*--------------------------------------------------------------------
Default constructor
@@ -15,3 +33,55 @@ SendBridge::SendBridge() : BrowserBridge{"sendBinding"} {
addMethod<GetSendSettings>();
addMethod<Send>();
} //SendBridge::SendBridge
/*--------------------------------------------------------------------
Handle an element change
event: The selection event
return: True if the event should be closed
--------------------------------------------------------------------*/
bool SendBridge::handle(const ElementEvent& event) {
using enum ElementEvent::Type;
auto eventType = event.getEventType();
switch (eventType) {
case begin:
m_changedElements.clear();
break;
case end: {
auto project = connector()->getActiveProject().lock();
auto connectorProject = dynamic_cast<ConnectorProject*>(project.get());
if (!connectorProject)
return false;
auto modelCardDatabase = connectorProject->getModelCardDatabase();
auto modelCards = modelCardDatabase->getCards();
// POC: this is probably not efficient, should test, review and refactor it
RecordIDList expiredModelCardIds;
for (const auto& modelCard : modelCards) {
if (auto senderCard = dynamic_cast<SenderModelCard*>(modelCard.get())) {
auto modelCardSelection = senderCard->getFilter().getElementIDs();
for (const auto& elemId : modelCardSelection) {
if (std::find(m_changedElements.begin(), m_changedElements.end(), elemId) != m_changedElements.end()) {
expiredModelCardIds.push_back(modelCard->getID());
break;
}
}
}
}
if (!expiredModelCardIds.empty()) {
auto wrapped = std::make_unique<CargoHold<ContainerWrap<RecordIDList>, RecordIDList>>(std::move(expiredModelCardIds));
sendEvent("setModelsExpired", std::move(wrapped));
}
break;
}
case changeElem: case editElem: case deleteElem: {
if (event.getElmentID())
m_changedElements.push_back(*event.getElmentID());
break;
}
default:
break;
}
return false;
} //SendBridge::handle
@@ -2,13 +2,14 @@
#define CONNECTOR_INTERFACE_BRIDGE_SEND_BRIDGE
#include "Speckle/Interface/Browser/Bridge/BrowserBridge.h"
#include "Speckle/Event/Subscriber/ElementSubscriber.h"
namespace connector::interfac::browser::bridge {
/*!
A browser bridge to support sending model data to a Speckle server
*/
class SendBridge : public speckle::interfac::browser::bridge::BrowserBridge {
class SendBridge : public speckle::interfac::browser::bridge::BrowserBridge, public speckle::event::ElementSubscriber {
public:
// MARK: - Types
@@ -22,6 +23,14 @@ namespace connector::interfac::browser::bridge {
Default constructor
*/
SendBridge();
protected:
/*!
Handle an element change
@param event The selection event
@return True if the event should be closed
*/
bool handle(const speckle::event::ElementEvent& event) override;
};
}
@@ -1,5 +1,5 @@
#ifndef CONNECTOR_INTERFACE_BRIDGE_GET_CONFIG
#define CONNECTOR_INTERFACE_BRIDGE_GET_CONFIG
#ifndef CONNECTOR_INTERFACE_BRIDGE_GET_COMPLEX_TYPE
#define CONNECTOR_INTERFACE_BRIDGE_GET_COMPLEX_TYPE
#include "Speckle/Interface/Browser/Bridge/BridgeMethod.h"
@@ -15,7 +15,6 @@ namespace connector::interfac::browser::bridge {
/*!
Constructor
@param bridge The parent bridge object (provides access to bridge methods)
*/
GetComplexType();
@@ -30,4 +29,4 @@ namespace connector::interfac::browser::bridge {
}
#endif //CONNECTOR_INTERFACE_BRIDGE_GET_CONFIG
#endif //CONNECTOR_INTERFACE_BRIDGE_GET_COMPLEX_TYPE
@@ -1,8 +1,9 @@
#include "Connector/Interface/Browser/Bridge/Test/GoAway.h"
using namespace connector::interfac::browser::bridge;
#include "Speckle/Environment/Platform.h"
#include <iostream>
using namespace connector::interfac::browser::bridge;
using namespace speckle::environment;
/*--------------------------------------------------------------------
Default constructor
@@ -16,5 +17,5 @@ GoAway::GoAway() : BridgeMethod{"GoAway", [&]() {
Write a message to the console
--------------------------------------------------------------------*/
void GoAway::run() const {
std::cout << "Okay, going away.";
platform()->writeToConsole("Okay, going away.");
} //GoAway::run
@@ -17,6 +17,8 @@
#include "Speckle/Event/Type/MenuEvent.h"
#include "Speckle/Interface/Browser/JSPortal.h"
#include "Speckle/Event/Type/ProjectEvent.h"
#include <ACAPinc.h>
#include <DGModule.hpp>
#include <DGBrowser.hpp>
@@ -108,7 +110,9 @@ ConnectorPalette::ConnectorPalette() {
return: The subscription list (an empty list will put the subscriber into a suspended state)
--------------------------------------------------------------------*/
ConnectorPalette::Subscription ConnectorPalette::subscription() const {
return { {toggleConnectorPaletteID} };
auto result = ProjectSubscriber::subscription();
result.insert(toggleConnectorPaletteID);
return result;
} //ConnectorPalette::subscription
@@ -130,16 +134,49 @@ bool ConnectorPalette::start() {
return: True if the event should be closed
--------------------------------------------------------------------*/
bool ConnectorPalette::receive(const active::event::Event& event) {
if (BrowserPalette::HasInstance() && BrowserPalette::GetInstance().IsVisible()) {
BrowserPalette::GetInstance().Hide ();
} else {
if (!BrowserPalette::HasInstance())
BrowserPalette::CreateInstance();
BrowserPalette::GetInstance().Show();
if (event == toggleConnectorPaletteID) {
if (BrowserPalette::HasInstance() && BrowserPalette::GetInstance().IsVisible()) {
BrowserPalette::GetInstance().Hide();
}
else {
if (!BrowserPalette::HasInstance())
BrowserPalette::CreateInstance();
BrowserPalette::GetInstance().Show();
}
return true;
}
return true;
return ProjectSubscriber::receive(event);
} //ConnectorPalette::receive
/*--------------------------------------------------------------------
Handle a project event
event: The project event
return: True if the event should be closed
--------------------------------------------------------------------*/
bool ConnectorPalette::handle(const speckle::event::ProjectEvent& event) {
using enum speckle::event::ProjectEvent::Type;
switch (event.getType()) {
case open: {
if (BrowserPalette::HasInstance() && !BrowserPalette::GetInstance().IsVisible()) {
BrowserPalette::GetInstance().Show();
BrowserPalette::GetInstance().EnableItems();
}
} break;
case close: {
if (BrowserPalette::HasInstance() && BrowserPalette::GetInstance().IsVisible()) {
BrowserPalette::GetInstance().Hide();
}
} break;
default:
break;
}
return false;
} //ConnectorPalette::handle
//NB: Following is placeholder from GS example code - will be refactored to better suit our purposes
@@ -166,15 +203,29 @@ BrowserPalette::BrowserPalette() :
BeginEventProcessing();
//Install required connector bridges
install<AccountBridge>();
install<BaseBridge>();
if (auto ref = install<BaseBridge>(); ref) {
if (auto baseBridgeRef = std::dynamic_pointer_cast<BaseBridge>(ref); baseBridgeRef) {
connector::connector()->addWeak(baseBridgeRef);
}
}
install<ConfigBridge>();
install<SendBridge>();
if (auto ref = install<SendBridge>(); ref) {
if (auto sendBridgeRef = std::dynamic_pointer_cast<SendBridge>(ref); sendBridgeRef) {
connector::connector()->addWeak(sendBridgeRef);
sendBridgeRef->start();
}
}
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();
}
@@ -214,8 +265,8 @@ void BrowserPalette::Hide() {
void BrowserPalette::InitBrowserControl() {
#ifdef TESTING_MODE
browser->LoadURL("https://deploy-preview-3180--boisterous-douhua-e3cefb.netlify.app/");
//browser->LoadURL("https://boisterous-douhua-e3cefb.netlify.app/test");
browser->LoadURL("https://boisterous-douhua-e3cefb.netlify.app");
#else
browser->LoadURL("https://boisterous-douhua-e3cefb.netlify.app/");
#endif
@@ -268,18 +319,10 @@ GSErrCode __ACENV_CALL BrowserPalette::PaletteControlCallBack(Int32, API_Palette
break;
case APIPalMsg_HidePalette_End:
if(HasInstance() && !GetInstance().IsVisible())
if (HasInstance() && !GetInstance().IsVisible())
{
GetInstance().Show();
break;
case APIPalMsg_DisableItems_Begin:
if(HasInstance() && GetInstance().IsVisible())
GetInstance().DisableItems();
break;
case APIPalMsg_DisableItems_End:
if(HasInstance() && GetInstance().IsVisible())
GetInstance().EnableItems();
}
break;
case APIPalMsg_IsPaletteVisible:
@@ -2,10 +2,11 @@
#define CONNECTOR_CONNECTOR_PALETTE
#include "Active/Event/Subscriber.h"
#include "Speckle/Event/Subscriber/ProjectSubscriber.h"
namespace connector {
class ConnectorPalette : public active::event::Subscriber {
class ConnectorPalette : public speckle::event::ProjectSubscriber {
public:
/*!
Default constructor
@@ -32,6 +33,13 @@ namespace connector {
@return True if the event should be closed
*/
bool receive(const active::event::Event& event) override;
protected:
/*!
Handle the project events
@param event The project event
@return True if the event should be closed
*/
bool handle(const speckle::event::ProjectEvent& event) override;
};
}
@@ -9,6 +9,7 @@
#include "Connector/Record/Collection/FinishProxy.h"
#include "Speckle/Database/BIMAttributeDatabase.h"
#include "Speckle/Database/BIMElementDatabase.h"
#include "Speckle/Record/Attribute/Finish.h"
#include "Speckle/Record/Element/Element.h"
#ifdef ARCHICAD
@@ -24,7 +25,7 @@ using namespace speckle::utility;
#ifdef ARCHICAD
namespace connector::record {
class ProjectCollection::FinishCache : public std::unordered_map<active::utility::Guid, Finish::Unique> {};
class ProjectCollection::FinishCache : public std::unordered_map<active::utility::Guid, Finish> {};
}
#endif
@@ -114,12 +115,12 @@ bool ProjectCollection::addElement(const speckle::record::element::Element& elem
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) {
bool ProjectCollection::addFinishProxy(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
} //ProjectCollection::addFinishProxy
#ifdef ARCHICAD
@@ -131,15 +132,12 @@ bool ProjectCollection::addMaterialProxy(const speckle::database::BIMIndex& mate
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
bool ProjectCollection::addFinishProxy(const Finish& finish, const speckle::database::BIMRecordID& objectID) {
auto iter = m_finishes->find(finish.getBIMID());
if (iter == m_finishes->end())
iter = m_finishes->insert({finish.getBIMID(), finish}).first;
return addFinishProxy(speckle::database::BIMIndex{finish.getBIMID()}, objectID);
} //ProjectCollection::addFinishProxy
#endif
@@ -181,7 +179,7 @@ Cargo::Unique ProjectCollection::getCargo(const Inventory::Item& item) const {
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();
finish = &fin->second;
else if (auto attribute = m_project->getAttributeDatabase()->getAttribute(iter->first, iter->first.tableID); attribute)
finish = dynamic_cast<const Finish*>(attribute.get());
if (finish != nullptr) {
@@ -69,16 +69,14 @@ namespace connector::record {
@param objectID The object the material is applied to
@return True if the material proxy was added (false typically means the record already exists)
*/
bool addMaterialProxy(const speckle::database::BIMIndex& materialIndex, const speckle::database::BIMRecordID& objectID) override;
#ifdef ARCHICAD
bool addFinishProxy(const speckle::database::BIMIndex& materialIndex, const speckle::database::BIMRecordID& objectID) override;
/*!
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 finish A finish
@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
bool addFinishProxy(const speckle::record::attribute::Finish& finish, const speckle::database::BIMRecordID& objectID) override;
// MARK: - Serialisation
@@ -101,11 +99,9 @@ namespace connector::record {
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
///Finishes cache
std::unique_ptr<FinishCache> m_finishes;
#endif
};
}
@@ -3,6 +3,7 @@
#include "Connector/Record/Model/ReceiverModelCard.h"
#include "Connector/Record/Model/SenderModelCard.h"
using namespace active::serialise;
using namespace connector::record;
namespace {
@@ -32,7 +33,7 @@ namespace {
}
///The handler for model card packages
std::shared_ptr<active::serialise::Handler> CardMover::m_handler = std::make_shared<active::serialise::Handler>(attributeTag);
std::shared_ptr<Handler> CardMover::m_handler = std::make_shared<Handler>(attributeTag);
/*--------------------------------------------------------------------
@@ -6,10 +6,10 @@
namespace connector::record {
/*!
Wrapper to box/unbox objects during (de)serialisation, including reading/writing a specified attribute to determine object type
Wrapper to box/unbox model cards during (de)serialisation
Note that a derived class could also define the package handler, allowing the wrapper to be created via a default constructor that is
automatically bound to a set of internally defined object types
Model cards are polymorphic - this class ensures the type information is included when a card is serialised
and the correct object type is constructed on deserialisation
*/
class CardMover : public active::serialise::Mover {
public:
@@ -11,7 +11,10 @@
namespace connector::record {
/*!
A connector send filter
Base class for a Speckle model card
A model card captures key information about a model submitted to a Speckle server, e.g. the model ID, the target server
and account, and any settings or filters applicable to the host BIM application and open document
*/
class ModelCard : public speckle::database::Record {
public:
@@ -60,13 +63,13 @@ namespace connector::record {
*/
const speckle::utility::String& getModelID() const { return m_modelID; }
/*!
Get the setting type
@return The setting type
Get the ID of the active BIM project
@return The ID of the active BIM project
*/
const speckle::utility::String& getProjectID() const { return m_projectID; }
/*!
Get the setting type
@return The setting type
Get the user account ID
@return The user account ID
*/
const speckle::utility::String& getAccountID() const { return m_accountID; }
/*!
@@ -75,8 +78,8 @@ namespace connector::record {
*/
const speckle::utility::String& getMessage() const { return m_message; }
/*!
Get the setting type
@return The setting type
Get the server URL
@return The server URL
*/
const speckle::utility::String& getServerURL() const { return m_serverURL; }
/*!
+1
View File
@@ -11,5 +11,6 @@
#include "Speckle.grc.rc2"
#include "ConnectorFix.grc.rc2"
#include "ConnectorImagesFix.grc.rc2"
1 ICON LOADONCALL MOVEABLE IMPURE ACAP.ico
@@ -0,0 +1,10 @@
#ifdef macintosh
'GICN' 32500 "Speckle menu icon" {
"32500Mac"
}
#else
'GICN' 32500 "Speckle menu icon" {
"32500Win"
}
#endif
@@ -0,0 +1,5 @@
<svg width="52" height="52" viewBox="0 0 52 52" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9 10L2 4V44L9 50V10Z" stroke="black" stroke-width="3" stroke-linejoin="round"/>
<path d="M43 2L2 4L9 10L50 8L43 2Z" stroke="black" stroke-width="3" stroke-linejoin="round"/>
<path d="M50 8L9 10V50L50 48V8Z" stroke="black" stroke-width="3" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 378 B

@@ -0,0 +1,5 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7 8L0 2V42L7 48V8Z" fill="#313BCF"/>
<path d="M41 0L0 2L7 8L48 6L41 0Z" fill="#7BBCFF"/>
<path d="M48 6L7 8V48L48 46V6Z" fill="#047EFB"/>
</svg>

After

Width:  |  Height:  |  Size: 251 B

+1 -1
View File
@@ -1,5 +1,5 @@
'STR#' 32500 "Connector Menu" {
/*[ 1]*/ "Speckle Connector"
/*[ 1]*/ "Speckle Connector^E3^EL^ES^ED^EE^EI^EW^ET^32500"
}
+2 -2
View File
@@ -1,7 +1,7 @@
/* --- Dockable browser palette ----------------------------------------------*/
'GDLG' 32500 Palette | topCaption | close | grow 0 0 450 150 "Speckle Connector" {
/* [ 1] */ Browser 0 0 450 150
'GDLG' 32500 Palette | topCaption | close | grow 0 0 350 150 "Speckle Connector" {
/* [ 1] */ Browser 0 0 350 150
}
'DLGH' 32500 DLG_32500_Browser_Palette {
@@ -33,8 +33,9 @@ namespace speckle::database {
};
///Element database storage declaration
class BIMElementDatabase::Store : public Storage<Element, UnboxedTransport, BIMRecordID, BIMRecordID, BIMRecordID, BIMRecordID> {
using base = Storage<Element, UnboxedTransport, BIMRecordID, BIMRecordID, BIMRecordID, BIMRecordID>;
class BIMElementDatabase::Store : public Storage<Element, UnboxedTransport, BIMRecordID, BIMRecordID,
BIMRecordID, BIMRecordID, ElementStorage::TableType> {
using base = Storage<Element, UnboxedTransport, BIMRecordID, BIMRecordID, BIMRecordID, BIMRecordID, ElementStorage::TableType>;
using base::base;
};
@@ -75,6 +76,48 @@ BIMElementDatabase::BIMElementDatabase() {
BIMElementDatabase::~BIMElementDatabase() {}
/*--------------------------------------------------------------------
Get the available element tables
targetType: An optional filtr for table type to retrieve, e.g. get all sections (nullopt = all table types)
return: A list of available tables
--------------------------------------------------------------------*/
BIMRecordIDList BIMElementDatabase::getTables(std::optional<TableType> targetType) const {
return m_engine->getTables(targetType);
} //BIMElementDatabase::getTables
/*--------------------------------------------------------------------
Get the default dbase table
return: The default dbase table (nullopt if no table is available)
--------------------------------------------------------------------*/
std::optional<BIMRecordID> BIMElementDatabase::getDefaultTable() const {
return m_engine->getDefaultTable();
} //BIMElementDatabase::getDefaultTable
/*--------------------------------------------------------------------
Set the default dbase table
tableID: The new default dbase table
--------------------------------------------------------------------*/
void BIMElementDatabase::setDefaultTable(const BIMRecordID& tableID) const {
m_engine->setDefaultTable(tableID);
} //BIMElementDatabase::setDefaultTable
/*--------------------------------------------------------------------
Bring the view of this database to the front (i.e. so the user sees it)
tableID: The ID of the table to bring to the front
--------------------------------------------------------------------*/
void BIMElementDatabase::bringViewToFront(BIMRecordID tableID) const {
m_engine->bringViewToFront(tableID);
} //BIMElementDatabase::bringViewToFront
/*--------------------------------------------------------------------
Get the current user element selection
@@ -101,10 +144,27 @@ void BIMElementDatabase::clearSelection() const {
} //BIMElementDatabase::clearSelection
/*--------------------------------------------------------------------
Find a filtered list of objects
filter: The object filter (nullptr = find all objects)
tableID: Optional table ID (defaults to the first table)
documentID: Optional document ID (filter for this document only - nullopt = all objects)
return: A list containing IDs of found elements (empty if none found)
--------------------------------------------------------------------*/
BIMRecordIDList BIMElementDatabase::findElements(const Filter& filter, std::optional<BIMRecordID> tableID,
std::optional<BIMRecordID> documentID) const {
return m_engine->findObjects(filter, tableID, documentID);
} //BIMElementDatabase::findElements
/*--------------------------------------------------------------------
Get a specified element
elementID: The ID of the target element
tableID: Optional table ID (defaults to the first table)
documentID: Optional document ID (filter for this document only - nullopt = all objects)
return: The requested element (nullptr on failure)
--------------------------------------------------------------------*/
@@ -117,10 +177,14 @@ Element::Unique BIMElementDatabase::getElement(const BIMRecordID& elementID, std
/*--------------------------------------------------------------------
Get all elements
tableID: Optional table ID (defaults to the first table)
documentID: Optional document ID (filter for this document only - nullopt = all objects)
return: All the elements
--------------------------------------------------------------------*/
Vector<Element> BIMElementDatabase::getElements() const {
return m_store->getObjects();
Vector<Element> BIMElementDatabase::getElements(std::optional<BIMRecordID> tableID,
std::optional<BIMRecordID> documentID) const {
return m_store->getObjects(tableID, documentID);
} //BIMElementDatabase::getElements
@@ -2,6 +2,7 @@
#define CONNECTOR_DATABASE_BIM_ELEMENT_DATABASE
#include "Speckle/Database/Identity/BIMLink.h"
#include "Speckle/Database/Storage/Element/ElementStorage.h"
#include "Speckle/Record/Element/Element.h"
#include "Speckle/Record/Element/Interface/Part.h"
#include "Speckle/Utility/Guid.h"
@@ -19,7 +20,7 @@ namespace speckle::database {
/*!
Database of model elements relating to a specific project
*/
class BIMElementDatabase {
class BIMElementDatabase : public ElementStorage {
public:
// MARK: - Constructors
@@ -36,6 +37,27 @@ namespace speckle::database {
// MARK: - Functions (const)
/*!
Get the available element tables
@param targetType An optional filtr for table type to retrieve, e.g. get all sections (nullopt = all table types)
@return A set of available tables
*/
BIMRecordIDList getTables(std::optional<TableType> targetType) const;
/*!
Get the default dbase table
@return The default dbase table (nullopt if no table is available)
*/
std::optional<BIMRecordID> getDefaultTable() const;
/*!
Set the default dbase table
@param tableID The new default dbase table
*/
void setDefaultTable(const BIMRecordID& tableID) const;
/*!
Bring the view of this database to the front (i.e. so the user sees it)
@param tableID The ID of the table to bring to the front
*/
void bringViewToFront(BIMRecordID tableID) const;
/*!
Get the current user element selection
@return A list of selected element IDs
@@ -49,6 +71,15 @@ namespace speckle::database {
Clear the element selection
*/
void clearSelection() const;
/*!
Find a filtered list of objects
@param filter The object filter (nullptr = find all objects)
@param tableID Optional table ID (defaults to the first table)
@param documentID Optional document ID (filter for this document only - nullopt = all objects)
@return A list containing IDs of found elements (empty if none found)
*/
BIMRecordIDList findElements(const Filter& filter = nullptr, std::optional<BIMRecordID> tableID = std::nullopt,
std::optional<BIMRecordID> documentID = std::nullopt) const;
/*!
Get a specified element
@param elementID The ID of the target element
@@ -66,9 +97,12 @@ namespace speckle::database {
std::unique_ptr<record::element::Element> getElement(const BIMLink& link) const { return getElement(link, link.tableID, link.docID); }
/*!
Get all model elements
@param tableID Optional table ID (defaults to the first table)
@param documentID Optional document ID (filter for this document only - nullopt = all objects)
@return All the elements
*/
active::container::Vector<record::element::Element> getElements() const;
active::container::Vector<record::element::Element> getElements(std::optional<BIMRecordID> tableID = std::nullopt,
std::optional<BIMRecordID> documentID = std::nullopt) const;
/*!
Get memo memo (supplementary) data for a specified element
@param elementID The of the source element
@@ -62,7 +62,7 @@ namespace speckle::database {
Get a link to the BIM record
@return The BIM record link
*/
BIMLink getBIMLink() const { return BIMLink{ BIMLink::base {m_applicationID, m_applicationTableID} }; }
virtual 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)
@@ -14,11 +14,8 @@ BIMLink::BIMLink(const API_Neig& selected, const BIMRecordID& tableID) : base{Gu
//More info should be extracted from API_Neig in future (as required) - extract into link settings, e.g. selection target etc
} //Link::Link
BIMLinkList::BIMLinkList(const ElementIDList& elementIDList) {
for (const auto& id : elementIDList)
push_back(id);
}
#endif
@@ -34,6 +34,7 @@ namespace speckle::database {
using Attribute = record::attribute::Attribute;
using Filter = base::Filter;
using Outline = base::Outline;
using ObjIDList = base::ObjIDList;
// MARK: - Constructors
@@ -51,6 +52,15 @@ namespace speckle::database {
// MARK: - Functions (const)
/*!
Find a filtered list of objects
@param filter The object filter (nullptr = find all objects)
@param tableID Optional table ID (defaults to the first table)
@param documentID Optional document ID (filter for this document only - nullopt = all objects)
@return A list containing IDs of found elements (empty if none found)
*/
virtual ObjIDList findObjects(const Filter& filter = nullptr, std::optional<BIMRecordID> tableID = std::nullopt,
std::optional<BIMRecordID> documentID = std::nullopt) const override { return {}; } //Implement when required
/*!
Get an object by ID
@param objID The object ID
@@ -64,7 +74,7 @@ namespace speckle::database {
@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)
@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;
/*!
@@ -16,6 +16,12 @@
#include "Speckle/Record/Element/Beam.h"
#include "Speckle/Record/Element/BeamSegment.h"
#include "Speckle/Record/Element/Memo.h"
#include "Speckle/Record/Element/MeshElem.h"
#include "Speckle/Record/Element/Morph.h"
#include "Speckle/Record/Element/Roof.h"
#include "Speckle/Record/Element/Shell.h"
#include "Speckle/Record/Element/Slab.h"
#include "Speckle/Record/Element/Wall.h"
#include "Speckle/Utility/Guid.h"
#include "Speckle/Utility/String.h"
@@ -35,14 +41,24 @@ using enum ArchicadDBaseCore::Status;
namespace {
//ID for the floor plan view
static const Guid primary2DViewID{String{"ddad27c0-c17b-4ad3-b76b-53d1e176d5ef"}};
//ID for the 3D view
static const Guid primary3DViewID{String{"ec368939-fb7d-4d8c-bc88-6d29806d9212"}};
/*!
Get information about a specified Archicad table
@param tableID The ID of the target table
@return The requested table info (nullopt on failure)
*/
std::optional<API_DatabaseInfo> getTableInfo(const BIMRecordID& tableID) {
API_DatabaseInfo dbaseInfo;
dbaseInfo.databaseUnId.elemSetId = tableID;
API_DatabaseInfo dbaseInfo{};
if (tableID == primary2DViewID)
dbaseInfo.typeID = APIWind_FloorPlanID;
else if (tableID == primary3DViewID)
dbaseInfo.typeID = APIWind_3DModelID;
else
dbaseInfo.databaseUnId.elemSetId = tableID;
if (auto err = ACAPI_Window_GetDatabaseInfo(&dbaseInfo); err == NoError)
return dbaseInfo;
return std::nullopt;
@@ -56,7 +72,7 @@ namespace {
*/
bool setActiveTable(const BIMRecordID& tableID) {
if (!tableID)
return false; //Null guid doens't point to anything
return false; //Null guid doesn't point to anything
if (auto activeTable = ArchicadElementDBaseEngine::getActiveTable(); activeTable && *activeTable == tableID)
return true;
auto dbaseInfo = getTableInfo(tableID);
@@ -82,6 +98,22 @@ namespace {
return std::make_unique<Beam>(elementData, tableID);
case API_BeamSegmentID:
return std::make_unique<BeamSegment>(elementData, tableID);
case API_MeshID:
return std::make_unique<Mesh>(elementData, tableID);
case API_MorphID:
return std::make_unique<Morph>(elementData, tableID);
case API_RoofID:
return std::make_unique<Roof>(elementData, tableID);
case API_ShellID:
return std::make_unique<Shell>(elementData, tableID);
case API_SlabID:
return std::make_unique<Slab>(elementData, tableID);
case API_WallID:
return std::make_unique<Wall>(elementData, tableID);
case API_ObjectID:
// POC: change this case once we are ready to convert Grid Elements
if (elementData.header.type.variationID == APIVarId_GridElement)
return nullptr;
default:
return std::make_unique<GenericModelElement>(elementData, tableID);
}
@@ -96,12 +128,34 @@ namespace {
std::optional<BIMRecordID> ArchicadElementDBaseEngine::getActiveTable() {
API_WindowInfo dbaseInfo;
active::utility::Memory::erase(dbaseInfo);
if (auto err = ACAPI_Database_GetCurrentDatabase(&dbaseInfo); err == NoError)
if (auto err = ACAPI_Database_GetCurrentDatabase(&dbaseInfo); err == NoError) {
if (dbaseInfo.typeID == APIWind_FloorPlanID)
return primary2DViewID;
else if (dbaseInfo.typeID == APIWind_3DModelID)
return primary3DViewID;
return dbaseInfo.databaseUnId.elemSetId;
}
return std::nullopt;
} //ArchicadElementDBaseEngine::getActiveTable
/*--------------------------------------------------------------------
Bring the view of this database to the front (i.e. so the user sees it)
tableID: The ID of the table to bring to the front
--------------------------------------------------------------------*/
void ArchicadElementDBaseEngine::bringViewToFront(BIMRecordID tableID) const {
auto dbaseInfo = getTableInfo(tableID);
if (!dbaseInfo)
return;
API_WindowInfo windowInfo{};
windowInfo.typeID = dbaseInfo->typeID;
if ((windowInfo.typeID != APIWind_FloorPlanID) && (windowInfo.typeID != APIWind_3DModelID))
windowInfo.databaseUnId = dbaseInfo->databaseUnId;
ACAPI_Window_ChangeWindow(&windowInfo);
} //ArchicadElementDBaseEngine::bringViewToFront
/*--------------------------------------------------------------------
Get the current user element selection
@@ -128,7 +182,7 @@ BIMLinkList ArchicadElementDBaseEngine::getSelection() const {
--------------------------------------------------------------------*/
void ArchicadElementDBaseEngine::setSelection(const BIMLinkList& elementIDs) const {
GS::Array<API_Neig> selNeigs;
for (const auto elemID : elementIDs) {
for (const auto& elemID : elementIDs) {
API_Neig neig(elemID);
selNeigs.Push(neig);
}
@@ -144,6 +198,73 @@ void ArchicadElementDBaseEngine::clearSelection() const {
} //ArchicadElementDBaseEngine::clearSelection
/*--------------------------------------------------------------------
Get the available dbase tables
targetType: An optional filtr for table type/group to retrieve
return: A list of available tables
--------------------------------------------------------------------*/
ArchicadElementDBaseEngine::TableIDList ArchicadElementDBaseEngine::getTables(std::optional<TableType> targetType) const {
using enum ElementStorage::TableType;
TableIDList result;
if (!targetType || (targetType == primary2D))
result.insert(primary2DViewID);
if (!targetType || (targetType == primary3D))
result.insert(primary3DViewID);
return result;
} //ArchicadElementDBaseEngine::getTables
/*--------------------------------------------------------------------
Get the default dbase table
return: The default dbase table (nullopt if no table is available)
--------------------------------------------------------------------*/
std::optional<BIMRecordID> ArchicadElementDBaseEngine::getDefaultTable() const {
return ArchicadElementDBaseEngine::getActiveTable();
} //ArchicadElementDBaseEngine::getDefaultTable
/*--------------------------------------------------------------------
Set the default dbase table
tableID: The new default dbase table
--------------------------------------------------------------------*/
void ArchicadElementDBaseEngine::setDefaultTable(const BIMRecordID& tableID) const {
setActiveTable(tableID);
} //ArchicadElementDBaseEngine::setDefaultTable
/*--------------------------------------------------------------------
Find a filtered list of objects
filter: The object filter (nullptr = find all objects)
tableID: Optional table ID (defaults to the first table)
documentID: Optional document ID (filter for this document only - nullopt = all objects)
return: A list containing IDs of found elements (empty if none found)
--------------------------------------------------------------------*/
BIMRecordIDList ArchicadElementDBaseEngine::findObjects(const Filter& filter, std::optional<BIMRecordID> tableID,
std::optional<BIMRecordID> documentID) const {
//Switch to the target table (when specified). Otherwise the currently active table will be used
if (tableID)
setActiveTable(*tableID);
//First check for no filter (in which case we return all objects)
if (filter == nullptr) {
GS::Array<API_Guid> found;
if ((ACAPI_Element_GetElemList({}, &found) != NoError) || found.IsEmpty())
return {};
BIMRecordIDList result;
for (const auto& item : found)
result.insert(item);
return result;
}
//Implement other filtering as required - ideally identify characteristics supported by API, e.g. filter by type/renovation etc
return {};
} //ArchicadElementDBaseEngine::findObjects
/*--------------------------------------------------------------------
Get an object by index
@@ -211,7 +332,19 @@ active::container::Vector<Element> ArchicadElementDBaseEngine::getObjects(std::o
std::optional<BIMRecordID> documentID) const {
if (tableID)
setActiveTable(*tableID);
return {}; //TODO: Implement
else {
//Use the active table if none is specified
tableID = getActiveTable();
if (!tableID)
return {};
}
//Retrieve the element objects to build the result
active::container::Vector<Element> result;
auto objectIDs = findObjects();
for (const auto& ID : objectIDs)
if (auto element = getObject(ID, tableID); element)
result.emplace_back(std::move(element));
return result;
} //ArchicadElementDBaseEngine::getObjects
@@ -4,6 +4,7 @@
#include "Active/Database/Storage/DBaseEngine.h"
#include "Active/Serialise/UnboxedTransport.h"
#include "Speckle/Database/Storage/ArchicadDBase/ArchicadDBaseCore.h"
#include "Speckle/Database/Storage/Element/ElementStorage.h"
#include "Speckle/Database/Identity/BIMLink.h"
#include "Speckle/Record/Element/Element.h"
#include "Speckle/Utility/Guid.h"
@@ -17,16 +18,17 @@ 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> {
class ArchicadElementDBaseEngine : public ArchicadDBaseCore, public ElementStorage,
public active::database::DBaseEngine<record::element::Element, BIMRecordID, BIMRecordID, BIMRecordID, ElementStorage::TableType> {
public:
// MARK: - Types
using base = active::database::DBaseEngine<record::element::Element, BIMRecordID, BIMRecordID, BIMRecordID>;
using Element = record::element::Element;
using Filter = base::Filter;
using Filter = ElementStorage::Filter;
using Outline = base::Outline;
using ObjIDList = base::ObjIDList;
// MARK: - Constants
@@ -53,6 +55,11 @@ namespace speckle::database {
// MARK: - Functions (const)
/*!
Bring the view of this database to the front (i.e. so the user sees it)
@param tableID The ID of the table to bring to the front
*/
void bringViewToFront(BIMRecordID tableID) const;
/*!
Get the current user element selection
@return A list of selected element IDs
@@ -66,6 +73,31 @@ namespace speckle::database {
Clear the element selection
*/
void clearSelection() const;
/*!
Get the available dbase tables
@param targetType An optional filtr for table type/group to retrieve
@return A list of available tables
*/
TableIDList getTables(std::optional<TableType> targetType) const override;
/*!
Get the default dbase table
@return The default dbase table (nullopt if no table is available)
*/
std::optional<BIMRecordID> getDefaultTable() const;
/*!
Set the default dbase table
@param tableID The new default dbase table
*/
void setDefaultTable(const BIMRecordID& tableID) const;
/*!
Find a filtered list of objects
@param filter The object filter (nullptr = find all objects)
@param tableID Optional table ID (defaults to the first table)
@param documentID Optional document ID (filter for this document only - nullopt = all objects)
@return A list containing IDs of found elements (empty if none found)
*/
virtual BIMRecordIDList findObjects(const Filter& filter = nullptr, std::optional<BIMRecordID> tableID = std::nullopt,
std::optional<BIMRecordID> documentID = std::nullopt) const override;
/*!
Get an object by index
@param objID The object ID
@@ -79,7 +111,7 @@ namespace speckle::database {
@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)
@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;
/*!
@@ -29,6 +29,7 @@ namespace speckle::database {
using Group = record::property::Group;
using Filter = base::Filter;
using Outline = base::Outline;
using ObjIDList = base::ObjIDList;
// MARK: - Constructors
@@ -46,6 +47,15 @@ namespace speckle::database {
// MARK: - Functions (const)
/*!
Find a filtered list of objects
@param filter The object filter (nullptr = find all objects)
@param tableID Optional table ID (defaults to the first table)
@param documentID Optional document ID (filter for this document only - nullopt = all objects)
@return A list containing IDs of found elements (empty if none found)
*/
virtual ObjIDList findObjects(const Filter& filter = nullptr, std::optional<BIMRecordID> tableID = std::nullopt,
std::optional<BIMRecordID> documentID = std::nullopt) const override { return {}; } //Implement when required
/*!
Get an object by ID
@param objID The object ID
@@ -59,7 +69,7 @@ namespace speckle::database {
@param objID The object ID
@param tableID Optional table ID (default selected based on record type)
@param documentID Optional document ID (when the object is bound to a specific document)
@return: The requested wrapped cargo (nullptr on failure)
@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;
/*!
@@ -30,6 +30,7 @@ namespace speckle::database {
using Template = record::property::Template;
using Filter = base::Filter;
using Outline = base::Outline;
using ObjIDList = base::ObjIDList;
// MARK: - Constructors
@@ -47,6 +48,15 @@ namespace speckle::database {
// MARK: - Functions (const)
/*!
Find a filtered list of objects
@param filter The object filter (nullptr = find all objects)
@param tableID Optional table ID (defaults to the first table)
@param documentID Optional document ID (filter for this document only - nullopt = all objects)
@return A list containing IDs of found elements (empty if none found)
*/
virtual ObjIDList findObjects(const Filter& filter = nullptr, std::optional<BIMRecordID> tableID = std::nullopt,
std::optional<BIMRecordID> documentID = std::nullopt) const override { return {}; } //Implement when required
/*!
Find all property templates linked to specified classifications
@param classifications The classifications
@@ -66,7 +76,7 @@ namespace speckle::database {
@param objID The object ID
@param tableID Optional table ID (default selected based on record type)
@param documentID Optional document ID (when the object is bound to a specific document)
@return: The requested wrapped cargo (nullptr on failure)
@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;
/*!
@@ -239,7 +239,7 @@ void DocumentStoreCore::writeStore() {
GS::HashTable<API_Guid, short> conflicts;
if (auto statusCode = convertArchicadError(ACAPI_AddOnObject_ReserveObjects({Guid{m_id.id}}, &conflicts)); statusCode != nominal)
throw std::system_error(makeError(statusCode));
//TODO: Implamenent handling for conflicts
//TODO: Implement handling for conflicts
}
auto toWrite = buildStore();
//Write the new data
@@ -46,6 +46,7 @@ namespace speckle::database {
using base = active::database::DBaseEngine<Obj, ObjID, RecordID, RecordID>;
using Filter = base::Filter;
using Outline = base::Outline;
using ObjIDList = base::ObjIDList;
using Cache = active::database::RecordCache<Obj, ObjWrapper, ObjID, RecordID, RecordID>;
// MARK: - Constructors
@@ -59,6 +60,15 @@ namespace speckle::database {
// MARK: - Functions (const)
/*!
Find a filtered list of objects
@param filter The object filter (nullptr = find all objects)
@param tableID Optional table ID (defaults to the first table)
@param documentID Optional document ID (filter for this document only - nullopt = all objects)
@return A list containing IDs of found elements (empty if none found)
*/
virtual ObjIDList findObjects(const Filter& filter = nullptr, std::optional<RecordID> tableID = std::nullopt,
std::optional<RecordID> documentID = std::nullopt) const override { return {}; } //Implement when required
/*!
Get an object by index
@param ID The object ID
@@ -72,7 +82,7 @@ namespace speckle::database {
@param ID The object ID
@param tableID Optional table ID (defaults to the first table)
@param documentID Optional document ID (when the object is bound to a specific document)
@return: The requested wrapped cargo (nullptr on failure)
@return The requested wrapped cargo (nullptr on failure)
*/
active::serialise::Cargo::Unique getObjectCargo(const ObjID& objID, std::optional<RecordID> tableID = std::nullopt, std::optional<RecordID> documentID = std::nullopt) const override;
/*!
@@ -171,8 +181,10 @@ namespace speckle::database {
//Read the data stored in the document
auto storedData = readStore();
m_cache = std::make_unique<Cache>();
if (!storedData)
if (!storedData) {
m_cache->setID(speckle::utility::Guid{true}.operator speckle::utility::String()); //Needs an ID - substitute for the Speckle 'document ID'
return m_cache.get(); //Return an empty container if there's no data
}
//Import the document data into the record cache
if constexpr (std::is_same_v<ObjWrapper, Obj>)
Transport().receive(std::forward<active::serialise::Cargo&&>(*m_cache), active::serialise::Identity{}, storedData);
@@ -0,0 +1,29 @@
#ifndef SPECKLE_DATABASE_ELEMENT_STORAGE
#define SPECKLE_DATABASE_ELEMENT_STORAGE
#include "Speckle/Record/Element/Element.h"
namespace speckle::database {
/*!
Fundamental concepts for element storage
*/
class ElementStorage {
public:
// MARK: - Types
///Element storage table types
enum class TableType {
primary2D,
primary3D,
section,
elevation,
};
///Element filter
using Filter = std::function<bool(const record::element::Element&)>;
};
}
#endif //SPECKLE_DATABASE_ELEMENT_STORAGE
+13 -1
View File
@@ -2,6 +2,7 @@
#include "Speckle/Environment/Project.h"
#include "Speckle/Event/Type/ProjectEvent.h"
#include "Speckle/Event/Subscriber/ProjectSubscriber.h"
#include <limits>
@@ -18,6 +19,14 @@ namespace {
//An object representing the active addon
Addon* m_addonInstance = nullptr;
///An instance of this class is used to force project notifications to be issued from the moment the add-on is launched
class DummyProjectSubscriber : public ProjectSubscriber {
public:
bool start() override { return ProjectSubscriber::start(); }
bool handle(const ProjectEvent& event) override { return false; }
};
}
/*--------------------------------------------------------------------
@@ -77,6 +86,7 @@ std::weak_ptr<Project> Addon::getActiveProject() const {
void Addon::publishExternal(const active::event::Event& event) {
if (!logCallback())
return;
++m_sessionCount;
try {
preprocessEvent(event);
publish(event);
@@ -120,6 +130,8 @@ bool Addon::attach() {
return: True if the participant is able to continue
--------------------------------------------------------------------*/
bool Addon::start() {
//Force project notifications to be published
DummyProjectSubscriber().start();
//Add add-on functionality as required
return App::start();
} //Addon::start
@@ -165,7 +177,7 @@ bool Addon::logCallback(bool initialise) {
return false;
}
return true;
} //Addon::publishExternalEvent
} //Addon::logCallback
/*--------------------------------------------------------------------
+8 -1
View File
@@ -40,7 +40,12 @@ namespace speckle::environment {
Get the active project
@return The active project (nullptr = no open project)
*/
std::weak_ptr<Project> getActiveProject() const;
virtual std::weak_ptr<Project> getActiveProject() const;
/*!
Get the session index
@return The session index (non-recursive entries into the add-on)
*/
uint32_t getSession() const { return m_sessionCount; }
// MARK: - Functions (mutating)
@@ -103,6 +108,8 @@ namespace speckle::environment {
std::shared_ptr<Project> m_activeProject;
///The depth of nested callbacks - the root call starts at depth 0 (important for some entry-point initialisation)
uint32_t m_callDepth = 0;
///The index of the active session (non-recursive entries into the add-on)
uint32_t m_sessionCount = 0;
};
+43
View File
@@ -0,0 +1,43 @@
#include "Speckle/Environment/Host.h"
#ifdef ARCHICAD
#include "DG.h"
#endif
using namespace speckle::utility;
using namespace speckle::environment;
namespace {
//An object representing the active host
Host m_hostInstance;
}
/*--------------------------------------------------------------------
Default constructor
--------------------------------------------------------------------*/
Host::Host() {
} //Host::Host
/*--------------------------------------------------------------------
Display an alert dialog
message: The alert message
--------------------------------------------------------------------*/
void Host::displayAlert(const String& message) const {
#ifdef ARCHICAD
DGAlert(DG_INFORMATION, "Notification", message.data(), "", "OK");
#endif
} //Host::displayAlert
/*--------------------------------------------------------------------
Get an object representing the parent process/application
return: The active application instance
--------------------------------------------------------------------*/
speckle::environment::Host* speckle::environment::host() {
return &m_hostInstance;
} //speckle::environment::host
+41
View File
@@ -0,0 +1,41 @@
#ifndef SPECKLE_ENVIRONMENT_HOST
#define SPECKLE_ENVIRONMENT_HOST
#include "Speckle/Utility/String.h"
namespace speckle::environment {
/*!
Class to represent a host application (for plugin contexts)
*/
class Host {
public:
// MARK: Constructors
/*!
Default constructor
*/
Host();
// MARK: Functions (const)
/*!
Display an alert dialog
@param message The alert message
*/
void displayAlert(const speckle::utility::String& message) const;
// MARK: Functions (mutating)
};
/*!
Get an object representing the host instance
@return The active host instance (nullptr if the host is not running)
*/
speckle::environment::Host* host();
}
#endif //SPECKLE_ENVIRONMENT_HOST
@@ -27,6 +27,22 @@ void Platform::writeToConsole(const active::utility::String& message) {
} //Platform::writeToConsole
/*--------------------------------------------------------------------
Open a URL
URL: The URL to open
--------------------------------------------------------------------*/
void Platform::openURL(const active::utility::String& URL) {
#if WINDOWS
std::system((String{"start "} + URL).data());
#elif __APPLE__
std::system((String{"open "} + URL).data());
#elif __linux__
std::system((String{"xdg-open"} + url).data());
#endif
} //Platform::openURL
/*--------------------------------------------------------------------
Get an object representing the parent process/application
@@ -18,6 +18,11 @@ namespace speckle::environment {
@param message The message to write
*/
void writeToConsole(const active::utility::String& message);
/*!
Open a URL
@param URL The URL to open
*/
void openURL(const active::utility::String& URL);
};
+1 -1
View File
@@ -48,7 +48,7 @@ namespace speckle::environment {
/*!
Destructor
*/
~Project();
virtual ~Project();
// MARK: - Functions (const)
@@ -0,0 +1,113 @@
#include "Speckle/Event/Subscriber/ElementSubscriber.h"
#include "Speckle/Environment/Addon.h"
#include "Speckle/Database/Identity/BIMLink.h"
#include "Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.h"
#include "Speckle/Event/Type/ElementEvent.h"
#ifdef ARCHICAD
#include <ACAPinc.h>
#endif
using namespace active::environment;
using namespace active::event;
using namespace speckle::database;
using namespace speckle::environment;
using namespace speckle::event;
namespace {
using enum ElementEvent::Type;
#ifdef ARCHICAD
/*!
Callback for an Archicad element change
@param elemType Info about the last changed element
*/
GSErrCode __ACENV_CALL elementChangedCallback(const API_NotifyElementType* elemType) {
if (addon() == nullptr)
return NoError;
// POC: can we do this switch smater?
switch (elemType->notifID)
{
case APINotifyElement_New: {
// POC: Put this back once we decide to use Object Tracking
// ACAPI_Element_AttachObserver(elemType->elemHead.guid);
addon()->publishExternal(ElementEvent{newElem, ElementID{elemType->elemHead.guid}});
} break;
case APINotifyElement_Change: {
addon()->publishExternal(ElementEvent{changeElem, ElementID{elemType->elemHead.guid}});
} break;
case APINotifyElement_Edit: {
addon()->publishExternal(ElementEvent{editElem, ElementID{elemType->elemHead.guid}});
} break;
case APINotifyElement_Delete: {
addon()->publishExternal(ElementEvent{deleteElem, ElementID{ elemType->elemHead.guid}});
} break;
case APINotifyElement_BeginEvents:
addon()->publishExternal(ElementEvent{begin});
break;
case APINotifyElement_EndEvents: {
addon()->publishExternal(ElementEvent{end});
} break;
default:
break;
}
return NoError;
}
#endif
}
/*--------------------------------------------------------------------
Get the event subscription list
return: The subscription list (an empty list will put the subscriber into a suspended state)
--------------------------------------------------------------------*/
Subscriber::Subscription ElementSubscriber::subscription() const {
return { {ElementEvent::ID} };
} //ElementSubscriber::subscription
/*--------------------------------------------------------------------
Receive a subscribed event
event: The incoming event
return: True if the event should be closed
--------------------------------------------------------------------*/
bool ElementSubscriber::receive(const Event& event) {
//Pass a menu event to the specified handler function
if (auto changeEvent = dynamic_cast<const ElementEvent*>(&event); changeEvent != nullptr)
return handle(*changeEvent);
return false;
} //ElementSubscriber::receive
/*--------------------------------------------------------------------
Start the participant operation
return: True if the participant is able to continue
--------------------------------------------------------------------*/
bool ElementSubscriber::start() {
#ifdef ARCHICAD
GSErrCode err = ACAPI_Element_InstallElementObserver(elementChangedCallback);
if (err != NoError)
return false;
return (ACAPI_Element_CatchNewElement(nullptr, elementChangedCallback) == NoError);
#else
return false;
#endif
} //ElementSubscriber::start
/*--------------------------------------------------------------------
Stop participation (release resources etc)
--------------------------------------------------------------------*/
void ElementSubscriber::stop() {
#ifdef ARCHICAD
ACAPI_Notification_CatchSelectionChange(nullptr);
#endif
} //ElementSubscriber::stop
@@ -0,0 +1,73 @@
#ifndef SPECKLE_EVENT_ELEMENT_CHANGED_SUBSCRIBER
#define SPECKLE_EVENT_ELEMENT_CHANGED_SUBSCRIBER
#include "Active/Event/Subscriber.h"
#include "Speckle/Database/Identity/RecordID.h"
namespace speckle::event {
class ElementEvent;
/*!
Base class for subscribers responding to element changes
*/
class ElementSubscriber : public virtual active::event::Subscriber {
public:
// MARK: - Constructors
/*!
Default constructor
*/
ElementSubscriber() = default;
/*!
Copy constructor
@param source The object to copy
*/
ElementSubscriber(const ElementSubscriber& source) = default;
/*!
Destructor
*/
~ElementSubscriber() = default;
// MARK: - Functions (const)
/*!
Get the event subscription list
@return The subscription list (an empty list will put the subscriber into a suspended state)
*/
Subscription subscription() const override;
// MARK: - Functions (mutating)
/*!
Receive a subscribed event
@param event The incoming event
@return True if the event should be closed
*/
bool receive(const active::event::Event& event) override;
/*!
Start the participant operation
@return True if the participant is able to continue
*/
virtual bool start() override;
/*!
Stop participation (release resources etc)
*/
void stop() override;
protected:
/*!
Handle an element change
@param event The element change event
@return True if the event should be closed
*/
virtual bool handle(const ElementEvent& event) = 0;
speckle::database::ElementIDList m_changedElements;
};
}
#endif //SPECKLE_EVENT_ELEMENT_CHANGED_SUBSCRIBER
@@ -81,4 +81,4 @@ void SelectionSubscriber::stop() {
#ifdef ARCHICAD
ACAPI_Notification_CatchSelectionChange(nullptr);
#endif
}
} //SelectionSubscriber::stop
@@ -0,0 +1,65 @@
#ifndef SPECKLE_EVENT_ELEMENT_EVENT
#define SPECKLE_EVENT_ELEMENT_EVENT
#include "Active/Event/Event.h"
#include "Active/Utility/Guid.h"
#include "Active/Utility/String.h"
namespace speckle::event {
/*!
Class representing an event signaling a database transaction operating on a BIM element, e.g. adding, editing, deleting etc
*/
class ElementEvent : public active::event::Event {
public:
enum Type {
newElem, ///<A new element has been created
begin, ///<An element database transaction has started - subsequent events will detail specific actions
end, ///<The current element database transaction has ended - any handling based on the transaction events should be fone now
changeElem, ///<An element has been changed
editElem, ///<An element has been edited
deleteElem ///<An element has been deleted
};
static const inline active::utility::NameID ID{active::utility::String{"element transaction"},
active::utility::Guid{active::utility::String{"ac9366d5-90fd-497e-b7f7-a7b4c8d97c91"}}};
// MARK: - Constructors
/*!
Constructor
@param eventType An event type identifier
@param targetID The ID of the element targeted by the database transaction (nullopt = undefined, e.g. for a begin/end event)
*/
ElementEvent(Type eventType, database::ElementID::Option targetID = std::nullopt) : Event{ID}, m_elementID{targetID}, m_eventType{eventType} {}
/*!
Copy constructor
@param source The object to copy
*/
ElementEvent(const ElementEvent& source) = default;
/*!
Destructor
*/
~ElementEvent() = default;
// MARK: - Functions (const)
/*!
Get the ID of the database transaction target element
@return The target element ID (nullopt = no target, e.g. a begin/end event)
*/
database::ElementID::Option getElmentID() const { return m_elementID; }
Type getEventType() const { return m_eventType; }
private:
///The ID of the target element (nullopt = undefined)
database::ElementID::Option m_elementID;
///The specific database operation performed
Type m_eventType;
};
}
#endif //SPECKLE_EVENT_ELEMENT_EVENT
@@ -62,12 +62,17 @@ namespace speckle::interfac::browser::bridge {
@return The number of parameters
*/
virtual uint32_t parameterCount() const { return 1; }
/*!
Get any error message relating to the arguments
@return The error message (nullopt if no errors occurred)
*/
speckle::utility::String::Option errorMessage() const { return m_errorMessage; }
/*!
Write the item data to a string
@param dest The string to write the data to
@return True if the data was successfully written
*/
bool write(active::utility::String& dest) const override { return true; }
/*!
Fill an inventory with the cargo items
@param inventory The inventory to receive the cargo items
@@ -83,6 +88,12 @@ namespace speckle::interfac::browser::bridge {
// MARK: - Functions (mutating)
/*!
Read the cargo data from the specified string
@param source The string to read
@return True if the data was successfully read
*/
bool read(const active::utility::String& source) override { return true; }
/*!
Set to the default package content
*/
@@ -121,12 +132,24 @@ namespace speckle::interfac::browser::bridge {
*/
JSArgType(const JSArgType& source) : BridgeArgument{source}, T{source} {}
/*!
/*!
Write the item data to a string
@param dest The string to write the data to
@return True if the data was successfully written
*/
bool write(active::utility::String& dest) const override { return true; }
/*!
Get the number of parameters in the argument
@return The number of parameters
*/
uint32_t parameterCount() const override { return Params; }
/*!
Read the cargo data from the specified string
@param source The string to read
@return True if the data was successfully read
*/
bool read(const active::utility::String& source) override { return true; }
/*!
Set to the default package content
*/
@@ -4,6 +4,7 @@
#include "Active/Serialise/JSON/JSONTransport.h"
#include "Active/Utility/BufferOut.h"
#include "Speckle/Interface/Browser/Bridge/BrowserBridge.h"
#include "Speckle/Record/Element/ModelElement.h"
#include <utility>
@@ -45,5 +46,6 @@ std::unique_ptr<WrappedResultArg> GetCallResult::getResult(const WrappedResultAr
return nullptr;
String jsonOutput;
JSONTransport().send(std::forward<Cargo&&>(*item), Identity{}, jsonOutput);
record::element::ModelElement::resetCache();
return std::make_unique<WrappedResultArg>(jsonOutput);
} //GetCallResult::getResult
+3 -2
View File
@@ -1,6 +1,7 @@
#include "Speckle/Primitive/Mesh/Mesh.h"
#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
#include "Active/Serialise/Item/Wrapper/FastDoubleWrap.h"
#include "Active/Serialise/Package/Wrapper/PackageWrap.h"
#include "Active/Serialise/Package/Wrapper/ContainerWrap.h"
#include "Active/Serialise/Inventory/Identity.h"
@@ -78,7 +79,7 @@ Cargo::Unique Mesh::getCargo(const Inventory::Item& item) const {
using namespace active::serialise;
switch (item.index) {
case vertexID:
return std::make_unique<ContainerWrap<std::vector<double>>>(m_vertices);
return std::make_unique<ContainerWrap<std::vector<double>, FastDoubleWrap>>(m_vertices);
case faceID:
return std::make_unique<ContainerWrap<std::vector<int>>>(m_faces);
case colorID:
@@ -98,6 +99,6 @@ 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());
collector->addFinishProxy(m_finish, getBIMID());
}
} //Mesh::useManagement
+10 -15
View File
@@ -3,10 +3,7 @@
#include "Speckle/Database/Content/BIMRecord.h"
#include "Speckle/Utility/String.h"
#ifdef ARCHICAD
#include "ModelMaterial.hpp"
#endif
#include "Speckle/Record/Attribute/Finish.h"
namespace speckle::primitive {
@@ -30,23 +27,23 @@ namespace speckle::primitive {
/*!
Constructor
@param unit The mesh unit type
@param material The mesh material
@param finish The mesh finish
*/
Mesh(const ModelerAPI::Material& material,
Mesh(const record::attribute::Finish& finish,
active::measure::LengthType unit = active::measure::LengthType::metre) :
base{ utility::Guid{true}, utility::Guid{}, unit }, m_material{ material } {}
base{ utility::Guid{true}, utility::Guid{}, unit }, m_finish{ finish } {}
/*!
Constructor
@param unit The mesh unit type
@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 material The mesh material
@param finish The mesh material
@param unit The mesh unit type
*/
Mesh(std::vector<double>&& vertices, std::vector<int>&& faces, std::vector<int>&& colors, const ModelerAPI::Material& material,
Mesh(std::vector<double>&& vertices, std::vector<int>&& faces, std::vector<int>&& colors, const record::attribute::Finish& finish,
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} {}
base{utility::Guid{true}, utility::Guid{}, unit}, m_vertices{std::move(vertices)}, m_faces{std::move(faces)}, m_colors{std::move(colors)}, m_finish{finish} {}
// MARK: - Functions (const)
/*!
@@ -85,9 +82,7 @@ namespace speckle::primitive {
std::vector<double> m_vertices;
std::vector<int> m_faces;
std::vector<int> m_colors;
#ifdef ARCHICAD
ModelerAPI::Material m_material;
#endif
record::attribute::Finish m_finish;
};
}
@@ -156,6 +156,22 @@ Finish::Finish(const Finish& source) : base{source} {
Finish::~Finish() {}
/*--------------------------------------------------------------------
Assignment operator
source: The object to assign
return: A reference to this
--------------------------------------------------------------------*/
Finish& Finish::operator=(const Finish& source) {
if (this != &source) {
base::operator=(source);
m_data = source.m_data ? std::make_unique<Data>(*source.m_data) : nullptr;
}
return *this;
} //Finish::operator=
#ifdef ARCHICAD
/*--------------------------------------------------------------------
Get the (immutable) API attribute header data
+9 -1
View File
@@ -77,7 +77,15 @@ namespace speckle::record::attribute {
@return A clone of this object
*/
Finish* clonePtr() const override { return new Finish{*this}; }
// MARK: - Operators
/*!
Assignment operator
@param source The object to assign
@return A reference to this
*/
Finish& operator=(const Finish& source);
// MARK: - Functions (const)
@@ -0,0 +1,196 @@
#include "Speckle/Record/Attribute/Material.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"
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 Material::Data {
public:
#ifdef ARCHICAD
/*!
Constructor from Archicad material
@param attr An Archicad attribute
*/
Data(const API_Attribute& attr) : root{attr.buildingMaterial} {
}
///Archicad representation of a building material
API_BuildingMaterialType root;
#endif
};
}
namespace {
///Serialisation fields
enum FieldIndex {
thermConductID,
//TODO: Add other fields as required
};
///Serialisation field IDs
static std::array fieldID = {
Identity{"thermalConductivity"},
//TODO: Add other fields as required
};
}
/*--------------------------------------------------------------------
Default constructor
--------------------------------------------------------------------*/
Material::Material() {
} //Material::Material
/*--------------------------------------------------------------------
Constructor
ID: The attribute ID
--------------------------------------------------------------------*/
Material::Material(const database::BIMRecordID& ID) : base{ID, Material::table} {
} //Material::Material
#ifdef ARCHICAD
/*--------------------------------------------------------------------
Constructor
attrData: Archicad attribute data
tableID: The ID of the parent table
--------------------------------------------------------------------*/
Material::Material(const API_Attribute& attrData, const BIMRecordID& tableID) : base{attrData.header.guid, Material::table} {
m_data = std::make_unique<Data>(attrData);
setUnit(std::nullopt); //Finishes have no unit
}
#endif
/*--------------------------------------------------------------------
Copy constructor
source: The object to copy
--------------------------------------------------------------------*/
Material::Material(const Material& source) : base{source} {
m_data = source.m_data ? std::make_unique<Data>(*source.m_data) : nullptr;
} //Material::Material
/*--------------------------------------------------------------------
Destructor
--------------------------------------------------------------------*/
Material::~Material() {}
/*--------------------------------------------------------------------
Assignment operator
source: The object to assign
return: A reference to this
--------------------------------------------------------------------*/
Material& Material::operator=(const Material& source) {
if (this != &source) {
base::operator=(source);
m_data = source.m_data ? std::make_unique<Data>(*source.m_data) : nullptr;
}
return *this;
} //Material::operator=
#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& Material::getHead() const {
confirmData();
return m_data->root.head;
} //Material::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& Material::getHead() {
confirmData();
return m_data->root.head;
} //Material::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 Material::fillInventory(Inventory& inventory) const {
using enum Entry::Type;
inventory.merge(Inventory{
{
{ fieldID[thermConductID], thermConductID, element },
},
}.withType(&typeid(Material)));
return base::fillInventory(inventory);
} //Material::fillInventory
/*--------------------------------------------------------------------
Get the specified cargo
item: The inventory item to retrieve
return: The requested cargo (nullptr on failure)
--------------------------------------------------------------------*/
Cargo::Unique Material::getCargo(const Inventory::Item& item) const {
if (item.ownerType != &typeid(Material))
return base::getCargo(item);
confirmData();
using namespace active::serialise;
switch (item.index) {
case thermConductID:
return std::make_unique<DoubleWrap>(m_data->root.thermalConductivity);
default:
return nullptr; //Requested an unknown index
}
} //Material::getCargo
/*--------------------------------------------------------------------
Set to the default package content
--------------------------------------------------------------------*/
void Material::setDefault() {
m_data->root = {};
} //Material::setDefault
/*--------------------------------------------------------------------
Confirm the internal data, either loading from the BIM application or setting a default
--------------------------------------------------------------------*/
void Material::confirmData() const {
if (m_data)
return;
m_data = std::make_unique<Data>(getData());
} //Material::confirmData
@@ -0,0 +1,143 @@
#ifndef SPECKLE_RECORD_ATTRIBUTE_MATERIAL
#define SPECKLE_RECORD_ATTRIBUTE_MATERIAL
#include "Speckle/Record/Attribute/Attribute.h"
#ifdef ARCHICAD
namespace ModelerAPI {
class Material;
}
#endif
namespace speckle::record::attribute {
/*!
Class to represent the construction material of a building element, e.g. concrete, timber, glass, stone etc
Note the difference with a Finish (which is only applied to the surface).
In Archicad this attribute is represented by `API_BuildingMaterialType`
*/
class Material : public Attribute {
public:
// MARK: - Types
using base = Attribute;
///Unique pointer
using Unique = std::unique_ptr<Material>;
///Shared pointer
using Shared = std::shared_ptr<Material>;
///Optional
using Option = std::optional<Material>;
// MARK: - Constants
#ifdef ARCHICAD
///The finishes table identifier
static constexpr active::utility::Guid table{active::utility::Guid::fromInt(API_BuildingMaterialID)};
#endif
// MARK: - Constructors
using base::base;
/*!
Default constructor
*/
Material();
/*!
Constructor
@param ID The attribute ID
*/
Material(const database::BIMRecordID& ID);
#ifdef ARCHICAD
/*!
Constructor
@param attrData Archicad attribute data
@param tableID The ID of the parent table
*/
Material(const API_Attribute& attrData, const database::BIMRecordID& tableID);
#endif
/*!
Copy constructor
@param source The object to copy
*/
Material(const Material& source);
/*!
Destructor
*/
~Material();
/*!
Object cloning
@return A clone of this object
*/
Material* clonePtr() const override { return new Material{*this}; }
// MARK: - Operators
/*!
Assignment operator
@param source The object to assign
@return A reference to this
*/
Material& operator=(const Material& source);
// 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.Material"; }
#ifdef ARCHICAD
/*!
Get the (immutable) API attribute header data
@return The attribute header data (only use this data for low-level operations - for normal code, call getters/setters)
*/
const API_Attr_Head& getHead() const override;
#endif
// MARK: - Functions (mutating)
#ifdef ARCHICAD
/*!
Get the (mutable) API attribute header data
@return The attribute header data (only use this data for low-level operations - for normal code, call getters/setters)
*/
API_Attr_Head& getHead() override;
#endif
// MARK: - Serialisation
/*!
Fill an inventory with the package items
@param inventory The inventory to receive the package items
@return True if the package has added items to the inventory
*/
bool fillInventory(active::serialise::Inventory& inventory) const override;
/*!
Get the specified cargo
@param item The inventory item to retrieve
@return The requested cargo (nullptr on failure)
*/
Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
/*!
Set to the default package content
*/
void setDefault() override;
private:
/*!
Confirm the internal data, either loading from the BIM application or setting a default
*/
void confirmData() const;
class Data;
///The attribute data - mutable to support lazy loading
mutable std::unique_ptr<Data> m_data;
};
}
#endif //SPECKLE_RECORD_ATTRIBUTE_MATERIAL
+4 -12
View File
@@ -1,15 +1,8 @@
#include "Speckle/Record/Element/Beam.h"
#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
#include "Active/Serialise/Package/Wrapper/PackageWrap.h"
#include "Active/Serialise/Package/Wrapper/ContainerWrap.h"
#include "Speckle/Environment/Addon.h"
#include "Speckle/Primitive/Mesh/Mesh.h"
#include "Speckle/SpeckleResource.h"
#include "Speckle/Utility/Guid.h"
using namespace active::serialise;
using namespace speckle::environment;
using namespace speckle::record::attribute;
using namespace speckle::record::element;
using namespace speckle::utility;
@@ -24,12 +17,11 @@ namespace speckle::record::element {
friend class Beam;
#ifdef ARCHICAD
Data(const API_Element& elem) : root{ std::make_unique<API_BeamType>(elem.beam) } {}
Data(const Data& source) : root{ std::make_unique<API_BeamType>(*source.root) } {}
Data(const API_Element& elem) : root{elem.beam} {}
#endif
private:
std::unique_ptr<API_BeamType> root;
API_BeamType root;
};
}
@@ -91,7 +83,7 @@ Beam::~Beam() {}
return: The element header data (only use this data for low-level operations - for normal code, call getters/setters)
--------------------------------------------------------------------*/
const API_Elem_Head& Beam::getHead() const {
return m_data->root->head;
return m_data->root.head;
} //Beam::getHead
/*--------------------------------------------------------------------
@@ -100,7 +92,7 @@ const API_Elem_Head& Beam::getHead() const {
return: The element header data (only use this data for low-level operations - for normal code, call getters/setters)
--------------------------------------------------------------------*/
API_Elem_Head& Beam::getHead() {
return m_data->root->head;
return m_data->root.head;
} //Beam::getHead
@@ -1,21 +1,17 @@
#include "Speckle/Record/Element/BeamSegment.h"
#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
#include "Active/Serialise/Package/Wrapper/PackageWrap.h"
#include "Active/Serialise/Package/Wrapper/ContainerWrap.h"
#include "Speckle/Environment/Addon.h"
#include "Speckle/Primitive/Mesh/Mesh.h"
#include "Speckle/SpeckleResource.h"
#include "Speckle/Utility/Guid.h"
#include "Speckle/Record/Element/Quants/Surveyor.h"
#include "Speckle/Record/Element/Setting/Conversion.h"
#include "Speckle/Utility/BIMMemory.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::record::element::quants;
using namespace speckle::utility;
#include <array>
@@ -28,11 +24,10 @@ namespace speckle::record::element {
friend class BeamSegment;
#ifdef ARCHICAD
Data(const API_BeamSegmentType& seg) : root{ std::make_unique<API_BeamSegmentType>(seg) } {}
Data(const Data& source) : root{ std::make_unique<API_BeamSegmentType>(*source.root) } {}
Data(const API_BeamSegmentType& seg) : root{seg} {}
private:
std::unique_ptr<API_BeamSegmentType> root;
API_BeamSegmentType root;
#endif
};
@@ -102,6 +97,46 @@ BeamSegment::BeamSegment(BeamSegment&& source) noexcept : base{source} {
BeamSegment::~BeamSegment() {}
/*--------------------------------------------------------------------
Get the composition of materials in the element
return: The material composition (element with ordered material composition should override)
--------------------------------------------------------------------*/
ModelElement::Composition BeamSegment::getComposition() const {
#ifdef ARCHICAD
return convert(m_data->root.assemblySegmentData.modelElemStructureType);
#endif
} //BeamSegment::getComposition
/*--------------------------------------------------------------------
Get the element material (applicable to elements with a single, homogenous material)
return: The element material (nullopt if not applicable to the element)
--------------------------------------------------------------------*/
std::optional<Material> BeamSegment::getMaterial() const {
#ifdef ARCHICAD
return Material{Guid{Guid::fromInt(m_data->root.assemblySegmentData.buildingMaterial.GenerateHashValue())}};
#endif
} //BeamSegment::getMaterial
/*--------------------------------------------------------------------
Get a spatial measurement from this element (area/volume, as used for material quantities)
return: The element measurement (empty if unavailable)
--------------------------------------------------------------------*/
ModelElement::SpatialMeasure BeamSegment::getSpatialMeasure() const {
#ifdef ARCHICAD
Surveyor surveyor;
BIMMemory::setMask(&surveyor.elementMask().beamSegment.rightSurface);
BIMMemory::setMask(&surveyor.elementMask().beamSegment.volume);
surveyor.measure(getBIMLink());
return SpatialMeasure{surveyor.quantity().beamSegment.rightSurface, surveyor.quantity().beamSegment.volume};
#endif
} //BeamSegment::getSpatialMeasure
#ifdef ARCHICAD
/*--------------------------------------------------------------------
Get the (immutable) API element header data
@@ -109,7 +144,7 @@ BeamSegment::~BeamSegment() {}
return: The element header data (only use this data for low-level operations - for normal code, call getters/setters)
--------------------------------------------------------------------*/
const API_Elem_Head& BeamSegment::getHead() const {
return m_data->root->head;
return m_data->root.head;
} //BeamSegment::getHead
@@ -119,7 +154,7 @@ const API_Elem_Head& BeamSegment::getHead() const {
return: The element header data (only use this data for low-level operations - for normal code, call getters/setters)
--------------------------------------------------------------------*/
API_Elem_Head& BeamSegment::getHead() {
return m_data->root->head;
return m_data->root.head;
} //BeamSegment::getHead
#endif
@@ -64,6 +64,21 @@ namespace speckle::record::element {
// MARK: - Functions (const)
/*!
Get the composition of materials in the element
@return The material composition (element with ordered material composition should override)
*/
Composition getComposition() const override;
/*!
Get the element material (applicable to elements with a single, homogenous material)
@return The element material (nullopt if not applicable to the element)
*/
std::optional<record::attribute::Material> getMaterial() const override;
/*!
Get a spatial measurement from this element (area/volume, as used for material quantities)
@return The element measurement (empty if unavailable)
*/
SpatialMeasure getSpatialMeasure() const override;
#ifdef ARCHICAD
/*!
Get the (immutable) API element header data
+4 -12
View File
@@ -1,15 +1,8 @@
#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;
@@ -24,12 +17,11 @@ namespace speckle::record::element {
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) } {}
Data(const API_Element& elem) : root{elem.column} {}
#endif
private:
std::unique_ptr<API_ColumnType> root;
API_ColumnType root;
};
}
@@ -91,7 +83,7 @@ Column::~Column() {}
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;
return m_data->root.head;
} //Column::getHead
/*--------------------------------------------------------------------
@@ -100,7 +92,7 @@ const API_Elem_Head& Column::getHead() const {
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;
return m_data->root.head;
} //Column::getHead
@@ -1,21 +1,17 @@
#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"
#include "Speckle/Record/Element/Quants/Surveyor.h"
#include "Speckle/Record/Element/Setting/Conversion.h"
#include "Speckle/Utility/BIMMemory.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::record::element::quants;
using namespace speckle::utility;
#include <array>
@@ -28,11 +24,10 @@ namespace speckle::record::element {
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) } {}
Data(const API_ColumnSegmentType& seg) : root{seg} {}
private:
std::unique_ptr<API_ColumnSegmentType> root;
API_ColumnSegmentType root;
#endif
};
@@ -102,6 +97,46 @@ ColumnSegment::ColumnSegment(ColumnSegment&& source) noexcept : base{source} {
ColumnSegment::~ColumnSegment() {}
/*--------------------------------------------------------------------
Get the composition of materials in the element
return: The material composition (element with ordered material composition should override)
--------------------------------------------------------------------*/
ModelElement::Composition ColumnSegment::getComposition() const {
#ifdef ARCHICAD
return convert(m_data->root.assemblySegmentData.modelElemStructureType);
#endif
} //ColumnSegment::getComposition
/*--------------------------------------------------------------------
Get the element material (applicable to elements with a single, homogenous material)
return: The element material (nullopt if not applicable to the element)
--------------------------------------------------------------------*/
std::optional<Material> ColumnSegment::getMaterial() const {
#ifdef ARCHICAD
return Material{Guid{Guid::fromInt(m_data->root.assemblySegmentData.buildingMaterial.GenerateHashValue())}};
#endif
} //ColumnSegment::getMaterial
/*--------------------------------------------------------------------
Get a spatial measurement from this element (area/volume, as used for material quantities)
return: The element measurement (empty if unavailable)
--------------------------------------------------------------------*/
ModelElement::SpatialMeasure ColumnSegment::getSpatialMeasure() const {
#ifdef ARCHICAD
Surveyor surveyor;
BIMMemory::setMask(&surveyor.elementMask().columnSegment.coreNetSurface);
BIMMemory::setMask(&surveyor.elementMask().columnSegment.volume);
surveyor.measure(getBIMLink());
return SpatialMeasure{surveyor.quantity().columnSegment.coreNetSurface, surveyor.quantity().columnSegment.volume};
#endif
} //ColumnSegment::getSpatialMeasure
#ifdef ARCHICAD
/*--------------------------------------------------------------------
Get the (immutable) API element header data
@@ -109,7 +144,7 @@ ColumnSegment::~ColumnSegment() {}
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;
return m_data->root.head;
} //ColumnSegment::getHead
@@ -119,7 +154,7 @@ const API_Elem_Head& ColumnSegment::getHead() const {
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;
return m_data->root.head;
} //ColumnSegment::getHead
#endif
@@ -64,6 +64,21 @@ namespace speckle::record::element {
// MARK: - Functions (const)
/*!
Get the composition of materials in the element
@return The material composition (element with ordered material composition should override)
*/
Composition getComposition() const override;
/*!
Get the element material (applicable to elements with a single, homogenous material)
@return The element material (nullopt if not applicable to the element)
*/
std::optional<record::attribute::Material> getMaterial() const override;
/*!
Get a spatial measurement from this element (area/volume, as used for material quantities)
@return The element measurement (empty if unavailable)
*/
SpatialMeasure getSpatialMeasure() const override;
#ifdef ARCHICAD
/*!
Get the (immutable) API element header data
@@ -1,15 +1,6 @@
#include "Speckle/Record/Element/DrawingElement.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;
+16 -5
View File
@@ -1,17 +1,14 @@
#include "Speckle/Record/Element/Element.h"
#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/Record/Element/Setting/TypeSetting.h"
#include "Speckle/SpeckleResource.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::record::element;
@@ -74,6 +71,20 @@ Storey::Option Element::getStorey() const {
} //Element::getStorey
/*--------------------------------------------------------------------
Get a link to the BIM record
return: The BIM record link
--------------------------------------------------------------------*/
BIMLink Element::getBIMLink() const {
auto result = base::getBIMLink();
#ifdef ARCHICAD
result.emplace_back(std::make_unique<TypeSetting>(getHead()));
#endif
return result;
} //Element::getLink
/*--------------------------------------------------------------------
Get the element type name, e.g. "Wall", "Roof" etc
@@ -71,6 +71,11 @@ namespace speckle::record::element {
@return The element storey (nullopt if the element isn't linked to a storey)
*/
virtual attribute::Storey::Option getStorey() const;
/*!
Get a link to the BIM record
@return The BIM record link
*/
database::BIMLink getBIMLink() const override;
#ifdef ARCHICAD
/*!
Get the (immutable) API element header data
@@ -1,15 +1,6 @@
#include "Speckle/Record/Element/GenericDrawingElement.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;
@@ -24,12 +15,11 @@ namespace speckle::record::element {
friend class GenericDrawingElement;
#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) } {}
Data(const API_Element& elem) : root{elem} {}
#endif
private:
std::unique_ptr<API_Element> root;
API_Element root;
};
}
@@ -75,7 +65,7 @@ GenericDrawingElement::~GenericDrawingElement() {}
return: The element header data (only use this data for low-level operations - for normal code, call getters/setters)
--------------------------------------------------------------------*/
const API_Elem_Head& GenericDrawingElement::getHead() const {
return m_data->root->header;
return m_data->root.header;
} //GenericDrawingElement::getHead
/*--------------------------------------------------------------------
@@ -84,7 +74,7 @@ const API_Elem_Head& GenericDrawingElement::getHead() const {
return: The element header data (only use this data for low-level operations - for normal code, call getters/setters)
--------------------------------------------------------------------*/
API_Elem_Head& GenericDrawingElement::getHead() {
return m_data->root->header;
return m_data->root.header;
} //GenericDrawingElement::getHead
#endif
@@ -1,15 +1,6 @@
#include "Speckle/Record/Element/GenericModelElement.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;
@@ -24,12 +15,11 @@ namespace speckle::record::element {
friend class GenericModelElement;
#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) } {}
Data(const API_Element& elem) : root{elem} {}
#endif
private:
std::unique_ptr<API_Element> root;
API_Element root;
};
}
@@ -75,7 +65,7 @@ GenericModelElement::~GenericModelElement() {}
return: The element header data (only use this data for low-level operations - for normal code, call getters/setters)
--------------------------------------------------------------------*/
const API_Elem_Head& GenericModelElement::getHead() const {
return m_data->root->header;
return m_data->root.header;
} //GenericModelElement::getHead
/*--------------------------------------------------------------------
@@ -84,7 +74,7 @@ const API_Elem_Head& GenericModelElement::getHead() const {
return: The element header data (only use this data for low-level operations - for normal code, call getters/setters)
--------------------------------------------------------------------*/
API_Elem_Head& GenericModelElement::getHead() {
return m_data->root->header;
return m_data->root.header;
} //GenericModelElement::getHead
#endif
@@ -0,0 +1,164 @@
#include "Speckle/Record/Element/MeshElem.h"
#include "Speckle/Record/Element/Quants/Surveyor.h"
#include "Speckle/Record/Element/Setting/Conversion.h"
#include "Speckle/Utility/BIMMemory.h"
#ifdef ARCHICAD
#include <ACAPinc.h>
#endif
using namespace active::serialise;
using namespace speckle::record::attribute;
using namespace speckle::record::element;
using namespace speckle::record::element::quants;
using namespace speckle::utility;
#include <array>
#include <memory>
namespace speckle::record::element {
class Mesh::Data {
public:
friend class Mesh;
#ifdef ARCHICAD
Data(const API_MeshType& seg) : root{seg} {}
private:
API_MeshType root;
#endif
};
}
/*--------------------------------------------------------------------
Default constructor
--------------------------------------------------------------------*/
Mesh::Mesh() {
} //Mesh::Mesh
#ifdef ARCHICAD
/*--------------------------------------------------------------------
Constructor
elemData: Archicad element data
tableID: The element table ID (AC database, e.g. floor plan, 3D)
--------------------------------------------------------------------*/
Mesh::Mesh(const API_Element& elemData, const speckle::utility::Guid& tableID) : base{ elemData.header.guid, tableID } {
m_data = std::make_unique<Data>(elemData.mesh);
} //Mesh::Mesh
#endif
/*--------------------------------------------------------------------
Copy constructor
source: The object to copy
--------------------------------------------------------------------*/
Mesh::Mesh(const Mesh& source) : base{ source } {
m_data = source.m_data ? std::make_unique<Data>(*source.m_data) : nullptr;
} //Mesh::Mesh
/*--------------------------------------------------------------------
Move constructor
source: The object to move
--------------------------------------------------------------------*/
Mesh::Mesh(Mesh&& source) noexcept : base{source} {
m_data = std::move(source.m_data);
} //Mesh::Mesh
/*--------------------------------------------------------------------
Destructor
--------------------------------------------------------------------*/
Mesh::~Mesh() {}
/*--------------------------------------------------------------------
Get the element material (applicable to elements with a single, homogenous material)
return: The element material (nullopt if not applicable to the element)
--------------------------------------------------------------------*/
std::optional<Material> Mesh::getMaterial() const {
#ifdef ARCHICAD
return Material{Guid{Guid::fromInt(m_data->root.buildingMaterial.GenerateHashValue())}};
#endif
} //Mesh::getMaterial
/*--------------------------------------------------------------------
Get a spatial measurement from this element (area/volume, as used for material quantities)
return: The element measurement (empty if unavailable)
--------------------------------------------------------------------*/
ModelElement::SpatialMeasure Mesh::getSpatialMeasure() const {
#ifdef ARCHICAD
Surveyor surveyor;
BIMMemory::setMask(&surveyor.elementMask().mesh.topSurface);
BIMMemory::setMask(&surveyor.elementMask().mesh.volume);
surveyor.measure(getBIMLink());
return SpatialMeasure{surveyor.quantity().mesh.topSurface, surveyor.quantity().mesh.volume};
#endif
} //Mesh::getSpatialMeasure
#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& Mesh::getHead() const {
return m_data->root.head;
} //Mesh::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& Mesh::getHead() {
return m_data->root.head;
} //Mesh::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 Mesh::fillInventory(Inventory& inventory) const {
using enum Entry::Type;
//TODO: Implement other fields as required
return base::fillInventory(inventory);
} //Mesh::fillInventory
/*--------------------------------------------------------------------
Get the specified cargo
item: The inventory item to retrieve
return: The requested cargo (nullptr on failure)
--------------------------------------------------------------------*/
Cargo::Unique Mesh::getCargo(const Inventory::Item& item) const {
//TODO: Implement other fields as required
return base::getCargo(item);
} //Mesh::getCargo
/*--------------------------------------------------------------------
Set to the default package content
--------------------------------------------------------------------*/
void Mesh::setDefault() {
m_data.reset();
} //Mesh::setDefault
@@ -0,0 +1,120 @@
#ifndef SPECKLE_RECORD_ELEMENT_MESH
#define SPECKLE_RECORD_ELEMENT_MESH
#include "Speckle/Record/Element/ModelElement.h"
#include "Speckle/Record/Element/Interface/Assembly/Segment.h"
namespace speckle::record::element {
/*!
BIM mesh class
*/
class Mesh : public ModelElement {
public:
// MARK: - Types
using base = ModelElement;
///Unique pointer
using Unique = std::unique_ptr<Mesh>;
///Shared pointer
using Shared = std::shared_ptr<Mesh>;
///Optional
using Option = std::optional<Mesh>;
// MARK: - Constructors
using base::base;
/*!
Default constructor
*/
Mesh();
#ifdef ARCHICAD
/*!
Constructor
@param elemData Archicad element data
@param tableID The element table ID (AC database, e.g. floor plan, 3D)
*/
Mesh(const API_Element& elemData, const speckle::utility::Guid& tableID);
#endif
/*!
Copy constructor
@param source The object to copy
*/
Mesh(const Mesh& source);
/*!
Move constructor
@param source The object to move
*/
Mesh(Mesh&& source) noexcept;
/*!
Destructor
*/
~Mesh();
/*!
Object cloning
@return A clone of this object
*/
Mesh* clonePtr() const override { return new Mesh{*this}; }
// MARK: - Functions (const)
/*!
Get the element material (applicable to elements with a single, homogenous material)
@return The element material (nullopt if not applicable to the element)
*/
std::optional<record::attribute::Material> getMaterial() const override;
/*!
Get a spatial measurement from this element (area/volume, as used for material quantities)
@return The element measurement (empty if unavailable)
*/
SpatialMeasure getSpatialMeasure() const override;
#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;
private:
class Data;
///The beam data
std::unique_ptr<Data> m_data;
};
}
#endif //SPECKLE_RECORD_ELEMENT_MESH
@@ -1,29 +1,31 @@
#include "Speckle/Record/Element/ModelElement.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/Record/Element/Memo.h"
#include "Speckle/Record/Property/Wrapper/PropertiedWrapper.h"
#include "Speckle/SpeckleResource.h"
#include "Speckle/Utility/Guid.h"
#include "Speckle/Utility/BIMMemory.h"
#ifdef ARCHICAD
#include <Sight.hpp>
#include <Model.hpp>
#include <ModelMaterial.hpp>
#include <ModelElement.hpp>
#include <exp.h>
#include <ModelMeshBody.hpp>
#include <AttributeIndex.hpp>
#include <ConvexPolygon.hpp>
#include <Model.hpp>
#include <ModelElement.hpp>
#include <ModelMaterial.hpp>
#include <ModelMeshBody.hpp>
#include <Sight.hpp>
#endif
using namespace active::measure;
using namespace active::serialise;
using namespace speckle::database;
using namespace speckle::environment;
using namespace speckle::record::attribute;
using namespace speckle::record::element;
using namespace speckle::record::element::quants;
using namespace speckle::record::property;
using namespace speckle::utility;
@@ -45,6 +47,40 @@ namespace speckle::record::element {
std::unique_ptr<ModelElement::Body> m_cache;
};
/*!
Cache for materials in Archicad
NB: This has been implemented because looking up materials through the API is very slow (can easily triple processing time)
This can be eliminated in future if this problem is remedied
*/
class ModelElement::FinishCache : public std::unordered_map<Guid, Finish> {
public:
using base = std::unordered_map<Guid, Finish>;
using base::base;
FinishCache() : base{} { activeSession = addon()->getSession(); }
///The active session value when the cache was created - enables the content to be reset between sessions
uint32_t activeSession = 0;
/*!
Validate the cache (ensure matches the active session)
@return True if the content is valid
*/
bool validate() {
if (activeSession != addon()->getSession()) {
m_finishCache.reset();
return false;
}
return true;
}
};
///Allocation for the ModelElement finishes cache (used because repeated API access is very slow)
std::unique_ptr<ModelElement::FinishCache> ModelElement::m_finishCache;
}
namespace {
@@ -52,15 +88,99 @@ namespace {
///Serialisation fields
enum FieldIndex {
bodyID,
materialQuantsID,
propertyID,
};
///Serialisation field IDs
static std::array fieldID = {
Identity{"displayValue"},
Identity{"materialQuantities"},
Identity{"properties"},
};
#ifdef ARCHICAD
/*!
Collect the IDs of individual parts from an assembly (e.g. stair, curtain wall)
@param parts A pointer to the assembly parts
@param partIDs The assembly part IDs
*/
template<typename T>
void getPartIDs(T* parts, std::set<API_Guid>& partIDs) {
GSSize nSubElements = BMGetPtrSize(reinterpret_cast<GSPtr>(parts)) / sizeof(T);
for (Int32 idx = 0; idx < nSubElements; ++idx)
partIDs.insert(parts[idx].head.guid);
}
/*!
Measure material quantities from the composite materials of a specified element
@param guid The ID of the element to measure
@param elementQuantity Quantities extracted from the target element (out)
@param extendedQuantity Optional extended quantities calculated for some element types
@param quantityMask Mask to determine which quantities are required (minimise calculation time)
*/
void measureQuantities(const API_Guid& guid, API_ElementQuantity& elementQuantity,
API_Quantities& extendedQuantity, const API_QuantitiesMask& quantityMask) {
extendedQuantity.elements = &elementQuantity;
GS::Array<API_ElemPartQuantity> elementPartQuantities;
API_QuantityPar quantityParameters{};
quantityParameters.minOpeningSize = Eps;
ACAPI_Element_GetQuantities(guid, &quantityParameters, &extendedQuantity, &quantityMask);
} //measureQuantities
/*!
Collect the IDs of individual parts from an element (e.g. stair, curtain wall)
@param elemId The element to collect part IDs from
@param typeID The element type identifier
@param memo The element memo data
*/
std::set<API_Guid> collectPartIDs(const API_Guid& elemId, API_ElemTypeID typeID, const Memo& memo) {
std::set<API_Guid> partIDs{};
partIDs.insert(elemId);
if (!memo)
return partIDs;
switch (typeID) {
case API_StairID:
getPartIDs(memo.root()->stairRisers, partIDs);
getPartIDs(memo.root()->stairTreads, partIDs);
getPartIDs(memo.root()->stairStructures, partIDs);
break;
case API_RailingID:
getPartIDs(memo.root()->railingSegments, partIDs);
getPartIDs(memo.root()->railingPatterns, partIDs);
getPartIDs(memo.root()->railingRails, partIDs);
getPartIDs(memo.root()->railingHandrails, partIDs);
getPartIDs(memo.root()->railingToprails, partIDs);
getPartIDs(memo.root()->railingBalusterSets, partIDs);
getPartIDs(memo.root()->railingBalusters, partIDs);
getPartIDs(memo.root()->railingPanels, partIDs);
getPartIDs(memo.root()->railingInnerPosts, partIDs);
getPartIDs(memo.root()->railingNodes, partIDs);
getPartIDs(memo.root()->railingRailConnections, partIDs);
getPartIDs(memo.root()->railingHandrailConnections, partIDs);
getPartIDs(memo.root()->railingToprailConnections, partIDs);
getPartIDs(memo.root()->railingPosts, partIDs);
getPartIDs(memo.root()->railingRailEnds, partIDs);
getPartIDs(memo.root()->railingHandrailEnds, partIDs);
getPartIDs(memo.root()->railingToprailEnds, partIDs);
break;
case API_CurtainWallID:
getPartIDs(memo.root()->cWallSegments, partIDs);
getPartIDs(memo.root()->cWallFrames, partIDs);
getPartIDs(memo.root()->cWallPanels, partIDs);
getPartIDs(memo.root()->cWallJunctions, partIDs);
getPartIDs(memo.root()->cWallAccessories, partIDs);
break;
default:
break;
}
return partIDs;
}
#endif
}
/*--------------------------------------------------------------------
@@ -97,6 +217,89 @@ ModelElement::ModelElement(const ModelElement& source) : base{source}, Classifie
ModelElement::~ModelElement() {}
/*--------------------------------------------------------------------
Get mesh finish from the cache
finishID: The finish ID
return: A pointer to the requested material (nullptr on failure)
--------------------------------------------------------------------*/
Finish* ModelElement::getFinish(const Guid& finishID) {
if (!m_finishCache || !m_finishCache->validate())
return nullptr;
if (auto iter = m_finishCache->find(finishID); iter != m_finishCache->end())
return &iter->second;
return nullptr;
} //ModelElement::getFinish
/*--------------------------------------------------------------------
Add a mesh finish to the cache
finishID: The finish ID
finish: The mesh finish
--------------------------------------------------------------------*/
Finish* ModelElement::cacheFinish(const Guid& finishID, const Finish& finish) {
if (!m_finishCache || !m_finishCache->validate())
m_finishCache = std::make_unique<ModelElement::FinishCache>();
return &m_finishCache->insert({finishID, finish}).first->second;
} //ModelElement::cacheFinish
/*--------------------------------------------------------------------
Reset the Archicad material cache
--------------------------------------------------------------------*/
void ModelElement::resetCache() {
m_finishCache.reset();
} //ModelElement::resetCache
/*--------------------------------------------------------------------
Get material quantities measured from this element
return: An list of material quantities
--------------------------------------------------------------------*/
MaterialQuantityList ModelElement::getMaterialQuantities() const {
using enum Composition;
MaterialQuantityList result;
switch (getComposition()) {
case unordered: {
//Get the material and spatial measurements
auto material = getMaterial();
if (!material)
return result;
auto spatialMeasure = getSpatialMeasure();
if (!spatialMeasure)
return result;
//Create a material quantity from the quantity takeoff
result.push_back({material->getBIMID(), spatialMeasure.area, spatialMeasure.volume});
break;
}
case skinned: {
#ifdef ARCHICAD
API_ElementQuantity elementQuantity{};
API_Quantities extendedQuantity{};
GS::Array<API_CompositeQuantity> compositeQuantity{};
extendedQuantity.composites = &compositeQuantity;
API_QuantitiesMask quantityMask{};
//Set the appropriate masks for composite material volume/area quantity takeoffs
BIMMemory::setMask(&quantityMask.composites.buildMatIndices);
BIMMemory::setMask(&quantityMask.composites.volumes);
BIMMemory::setMask(&quantityMask.composites.projectedArea);
measureQuantities(getHead().guid, elementQuantity, extendedQuantity, quantityMask);
//Create material quantities from the quantity takeoff (one oer skin in the composite structure)
for (auto& skinQuant : compositeQuantity)
result.push_back({Guid{Guid::fromInt(skinQuant.buildMatIndices.GenerateHashValue())}, skinQuant.projectedArea, skinQuant.volumes});
#endif
break;
}
case profiled:
break;
}
return result;
} //ModelElement::getMaterialQuantities
/*--------------------------------------------------------------------
Get the element body as a list of faces or Meshes
@@ -104,89 +307,79 @@ ModelElement::~ModelElement() {}
--------------------------------------------------------------------*/
ModelElement::Body* ModelElement::getBody() const {
#ifdef ARCHICAD
if (m_data && m_data->m_cache) {
if (m_data && m_data->m_cache)
return m_data->m_cache.get();
}
void* dummy = nullptr;
GSErrCode err = ACAPI_Sight_GetCurrentWindowSight(&dummy);
if (err != NoError)
{
if (err != NoError) {
// TODO: should this throw?
}
Modeler::SightPtr currentSightPtr((Modeler::Sight*)dummy); // init the shared ptr with the raw pointer
ModelerAPI::Model acModel;
Modeler::IAttributeReader* attrReader = ACAPI_Attribute_GetCurrentAttributeSetReader();
err = EXPGetModel(currentSightPtr, &acModel, attrReader);
if (err != NoError)
{
if (err != NoError) {
// TODO: should this throw?
}
auto elementBody = new ModelElement::Body();
// Map to collect meshes per material name
std::map<GS::UniString, primitive::Mesh> materialMeshMap;
std::unordered_map<String, primitive::Mesh> materialMeshMap;
std::unique_ptr<Memo> memo;
loadMemo(APIMemoMask_All, memo);
auto partIDs = collectPartIDs(getHead().guid, getHead().type.typeID, *memo);
memo.reset();
Int32 nElements = acModel.GetElementCount();
for (Int32 iElement = 1; iElement <= nElements; iElement++)
{
for (Int32 iElement = 1; iElement <= nElements; iElement++) {
ModelerAPI::Element elem{};
acModel.GetElement(iElement, &elem);
if (elem.GetElemGuid() != getHead().guid)
API_Guid apiGuid{GSGuid2APIGuid(elem.GetElemGuid())};
if (partIDs.find(apiGuid) == partIDs.end())
continue;
Int32 nBodies = elem.GetTessellatedBodyCount();
for (Int32 bodyIndex = 1; bodyIndex <= nBodies; ++bodyIndex)
{
ModelerAPI::Material material{};
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)
{
for (Int32 polyIndex = 1; polyIndex <= polyCount; ++polyIndex) {
ModelerAPI::Polygon polygon{};
body.GetPolygon(polyIndex, &polygon);
ModelerAPI::Material material{};
polygon.GetMaterial(&material);
auto materialName = material.GetName();
if (materialMeshMap.find(materialName) == materialMeshMap.end()) {
materialMeshMap[materialName] = primitive::Mesh(material);
ModelerAPI::AttributeIndex attrIndex{};
polygon.GetMaterialIndex(attrIndex);
Guid finishID{Guid::fromInt(attrIndex.GetIndex())};
auto faceFinish = ModelElement::getFinish(finishID);
if (faceFinish == nullptr) {
ModelerAPI::Material material{};
polygon.GetMaterial(&material);
Finish finish{material};
faceFinish = ModelElement::cacheFinish(finishID, finish);
}
auto materialName = faceFinish->getName();
if (materialMeshMap.find(materialName) == materialMeshMap.end())
materialMeshMap[materialName] = primitive::Mesh(*faceFinish);
Int32 convexPolyCount = polygon.GetConvexPolygonCount();
for (Int32 convPolyIndex = 1; convPolyIndex <= convexPolyCount; ++convPolyIndex)
{
for (Int32 convPolyIndex = 1; convPolyIndex <= convexPolyCount; ++convPolyIndex) {
std::vector<double> vertices;
ModelerAPI::ConvexPolygon convexPolygon{};
polygon.GetConvexPolygon(convPolyIndex, &convexPolygon);
Int32 vertexCount = convexPolygon.GetVertexCount();
for (Int32 vertexIndex = 1; vertexIndex <= vertexCount; ++vertexIndex)
{
for (Int32 vertexIndex = 1; vertexIndex <= vertexCount; ++vertexIndex) {
ModelerAPI::Vertex vertex{};
body.GetVertex(convexPolygon.GetVertexIndex(vertexIndex), &vertex);
// Collect vertices (as doubles for now, but should be changed to Vertex type)
// Collect vertices (as doubles for now, but should be changed to Vertex type)
vertices.push_back(vertex.x);
vertices.push_back(vertex.y);
vertices.push_back(vertex.z);
}
materialMeshMap[materialName].appendFace(std::move(vertices));
}
}
}
}
for (auto& [materialName, mesh] : materialMeshMap)
{
for (auto& [materialName, mesh] : materialMeshMap)
elementBody->push_back(std::move(mesh));
}
m_data = std::make_unique<Data>();
m_data->m_cache.reset(elementBody);
return m_data->m_cache.get();
@@ -206,6 +399,7 @@ bool ModelElement::fillInventory(Inventory& inventory) const {
inventory.merge(Inventory{
{
{ fieldID[bodyID], bodyID, element },
{ fieldID[materialQuantsID], materialQuantsID, element },
{ fieldID[propertyID], propertyID, element },
},
}.withType(&typeid(ModelElement)));
@@ -227,9 +421,12 @@ Cargo::Unique ModelElement::getCargo(const Inventory::Item& item) const {
switch (item.index) {
case bodyID:
if (auto body = getBody(); body != nullptr)
return Cargo::Unique{ new active::serialise::ContainerWrap{*body} };
else
return nullptr;
return Cargo::Unique{new active::serialise::ContainerWrap{*body}};
return nullptr;
case materialQuantsID:
if (auto quants = getMaterialQuantities(); !quants.empty())
return Cargo::Unique{new CargoHold<ContainerWrap<MaterialQuantityList>, MaterialQuantityList>{quants}};
return nullptr;
case propertyID:
return std::make_unique<PropertiedWrapper>(*this);
default:
@@ -1,11 +1,17 @@
#ifndef SPECKLE_RECORD_MODEL_ELEMENT
#define SPECKLE_RECORD_MODEL_ELEMENT
#include "Speckle/Record/Attribute/Material.h"
#include "Speckle/Record/Classification/Classified.h"
#include "Speckle/Record/Element/Element.h"
#include "Speckle/Record/Element/Element.h"
#include "Speckle/Record/Element/Quants/MaterialQuantity.h"
#include "Speckle/Record/Property/Propertied.h"
namespace speckle::record::attribute {
class Finish;
class Material;
}
namespace speckle::record::element {
/*!
@@ -25,7 +31,42 @@ namespace speckle::record::element {
using Option = std::optional<ModelElement>;
///A model element 3D body primitive
using Body = std::vector<primitive::Mesh>;
//Material composition
enum class Composition {
unordered, ///<Element is composed of materials with no fixed relationship
skinned, ///<Element is composed of layered materials 'skins', e.g. brick/air/insulation/block in a wall
profiled, ///<Element is composed of materials extruded through a profile along a space-curve, e.g. window frames
};
///Model element spatial measurements
struct SpatialMeasure {
///Element area
double area = 0.0;
///Element volume
double volume = 0.0;
///True if either a volume or area has been measured
operator bool() const { return active::math::isGreaterZero(area) || active::math::isGreaterZero(volume); }
};
// MARK: - Static functions
/*!
Get a mesh finish from the cache
@param finishID A finish ID
@return A pointer to the requested finish (nullptr on failure)
*/
static record::attribute::Finish* getFinish(const utility::Guid& finishID);
/*!
Add a mesh finish to the cache
@param finishID A finish ID
@param finish The mesh finish
@return A pointer to the cached finish
*/
static record::attribute::Finish* cacheFinish(const utility::Guid& finishID, const record::attribute::Finish& finish);
/*!
Reset the Archicad material cache
*/
static void resetCache();
// MARK: - Constructors
using base::base;
@@ -55,6 +96,26 @@ namespace speckle::record::element {
// MARK: - Functions (const)
/*!
Get the composition of materials in the element
@return The material composition (element with ordered material composition should override)
*/
virtual Composition getComposition() const { return Composition::unordered; }
/*!
Get the element material (applicable to elements with a single, homogenous material)
@return The element material (nullopt if not applicable to the element)
*/
virtual std::optional<record::attribute::Material> getMaterial() const { return std::nullopt; }
/*!
Get a spatial measurement from this element (area/volume, as used for material quantities)
@return The element measurement (empty if unavailable)
*/
virtual SpatialMeasure getSpatialMeasure() const { return SpatialMeasure{}; }
/*!
Get material quantities measured from this element
@return An list of material quantities
*/
quants::MaterialQuantityList getMaterialQuantities() const;
/*!
Get the element body
@return An array of meshes from the element body (nullptr if no body data is available)
@@ -87,6 +148,9 @@ namespace speckle::record::element {
class Data;
///The element data
mutable std::unique_ptr<Data> m_data;
class FinishCache;
///Cached finishes (API lookup is very slow)
static std::unique_ptr<FinishCache> m_finishCache;
};
}
+164
View File
@@ -0,0 +1,164 @@
#include "Speckle/Record/Element/Morph.h"
#include "Speckle/Record/Element/Quants/Surveyor.h"
#include "Speckle/Record/Element/Setting/Conversion.h"
#include "Speckle/Utility/BIMMemory.h"
#ifdef ARCHICAD
#include <ACAPinc.h>
#endif
using namespace active::serialise;
using namespace speckle::record::attribute;
using namespace speckle::record::element;
using namespace speckle::record::element::quants;
using namespace speckle::utility;
#include <array>
#include <memory>
namespace speckle::record::element {
class Morph::Data {
public:
friend class Morph;
#ifdef ARCHICAD
Data(const API_MorphType& seg) : root{seg} {}
private:
API_MorphType root;
#endif
};
}
/*--------------------------------------------------------------------
Default constructor
--------------------------------------------------------------------*/
Morph::Morph() {
} //Morph::Morph
#ifdef ARCHICAD
/*--------------------------------------------------------------------
Constructor
elemData: Archicad element data
tableID: The element table ID (AC database, e.g. floor plan, 3D)
--------------------------------------------------------------------*/
Morph::Morph(const API_Element& elemData, const speckle::utility::Guid& tableID) : base{ elemData.header.guid, tableID } {
m_data = std::make_unique<Data>(elemData.morph);
} //Morph::Morph
#endif
/*--------------------------------------------------------------------
Copy constructor
source: The object to copy
--------------------------------------------------------------------*/
Morph::Morph(const Morph& source) : base{ source } {
m_data = source.m_data ? std::make_unique<Data>(*source.m_data) : nullptr;
} //Morph::Morph
/*--------------------------------------------------------------------
Move constructor
source: The object to move
--------------------------------------------------------------------*/
Morph::Morph(Morph&& source) noexcept : base{source} {
m_data = std::move(source.m_data);
} //Morph::Morph
/*--------------------------------------------------------------------
Destructor
--------------------------------------------------------------------*/
Morph::~Morph() {}
/*--------------------------------------------------------------------
Get the element material (applicable to elements with a single, homogenous material)
return: The element material (nullopt if not applicable to the element)
--------------------------------------------------------------------*/
std::optional<Material> Morph::getMaterial() const {
#ifdef ARCHICAD
return Material{Guid{Guid::fromInt(m_data->root.buildingMaterial.GenerateHashValue())}};
#endif
} //Morph::getMaterial
/*--------------------------------------------------------------------
Get a spatial measurement from this element (area/volume, as used for material quantities)
return: The element measurement (empty if unavailable)
--------------------------------------------------------------------*/
ModelElement::SpatialMeasure Morph::getSpatialMeasure() const {
#ifdef ARCHICAD
Surveyor surveyor;
BIMMemory::setMask(&surveyor.elementMask().morph.surface);
BIMMemory::setMask(&surveyor.elementMask().morph.volume);
surveyor.measure(getBIMLink());
return SpatialMeasure{surveyor.quantity().morph.surface, surveyor.quantity().morph.volume};
#endif
} //Morph::getSpatialMeasure
#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& Morph::getHead() const {
return m_data->root.head;
} //Morph::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& Morph::getHead() {
return m_data->root.head;
} //Morph::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 Morph::fillInventory(Inventory& inventory) const {
using enum Entry::Type;
//TODO: Implement other fields as required
return base::fillInventory(inventory);
} //Morph::fillInventory
/*--------------------------------------------------------------------
Get the specified cargo
item: The inventory item to retrieve
return: The requested cargo (nullptr on failure)
--------------------------------------------------------------------*/
Cargo::Unique Morph::getCargo(const Inventory::Item& item) const {
//TODO: Implement other fields as required
return base::getCargo(item);
} //Morph::getCargo
/*--------------------------------------------------------------------
Set to the default package content
--------------------------------------------------------------------*/
void Morph::setDefault() {
m_data.reset();
} //Morph::setDefault
+120
View File
@@ -0,0 +1,120 @@
#ifndef SPECKLE_RECORD_ELEMENT_MORPH
#define SPECKLE_RECORD_ELEMENT_MORPH
#include "Speckle/Record/Element/ModelElement.h"
#include "Speckle/Record/Element/Interface/Assembly/Segment.h"
namespace speckle::record::element {
/*!
BIM morph class
*/
class Morph : public ModelElement {
public:
// MARK: - Types
using base = ModelElement;
///Unique pointer
using Unique = std::unique_ptr<Morph>;
///Shared pointer
using Shared = std::shared_ptr<Morph>;
///Optional
using Option = std::optional<Morph>;
// MARK: - Constructors
using base::base;
/*!
Default constructor
*/
Morph();
#ifdef ARCHICAD
/*!
Constructor
@param elemData Archicad element data
@param tableID The element table ID (AC database, e.g. floor plan, 3D)
*/
Morph(const API_Element& elemData, const speckle::utility::Guid& tableID);
#endif
/*!
Copy constructor
@param source The object to copy
*/
Morph(const Morph& source);
/*!
Move constructor
@param source The object to move
*/
Morph(Morph&& source) noexcept;
/*!
Destructor
*/
~Morph();
/*!
Object cloning
@return A clone of this object
*/
Morph* clonePtr() const override { return new Morph{*this}; }
// MARK: - Functions (const)
/*!
Get the element material (applicable to elements with a single, homogenous material)
@return The element material (nullopt if not applicable to the element)
*/
std::optional<record::attribute::Material> getMaterial() const override;
/*!
Get a spatial measurement from this element (area/volume, as used for material quantities)
@return The element measurement (empty if unavailable)
*/
SpatialMeasure getSpatialMeasure() const override;
#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;
private:
class Data;
///The beam data
std::unique_ptr<Data> m_data;
};
}
#endif //SPECKLE_RECORD_ELEMENT_MORPH

Some files were not shown because too many files have changed in this diff Show More